Was ist modulare Architektur? Lassen Sie uns ein Beispiel durchgehen, was es nicht ist, und
Wir werden daran arbeiten, es zu transformieren. Am Ende werden Sie vielleicht davon überzeugt sein
Verdienste oder dass es eine kolossale Zeitverschwendung ist.
Das ist ein reales Szenario, das ich bei der Arbeit wachstumsorientiert durchgespielt habe. Namen und Details
anonymisiert, aber ein reales Beispiel eines gemeinsamen Konzepts sollte Spaß machen
durch, wenn nichts anderes.
Unsere Website verfügt über eine Schaltfläche, die sich in der Kopfzeile der Website befindet. Es zeigt an, wie viele
Der Benutzer hat V-Bucks übrig, aber es ist auch eine gewisse Geschäftslogik darin integriert:
Und so weiter. Es gibt viele solcher Fälle bei unseren Produktmanagern und Projektmanagern
und Designmanager und Group V-Bucks-Direktoren haben sich ausgedacht, dass wir das tun müssen
Griff.
Jimbo, der Praktikant, wurde mit der Umsetzung beauftragt, weil es nur ein
ist
Knopf!
Er sichtet fünfzehn widersprüchliche Versionen von Figma-Designs. Er findet
Anforderungen in so vielen separaten Word-Dokumenten, wie es PMs gibt. Er organisiert und
durchläuft sieben Wissenstransfersitzungen mit sieben Teams, um das
aufzudecken
altes, proprietäres Wissen darüber, welche Dienste die von ihm benötigten Daten bereitstellen
für Benutzertyp und V-Bucks-Anzahl. Das Content-Team hat ihm versichert, dass die
Die endgültige Version aller Saiten wird bis zum Ende von der Rechts- und Marketingabteilung genehmigt
der Woche, und damit ist er bereit, diesen Button zu bauen.
Hier ist die erste Version seines V-Bucks-Buttons, seiner Popovers und anderer relevanter Elemente
Geschäftslogik.
Jimbo ist mit der einfachen Verzeichnisstruktur, die er sich ausgedacht hat, zufrieden:
/v-bucks-button ├── button.tsx ├── index.ts └── /v-bucks-popover │ ├── popover.tsx
Also beginnt er mit dem Bau dieses Knopfes, und es beginnt ganz harmlos.
export const VBucksButton: React.FC<VBBProps> = ({ ... }) => { // Set up state const authConfig = { ... } const { user } = useAuth({ ...authConfig }) const { vBucks } = useGetVBucks({ user }) const { telemetry } = useTelemetry() const { t } = useTranslation('vBucksButton.content') const styles = useButtonStyles() // Derive some state via business logic const handleClick = () => { ... } const buttonText = vBucks === ERROR ? '--' : vBucks.toString(); // About 25 more lines of various button state, error handling, // conditional rendering, with comments throughout explaining // why we're showing or hiding something or other const popoverProps = { // About 200 lines of typical popover handling, // telemetry, business logic, content to display, etc } const tooltipProps = { // Another 100 lines of the same for tooltip } return ( <VBucksPopover {...popoverProps} trigger={ <Tooltip {...tooltipProps}> <button ariaLabel={t('ariaLabel')} className={` about seven-hundred classnames for responsive design, accessibility, conditional premium styles, et cetera`} onClick={handleClick}> {buttonText} </button> </Tooltip> } /> ) } <p>Er hat einen ersten Versuch umgesetzt. Das VBucksPopover ist ähnlich komplex<br> Geschäftslogik, Fehlerbehandlung, Zustandsverwaltung, Styling und Kommentarentschuldigung<br> Tech-Schulden im Namen der Schifffahrt.</p> <p>Mit knapp 400 Zeilen ist dieser Button trivial einfach. Auch wenn der Popover<br> ist weitere 500 Zeilen Spaghetti. Macht es wirklich „aufräumen“ oder aufteilen<br> Kommt es uns oder unseren Nutzern in irgendeiner Weise zugute? Es kommt darauf an. Wenn das alles ist, was wir brauchen<br> Dieser Knopf, wen interessiert das? Lass uns weitermachen!</p> <p>Aber zwei Monate sind vergangen und ein PM und ein Designer eines anderen Produktteams lieben<br> Ihre Schaltfläche und möchte sie im Header ihrer App haben. Sie haben eine <em>einfache</em> Liste, nein<br> Druck von ihrer Seite, von einigen Änderungen, die Sie gerne berücksichtigen würden, und wenn<br> Sie könnten uns bitte bis zum Ende des Tages eine voraussichtliche Ankunftszeit für LT mitteilen, das wäre großartig, danke:</p> <ul> <li>Aktualisieren Sie den Stil und den Anzeigetext der Schaltfläche basierend auf der App, in der sie angezeigt wird</li> <li>Zeigen Sie pro App einen völlig anderen Satz Popovers an</li> <li>Öffnen Sie ein neues unternehmensweites, standardmäßiges Upsell-Modal, wenn der Benutzer keine V-Bucks mehr hat. aber nur in einigen Regionen und nur für Benutzer ab 16 Jahren und nur, wenn sie dort sind Experimentgruppe A</li> </ul> <p>Kann Jimbo all diese neuen Funktionen in denselben Komponenten unterbringen?<br><br> Ja. Wird die Aufteilung oder Umgestaltung den Benutzern zugute kommen oder Ihre Manager beeindrucken?<br><br> Nein. Aber Refactoring hat auf dieser Ebene der Komplexität einige starke Argumente:</p> <ul> <li>Vernunft der Entwickler</li> <li>Die Vernunft des Entwicklers, der Jimbo ersetzt, wenn er wegen fehlender Umgestaltung angeklagt wird</li> <li>Mehr Wiederholungen, damit Sie beim nächsten Mal von Anfang an besser abschneiden</li> <li>Etwas, worüber man später bloggen kann</li> </ul> <h3> Der modulare Architekturansatz </h3> <p>Die Moral der Eingeweihten des Clean Code und anderer Analtypen, die genug dazu wissen<br> Antworten Sie regelmäßig auf Stack Overflow, und sogar Ihre Großeltern schauen sich etwas an<br> so:</p> <ul> <li>KISS, DRY und andere Akronymdecken</li> <li>Belangetrennung</li> <li>Atomizität! Entkopplung! Lautmalerei!</li> </ul> <p>Das ist großartig und hilft Jimbo bei seinem nächsten Versuch. Er wurde danach nicht mehr per PIP benachrichtigt<br> Alles, und ich habe tatsächlich eine Werbeaktion für die vorzeitige Lieferung und das Teilen erhalten<br> so viele Besprechungen und Dokumente.<br><br> Aber jetzt ist er klüger und hat eine coole Art gelernt, diese Sprichwörter umzusetzen. Es sieht aus<br> etwa so:<br> </p> <div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">/v-bucks-button ├── button.tsx ├── index.ts └── /v-bucks-popover │ ├── popover.tsx
Sieht aus wie jede Menge Boilerplate für einen Button und ein Popover. Warum sollte das so sein?
besser?
Es kommt darauf an. Hier ist Jimbos kurzer Überblick mit Begründung:
Es ist unendlich skalierbar! Diese Bausteine werden nicht nach
aufgeschlüsselt
willkürliche Regeln wie Codezeilen oder „Komplexität“. Sie sind aufgeschlüsselt nach
Zweck: Jede konzeptionelle Grenze dient einem einzigen Zweck.
Eine PM möchte, dass du 10 neue Popovers machst? Kein Problem – Jimbos Architektur kann
Kümmere dich darum.
Die Führung möchte in einigen Apps bessere Umsatzkennzahlen, andere Teams jedoch nicht
Wir verfügen über die Mittel, um die Telemetrie auszubauen, um dies zu unterstützen. Großartig! Wir haben
Telemetrie-Utilities, die wir horizontal skalieren können, um verschiedenen, sich ändernden Anforderungen gerecht zu werden
Anforderungen.
Eine umfassende Neugestaltung bedeutet, dass jedes einzelne Popover unterschiedliche Dinge anzeigen muss,
basierend auf unterschiedlichen Bedingungen. Es ist normalerweise viel jetzt, da alle
Dinge, die wir rendern, und die gesamte Logik, die wir zum Rendern verwenden, existieren in wohldefinierter Form
Blöcke. Sie sind nicht mehr in einem riesigen Haufen von Konflikten und Logik vermengt
Ketten mit einer Länge von 20 Zeilen.
Hier ist ein Beispiel dieses Container-/Renderer-Musters:
/v-bucks-button ├── button.tsx ├── index.ts └── /v-bucks-popover │ ├── popover.tsx
export const VBucksButton: React.FC<VBBProps> = ({ ... }) => { // Set up state const authConfig = { ... } const { user } = useAuth({ ...authConfig }) const { vBucks } = useGetVBucks({ user }) const { telemetry } = useTelemetry() const { t } = useTranslation('vBucksButton.content') const styles = useButtonStyles() // Derive some state via business logic const handleClick = () => { ... } const buttonText = vBucks === ERROR ? '--' : vBucks.toString(); // About 25 more lines of various button state, error handling, // conditional rendering, with comments throughout explaining // why we're showing or hiding something or other const popoverProps = { // About 200 lines of typical popover handling, // telemetry, business logic, content to display, etc } const tooltipProps = { // Another 100 lines of the same for tooltip } return ( <VBucksPopover {...popoverProps} trigger={ <Tooltip {...tooltipProps}> <button ariaLabel={t('ariaLabel')} className={` about seven-hundred classnames for responsive design, accessibility, conditional premium styles, et cetera`} onClick={handleClick}> {buttonText} </button> </Tooltip> } /> ) }
/vBucksButton ├── /hooks │ ├── index.ts │ └── useButtonState.hook.ts ├── /vBucksPopover │ ├── /app1Popover │ │ ├── /hooks │ │ │ ├── index.ts │ │ │ └── usePopoverState.hook.ts │ │ ├── ... │ ├── /app2Popover │ ├── index.ts │ ├── popover.renderer.tsx │ ├── popover.styles.ts │ ├── popover.tsx │ └── popover.types.ts ├── /utils │ ├── experimentation.util.ts │ ├── store.util.ts │ ├── telemetry.util.ts │ └── vBucks.businessLogic.util.ts ├── button.renderer.tsx ├── button.styles.ts ├── button.tsx ├── button.types.ts └── index.ts
Nebenbei: In den TailwindCSS-Dokumenten wird ausdrücklich davon abgeraten, @apply zum Extrahieren allgemeiner Klassen wie dieser zu verwenden. Dies führt zu nahezu keinem Unterschied in der Bundle-Größe und zu keinem anderen Unterschied als dem „Sie müssen sich Klassennamen ausdenken“. CSS in Produktionsqualität ist am Ende fast immer Dutzende Zeilen lang, multipliziert mit der Anzahl der Elemente, die in einer bestimmten Komponente gestylt werden müssen. Dieser Kompromiss scheint sich in 90 % der Fälle zu lohnen.
Und der Rest der bestehenden und neuen Geschäftslogik lebt in Hooks und Utilities!
Diese neue Architektur stellt die Eiferer zufrieden und erleichtert die Skalierung oder
löschen oder verschieben.
Das Schreiben von Unit-Tests wird weniger schmerzhaft, da Sie alles klar definiert haben
Grenzen. Ihr Renderer muss nicht mehr zehn verschiedene Dienste verspotten, um
Überprüfen Sie anhand einiger Eingaben, ob einige glänzende Elemente angezeigt werden. Deine Haken können
Testen Sie isoliert, ob sie Ihrer beabsichtigten Geschäftslogik entsprechen.
Hat sich gerade Ihre gesamte Statusebene geändert? Es wäre schade, wenn der Code in Ihrem
Hook war eng mit dem Code verknüpft, der ihn verwendet, aber jetzt ist er einfacher
ändern und Ihr Renderer erwartet immer noch einige Eingaben.
Diese modulare Architektur fügt eine Menge Grundbausteine hinzu und kann letztendlich Folgendes bieten
Null Nutzen.
Ich kann es praktisch nicht empfehlen, wenn Sie an einem Leidenschaftsprojekt arbeiten oder
Priorisieren Sie vor allem den Versand und die Bereitstellung eines Mehrwerts. Wenn Sie etwas haben, das
Es sieht so aus, als ob der Umfang im Laufe der Zeit erweitert werden könnte oder dass Sie dies wünschen
Eine komplette Überholung nach einem POC kann die technischen Schulden reduzieren ... manchmal.
Sie können Tools wie Plop verwenden, um dieses Boilerplate zu erstellen.
Was habe ich also wirklich aus Jimbos Arbeit und seiner modularen Architektur gelernt?
Sauberen Code und Akronyme lernen wir in der Schule und in den Well Ackshuallys der Welt
sind ein Ende eines Spektrums. Das Zusammenhacken von funktionalem Spaghetti-Code ist eine weitere Möglichkeit
Ende und funktioniert oft ganz gut, denn letztendlich ist jeder Code eine technische Schuld.
Die beste Lösung existiert in einem Quantenzustand oder einer Kombination dieser Enden und
Der Weg, den wir wählen, wird wahrscheinlich auf der Grundlage von Folgendem entschieden:
Das obige ist der detaillierte Inhalt vonModulare React-Architektur. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!