In der Firma, in der ich arbeite, ist mir ein Malheur passiert, und zwar beim Testen der von mir geschriebenen Software. Ich will (vielleicht darf) ich keine Details verraten, aber es geht um ein Programm, welches ein anderes Programm startet, überwacht und beendet. Nichts Großes, nichts Kompliziertes. Eine Sache muss man aber wissen: das Programm, an dem ich arbeite und das Programm, dass von meinem gestartet wird, soll auf macOS arm64 und macOS amd64 laufen und ist keine Fat-Binary, was bedeutet, dass es für die jeweilige Plattform immer ein Bundle gibt.
Jetzt ging es zum Glück nur um eine Testversion, die ich meinen Kollegen zum Ausprobieren geben wollte. Ich packte mein Programm also, zusammen mit dem Fremdprogramm. Einmal für macOS amd64, einmal für macOS arm64 (und noch weitere Plattformen). Faul, wie ich bin, hatte ich dafür ein Script geschrieben. Leider habe ich nicht weit genug automatisiert, denn hier passierte das Problem: Ich packte mein Programm für amd64 und das Fremdprogramm für arm64. Bevor ich meine Software zum Testen herausgebe, probiere ich diese immer einmal aus, zumindest im kleinen Rahmen. Eine CI-CD-Pipeline gab es in dem frühen Entwicklungsstadium leider noch nicht (Das ist ein Fehler! Kümmert euch direkt darum!). Jetzt hätte das Problem beim Testen auffallen müssen, aber hier beging ich den entscheidenden großen Fehler in der gesamten, sehr suboptimalen Kette: Ich probierte die arm64 und die amd64 meine Software und der Fremdsoftware nur auf meiner arm64-macOS-VM aus.
Wer aufgepasst hat, kann sich sicher denken, was jetzt passiert ist: Da Rosetta 2 lief, startete sie natürlich mein amd64-Programm und mein amd64-Programm startete das arm64-Fremdprogramm, ohne, dass ich was von einem Fehler mitbekam.
Ich lieferte natürlich die amd64-Version aus und es kam, wie es kommen musste: bei den Kollegen mit amd64 macOS funktionierte zwar mein Programm, das Fremdprogramm aber natürlich nicht, da es kein Rosetta-Äquivalent auf macOS amd64 gibt.
Dabei hatte ich den Fehler die ganze Zeit auf dem Schirm, denn mein Paketierungsscript lieferte Hinweise, wenn die Architektur der Fremdsoftware mit der Architektur meines Programms nicht zusammenpasst. Aber ein Hinweis lässt sich im Stress leicht übersehen. Hier hätte ich doch besser einen Abbruch eingebaut.
Was lernen wir daraus? Am Besten vollständig automatisierte Tests implementieren, aber wenn man für verschiedene Architekturen händisch testet, das dann auch direkt auf der jeweiligen Architektur durchführen und nicht in einer Emulation.