Der Autor des Materials, dessen Ăbersetzung wir heute veröffentlichen, sagt, dass das
GitHub-Repository , an dem er gearbeitet hat, und mehrere andere Freiberufler aus verschiedenen GrĂŒnden in 3 Tagen etwa 8.200 Sterne erhalten haben. Dieses Repository belegte bei HackerNews und GitHub Trending den ersten Platz, und 20.000 Reddit-Benutzer stimmten dafĂŒr.

Dieses Repository spiegelt die Methodik zum Entwickeln von Full-Stack-Anwendungen wider, der dieser Artikel gewidmet ist.
Hintergrund
Ich wollte dieses Material fĂŒr einige Zeit schreiben. Ich glaube, ich kann keinen besseren Moment als diesen finden, wenn unser Repository sehr beliebt ist.
Nr. 1 bei GitHub TrendingIch arbeite in einem Team von
Freiberuflern . Unsere Projekte verwenden React / React Native, NodeJS und GraphQL. Dieses Material richtet sich an diejenigen, die erfahren möchten, wie wir Anwendungen entwickeln. DarĂŒber hinaus wird es fĂŒr diejenigen nĂŒtzlich sein, die in Zukunft unserem Team beitreten werden.
Jetzt werde ich ĂŒber die Grundprinzipien sprechen, die wir bei der Entwicklung von Projekten verwenden.
Je einfacher, desto besser.
"Je einfacher desto besser" ist leichter gesagt als getan. Die meisten Entwickler sind sich bewusst, dass Einfachheit ein wichtiges Prinzip in der Softwareentwicklung ist. Dieses Prinzip ist jedoch nicht immer leicht zu befolgen. Wenn der Code einfach ist, erleichtert dies die ProjektunterstĂŒtzung und vereinfacht die Teamarbeit an diesem Projekt. DarĂŒber hinaus hilft die Einhaltung dieses Prinzips bei der Arbeit mit Code, der beispielsweise vor sechs Monaten geschrieben wurde.
Hier sind die Fehler, auf die ich in Bezug auf dieses Prinzip gestoĂen bin:
- Ungerechtfertigter Wunsch, das DRY-Prinzip zu erfĂŒllen. Manchmal ist das Kopieren und EinfĂŒgen von Code ganz normal. Es ist nicht erforderlich, alle 2 Codefragmente zu abstrahieren, die einander etwas Ă€hnlich sind. Ich selbst habe diesen Fehler gemacht. Alle haben es vielleicht begangen. DRY ist ein guter Programmieransatz, aber die Auswahl einer fehlgeschlagenen Abstraktion kann die Situation nur verschlechtern und die Codebasis komplizieren. Wenn Sie mehr ĂŒber diese Ideen erfahren möchten, empfehle ich, die AHA-Programmierung von Kent A Dodds zu lesen.
- Verweigerung der Verwendung der verfĂŒgbaren Tools. Ein Beispiel fĂŒr diesen Fehler ist die Verwendung von
reduce
anstelle von map
oder filter
. NatĂŒrlich kann die Verwendung von reduce
das Verhalten der map
reproduzieren. Dies fĂŒhrt jedoch wahrscheinlich zu einer VergröĂerung des Codes und zu der Tatsache, dass es fĂŒr andere Menschen schwieriger sein wird, diesen Code zu verstehen, da âEinfachheit des Codesâ ein subjektives Konzept ist. Manchmal kann es notwendig sein, nur zu reduce
. Wenn Sie die Verarbeitungsgeschwindigkeit des Datensatzes mit den in einer Kette kombinierten map
und filter
und mit reduce
, stellt sich heraus, dass die zweite Option schneller funktioniert. Bei der Option mit reduce
Sie den Wertesatz einmal und nicht zweimal betrachten. Vor uns liegt eine Debatte ĂŒber ProduktivitĂ€t und Einfachheit. In den meisten FĂ€llen wĂŒrde ich die Einfachheit bevorzugen und versuchen, eine vorzeitige Codeoptimierung zu vermeiden, dh ich wĂŒrde ein map
/ filter
Paar wÀhlen, anstatt es zu reduce
. Und wenn sich herausstellen wĂŒrde, dass die Konstruktion von map
und filter
zum Engpass des Systems wird, wĂŒrde der zu reduce
Code ĂŒbersetzt.
Viele der unten diskutierten Ideen zielen darauf ab, die Codebasis so einfach wie möglich zu gestalten und in diesem Zustand zu halten.
Halten Sie Àhnliche Objekte nahe beieinander
Dieses Prinzip, das âColocation-Prinzipâ, gilt fĂŒr viele Teile der Anwendung. Dies ist die Struktur der Ordner, in denen der Client- und Servercode gespeichert ist. Dies ist die Speicherung des Projektcodes in einem Repository. Dies ist auch die Entscheidung darĂŒber, welcher Code in einer bestimmten Datei enthalten ist.
â Repository
Es wird empfohlen, den Client- und Servercode im selben Repository zu belassen. Das ist einfach. Komplizieren Sie nicht, was nicht notwendig ist, um zu komplizieren. Mit diesem Ansatz ist es bequem, eine koordinierte Teamarbeit an einem Projekt zu organisieren. Ich habe an Projekten gearbeitet, in denen verschiedene Repositories zum Speichern von Materialien verwendet wurden. Dies ist keine Katastrophe, aber Mono-Repositories erleichtern das Leben erheblich.
â Projektstruktur des Client-Teils der Anwendung
Wir schreiben Full-Stack-Anwendungen. Das heiĂt, sowohl der Client-Code als auch der Server-Code. Die Ordnerstruktur eines typischen Client-Projekts bietet separate Verzeichnisse fĂŒr Komponenten, Container, Aktionen, Reduzierungen und Routen.
Aktionen und Reduzierungen sind in Projekten vorhanden, die Redux verwenden. Ich bemĂŒhe mich, auf diese Bibliothek zu verzichten. Ich bin sicher, dass es qualitativ hochwertige Projekte gibt, die dieselbe Struktur verwenden. Einige meiner Projekte haben separate Ordner fĂŒr Komponenten und Container. Ein Komponentenordner kann so etwas wie Dateien mit Code fĂŒr EntitĂ€ten wie
BlogPost
und
Profile
BlogPost
. Im Containerordner befinden sich Dateien, in denen der Containercode
BlogPostContainer
und
BlogPostContainer
. Der Container empfĂ€ngt Daten vom Server und ĂŒbergibt sie an die "dumme" untergeordnete Komponente, deren Aufgabe es ist, diese Daten auf dem Bildschirm anzuzeigen.
Dies ist eine Arbeitsstruktur. Es ist zumindest homogen, und das ist sehr wichtig. Dies fĂŒhrt dazu, dass der Entwickler, der sich der Arbeit an dem Projekt angeschlossen hat, schnell versteht, was darin passiert und welche Rolle die einzelnen Teile spielen. Der Nachteil dieses Ansatzes, aufgrund dessen ich kĂŒrzlich versucht habe, ihn nicht zu verwenden, besteht darin, dass er den Programmierer zwingt, sich stĂ€ndig in der Codebasis zu bewegen. Beispielsweise haben die
BlogPostContainer
und
BlogPostContainer
nichts gemeinsam, aber ihre Dateien befinden sich nebeneinander und weit entfernt von den Dateien, in denen sie tatsÀchlich verwendet werden.
Seit einiger Zeit bemĂŒhe ich mich, Dateien, deren Inhalt freigegeben werden soll, in denselben Ordnern abzulegen. Dieser Ansatz zur Projektstrukturierung basiert auf der Gruppierung von Dateien nach ihren FĂ€higkeiten. Dank dieses Ansatzes können Sie Ihr Leben erheblich vereinfachen, wenn Sie beispielsweise die ĂŒbergeordnete Komponente und ihre âdummeâ untergeordnete Komponente im selben Ordner ablegen.
Normalerweise verwenden wir den Ordner
routes
/
screens
und den Ordner
components
. Der Komponentenordner speichert normalerweise Code fĂŒr Elemente wie
Button
oder
Input
. Dieser Code kann auf jeder Seite der Anwendung verwendet werden. Jeder Ordner im Ordner fĂŒr Routen ist eine separate Anwendungsseite. Gleichzeitig befinden sich Dateien mit dem Komponentencode und dem Anwendungslogikcode fĂŒr diese Route im selben Ordner. Der Code der Komponenten, die auf mehreren Seiten verwendet werden, fĂ€llt in den
components
.
Innerhalb des Routenordners können Sie zusĂ€tzliche Ordner erstellen, in denen der Code gruppiert ist, der fĂŒr die Bildung verschiedener Teile der Seite verantwortlich ist. Dies ist in FĂ€llen sinnvoll, in denen die Route durch eine groĂe Menge Code dargestellt wird. Hier möchte ich den Leser jedoch warnen, dass es sich nicht lohnt, Strukturen aus Ordnern mit einem sehr hohen Verschachtelungsgrad zu erstellen. Dies erschwert die Bewegung des Projekts. Tief verschachtelte Ordnerstrukturen sind eines der Anzeichen fĂŒr eine Ăberkomplikation eines Projekts. Es sollte beachtet werden, dass die Verwendung spezieller Tools wie Suchbefehle dem Programmierer bequeme Tools zum Arbeiten mit dem Projektcode und zum Finden dessen, was er benötigt, bietet. Die Dateistruktur des Projekts wirkt sich jedoch auch auf die Benutzerfreundlichkeit aus.
Wenn Sie den Projektcode strukturieren, können Sie Dateien nicht nach der Route, sondern nach den von diesen Dateien implementierten Projektfunktionen gruppieren. In meinem Fall zeigt sich dieser Ansatz perfekt bei einseitigen Projekten, die viele Funktionen auf ihrer einzigen Seite implementieren. Es ist jedoch zu beachten, dass das Gruppieren von Projektmaterialien nach Routen einfacher ist. Dieser Ansatz erfordert keine besonderen mentalen Anstrengungen, um Entscheidungen darĂŒber zu treffen, welche EntitĂ€ten nebeneinander platziert werden sollen, und um nach etwas zu suchen.
Wenn wir den Code weiter gruppieren, können wir entscheiden, dass der Code von Containern und Komponenten zu Recht in derselben Datei abgelegt wird. Und Sie können noch weiter gehen - fĂŒgen Sie den Code zweier Komponenten in eine Datei ein. Ich nehme an, Sie denken jetzt vielleicht, dass es wirklich GotteslĂ€sterung ist, solche Dinge zu empfehlen. Aber in Wirklichkeit ist alles alles andere als schlecht. TatsĂ€chlich ist dieser Ansatz völlig gerechtfertigt. Und wenn Sie React-Hooks oder generierten Code (oder beides) verwenden, wĂŒrde ich diesen Ansatz empfehlen.
TatsĂ€chlich ist die Frage, wie der Code in Dateien zerlegt werden soll, nicht von gröĂter Bedeutung. Die eigentliche Frage ist, warum Sie die Komponenten möglicherweise in intelligent und dumm unterteilen mĂŒssen. Was sind die Vorteile dieser Trennung? Auf diese Frage gibt es mehrere Antworten:
- Auf diese Weise erstellte Anwendungen sind einfacher zu testen.
- Die Entwicklung solcher Anwendungen erleichtert die Verwendung von Tools wie dem Storybook.
- Dumme Komponenten können mit vielen verschiedenen intelligenten Komponenten verwendet werden (und umgekehrt).
- Intelligente Komponenten können auf verschiedenen Plattformen verwendet werden (z. B. auf den Plattformen React und React Native).
All dies sind echte Argumente fĂŒr die Unterteilung der Komponenten in âintelligentâ und âdummâ, aber sie gelten nicht fĂŒr alle Situationen. Beispielsweise verwenden wir beim Erstellen von Projekten hĂ€ufig
Apollo Client mit Hooks. Um solche Projekte zu testen, können Sie entweder Apollo-Antwort-Mocks oder Hook-Mocks erstellen. Gleiches gilt fĂŒr das Storybook. Wenn wir ĂŒber das Mischen und Teilen von âintelligentenâ und âdummenâ Komponenten sprechen, habe ich dies in der Praxis noch nie erlebt. In Bezug auf die plattformĂŒbergreifende Verwendung des Codes gab es ein Projekt, in dem ich etwas Ăhnliches tun wollte, dies aber nie tat. Es sollte das Lerna-
Mono-Repository sein . Anstelle dieses Ansatzes können Sie sich heutzutage fĂŒr React Native Web entscheiden.
Infolgedessen können wir sagen, dass die Trennung von Komponenten in âintelligentâ und âalbernâ eine bestimmte Bedeutung hat. Dies ist ein wichtiges wissenswertes Konzept. Oft mĂŒssen Sie sich jedoch keine groĂen Sorgen machen, insbesondere angesichts des jĂŒngsten Auftretens von React-Hooks.
Die StĂ€rke der Kombination der Funktionen von âintelligentenâ und âalbernenâ Komponenten in einer EntitĂ€t besteht darin, dass die Entwicklung beschleunigt und die Struktur des Codes vereinfacht wird.
DarĂŒber hinaus kann eine Komponente bei Bedarf immer in zwei separate Komponenten unterteilt werden - âintelligentâ und âdummâ.
Stilisierung
Wir verwenden
emotionale /
gestaltete Komponenten fĂŒr Styling-Anwendungen. Es besteht immer die Versuchung, Stile in eine separate Datei zu trennen. Ich habe einige Entwickler gesehen, die dies getan haben. Nachdem ich beide AnsĂ€tze ausprobiert hatte, konnte ich am Ende keinen Grund finden, die Stile in eine separate Datei zu verschieben. Wie bei vielen anderen Dingen, ĂŒber die wir hier sprechen, kann ein Entwickler sein Leben erleichtern, indem er die Stile und Komponenten, auf die sie sich beziehen, in einer Datei kombiniert.
âProjektstruktur des Serverteils der Anwendung
All dies gilt fĂŒr die Strukturierung des serverseitigen Codes der Anwendung. Eine typische Struktur, die ich persönlich zu vermeiden versuche, könnte ungefĂ€hr so ââaussehen:
src â app.js # ââââapi # Express ââââconfig # ââââjobs # agenda.js ââââloaders # ââââmodels # ââââservices # - ââââsubscribers # ââââtypes # (d.ts) Typescript
Normalerweise verwenden wir GraphQL in unseren Projekten. Daher verwenden sie Dateien, in denen Modelle, Dienste und Erkenner gespeichert sind. Anstatt sie an verschiedenen Stellen des Projekts zu verteilen, sammle ich sie in einem Ordner. In den meisten FĂ€llen werden diese Dateien freigegeben, und es ist einfacher, mit ihnen zu arbeiten, wenn sie im selben Ordner gespeichert sind.
Ăberschreiben Sie Typdefinitionen nicht oft
In unseren Projekten verwenden wir viele Lösungen, die in irgendeiner Weise mit Datentypen zusammenhĂ€ngen. Dies sind TypeScript, GraphQL, Datenbankschemata und manchmal MobX. Infolgedessen kann sich herausstellen, dass die Typen fĂŒr dieselben EntitĂ€ten 3-4 Mal beschrieben werden. Solche Dinge sollten vermieden werden. Wir sollten uns bemĂŒhen, Werkzeuge zu verwenden, die automatisch Typbeschreibungen generieren.
Auf dem Server kann zu diesem Zweck eine Kombination aus TypeORM / Typegoose und TypeGraphQL verwendet werden. Dies reicht aus, um alle verwendeten Typen zu beschreiben. Mit TypeORM / Typegoose können Sie das Datenbankschema und die entsprechenden TypeScript-Typen beschreiben. TypeGraphQL hilft beim Erstellen der Typen von GraphQL und TypeScript.
Hier ist ein Beispiel fĂŒr die Bestimmung der Typen von TypeORM (MongoDB) und TypeGraphQL in einer Datei:
import { Field, ObjectType, ID } from 'type-graphql' import { Entity, ObjectIdColumn, ObjectID, Column, CreateDateColumn, UpdateDateColumn, } from 'typeorm' @ObjectType() @Entity() export default class Policy { @Field(type => ID) @ObjectIdColumn() _id: ObjectID @Field() @CreateDateColumn({ type: 'timestamp' }) createdAt: Date @Field({ nullable: true }) @UpdateDateColumn({ type: 'timestamp', nullable: true }) updatedAt?: Date @Field() @Column() name: string @Field() @Column() version: number }
GraphQL Code Generator kann auch viele verschiedene Typen generieren. Wir verwenden dieses Tool, um TypeScript-Typen auf dem Client sowie React-Hooks zu erstellen, die auf den Server zugreifen.
Wenn Sie MobX verwenden, um den Status der Anwendung zu steuern, und dann mithilfe einiger Codezeilen automatisch generierte TS-Typen erhalten. Wenn Sie auch GraphQL verwenden, sollten Sie sich das neue Paket
MST-GQL ansehen , das aus dem GQL-Schema einen
Statusbaum generiert.
Wenn Sie diese Tools zusammen verwenden, können Sie keine groĂen Mengen an Code neu schreiben und hĂ€ufige Fehler vermeiden.
Andere Lösungen wie
Prisma ,
Hasura und
AWS AppSync können ebenfalls dazu beitragen, doppelte Typdeklarationen zu vermeiden. Die Verwendung solcher Tools hat natĂŒrlich Vor- und Nachteile. In den von uns erstellten Projekten werden solche Tools nicht immer verwendet, da wir den Code auf unseren eigenen Servern von Organisationen bereitstellen mĂŒssen.
Verwenden Sie nach Möglichkeit die automatische Codegenerierung
Wenn Sie sich den Code ansehen, den Sie erstellen, ohne die oben genannten Tools zum automatischen Generieren von Code zu verwenden, stellt sich heraus, dass Programmierer stĂ€ndig dasselbe schreiben mĂŒssen. Der wichtigste Rat, den ich dazu geben kann, ist, dass Sie Snippets fĂŒr alles erstellen mĂŒssen, was Sie hĂ€ufig verwenden. Wenn Sie hĂ€ufig den Befehl
console.log
, erstellen Sie ein Snippet wie
cl
, das automatisch in
console.log()
. Wenn Sie dies nicht tun und mich bitten, Ihnen beim Debuggen von Code zu helfen, wird mich das sehr verÀrgern.
Es gibt viele Pakete mit Snippets, aber es ist einfach, eigene Snippets zu erstellen. Zum Beispiel mit dem
Snippet-Generator .
Hier ist der Code, mit dem ich einige meiner Lieblingsausschnitte zu VS Code hinzufĂŒgen kann:
{ "Export default": { "scope": "javascript,typescript,javascriptreact,typescriptreact", "prefix": "eid", "body": [ "export { default } from './${TM_DIRECTORY/.*[\\/](.*)$$/$1/}'", "$2" ], "description": "Import and export default in a single line" }, "Filename": { "prefix": "fn", "body": ["${TM_FILENAME_BASE}"], "description": "Print filename" }, "Import emotion styled": { "prefix": "imes", "body": ["import styled from '@emotion/styled'"], "description": "Import Emotion js as styled" }, "Import emotion css only": { "prefix": "imec", "body": ["import { css } from '@emotion/styled'"], "description": "Import Emotion css only" }, "Import emotion styled and css only": { "prefix": "imesc", "body": ["import styled, { css } from ''@emotion/styled'"], "description": "Import Emotion js and css" }, "Styled component": { "prefix": "sc", "body": ["const ${1} = styled.${2}`", " ${3}", "`"], "description": "Import Emotion js and css" }, "TypeScript React Function Component": { "prefix": "rfc", "body": [ "import React from 'react'", "", "interface ${1:ComponentName}Props {", "}", "", "const ${1:ComponentName}: React.FC<${1:ComponentName}Props> = props => {", " return (", " <div>", " ${1:ComponentName}", " </div>", " )", "}", "", "export default ${1:ComponentName}", "" ], "description": "TypeScript React Function Component" } }
ZusÀtzlich zu Snippets können Codegeneratoren helfen, Zeit zu sparen. Sie können sie selbst erstellen. Ich
benutze dafĂŒr gerne
Plop .
Angular verfĂŒgt ĂŒber eigene Codegeneratoren. Mit den Befehlszeilentools können Sie eine neue Komponente erstellen, die aus 4 Dateien besteht und alles enthĂ€lt, was Sie in der Komponente erwarten können. Es ist schade, dass React nicht ĂŒber eine solche Standardfunktion verfĂŒgt, aber etwas Ăhnliches kann unabhĂ€ngig mit plop erstellt werden. Wenn jede neue Komponente, die Sie erstellen, in Form eines Ordners angezeigt werden soll, der eine Datei mit dem Komponentencode, eine Testdatei und eine Storybook-Datei enthĂ€lt, hilft der Generator dabei, all dies mit einem Befehl zu erstellen. Dies erleichtert in vielen FĂ€llen das Leben des Entwicklers erheblich. Wenn Sie beispielsweise dem Server eine neue Funktion hinzufĂŒgen, fĂŒhren Sie einfach einen Befehl in der Befehlszeile aus. Danach werden automatisch Dateien der EntitĂ€t, Dienste und Erkenner erstellt, die alle erforderlichen Grundstrukturen enthalten.
Eine weitere StĂ€rke von Codegeneratoren besteht darin, dass sie zur Einheitlichkeit der Teamentwicklung beitragen. Wenn jeder den gleichen Plop-Generator verwendet, ist der Code fĂŒr alle sehr einheitlich.
Automatische Code-Formatierung
Das Formatieren des Codes ist eine einfache Aufgabe, die jedoch leider nicht immer richtig gelöst wird. Verschwenden Sie keine Zeit damit, den Code manuell auszurichten oder Semikolons einzufĂŒgen. Verwenden Sie
Prettier, um den Code beim
Festschreiben automatisch zu formatieren.
Zusammenfassung
In diesem Artikel habe ich Ihnen einige Dinge erzÀhlt, die wir im Laufe der Jahre der Arbeit, im Laufe der Jahre des Versuchs und Irrtums gelernt haben. Es gibt viele AnsÀtze zur Strukturierung der Codebasis von Projekten. Aber unter ihnen gibt es niemanden, der als der einzig richtige bezeichnet werden kann.
Das Wichtigste, was ich Ihnen vermitteln wollte, ist, dass der Programmierer sich um die Einfachheit der Organisation von Projekten, ihre HomogenitĂ€t und die Verwendung einer verstĂ€ndlichen Struktur bemĂŒht, mit der man leicht arbeiten kann. Dies vereinfacht Teamentwicklungsprojekte.
Liebe Leser! Was halten Sie von den in diesem Artikel beschriebenen Ideen fĂŒr die Entwicklung von Full-Stack-JavaScript-Anwendungen?

