1 Punkte von GN⁺ 2023-10-13 | 1 Kommentare | Auf WhatsApp teilen
  • The Twelve-Factor App ist eine Methodik für den langfristigen Betrieb und die Skalierung von Web-Apps und SaaS und behandelt gemeinsam Konfigurationsautomatisierung, Portabilität, Cloud-Deployment und Continuous Deployment
  • Sie ist nicht an eine bestimmte Kombination aus Programmiersprache oder Backing Services wie Datenbanken, Queues oder In-Memory-Caches gebunden und kann daher auf verschiedenste Service-Anwendungen angewendet werden
  • Grundlage sind Erfahrungen aus der direkten Beteiligung an Entwicklung und Deployment von Hunderten von Apps auf der Heroku-Plattform sowie aus der indirekten Beobachtung von Entwicklung, Betrieb und Skalierung von Hunderttausenden von Apps
  • Das zentrale Anliegen ist, ein gemeinsames Vokabular bereitzustellen, das die Kosten der Zusammenarbeit und die Software-Erosion verringert, wenn Apps organisch wachsen
  • Sie kann nicht nur von Entwicklern genutzt werden, die Service-Anwendungen bauen, sondern auch von Operations Engineers, die diese deployen und verwalten, als praxisnaher Standard

12 Betriebsprinzipien für SaaS-Apps

  • Moderne Software wird häufig als Web-App oder SaaS bereitgestellt, und The Twelve-Factor App ist eine Methodik zum Erstellen solcher Anwendungen
  • Ziel ist es, die Prozesse rund um Entwicklung, Deployment und Betrieb einer App besser vorhersehbar zu machen
    • Um Zeit- und Kostenaufwand zu verringern, wenn neue Entwickler zu einem Projekt dazustoßen, wird deklarative Konfigurationsautomatisierung verwendet
    • Durch einen klaren Vertrag mit dem zugrunde liegenden Betriebssystem wird die Portabilität zwischen Laufzeitumgebungen erhöht
    • Sie ist so entworfen, dass der Aufwand für Server- und Systemadministration sinkt und moderne Cloud-Plattform-Deployments unterstützt werden
    • Unterschiede zwischen Entwicklungs- und Produktionsumgebung werden reduziert, um Continuous Deployment zu ermöglichen
    • Sie ermöglicht Skalierung, ohne Werkzeuge, Architektur oder Entwicklungspraktiken grundlegend zu verändern
  • Der Anwendungsbereich ist nicht auf einen bestimmten Technologie-Stack beschränkt
    • Sie kann auf Apps angewendet werden, die in jeder Programmiersprache geschrieben sind
    • Zu den Backing Services zählen Datenbanken, Queues, In-Memory-Caches usw.

Aus Heroku-Erfahrungen abgeleiteter Hintergrund

  • Die Mitwirkenden waren auf der Heroku-Plattform direkt an Entwicklung und Deployment von Hunderten von Apps beteiligt und beobachteten indirekt Entwicklung, Betrieb und Skalierung von Hunderttausenden von Apps
  • Auf Basis von Erfahrungen und Beobachtungen aus realen SaaS-Apps werden ideale Praktiken der App-Entwicklung zusammengefasst
    • Der Fokus liegt auf dem Verlauf, in dem Apps im Lauf der Zeit organisch wachsen
    • Es geht darum, wie mehrere Entwickler auf derselben Codebasis zusammenarbeiten
    • Die Vermeidung von Software-Erosionskosten wird als wichtiges Ziel gesehen
  • Die Form ist inspiriert von Martin Fowlers Patterns of Enterprise Application Architecture und Refactoring

12 Faktoren

1 Kommentare

 
GN⁺ 2023-10-13
Meinungen auf Hacker News
  • 12-Factor App ist eine Empfehlung, die 2011 eher auf Heroku und die damaligen Grenzen containerartiger Infrastruktur zugeschnitten war, und wirkt nicht wie ein Dokument, das tief in Engineering-Prinzipien verankert ist
    Zum Beispiel kommt die Forderung, Konfiguration in Umgebungsvariablen zu legen, daher, dass die Autoren bei Heroku arbeiteten und Heroku Umgebungsvariablen über Eingabefelder für Web-Apps befüllte
    Wenn man den Verlauf von Konfiguration per Versionsverwaltung nachverfolgen möchte, GitOps nutzt, k8s ConfigMaps verwendet oder Konfigurationsdateien auf gemounteten Volumes ablegen will, sind das alles im Allgemeinen gute Alternativen. Denn sie trennen den Konfigurationszustand vom Deployment-Zustand der App
    Dieses Dokument verwechselt den Wald mit den Bäumen und gibt Empfehlungen, die eher zu den Produktfunktionen des Unternehmens passen, das es geschrieben hat, als zu echten Engineering-Prinzipien; deshalb halte ich es für eine schädliche Guideline

    • Es stimmt, dass es bis zu einem gewissen Grad von Herokus Funktionsweise beeinflusst wurde, aber ConfigMap und GitOps erfüllen nicht dieselben Sicherheits- und Usability-Anforderungen wie Herokus Konfiguration/Umgebungsvariablen
      Wenn man in Kubernetes sichere Speicherung von Konfiguration will, landet man letztlich bei Secrets, und die sind wie Umgebungsvariablen Key-Value-förmig. Um in Git ähnliche Sicherheit zu erreichen, braucht man eine Verschlüsselungsschicht; dadurch gehen Diffs kaputt und man benötigt zusätzliche Tools
      Am Ende kommt man wieder darauf zurück, warum High-Level-Deployment-Tools wie Heroku überhaupt entstanden sind
    • Heute nennt es zwar niemand mehr 12 factor, aber dank dessen befolgen wir weiterhin die allgemeinen Prinzipien. 12-Factor war ein Dokument aus der Zeit, bevor Docker und Kubernetes Mainstream wurden
      Das Prinzip, Logs als Stream zu behandeln, stimmt weiterhin. Man schreibt Logs nach STDOUT statt in Dateien und lässt sie vom Orchestrator lesen und speichern
      Konfiguration kommt aus der Umgebung. Apps neigen dazu, ihre Konfiguration je nach Deployment-Art aus unterschiedlichen Quellen zu lesen, lokal etwa aus .env und in Produktion aus einem Secret Store
      Bei Port Binding ist es ähnlich: Die App öffnet einen Port, und davor setzt man etwas wie nginx als Reverse Proxy. K8S Services und Ingress übernehmen diese Rolle
      Die größte Kritik, die man heute an 12-Factor üben kann, ist, dass das Dokument eigentlich nicht gut geschrieben ist und voraussetzt, dass die Lesenden bereits genau wissen, wovon die Rede ist
    • Heroku hat Umgebungsvariablen weder erfunden noch als Erstes die Idee gehabt, sie für App-Konfiguration zu nutzen. Das war schon lange vor Heroku ein gängiges Verfahren
      Ich erkenne aber an, dass Heroku dieses Konzept bekannt gemacht und seine Nutzung verbreitet hat
    • „Konfiguration in der Umgebung speichern“ heißt nicht zwingend, Konfiguration in Umgebungsvariablen zu legen. Es bedeutet, dass die Konfiguration aus der Hosting-Umgebung kommt und nicht aus der App selbst
      Also nicht so, dass man vor dem Start der App eine settings.json auf die Maschine legt, sondern dass derselbe Quellcode, wenn er in einen AKS-Cluster in Azure EU North deployt wird, die in diesem Cluster gesetzten Werte nutzt, und wenn er in einen RPi-Zero-Docker-Swarm-Cluster in einem Ikea-Bilderrahmen deployt wird, die Konfiguration dieses Clusters nutzt
      Dieser Cluster heißt Gibson
    • 12-Factor-Apps, die ihre Konfiguration in Umgebungsvariablen ablegten, ließen sich trivial auf ConfigMap umstellen. Umgekehrt werden heutige Business-Apps mit komplexen ConfigMap-Layouts, im schlimmsten Fall mit direkter Abhängigkeit von der k8s-API, zur Hölle, wenn sie auf das migriert werden müssen, was nach k8s kommt
  • Ich habe das Gefühl, dass sich diese Punkte jeweils ziemlich vernünftig widerlegen lassen
    Erstens ist das Prinzip „eine App, ein Repository“ nicht grundsätzlich falsch. Es ist kein Problem, mehrere Apps in einem Repository zu entwickeln, wenn sie funktional stark gekoppelt sind und einen Release-Zyklus teilen, aber separat deployt werden müssen, um Vorteile getrennter Prozesse und unabhängiger Skalierung zu bekommen. Mir fallen etwa die Trennung einer öffentlichen API und eines Worker-Prozesses ein, zum Beispiel Sidekiq in Ruby, Celery in Python oder ein gewöhnlicher Kafka-Consumer
    Zweitens ist die Aussage „Eine 12-Factor-App verlässt sich nicht auf die implizite Existenz systemweiter Pakete“ ohne etwas wie Nix in der Praxis sehr schwer zu erreichen. Auch Abhängigkeiten von Kernel-System-Call-APIs lecken durch, und die meisten Rust-Apps hängen, abgesehen von musl, implizit von glibc ab. Abgesehen von Slim-Distributionen wie Alpine ist das in den großen Linux-Distributionen vorhanden. Ich sehe Docker als Stütze, die nötig ist, um dieses Problem abzumildern
    Drittens wirkt es anfälliger, Konfiguration in Umgebungsvariablen zu speichern. Es kann die Sicherheit verschlechtern, weil Secrets in die Umgebung gezwungen werden, und man verzichtet auf strukturierte Dateikonfiguration mit Typsicherheit, IDE-Autovervollständigung und automatischem Parsing. Für komplexe Konfigurationswerte, die keine Strings sind, muss man bei Umgebungsvariablen eigene Parser implementieren. In der Praxis werden sie auch oft in Form von .env-Dateien im Repository committet, sodass das Argument der Commit-Sicherheit bedeutungslos wird

    • Das ist eine Fehlinterpretation dieser Anweisung. Im Original geht es um unterstützende Bibliotheken, die über sprachspezifische Packaging-Systeme wie CPAN oder Rubygems installiert werden, und es wird erklärt, dass solche Bibliotheken als systemweite „site packages“ installiert sein können
      Es bedeutet nicht, dass man sich nicht auf das Betriebssystem einschließlich glibc verlassen soll, sondern dass man nicht erzwingen soll, dass ein bestimmtes Paket eines Sprach-Paketmanagers auf der Maschine installiert sein muss
      Den übrigen Punkten stimme ich zu. Besonders der Teil zu Umgebungsvariablen wirkt weniger wie tatsächlich fundierter Rat und eher so, als hätten die Autoren eine damals in der Ruby-Entwicklung verbreitete Praxis als Best Practice angenommen und niedergeschrieben
    • Wenn sie separat deployt werden, teilen sie keinen Release-Zyklus. Irgendwann kann am Ende eine Kombination nicht zueinander passender Versionen laufen. Zum Beispiel kann das Deployment nur eines Teils fehlschlagen
      Deshalb muss man auf solche Situationen vorbereitet sein, und wenn man verschiedene Versionskombinationen leicht testen will, halte ich separate Repositories für besser
      Die meisten High-Level-Sprachen hängen nicht von einer bestimmten glibc ab. Wenn die jeweilige Sprachruntime korrekt läuft, läuft die App darauf ebenfalls. Natürlich greift man in manchen Fällen zu etwas wie Docker. Nur weil es schwierig ist, heißt das nicht, dass es wertlos ist
    • Wenn das der grundlegende Punkt sein soll, stimme ich nicht zu. Ich glaube, dass ein größerer Teil der Welt mir und den 12-Factor-Prinzipien zustimmt
    • Der Sicht auf die erste Regel stimme ich zu, und ich würde zusammengehörige mehrere Apps gern in ein Repository legen. Da keine Begründung dafür geliefert wird, warum ein Repository nur eine App enthalten sollte, kann man diese Regel ignorieren
      Dynamische oder verwaltete Sprachen können den Ärger rund um Systempakete oft weitgehend ignorieren
    • Der Nutzen eines Monorepos ist U-förmig. Die meisten Projekte liegen irgendwo in der Mitte, besonders Projekte, die von unabhängigen Engineering-Teams verwaltet werden, die kein zentralisiertes Plattform-/DevOps-/wie-man-das-heute-auch-nennt-Team haben
  • Insgesamt gefällt es mir, aber Nichttechniker oder Halbtechniker haben „12 factor“ so oft wie eine universelle Gelbe Karte gezogen und damit Releases verzögert, dass ich es fast völlig ignoriere.
    Mit „agile“ war es im Grunde ähnlich. Ich verstehe die Absicht solcher Richtlinien, aber ihr tatsächlicher Wert scheint vor allem für Leute deutlich größer zu sein, die nichts anderes bieten können als technische Führung aus dem Elfenbeinturm.

    • Es aus Prinzip völlig zu ignorieren, ist genauso schlecht wie es als verpflichtende Doktrin zu behandeln.
      Ich habe erlebt, wie übermotivierte Junior Engineers oder angehende Architekten den 12-Factor-Text als Pflichtanforderung für jedes Release verwendeten.
      Man muss klar und konsequent erklären, dass das zwar gute Ziele sind, die man anstreben sollte, dass man in der Realität aber Kompromisse eingehen muss, um zu releasen, und entscheiden muss, welche Teile man verzögert oder aufschiebt.
    • So etwas nennt man waffenfähige Doktrin. Trotzdem halte ich es immer noch für besser als Leute, die auf DRY bestehen und unverständliche generische Helper-Funktionen bauen, nur um drei oder vier Zeilen Code-Duplikation zu vermeiden.
    • Man muss Beispiele geben. Wie die meisten Dinge ist es kontextabhängig und hat Grauzonen, aber ich denke, die meisten Entwickler verwenden 12-Factor als Nordstern.
      Eine kleine Abweichung würde ein Release nicht blockieren, aber wenn es insgesamt nicht passt, sollte es zumindest als technische Schuld behandelt werden. Wenn ein Release bei einem Punkt einen großen Rückschritt macht, ist es fair, es zu blockieren oder zumindest eine genauere Prüfung zu erzwingen, warum man diesen Trade-off für lohnend hielt.
    • Keine Doktrin sollte ein Deployment im MVP-Umfang verhindern. Sobald man über das MVP hinaus ist, wird alles, was man aus Best-Practice-Sicht nicht erledigt hat, zu technischer Schuld.
      Wenn eine Organisation 12FA als Best Practice übernommen hat, sollte es erfüllt werden, aber es sollte Deployments nicht blockieren.
      12FA ist kein einzelnes Kästchen, das man abhaken muss. Wenn ein Produkt reifer wird, kann und sollte man es meistens umsetzen, indem man die einzelnen Punkte nacheinander – bei Bedarf weiter heruntergebrochen – in das Produkt einbaut.
      Wenn man anfangs gutes Engineering gemacht hat, also passende Abstraktionen und Interfaces vorgesehen und nicht alles hartkodiert hat, sollte das kein Problem sein.
      YAGNI wird genauso missbraucht wie 12FA. Was bei 12FA am stärksten fehlt, sind konkrete Beispiele, an denen sich Junior Engineers orientieren können.
    • Ich hatte früher solche Probleme, und die Lösung war ein klar dokumentierter Prozess, auf den man verweisen konnte.
      Ich habe gelernt, solche Probleme in guter Absicht zu interpretieren. Man muss schauen, warum jemand ein Problem anspricht, ob der bestehende Prozess unklar ist, Mängel hat oder nicht vertrauenswürdig wirkt.
      Wenn man berechtigte Bedenken findet, ändert man den Prozess und aktualisiert auch die Dokumentation.
  • Die Twelve-Factor App sagt, man solle die Umgebung für Konfiguration verwenden, Docker sagt, man solle die Umgebung nicht für Konfiguration verwenden, weil das unsicher ist.
    Viele Muster aus 12-Factor mag und verwende ich, aber einige entstanden im Kontext von VPS. Damals war die Umgebung stabil, sicher und stärker festgelegt; bei Containern kann die Umgebung aber in irgendeiner Layer landen.
    Im Container-Zeitalter war gerade dieser Punkt ziemlich problematisch. Docker secrets passen auch nicht immer gut, sodass man mehrere Verrenkungen braucht, damit es funktioniert.

    • Kannst du das genauer erklären? Mich interessiert, inwiefern Umgebungsvariablen unsicher sind. Wenn Secrets während der gesamten Lebensdauer der Anwendung vorhanden sein müssen, weiß ich nicht, was eine bessere Alternative wäre.
      Wenn man Secrets als Umgebungsvariablen in die App injiziert, heißt das nicht, dass auch deren Verarbeitung außerhalb davon unsicher ist. AWS-ECS-Container haben zum Beispiel eingebaute Unterstützung, um beim Start Secrets aus dem Secret Manager zu holen und sie als Umgebungsvariablen zu übergeben: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/...
      Die Secrets werden beim Start des Containers geholt, und zwar aus dem Secret Manager mit den IAM-Credentials der laufenden Anwendung. Man braucht also Berechtigungen für das jeweilige Secret.
      Der Vorteil der Nutzung von Umgebungsvariablen scheint letztlich vollständig davon abzuhängen, wie sie gesetzt werden. Bei so einem Mechanismus sehe ich keinen großen Nachteil.
      Der wichtigste sichtbare Nachteil ist, dass gewöhnliche Malware, die Umgebungsvariablen dumpen will, die Werte erfassen kann; wenn man Secrets aber nicht gerade vermeidet, dauerhaft im Speicher zu halten, ist die Abwehr dieser Bedrohung größtenteils eher Obfuskation.
    • Umgekehrt gibt es ohne Plattformunterstützung nicht viele einfache Alternativen. Zumindest fördert es die Trennung von Konfiguration und Code und ermöglicht, Secrets außerhalb der Versionsverwaltung zu halten.
    • Aus diesem Grund mochte ich es nie, Secrets in Umgebungsvariablen zu legen. Schlampige Debug-Konsolen haben erstaunlich oft versehentlich Umgebungsvariablen offengelegt.
      Dass private Schlüssel so offengelegt werden, sollte man wirklich vermeiden.
      Mit der Methode, Secrets in k8s ins Dateisystem zu mounten, habe ich kein besonderes Problem. Natürlich hängt all das von der Deployment-Umgebung ab.
      Manchmal sind Umgebungsvariablen die weniger schlechte Option. Secrets sind schließlich grundsätzlich immer schwierig.
    • Man könnte argumentieren, dass man keine Eingabe als „sicher konsumierbar“ betrachten sollte. Wenn man App-Code defensiv schreibt, nimmt man niemals an, dass ENV sicher ist oder die erwartete Form hat, sondern bereinigt es vor der Verwendung.
      Wenn man Eingaben blind vertraut, nur weil es ein Single-Tenant-System ist, bekommt man später schwer nachvollziehbare Bugs und lange Nächte, sobald sich die Bedingungen durch eine beliebige geschäftliche Richtungsänderung ändern.
    • Rückblickend wäre als Abschnittsname wohl Konfiguration vom Code trennen besser gewesen, wie es im ersten Absatz heißt.
  • In den letzten Jahren habe ich viel über 12-Factor-Apps diskutiert und auch viel Verwirrung gesehen. Die 12-Factor-Website ist großartig, aber sie ist vor allem für Leute gut, die bereits verstehen, warum diese Punkte wichtig sind.
    Für Leute, die die Gründe hinter den Regeln nicht kennen, brauchte es eine tiefere Erklärung. Deshalb habe ich das Video „What are 12 Factor Apps and Why Should You Care?“[1] gemacht, und ich habe gehört, dass es sehr hilfreich war, als einige Unternehmen es für die Einarbeitung neuer Engineers/DevOps-Mitarbeiter genutzt haben.
    Egal, wo man es lernt: Es lohnt sich, ein bis zwei Stunden in 12-Factor-Apps zu investieren. Die meisten „Regeln“ sind Dinge, für die man ein Bewusstsein entwickeln muss, und sie sind nicht sofort offensichtlich, bevor man selbst Fehler macht und Schmerzen dadurch erfährt.
    [1] https://youtu.be/REbM4BDeua0

    • Das ist ähnlich wie bei Unit-Tests. Die Idee, Code zu schreiben, der Code testet, war für mich seit Beginn des Programmierens so offensichtlich, dass ich überrascht war, warum andere so lange brauchten, um sie zu akzeptieren.
      Das Konzept „Unit-Test“ begann ungefähr Ende der 90er Jahre an traction zu gewinnen, und ich war erleichtert, dass sich eine Autoritätsperson dafür einsetzte.
      Der Grund, warum ich es nicht selbst gemacht habe, bevor Kent Beck JUnit veröffentlichte, war, dass der Code, an dem ich arbeitete, nicht so strukturiert war, dass er sich gut von anderem Code steuern ließ. Wegen globaler Variablen, weit verstreutem Zustand, Abhängigkeiten von externen Systemen und bestimmten Dateisystem-Layouts sowie ignorierter Modularität konnte außerhalb des vorgesehenen Kontexts nichts ausgeführt werden.
      All das war „schlechtes Design“, aber die Deadlines wurden eingehalten, also machten es alle so. Ich hoffte, dass Programmierer sich von monolithischem Design lösen würden, wenn Unit-Tests an traction gewinnen.
      Nachdem ich 25 Jahre lang Unit-Tests für Getter/Setter gesehen habe sowie einen riesigen Unit-Test, der eine In-Memory-Datenbank baut, weil jede Funktion der App schon zum bloßen Ausführen eine Live-Datenbank braucht, und der am Ende fehlschlägt und auskommentiert wird, habe ich den Glauben verloren, dass Unit-Tests mehr werden als eine bedeutungslose Checkbox. Alle haken sie ab, weil es eine „Best Practice“ ist, aber niemand hält inne und denkt darüber nach, warum man das tut.
  • Mit den Ratschlägen zur Konfiguration war ich immer am wenigsten einverstanden. Konfiguration wird von mehreren Akteuren definiert, oft auch von Entwicklern; daher ist es häufig am besten, sinnvolle Defaults mit der Anwendung auszuliefern und sie durch umgebungsspezifische Dateien und Umgebungsvariablen zu überschreiben.
    Für die meisten serverseitigen Anwendungen ist das der flexibelste Ansatz. Oft weiß man bereits, wie etwas konfiguriert sein soll, und das gehört besser in die Versionsverwaltung, während Secrets zur Laufzeit injiziert werden sollten.
    Wenn man in Entwicklung, Test und Produktion nicht enorm viel Zeit mit Konfiguration verbringen will, braucht Konfiguration hierarchische Überschreibungen.

    • Die Frage ist, ob „sinnvolle Defaults“ Defaults für Entwicklung oder für Produktion sind.
      Wenn sie für Entwicklung gedacht sind, werden sie am Ende die Produktion kaputtmachen; Produktions-Defaults können in der Entwicklung wiederum völlig bedeutungslos sein.
    • Zum Kontext, in dem die 12-Factor App geschrieben wurde, gehörte, dass man den Modus über Umgebungsvariablen wie RAILS_ENV=test umschalten konnte.
      Eine Möglichkeit, den Konfigurationsabschnitt zu betrachten, ist: „Passt diese Konfigurationsstrategie gut zu Containern?“ Wenn man ein Image baut, entsteht ein statischer Festplattenzustand, dessen Änderungen nicht bestehen bleiben, sofern man kein neues Image erstellt.
      Wenn Konfiguration ausschließlich dateibasiert ist, muss man ein komplett neues Image bauen, um zwischen Test- und Produktionsverhalten zu wechseln.
      Wenn Konfiguration unabhängig von der zugrunde liegenden Festplatte geändert werden kann, hilft das, Änderungen zu isolieren. Man muss unterscheiden können, ob die App kaputt ist, weil das Deployment, also die Image-Erstellung, kaputt ist, oder weil die Konfiguration falsch ist.
      Trennt man Image-Erstellung und Konfigurationsänderungen, verschwindet diese Frage selbst.
    • Wenn systematisch verhindert wird, dass QA-Instanzen an Produktionsressourcen angebunden werden, kann es in Ordnung sein, den Großteil der Konfiguration zusammen mit der App auszuliefern.
      Man sollte zum Beispiel keinen ausreichend vorhersehbaren menschlichen Fehler zulassen, bei dem QA 100.000 Wiederholungsversuche für abgelehnte Authentifizierungen in eine Produktions-Job-Queue schickt.
      Allerdings betrifft viele Konfiguration nicht die Infrastruktur, sondern häufig Dinge wie die Frage, welche ResolverStrategy-Bean in welcher Umgebung verdrahtet wird.
    • Man kann und sollte vermutlich sinnvolle Defaults haben.
      Konfiguration sollte versioniert werden, aber getrennt vom Sourcecode verwaltet werden. Denn Konfiguration beschreibt nicht das Image, das für ein Deployment verwendet wird, sondern das Deployment selbst.
    • Ich sehe keinen Grund, warum auch Defaults nicht als Konfiguration ausgedrückt werden sollten. Wenn das gemeint war, sehe ich darin keinen Verstoß gegen 12-Factor.
  • Es war definitiv eine einflussreiche Engineering-Norm. Heute gibt es viele einfache Abstraktionen bei Hosting-Anbietern wie Render oder Vercel; wenn man bedenkt, dass dieses Dokument 2012 geschrieben wurde und Web-Apps damals in Bezug auf akzeptierte gemeinsame Praktiken noch viel mehr wie der Wilde Westen waren, fühlt sich das etwas seltsam an.

  • Was in diesem Dokument weitgehend fehlt, ist eine Begründung der Regeln. Fast alles sind einfach nur Regeln.
    Es ist schwer zu beurteilen, ob die Regeln gut sind, und dieses Dokument hilft nicht dabei, das herauszufinden.

  • Nur vom Titel her dachte ich, es sei ein Kommentar zu Zwei-Faktor-Authentifizierung. Also Apps, die für einen einzigen Login Passfoto, Gesichtsscan, Führerschein, SMS, Google Authenticator, E-Mail-Link, Passwort und Fingerabdruck verlangen.

    • Klingt für mich nach der durchschnittlichen zentralisierten Kryptobörse.
    • Das entspricht ungefähr dem, was eine durchschnittliche Aktien- oder Kryptobörse verlangt, bevor sie Handel erlaubt.
  • In den frühen Docker-Tagen habe ich ziemlich viel Arbeit investiert, um WordPress dazu zu bringen, sich wie eine Twelve-Factor App zu verhalten.
    Traditionell verhielt sich WordPress nicht so, und bis zu einem gewissen Grad ist das verständlich. WordPress ist in einer Welt groß geworden, in der langlebige Server mit beschreibbarer, persistenter lokaler Festplatte üblich waren.
    Seitdem dürfte sich vieles geändert haben. Das war etwa 2016, aber es war eine wirklich interessante Herausforderung.

    • Ich erinnere mich an den Moment, als ich lernte, wie man Server zustandslos macht, also etwa Session-Informationen in der Datenbank speichert und nicht auf die Festplatte schreibt.
      Ich war überrascht, wie viel einfacher alles wurde, und man konnte mehrere Nodes per Load Balancing betreiben, ohne sich um Session-Affinität kümmern zu müssen.
      Natürlich wurde es auf andere Weise schwieriger, etwa weil man eine separate DB für Sessions brauchte.