{"id":18512446,"url":"https://github.com/marcbruederlin/clean-code-javascript","last_synced_at":"2025-10-16T08:58:14.369Z","repository":{"id":124183675,"uuid":"79374793","full_name":"marcbruederlin/clean-code-javascript","owner":"marcbruederlin","description":"🛁  Clean Code-Konzepte adaptiert für JavaScript.","archived":false,"fork":false,"pushed_at":"2024-01-05T08:35:35.000Z","size":28,"stargazers_count":48,"open_issues_count":0,"forks_count":8,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-09T22:12:51.845Z","etag":null,"topics":["best-practices","clean-architecture","clean-code","guidelines","javascript"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marcbruederlin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-01-18T19:16:10.000Z","updated_at":"2024-10-31T20:07:50.000Z","dependencies_parsed_at":"2024-01-05T09:44:09.484Z","dependency_job_id":null,"html_url":"https://github.com/marcbruederlin/clean-code-javascript","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/marcbruederlin/clean-code-javascript","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcbruederlin%2Fclean-code-javascript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcbruederlin%2Fclean-code-javascript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcbruederlin%2Fclean-code-javascript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcbruederlin%2Fclean-code-javascript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcbruederlin","download_url":"https://codeload.github.com/marcbruederlin/clean-code-javascript/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcbruederlin%2Fclean-code-javascript/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274402705,"owners_count":25278348,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-10T02:00:12.551Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["best-practices","clean-architecture","clean-code","guidelines","javascript"],"created_at":"2024-11-06T15:34:11.296Z","updated_at":"2025-10-16T08:58:09.324Z","avatar_url":"https://github.com/marcbruederlin.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Original Repository: [ryanmcdermott/clean-code-javascript](https://github.com/ryanmcdermott/clean-code-javascript)\n\n# clean-code-javascript\n\n## \u003ca id='table-of-contents'\u003eInhaltsverzeichnis\u003c/a\u003e\n  1. [Einführung](#table-of-contents)\n  2. [Variablen](#variables)\n  3. [Funktionen](#functions)\n  4. [Objekte und Datenstrukturen](#objects-and-data-structures)\n  5. [Klassen](#classes)\n  6. [SOLID](#solid)\n  7. [Testing](#testing)\n  8. [Parallelität](#concurrency)\n  9. [Fehlerbehandlung](#error-handling)\n  10. [Formatierung](#formatting)\n  11. [Kommentare](#comments)\n  12. [Übersetzungen](#translation)\n\n## \u003ca id='introduction'\u003eEinführung\u003c/a\u003e\n![Humorous image of software quality estimation as a count of how many expletives\nyou shout when reading code](http://www.osnews.com/images/comics/wtfm.jpg)\n\nSoftwareentwicklungs-Prinzipien aus Robert C. Martin's Buch\n[*Clean Code*](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882),\nadaptiert für JavaScript. Dies ist kein Styleguide. Es ist ein Leitfaden um lesbare, wiederverwendbare \nund wartbare Software mit JavaScript zu entwickeln.\n\nNicht jede Regel hier muss streng befolgt werden und noch weniger Regeln werden universell \nanwendbar sein. Dies sind Richtlinien und nicht mehr. Sie sind jedoch das Ergebnis \njahrelang gesammelter Erfahrung des Autors von *Clean Code*.\n\nUnser Handwerk der Softwareentwicklung ist nur etwas mehr als 50 Jahre alt und wir lernen \nimmer noch eine Menge. Wenn Softwarearchitektur ebenso alt ist wie die Architektur, haben wir \nwomöglich strengere Regeln denen wir zu folgen haben. Für den Moment, lass diese Richtlinien \nein Maßstab sein um die Qualität des JavaScript-Codes den du und dein Team produzierst, \nbeurteilen zu können.\n\nEine Sache noch: Diese Regeln zu kennen macht dich nicht unverzüglich zu einem besseren \nSoftwareentwickler. Und mit ihnen für viele Jahre zu arbeiten heißt nicht, dass du keine \nFehler machst. Jedes Stück Code startet mit einem ersten Entwurf – wie nasser Ton der in \nseine finale Form ausgestaltet wird. Wir meißeln endlich die Unvollkommenheiten weg, wenn \nwir unseren Code mit Kollegen überprüfen. Mach dich wegen ersten Entwürfen die Verbesserungen \nbenötigen nicht fertig. Verprügel stattdessen den Code!\n\n## \u003ca id='variables'\u003eVariablen\u003c/a\u003e\n### Verwende aussagekräftige und aussprechbare Variablennamen\n\n**Schlecht:**\n```javascript\nconst yyyymmdstr = moment().format('YYYY/MM/DD');\n```\n\n**Gut:**\n```javascript\nconst currentDate = moment().format('YYYY/MM/DD');\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Verwende dieselbe Bezeichnung für die selbe Art von Variablen\n\n**Schlecht:**\n```javascript\ngetUserInfo();\ngetClientData();\ngetCustomerRecord();\n```\n\n**Gut:**\n```javascript\ngetUser();\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Verwende suchbare Namen\nWir lesen mehr Code als wir jemals schreiben werden. Es ist daher wichtig, dass \nder Code den wir schreiben les- und durchsuchbar ist. Wir erschweren den Lesern\nunseres Codes die Arbeit, wenn wir unsere Variablen *nicht* aussagekräftig benennen\nund somit das Verständnis unseres Programms erschweren.\nMache deine Namen suchbar. Tools wie [buddy.js](https://github.com/danielstjules/buddy.js) und\n[ESLint](https://github.com/eslint/eslint/blob/660e0918933e6e7fede26bc675a0763a6b357c94/docs/rules/no-magic-numbers.md)\nkönnen dabei helfen, unbenannte Konstanten zu finden.\n\n**Schlecht:**\n```javascript\n// Wofür steht 86400000?\nsetTimeout(blastOff, 86400000);\n```\n\n**Gut:**\n```javascript\n// Deklariere diese als großgeschriebene `const` Globale.\nconst MILLISECONDS_IN_A_DAY = 86400000;\n\nsetTimeout(blastOff, MILLISECONDS_IN_A_DAY);\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Verwende selbsterklärende Variablen\n**Schlecht:**\n```javascript\nconst address = 'One Infinite Loop, Cupertino 95014';\nconst cityZipCodeRegex = /^[^,\\\\]+[,\\\\\\s]+(.+?)\\s*(\\d{5})?$/;\nsaveCityZipCode(address.match(cityZipCodeRegex)[1], address.match(cityZipCodeRegex)[2]);\n```\n\n**Gut:**\n```javascript\nconst address = 'One Infinite Loop, Cupertino 95014';\nconst cityZipCodeRegex = /^[^,\\\\]+[,\\\\\\s]+(.+?)\\s*(\\d{5})?$/;\nconst [, city, zipCode] = address.match(cityZipCodeRegex) || [];\nsaveCityZipCode(city, zipCode);\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Vermeide Mental Mapping\nExplizites ist besser als Implizites.\n\n**Schlecht:**\n```javascript\nconst locations = ['Austin', 'New York', 'San Francisco'];\nlocations.forEach((l) =\u003e {\n  doStuff();\n  doSomeOtherStuff();\n  // ...\n  // ...\n  // ...\n  // Moment, wofür steht `l` nochmal?\n  dispatch(l);\n});\n```\n\n**Gut:**\n```javascript\nconst locations = ['Austin', 'New York', 'San Francisco'];\nlocations.forEach((location) =\u003e {\n  doStuff();\n  doSomeOtherStuff();\n  // ...\n  // ...\n  // ...\n  dispatch(location);\n});\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Verzichte auf überflüssigen Kontext\nWenn dir deine Klasse/Objekt etwas sagt, wiederhole das nicht in deinem \nVariablennamen.\n\n**Schlecht:**\n```javascript\nconst Car = {\n  carMake: 'Honda',\n  carModel: 'Accord',\n  carColor: 'Blue'\n};\n\nfunction paintCar(car) {\n  car.carColor = 'Red';\n}\n```\n\n**Gut:**\n```javascript\nconst Car = {\n  make: 'Honda',\n  model: 'Accord',\n  color: 'Blue'\n};\n\nfunction paintCar(car) {\n  car.color = 'Red';\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Verwende Default-Werte anstatt Short-Circuiting oder Bedingungen\nDefault-Werte sind meistens sauberer als Short-Circuiting. Sei dir aber bewusst, dass \ndeine Funktion nur Default-Werte für `undefined`-Argumente vergibt. Andere „falsche“ Werte \nwie beispielsweise `''`, `false`, `null`, `0` und `NaN` werden nicht durch Default-Werte ersetzt.\n\n**Schlecht:**\n```javascript\nfunction createMicrobrewery(name) {\n  const breweryName = name || 'Hipster Brew Co.';\n  // ...\n}\n```\n\n**Gut:**\n```javascript\nfunction createMicrobrewery(breweryName = 'Hipster Brew Co.') {\n  // ...\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n## \u003ca id='functions'\u003eFunktionen\u003c/a\u003e\n### Funktionsargumente (2 oder idealerweise weniger)\nDie Anzahl der Funktionsargumente zu limitieren ist unglaublich wichtig, weil\ndadurch die Testbarkeit deiner Funktion erleichtert wird. Mehr als drei Argumente\nführen zu einer kombinatorischen Explosion und du musst unzählige verschiedene \nFälle mit jedem einzelnen Argument testen.\n\nEin bis zwei Argumente sind ideal, drei sollten aber wenn möglich vermieden werden. \nAlles darüber sollte zusammengefasst werden. Meistens erledigt deine Funktion zu viel, \nwenn du mehr als zwei Argumente benötigst. Falls nicht, reicht es ein übergeordnetes \nObjekt als Argument zu übergeben.\n\nWeil uns JavaScript erlaubt Objekte on-the-fly und ohne viel Klassen-Boilerplate zu \nerstellen, kannst du Objekte verwenden wenn du merkst, dass du eine Menge Argumente\nbenötigst.\n\nUm deutlich zu machen, welche Eigenschaften eine Funktion erwartet, kannst du die ES6 \ndestruktierende Zuweisung verwenden. Diese hat einige Vorteile:\n\n1. Wenn sich jemand die Methodensignatur anschaut, wird unmittelbar klar, welche Eigenschaften \nverwendet werden.\n2. Die destruktierende Zuweisung klont die spezifiziert primitiven Datentypen, die in die Funktion \nübergeben werden. Das kann helfen, Nebeneffekte zu verhindern. Anmerkung: Objekte und Arrays werden \nNICHT geklont.\n3. Linter können dich vor unbenutzten Eigenschaften warnen. Das wäre ohne die destruktierende Zuweisung \nunmöglich.\n\n**Schlecht:**\n```javascript\nfunction createMenu(title, body, buttonText, cancellable) {\n  // ...\n}\n```\n\n**Gut:**\n```javascript\nfunction createMenu({ title, body, buttonText, cancellable }) {\n  // ...\n}\n\ncreateMenu({\n  title: 'Foo',\n  body: 'Bar',\n  buttonText: 'Baz',\n  cancellable: true\n});\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Funktionen sollten eine Sache erledigen\nDies ist bei weitem die wichtigste Regel in der Softwareentwicklung. Wenn Funktionen\nmehr als eine Sache erledigen sind sie schwerer zu verfassen, zu testen und zu begründen.\nWenn du eine Funktion abgrenzen kannst nur eine Aktion auszuführen, dann kann diese\nproblemlos überarbeitet werden und dein Code liest sich sehr viel einfacher. Wenn du\naus diesem Leitfaden nichts außer diese Regel ziehen kannst, wirst du vielen Entwicklern\neinen Schritt voraus sein. \n\n**Schlecht:**\n```javascript\nfunction emailClients(clients) {\n  clients.forEach((client) =\u003e {\n    const clientRecord = database.lookup(client);\n    if (clientRecord.isActive()) {\n      email(client);\n    }\n  });\n}\n```\n\n**Gut:**\n```javascript\nfunction emailActiveClients(clients) {\n  clients\n    .filter(isActiveClient)\n    .forEach(email);\n}\n\nfunction isActiveClient(client) {\n  const clientRecord = database.lookup(client);\n  return clientRecord.isActive();\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Funktionsnamen sollten selbstdokumentierend sein\n\n**Schlecht:**\n```javascript\nfunction addToDate(date, month) {\n  // ...\n}\n\nconst date = new Date();\n\n// Es ist schwierig zu sagen was laut Funktionsnamen hinzugefügt wird\naddToDate(date, 1);\n```\n\n**Gut:**\n```javascript\nfunction addMonthToDate(month, date) {\n  // ...\n}\n\nconst date = new Date();\naddMonthToDate(1, date);\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Funktionen sollten nur eine Ebene der Abstraktion sein\nWenn du mehr als eine Ebene der Abstraktion hast, erledigt deine Funktion \nmöglicherweise zu viel. Funktionen in mehrere verschiedene Funktionen \naufzuteilen sorgt für eine bessere Wiederverwendbarkeit und einfacheres \nTesting.\n\n**Schlecht:**\n```javascript\nfunction parseBetterJSAlternative(code) {\n  const REGEXES = [\n    // ...\n  ];\n\n  const statements = code.split(' ');\n  const tokens = [];\n  REGEXES.forEach((REGEX) =\u003e {\n    statements.forEach((statement) =\u003e {\n      // ...\n    });\n  });\n\n  const ast = [];\n  tokens.forEach((token) =\u003e {\n    // lex...\n  });\n\n  ast.forEach((node) =\u003e {\n    // parse...\n  });\n}\n```\n\n**Gut:**\n```javascript\nfunction tokenize(code) {\n  const REGEXES = [\n    // ...\n  ];\n\n  const statements = code.split(' ');\n  const tokens = [];\n  REGEXES.forEach((REGEX) =\u003e {\n    statements.forEach((statement) =\u003e {\n      tokens.push( /* ... */ );\n    });\n  });\n\n  return tokens;\n}\n\nfunction lexer(tokens) {\n  const ast = [];\n  tokens.forEach((token) =\u003e {\n    ast.push( /* ... */ );\n  });\n\n  return ast;\n}\n\nfunction parseBetterJSAlternative(code) {\n  const tokens = tokenize(code);\n  const ast = lexer(tokens);\n  ast.forEach((node) =\u003e {\n    // parse...\n  });\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Entferne doppelten Code\nGib dein absolut bestes um doppelten Code zu vermeiden. Doppelter Code ist schlecht\nweil es bedeutet, dass es mehr als eine Stelle gibt um etwas anzupassen, wenn an dieser\nLogik etwas geändert werden soll.\n\nStelle dir vor du betreibst ein Restaurant und willst den Überblick über deinen Vorrat behalten:\nAll deine Tomaten, Zwiebeln, Knoblauch, Gewürze, etc. Wenn du deinen Lagerbestand auf mehreren \nListen festhälst, dann musst du all diese Listen aktualisieren wenn du einen Teller – auf dem \nsich Tomaten befinden – servierst. Wenn du nur eine List hast, dann musst du auch nur diese eine Liste \naktualisieren!\n\nHäufig hast du doppelten Code weil du zwei oder mehr nur geringfügig unterschiedliche Dinge hast, die\nzwar eine Menge exakt gleich erledigen aber ihre Unterschiede zwingen dich dazu zwei oder mehr seperate Funktionen \nzu schreiben. Doppelten Code zu entfernen heißt Abstraktionen zu erstellen, die diese Reihe von unterschiedlichen \nDingen mit nur einer Funktion/Modul/Klasse handhaben können.\n\nDiese Abstraktion gut hinzubekommen ist entscheidend und darum solltest du den SOLID-Regeln im *Klassen*-Kapitel \nfolgen. Schlechte Abstraktionen können schlimmer als doppelter Code sein, also sei vorsichtig! \nIn diesem Sinne, wenn du eine gute Abstraktion hinbekommst - mach es! Wiederhole dich nicht selbst, ansonsten\nwirst du jedes Mal verschiedene Stellen anpassen müssen, wenn du eine Sache ändern möchtest.\n\n**Schlecht:**\n```javascript\nfunction showDeveloperList(developers) {\n  developers.forEach((developer) =\u003e {\n    const expectedSalary = developer.calculateExpectedSalary();\n    const experience = developer.getExperience();\n    const githubLink = developer.getGithubLink();\n    const data = {\n      expectedSalary,\n      experience,\n      githubLink\n    };\n\n    render(data);\n  });\n}\n\nfunction showManagerList(managers) {\n  managers.forEach((manager) =\u003e {\n    const expectedSalary = manager.calculateExpectedSalary();\n    const experience = manager.getExperience();\n    const portfolio = manager.getMBAProjects();\n    const data = {\n      expectedSalary,\n      experience,\n      portfolio\n    };\n\n    render(data);\n  });\n}\n```\n\n**Gut:**\n```javascript\nfunction showEmployeeList(employees) {\n  employees.forEach((employee) =\u003e {\n    const expectedSalary = employee.calculateExpectedSalary();\n    const experience = employee.getExperience();\n\n    const data = {\n      expectedSalary,\n      experience\n    };\n\n    switch (employee.type) {\n      case 'manager':\n        data.portfolio = employee.getMBAProjects();\n        break;\n      case 'developer':\n        data.githubLink = employee.getGithubLink();\n        break;\n    }\n\n    render(data);\n  });\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Setze Default-Objekte mit Object.assign\n\n**Schlecht:**\n```javascript\nconst menuConfig = {\n  title: null,\n  body: 'Bar',\n  buttonText: null,\n  cancellable: true\n};\n\nfunction createMenu(config) {\n  config.title = config.title || 'Foo';\n  config.body = config.body || 'Bar';\n  config.buttonText = config.buttonText || 'Baz';\n  config.cancellable = config.cancellable !== undefined ? config.cancellable : true;\n}\n\ncreateMenu(menuConfig);\n```\n\n**Gut:**\n```javascript\nconst menuConfig = {\n  title: 'Order',\n  // Der User hat den 'body'-Key nicht angegeben\n  buttonText: 'Send',\n  cancellable: true\n};\n\nfunction createMenu(config) {\n  config = Object.assign({\n    title: 'Foo',\n    body: 'Bar',\n    buttonText: 'Baz',\n    cancellable: true\n  }, config);\n\n  // config entspricht nun: {title: \"Order\", body: \"Bar\", buttonText: \"Send\", cancellable: true}\n  // ...\n}\n\ncreateMenu(menuConfig);\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Verwende keine Flags als Funktionsparameter\nFlags zeigen dem Anwender dass diese Funktion mehr als eine Sache macht. Funktionen sollten \nnur eine Sache erledigen. Teile deine Funktionen auf, wenn diese beispielsweise auf Basis eines \nBoolean andere Pfade verwendet.\n\n**Schlecht:**\n```javascript\nfunction createFile(name, temp) {\n  if (temp) {\n    fs.create(`./temp/${name}`);\n  } else {\n    fs.create(name);\n  }\n}\n```\n\n**Gut:**\n```javascript\nfunction createFile(name) {\n  fs.create(name);\n}\n\nfunction createTempFile(name) {\n  createFile(`./temp/${name}`);\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Vermeide Nebeneffekte (Teil 1)\nEine Funktion erzeugt einen Nebeneffekt, wenn sie mehr macht als einen Wert entgegenzunehmen\nund einen oder mehrere Werte zurückzugeben. Ein Nebeneffekt könnte das Schreiben einer Datei,\ndas modifizieren einiger globaler Variablen oder das versehentliche Übertragen deines ganzen Geldes\nan einen Fremden sein.\n\nJetzt brauchst du bei einer Gelegenheit einen Nebeneffekt. Ähnlich wie im vorangegangen Beispiel möchtest\ndu möglicherweise eine Datei schreiben. Fasse dies zusammen um nicht etliche Funktionen und Klassen, die auf\nbestimmte Datei bezogen sind zu schreiben. Habe einen Service der dies erledigt. Einen und auch nur einen.\n\nDer Punkt ist, üblich Tücken wie beispielsweise das Teilen von State zwischen Objekten ohne jegliche\nStruktur mit veränderbaren Datentypen – die überall überschrieben werden können – zu verhindern und die Stellen\nan denen Nebeneffekte auftreten können zusammenzufassen. Wenn du das schaffst, wirst du glücklicher als eine \nVielzahl der anderen Programmierer sein. \n\n**Schlecht:**\n```javascript\n// Globale Variable die von der nachfolgenden Funktion referenziert wird.\n// Wenn wir eine andere Funktion hätten, die diese Variable verwendet, könnte es sein, dass diese nun nicht mehr funktioniert, weil diese Variable nun ein Array ist.\nlet name = 'Ryan McDermott';\n\nfunction splitIntoFirstAndLastName() {\n  name = name.split(' ');\n}\n\nsplitIntoFirstAndLastName();\n\nconsole.log(name); // ['Ryan', 'McDermott'];\n```\n\n**Gut:**\n```javascript\nfunction splitIntoFirstAndLastName(name) {\n  return name.split(' ');\n}\n\nconst name = 'Ryan McDermott';\nconst newName = splitIntoFirstAndLastName(name);\n\nconsole.log(name); // 'Ryan McDermott';\nconsole.log(newName); // ['Ryan', 'McDermott'];\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Vermeide Nebeneffekte (Teil 2)\nIn JavaScript werden primitive Datentypen als Werte und Objekte/Arrays als\nReferenzen übergeben. Wenn deine Funktion beispielsweise im Falle von Objekten \nund Arrays eine Änderung an einem Warenkorb-Array – durch das Hinzufügen eines \nItems – durchführt. Dann werden alle anderen Funktionen die dieses `cart`-Array\nverwenden von dieser Ergänzung betroffen sein. Das mag in manchen Fällen gewünscht \nsein. Es kann aber auch schlecht sein. Stellen wir uns folgende Situation vor:\n\nDer User klickt auf den \"Kaufen\"-Button, der eine `purchase`-Funktion aufruft.\nDiese wiederum erstellt einen Netzwerk-Request und sendet das `cart`-Array zu unserem\nServer. Aufgrund einer schlechten Internetverbindung muss die `purchase`-\nFunktion diesen Request wiederholen. Was passiert nun, wenn der User in der \nZwischenzeit versehentlich auf den „Kaufen“-Button eines Produkts klickt, dass \ner eigentlich gar nicht wollte? Wenn das passiert und der Request beginnt, dann \nwird diese `purchase`-Funktion das versehentlich hinzugefügte Produkt senden, weil \ndiese Funktion eine Referenz zum Warenkorb-Array hat, dass die `addItemToCart`-Funktion \n– durch das Hinzufügen eines ungewollten Produkts – modifiziert hat.\n\nEine tolle Lösung wäre für die `addItemToCart`-Funktion jedesmal `cart` zu kopieren,\nzu bearbeiten und die Kopie zurückzugeben. Dies stellt sicher, dass andere Funktionen \ndie eine Referenz zum Warenkorb besitzen, keine Möglichkeit haben Änderungen durchzuführen.\n\nZwei Einsprüche die zu diesem Ansatz erwähnt werden sollten:\n  1. Möglicherweise gibt es Fälle in denen du wirklich das Input-Objekt modifizieren willst.\nAllerdings werden diese Fälle sehr selten sein. Die meisten Dinge können so überarbeitet werden, \ndass keine Nebeneffekte auftreten!\n\n  2. Große Objekte zu kopieren kann sich hinsichtlich der Performance sehr negativ auswirken. Glücklicherweise \nist das in der Praxis kein großes Problem. Es gibt [tolle Bibliotheken](https://facebook.github.io/immutable-js/) \ndie es erlauben diese Art des Programmieransatzes schneller und nicht so speicherintensiv auszuführen \nwie es wäre wenn du manuell Objekte und Arrays kopierst.\n\n**Schlecht:**\n```javascript\nconst addItemToCart = (cart, item) =\u003e {\n  cart.push({ item, date: Date.now() });\n};\n```\n\n**Gut:**\n```javascript\nconst addItemToCart = (cart, item) =\u003e {\n  return [...cart, { item, date: Date.now() }];\n};\n```\n\n**[⬆ nach oben](#table-of-contents)**\n\n### Schreibe keine globalen Funktionen\nDen globalen Namespace zu verschmutzen ist in JavaScript eine schlechte Angewohnheit, \nweil du dadurch mit anderen Bibliotheken aneinandergeraten könntest und der Nutzer deiner \nSchnittstelle würde nichts davon mitbekommen, bis er einen Fehler bei der Veröffentlichung \nerhält. Stelle dir folgendes Beispiel vor: Was wenn du JavaScripts ursprüngliche Array-Methoden \num eine weitere `diff`-Methode – die dir die Unterschiede zwischen zwei Arrays darstellt – ergänzen \nmöchtest? Du könntest deine neue Funktion mit `Array.prototype` schreiben. Allerdings könnte dies \nmit einer anderen Bibliothek aneinandergeraten, die das selbe versucht hat. Was ist, wenn diese \nandere Bibliothek `diff` nur verwendet um das erste und letzte Element eines Arrays zu finden?\nDas ist der Grund warum es viel besser wäre die Klassen in ES2015/ES6 zu verwenden und einfach die \n`Array`-Globale zu ergänzen.\n\n**Schlecht:**\n```javascript\nArray.prototype.diff = function diff(comparisonArray) {\n  const hash = new Set(comparisonArray);\n  return this.filter(elem =\u003e !hash.has(elem));\n};\n```\n\n**Gut:**\n```javascript\nclass SuperArray extends Array {\n  diff(comparisonArray) {\n    const hash = new Set(comparisonArray);\n    return this.filter(elem =\u003e !hash.has(elem));\n  }\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Ziehe funktionale Programmierung imperativer Programmierung vor\nJavaScript ist keine funktionale Sprache wie es beispielsweise Haskell ist.\nJavaScript hat aber eine funktionale Variante. Funktionale Sprachen sind sauberer \nund einfacher zu testen. Ziehe diesen Stil der Programmierung vor, wenn du kannst.\n\n**Schlecht:**\n```javascript\nconst programmerOutput = [\n  {\n    name: 'Uncle Bobby',\n    linesOfCode: 500\n  }, {\n    name: 'Suzie Q',\n    linesOfCode: 1500\n  }, {\n    name: 'Jimmy Gosling',\n    linesOfCode: 150\n  }, {\n    name: 'Gracie Hopper',\n    linesOfCode: 1000\n  }\n];\n\nlet totalOutput = 0;\n\nfor (let i = 0; i \u003c programmerOutput.length; i++) {\n  totalOutput += programmerOutput[i].linesOfCode;\n}\n```\n\n**Gut:**\n```javascript\nconst programmerOutput = [\n  {\n    name: 'Uncle Bobby',\n    linesOfCode: 500\n  }, {\n    name: 'Suzie Q',\n    linesOfCode: 1500\n  }, {\n    name: 'Jimmy Gosling',\n    linesOfCode: 150\n  }, {\n    name: 'Gracie Hopper',\n    linesOfCode: 1000\n  }\n];\n\nconst totalOutput = programmerOutput\n  .map(output =\u003e output.linesOfCode)\n  .reduce((totalLines, lines) =\u003e totalLines + lines);\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Fasse Bedingungen zusammen\n\n**Schlecht:**\n```javascript\nif (fsm.state === 'fetching' \u0026\u0026 isEmpty(listNode)) {\n  // ...\n}\n```\n\n**Gut:**\n```javascript\nfunction shouldShowSpinner(fsm, listNode) {\n  return fsm.state === 'fetching' \u0026\u0026 isEmpty(listNode);\n}\n\nif (shouldShowSpinner(fsmInstance, listNodeInstance)) {\n  // ...\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Vermeide negative Bedingungen\n\n**Schlecht:**\n```javascript\nfunction isDOMNodeNotPresent(node) {\n  // ...\n}\n\nif (!isDOMNodeNotPresent(node)) {\n  // ...\n}\n```\n\n**Gut:**\n```javascript\nfunction isDOMNodePresent(node) {\n  // ...\n}\n\nif (isDOMNodePresent(node)) {\n  // ...\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Vermeide Bedingungen\nDas hört sich nach einer unmöglichen Aufgabe an. Menschen, die dies zum ersten \nMal hören, fragen sich: „Wie soll ich etwas ohne eine `if`-Anweisung tun?“ Die \nAntwort ist, dass du Polymorphie verwenden kannst um in vielen Fällen die selbe \nAufgabe zu erledigen. Die zweite Frage ist dann oft: „Gut, das ist toll aber \nwarum sollte ich das wollen?“ Die Antwort ist ein Clean-Code-Konzept, das wir bereits \nkennengelernt haben: Eine Funktion sollte lediglich eine Aufgabe erledigen. Wenn du Klassen \nund Funktionen mit `if`-Anweisungen schreibst, teilst du dem Nutzer deines Codes mit, dass \ndeine Funktion mehr als eine Sache erledigt. Vergiss nicht, mache nur eine Sache.\n\n**Schlecht:**\n```javascript\nclass Airplane {\n  // ...\n  getCruisingAltitude() {\n    switch (this.type) {\n      case '777':\n        return this.getMaxAltitude() - this.getPassengerCount();\n      case 'Air Force One':\n        return this.getMaxAltitude();\n      case 'Cessna':\n        return this.getMaxAltitude() - this.getFuelExpenditure();\n    }\n  }\n}\n```\n\n**Gut:**\n```javascript\nclass Airplane {\n  // ...\n}\n\nclass Boeing777 extends Airplane {\n  // ...\n  getCruisingAltitude() {\n    return this.getMaxAltitude() - this.getPassengerCount();\n  }\n}\n\nclass AirForceOne extends Airplane {\n  // ...\n  getCruisingAltitude() {\n    return this.getMaxAltitude();\n  }\n}\n\nclass Cessna extends Airplane {\n  // ...\n  getCruisingAltitude() {\n    return this.getMaxAltitude() - this.getFuelExpenditure();\n  }\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Vermeide es Datentypen zu prüfen (Teil 1)\nJavaScript besitzt keine Datentypen. Das bedeutet, dass deine Funktionen jegliche Datentypen \nals Argument entgegennehmen. Gelegentlich wirst du dich mit dieser Freiheit unwohl fühlen \nund es wird dich dazu verleiten in deinen Funktionen Datentypen zu prüfen. Es gibt viele \nMöglichkeiten, dies zu vermeiden. Der erste Schritt ist, auf einheitliche Schnittstellen zu achten.\n\n**Schlecht:**\n```javascript\nfunction travelToTexas(vehicle) {\n  if (vehicle instanceof Bicycle) {\n    vehicle.pedal(this.currentLocation, new Location('texas'));\n  } else if (vehicle instanceof Car) {\n    vehicle.drive(this.currentLocation, new Location('texas'));\n  }\n}\n```\n\n**Gut:**\n```javascript\nfunction travelToTexas(vehicle) {\n  vehicle.move(this.currentLocation, new Location('texas'));\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Vermeide es Datentypen zu prüfen (Teil 2)\nWenn du mit grundlegenden einfachen Werten wie Strings, Integer und Arrays arbeitest, \ndu Polymorphie nicht anwenden kannst und weiterhin das Bedüfniss verspürst, Datentypen \nzu prüfen. Dann solltest du dir überlegen TypeScript zu verwenden. TypeScript ist eine \nausgezeichnet Alternative zu normalem JavaScript, weil es statische Typen auf Grundlage \nder normalen JavaScript-Syntax anbietet. Das Problem mit dem manuellen Prüfen von Typen \nin JavaScript ist, dass dieser Mehraufwand um diese \"falsche\" Typensicherheit \nzu erreichen die verlorene Lesbarkeit nicht wieder gut macht. Halte dein JavaScript \nsauber, schreibe gute Tests und habe gute Code-Reviews. Anderenfalls erledige dies mit \nTypeScript (was wie gesagt, eine ausgezeichnete Alternative ist!).\n\n**Schlecht:**\n```javascript\nfunction combine(val1, val2) {\n  if (typeof val1 === 'number' \u0026\u0026 typeof val2 === 'number' ||\n      typeof val1 === 'string' \u0026\u0026 typeof val2 === 'string') {\n    return val1 + val2;\n  }\n\n  throw new Error('Must be of type String or Number');\n}\n```\n\n**Gut:**\n```javascript\nfunction combine(val1, val2) {\n  return val1 + val2;\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Überoptimiere nicht\nModerne Browser optimieren eine Menge während der Laufzeit. Du verschwendest häufig \ndeine Zeit, wenn du Dinge optimierst. [Es gibt gute Ressourcen](https://github.com/petkaantonov/bluebird/wiki/Optimization-killers) \num herauszufinden, wo die Optimierungen des Browsers mangelhaft sind. Fokusiere dich \nderweil auf diese Dinge bis sie behoben sind – wenn sie behoben werden können.\n\n**Schlecht:**\n```javascript\n// In alten Browsern würde jeder Durchlauf mit einem ungespeicherten `list.length` speicherintensiv sein,\n// weil `list.length` in jedem Durchlauf neu berechnet wird. In modernen Browsern ist das optimiert.\nfor (let i = 0, len = list.length; i \u003c len; i++) {\n  // ...\n}\n```\n\n**Gut:**\n```javascript\nfor (let i = 0; i \u003c list.length; i++) {\n  // ...\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Entferne veralteten Code\nVeralteter Code ist genau so schlecht wie doppelter Code. Es gibt keinen Grund diesen \nin deiner Code-Basis zu lassen. Wenn etwas nicht aufgerufen wird, werde es los! Es \nwird weiterhin in deiner Versionsverwaltung stehen, falls du es nochmal benötigst.\n\n**Schlecht:**\n```javascript\nfunction oldRequestModule(url) {\n  // ...\n}\n\nfunction newRequestModule(url) {\n  // ...\n}\n\nconst req = newRequestModule;\ninventoryTracker('apples', req, 'www.inventory-awesome.io');\n```\n\n**Gut:**\n```javascript\nfunction newRequestModule(url) {\n  // ...\n}\n\nconst req = newRequestModule;\ninventoryTracker('apples', req, 'www.inventory-awesome.io');\n```\n**[⬆ nach oben](#table-of-contents)**\n\n## \u003ca id='objects-and-data-structures'\u003eObjekte und Datenstrukturen\u003c/a\u003e\n### Verwende Getter und Setter\nGetter und Setter zu verwenden, um Zugriff auf Daten eines Objekts zu bekommen, ist um \neiniges besser als einfach nach der Eigenschaft eines Objekts zu schauen. „Warum?“ fragst \ndu dich vielleicht. Nun, hier ist eine ungeordnete Liste mit Gründen:\n\n* Wenn du mehr als nur das Erhalten eines Objekt-Eigenschaft erledigen möchtest, muss du \nnicht alle Zugrifssmethoden in deinem Code anpassen.\n* Macht es einfach, innerhalb eines `set`-Aufrufs eine Validierung hinzuzufügen.\n* Verschachtelt die interne Darstellung.\n* Macht es einfach, Logging und Fehlerbehandlung hinzuzufügen, wenn Daten gespeichert \noder abgerufen werden.\n* Du kannst die Eigenschaften eines Objekts mittels lazy-loading laden. Beispielsweise von \neinem Server.\n\n**Schlecht:**\n```javascript\nfunction makeBankAccount() {\n  // ...\n\n  return {\n    balance: 0,\n    // ...\n  };\n}\n\nconst account = makeBankAccount();\naccount.balance = 100;\n```\n\n**Gut:**\n```javascript\nfunction makeBankAccount() {\n  // Diese Variable ist privat\n  let balance = 0;\n\n  // Ein \"Getter\", wird duch das unten zurückgegebene Objekt public gemacht\n  function getBalance() {\n    return balance;\n  }\n\n  // Ein \"Setter\", wird duch das unten zurückgegebene Objekt public gemacht\n  function setBalance(amount) {\n    // ... validieren bevor der Kontostand aktualisiert wird\n    balance = amount;\n  }\n\n  return {\n    // ...\n    getBalance,\n    setBalance,\n  };\n}\n\nconst account = makeBankAccount();\naccount.setBalance(100);\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Sorge dafür, dass Objekte private Member besitzen\nDies kann durch Closures erreicht werden (für ES5 und darunter).\n\n**Schlecht:**\n```javascript\nconst Employee = function(name) {\n  this.name = name;\n};\n\nEmployee.prototype.getName = function getName() {\n  return this.name;\n};\n\nconst employee = new Employee('John Doe');\nconsole.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe\ndelete employee.name;\nconsole.log(`Employee name: ${employee.getName()}`); // Employee name: undefined\n```\n\n**Gut:**\n```javascript\nfunction makeEmployee(name) {\n  return {\n    getName() {\n      return name;\n    },\n  };\n}\n\nconst employee = makeEmployee('John Doe');\nconsole.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe\ndelete employee.name;\nconsole.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe\n```\n**[⬆ nach oben](#table-of-contents)**\n\n## \u003ca id='classes'\u003eKlassen\u003c/a\u003e\n### Ziehe ES2015-/ES6-Klassen einfachen ES5-Funktionen vor\nEs ist sehr schwer, lesbare Klassen-Vererbungen, Konstruktionen und Methoden-Definitionen mit \nklassischen ES5-Klassen zu schreiben. Wenn du Vererbungen benötigst (und sei dir bewusst, dass \ndu es möglicherweise doch nicht brauchst), dann bevorzuge Klassen. Verwende schlanke \nFunktionen bis du dir sicher bist, größere und komplexere Objekte zu benötigen.\n\n**Schlecht:**\n```javascript\nconst Animal = function(age) {\n  if (!(this instanceof Animal)) {\n    throw new Error('Instantiate Animal with `new`');\n  }\n\n  this.age = age;\n};\n\nAnimal.prototype.move = function move() {};\n\nconst Mammal = function(age, furColor) {\n  if (!(this instanceof Mammal)) {\n    throw new Error('Instantiate Mammal with `new`');\n  }\n\n  Animal.call(this, age);\n  this.furColor = furColor;\n};\n\nMammal.prototype = Object.create(Animal.prototype);\nMammal.prototype.constructor = Mammal;\nMammal.prototype.liveBirth = function liveBirth() {};\n\nconst Human = function(age, furColor, languageSpoken) {\n  if (!(this instanceof Human)) {\n    throw new Error('Instantiate Human with `new`');\n  }\n\n  Mammal.call(this, age, furColor);\n  this.languageSpoken = languageSpoken;\n};\n\nHuman.prototype = Object.create(Mammal.prototype);\nHuman.prototype.constructor = Human;\nHuman.prototype.speak = function speak() {};\n```\n\n**Gut:**\n```javascript\nclass Animal {\n  constructor(age) {\n    this.age = age;\n  }\n\n  move() { /* ... */ }\n}\n\nclass Mammal extends Animal {\n  constructor(age, furColor) {\n    super(age);\n    this.furColor = furColor;\n  }\n\n  liveBirth() { /* ... */ }\n}\n\nclass Human extends Mammal {\n  constructor(age, furColor, languageSpoken) {\n    super(age, furColor);\n    this.languageSpoken = languageSpoken;\n  }\n\n  speak() { /* ... */ }\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Verwende die Verkettung von Methoden\nDieses Entwurfsmuster ist in JavaScript sehr nützlich und du wirst es in vielen \nBibliotheken, wie beispielsweise in jQuery und Lodash finden. Es erlaubt deinem \nCode mehr aussagekräftig und weniger langatmig zu sein. Aus diesem Grund würde \nich sagen, verwende die Methoden-Verkettung und schaue dir an, wie sauber dein \nCode sein wird. Gib in deinen Klassen-Methoden am Ende jeder Funktion \neinfach `this` zurück und du wirst weitere Methoden verketten können.\n\n**Schlecht:**\n```javascript\nclass Car {\n  constructor(make, model, color) {\n    this.make = make;\n    this.model = model;\n    this.color = color;\n  }\n\n  setMake(make) {\n    this.make = make;\n  }\n\n  setModel(model) {\n    this.model = model;\n  }\n\n  setColor(color) {\n    this.color = color;\n  }\n\n  save() {\n    console.log(this.make, this.model, this.color);\n  }\n}\n\nconst car = new Car('Ford','F-150','red');\ncar.setColor('pink');\ncar.save();\n```\n\n**Gut:**\n```javascript\nclass Car {\n  constructor(make, model, color) {\n    this.make = make;\n    this.model = model;\n    this.color = color;\n  }\n\n  setMake(make) {\n    this.make = make;\n    // Anmerkung: Gib „this“ für die Verkettung zurück\n    return this;\n  }\n\n  setModel(model) {\n    this.model = model;\n    // Anmerkung: Gib „this“ für die Verkettung zurück\n    return this;\n  }\n\n  setColor(color) {\n    this.color = color;\n    // Anmerkung: Gib „this“ für die Verkettung zurück\n    return this;\n  }\n\n  save() {\n    console.log(this.make, this.model, this.color);\n    // Anmerkung: Gib „this“ für die Verkettung zurück\n    return this;\n  }\n}\n\nconst car = new Car('Ford','F-150','red')\n  .setColor('pink')\n  .save();\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Komposition an Stelle von Vererbung\nWie bekanntermaßen in [*Design Patterns*](https://en.wikipedia.org/wiki/Design_Patterns) von der Viererbande (Gang of Four) \ngesagt wurde, sollst du die Komposition der Vererbung vorziehen, wenn du kannst. Es gibt viele gute Gründe die Vererbung zu verwenden \nund eine Menge guter Gründe warum du die Komposition verwenden sollst. Der Kernpunkt dieses Denkansatzes ist, dass wenn dein Gehirn \ninstinktiv für die Vererbung ist, du versuchen sollst darüber nachzudenken, ob die Komposition dein Problem nicht besser lösen wird. \nIn manchen Fällen kann es das. \n\nDu fragst dich vielleicht, wann du Vererbungen verwenden sollst? Es ist von deinem \nvorliegenden Problem anhängig. Hier ist eine Liste mit Gründen die mehr für die Vererbung\nals für die Komposition sprechen:\n\n1. Deine Vererbung repräsentiert eine „ist-ein“-Beziehung und keine „hat-ein“-Beziehung \n(Mensch-\u003eTier vs. User-\u003eUserDetails).\n2. Du kannst Code von der Elternklasse verwenden (Menschen können sich wie alle Tiere bewegen).\n3. Du willst globale Änderungen – durch das Ändern der Elternklasse – auf abgeleitete Klassen übertragen. \n(Den Kalorienverbrauch aller Tiere ändern wenn sie sich bewegen).\n\n**Schlecht:**\n```javascript\nclass Employee {\n  constructor(name, email) {\n    this.name = name;\n    this.email = email;\n  }\n\n  // ...\n}\n\n// Schlecht, weil Angestellte Steuerdaten \"besitzen\". EmployeeTaxData ist keine Art eines Angestellten\nclass EmployeeTaxData extends Employee {\n  constructor(ssn, salary) {\n    super();\n    this.ssn = ssn;\n    this.salary = salary;\n  }\n\n  // ...\n}\n```\n\n**Gut:**\n```javascript\nclass EmployeeTaxData {\n  constructor(ssn, salary) {\n    this.ssn = ssn;\n    this.salary = salary;\n  }\n\n  // ...\n}\n\nclass Employee {\n  constructor(name, email) {\n    this.name = name;\n    this.email = email;\n  }\n\n  setTaxData(ssn, salary) {\n    this.taxData = new EmployeeTaxData(ssn, salary);\n  }\n  // ...\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n## \u003ca id='classes'\u003eSOLID\u003c/a\u003e\n### Single-Responsibility-Prinzip (SRP)\nWie in Clean Code bereits genannt: „Es sollte niemals mehr als einen Grund geben, \neine Klasse zu ändern“. Es ist verlockend, eine Klasse bis obenhin mit Funktionalität \nvoll zu stopfen, wie wenn du nur einen Koffer für deinen Flug mitnehmen kannst.\nDas Problem damit ist einfach, dass deine Klasse konzeptionell nicht unabhängig ist \nund es viele Gründe geben wird, deine Klasse zu ändern. Die Anzahl der Änderungen \nan einer Klasse zu reduzieren ist wichtig. Es ist wichtig, weil zu viel Funktionalität \neiner Klasse bedeutet, dass es schwierig ist zu verstehen wie die Änderung andere \nabhängige Module in deinem Code beeinflusst. \n\n**Schlecht:**\n```javascript\nclass UserSettings {\n  constructor(user) {\n    this.user = user;\n  }\n\n  changeSettings(settings) {\n    if (this.verifyCredentials()) {\n      // ...\n    }\n  }\n\n  verifyCredentials() {\n    // ...\n  }\n}\n```\n\n**Gut:**\n```javascript\nclass UserAuth {\n  constructor(user) {\n    this.user = user;\n  }\n\n  verifyCredentials() {\n    // ...\n  }\n}\n\nclass UserSettings {\n  constructor(user) {\n    this.user = user;\n    this.auth = new UserAuth(user);\n  }\n\n  changeSettings(settings) {\n    if (this.auth.verifyCredentials()) {\n      // ...\n    }\n  }\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Open-Closed-Prinzip (OCP)\nWie von Bertrand Meyer angegeben: „Software-Einheiten (Klassen, Module, Funktionen, \netc.) sollten offen für Erweiterungen aber geschlossen für Modifizierungen sein.“ \nWas soll das bedeuten? Diese Prinzip bedeutet, dass du es Anwendern ermöglichen \nsollst neue Funktionalitäten hinzuzufügen ohne bestehenden Code ändern zu müssen.\n\n**Schlecht:**\n```javascript\nclass AjaxAdapter extends Adapter {\n  constructor() {\n    super();\n    this.name = 'ajaxAdapter';\n  }\n}\n\nclass NodeAdapter extends Adapter {\n  constructor() {\n    super();\n    this.name = 'nodeAdapter';\n  }\n}\n\nclass HttpRequester {\n  constructor(adapter) {\n    this.adapter = adapter;\n  }\n\n  fetch(url) {\n    if (this.adapter.name === 'ajaxAdapter') {\n      return makeAjaxCall(url).then((response) =\u003e {\n        // transformiere die Response und gib sie zurück\n      });\n    } else if (this.adapter.name === 'httpNodeAdapter') {\n      return makeHttpCall(url).then((response) =\u003e {\n        // transformiere die Response und gib sie zurück\n      });\n    }\n  }\n}\n\nfunction makeAjaxCall(url) {\n  // führe den Request aus und gib eine Promise zurück\n}\n\nfunction makeHttpCall(url) {\n  // führe den Request aus und gib eine Promise zurück\n}\n```\n\n**Gut:**\n```javascript\nclass AjaxAdapter extends Adapter {\n  constructor() {\n    super();\n    this.name = 'ajaxAdapter';\n  }\n\n  request(url) {\n    // führe den Request aus und gib eine Promise zurück\n  }\n}\n\nclass NodeAdapter extends Adapter {\n  constructor() {\n    super();\n    this.name = 'nodeAdapter';\n  }\n\n  request(url) {\n    // führe den Request aus und gib eine Promise zurück\n  }\n}\n\nclass HttpRequester {\n  constructor(adapter) {\n    this.adapter = adapter;\n  }\n\n  fetch(url) {\n    return this.adapter.request(url).then((response) =\u003e {\n      // transformiere die Response und gib sie zurück\n    });\n  }\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Liskovsches Substitutionsprinzip (LSP)\nDas ist ein beängstigender Begriff für ein sehr einfaches Konzept. Es ist \nformell definiert als: „Wenn S ein Subtyp von T ist, dann können Objekte vom Typ \nT möglicherweise mit Objekten vom Typ S ersetzt werden. (D.h., Objekte vom Typ \nS ersetzen möglicherweise Objekte vom Typ T) ohne irgendwelche gewünschten \nEigenschaften des Programms (Korrektheit, Durchführen der Aufgabe, etc.) zu \nverändern.“. Das ist eine noch viel erschreckendere Definition.\n\nDie beste Erklärung für dieses Konzept ist, wenn du eine Eltern- und Kindklasse \nhast und die Basisklasse abwechselnd mit der Kindklasse verwendet werden kann ohne \nfalsche Ergebnisse zu bekommen. Möglicherweise ist das immer noch verwirrend. Also \nschauen wir uns das klassische Quadrat-Rechteck-Beispiel an. Mathematisch gesehen \nist ein Quadrat ein Rechteck. Wenn du es aber mit einer „ist-ein“-Beziehung durch \nVererbung darstellen willst, kommst du schnell in Schwierigkeiten.\n\n**Schlecht:**\n```javascript\nclass Rectangle {\n  constructor() {\n    this.width = 0;\n    this.height = 0;\n  }\n\n  setColor(color) {\n    // ...\n  }\n\n  render(area) {\n    // ...\n  }\n\n  setWidth(width) {\n    this.width = width;\n  }\n\n  setHeight(height) {\n    this.height = height;\n  }\n\n  getArea() {\n    return this.width * this.height;\n  }\n}\n\nclass Square extends Rectangle {\n  setWidth(width) {\n    this.width = width;\n    this.height = width;\n  }\n\n  setHeight(height) {\n    this.width = height;\n    this.height = height;\n  }\n}\n\nfunction renderLargeRectangles(rectangles) {\n  rectangles.forEach((rectangle) =\u003e {\n    rectangle.setWidth(4);\n    rectangle.setHeight(5);\n    const area = rectangle.getArea(); // SCHLECHT: Es wird 25 für ein Quadrat zurückgeben. Sollte aber 20 sein.\n    rectangle.render(area);\n  });\n}\n\nconst rectangles = [new Rectangle(), new Rectangle(), new Square()];\nrenderLargeRectangles(rectangles);\n```\n\n**Gut:**\n```javascript\nclass Shape {\n  setColor(color) {\n    // ...\n  }\n\n  render(area) {\n    // ...\n  }\n}\n\nclass Rectangle extends Shape {\n  constructor(width, height) {\n    super();\n    this.width = width;\n    this.height = height;\n  }\n\n  getArea() {\n    return this.width * this.height;\n  }\n}\n\nclass Square extends Shape {\n  constructor(length) {\n    super();\n    this.length = length;\n  }\n\n  getArea() {\n    return this.length * this.length;\n  }\n}\n\nfunction renderLargeShapes(shapes) {\n  shapes.forEach((shape) =\u003e {\n    const area = shape.getArea();\n    shape.render(area);\n  });\n}\n\nconst shapes = [new Rectangle(4, 5), new Rectangle(4, 5), new Square(5)];\nrenderLargeShapes(shapes);\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Interface-Segregation-Prinzip (ISP)\nJavaScript besitzt keine Interfaces. Dieses Prinzip ist also nicht so streng \nanwendbar wie die anderen. Wie auch immer, es ist wichtig und bedeutend trotz \nJavaScripts fehlendem Typen-System.\n\nISP heißt, dass „Anwender nicht dazu gezwungen werden sollten, sich auf Interfaces \nzu stützen die sie nicht verwenden“. Interfaces sind wegen des Duck-Typings indirekte \nVerträge.\n\nGute Beispiele, die dieses Prinzip in JavaScript anschaulich demonstrieren sind Klassen, \ndie umfangreiche Konfigurationsobjekte benötigen. Den Anwender nicht dazu zwingen, unzählige \nOptionen einzurichten ist vorteilhaft, weil sie in den meisten Fällen nicht alle Konfigurationsmöglichkeiten \nbrauchen. Diese optional anzubieten verhindert „üppige Interfaces“.\n\n**Schlecht:**\n```javascript\nclass DOMTraverser {\n  constructor(settings) {\n    this.settings = settings;\n    this.setup();\n  }\n\n  setup() {\n    this.rootNode = this.settings.rootNode;\n    this.animationModule.setup();\n  }\n\n  traverse() {\n    // ...\n  }\n}\n\nconst $ = new DOMTraverser({\n  rootNode: document.getElementsByTagName('body'),\n  animationModule() {} // In den meisten Fällen werden wir nicht animieren müssen.\n  // ...\n});\n```\n\n**Gut:**\n```javascript\nclass DOMTraverser {\n  constructor(settings) {\n    this.settings = settings;\n    this.options = settings.options;\n    this.setup();\n  }\n\n  setup() {\n    this.rootNode = this.settings.rootNode;\n    this.setupOptions();\n  }\n\n  setupOptions() {\n    if (this.options.animationModule) {\n      // ...\n    }\n  }\n\n  traverse() {\n    // ...\n  }\n}\n\nconst $ = new DOMTraverser({\n  rootNode: document.getElementsByTagName('body'),\n  options: {\n    animationModule() {}\n  }\n});\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Dependency-Inversion-Prinzip (DIP)\nDieses Prinzip steht für zwei essentielle Dinge:\n1. übergeordnete Module sollten nicht von untergeordneten Modulen abhängig \nsein. Beide sollten von Abstraktionen abhängig sein.\n2. Abstraktionen sollten nicht von Details abhängig sein. Details sollten \nvon Abstraktionen abhängig sein.\n\nDas kann im ersten Moment schwer zu verstehen sein. Aber wenn du bereits mit Angular.js \ngearbeitet hast, hast du eine Implementierung dieses Prinzips in Form der \nDependency Injection (DI) bereits kennengelernt. Obwohl diese keine komplett \nidentischen Konzepte sind, sorgt DIP dafür, dass übergeordnete Module nichts von \nden Details ihrer untergeordneten Module wissen. Das kann durch DI erreicht werden. \nEin großer Vorteil davon ist, dass es die Verknüpfungen zwischen Modulen reduziert.\nVerknüpfungen sind ein sehr schlechtes Entwurfsmuster weil dein Code dadurch \nschwieriger zu überarbeiten ist.\n\nWie schon davor angemerkt, besitzt JavaScript keine Interfaces. Die Abstraktionen \nsind also abhängig von indirekten Vereinbarungen. Das betrifft die Methoden und \nEigenschaften die ein Objekt/Klasse anderen Objekten/Klassen zur Verfügung stellt. \nIn dem untenstehenden Beispiel ist die indirekte Vereinbarung, dass jedes Request-Modul \nfür einen `InventoryTracker` eine `requestItems`-Methode besitzt.\n\n**Schlecht:**\n```javascript\nclass InventoryRequester {\n  constructor() {\n    this.REQ_METHODS = ['HTTP'];\n  }\n\n  requestItem(item) {\n    // ...\n  }\n}\n\nclass InventoryTracker {\n  constructor(items) {\n    this.items = items;\n\n    // SCHLECHT: Wir haben eine Abhänigkeit zu einer spezifischen Request-Implementierung geschaffen.\n    // Wir hätten requestItems von einer Request-Methode: `request` abhängig machen sollen\n    this.requester = new InventoryRequester();\n  }\n\n  requestItems() {\n    this.items.forEach((item) =\u003e {\n      this.requester.requestItem(item);\n    });\n  }\n}\n\nconst inventoryTracker = new InventoryTracker(['apples', 'bananas']);\ninventoryTracker.requestItems();\n```\n\n**Gut:**\n```javascript\nclass InventoryTracker {\n  constructor(items, requester) {\n    this.items = items;\n    this.requester = requester;\n  }\n\n  requestItems() {\n    this.items.forEach((item) =\u003e {\n      this.requester.requestItem(item);\n    });\n  }\n}\n\nclass InventoryRequesterV1 {\n  constructor() {\n    this.REQ_METHODS = ['HTTP'];\n  }\n\n  requestItem(item) {\n    // ...\n  }\n}\n\nclass InventoryRequesterV2 {\n  constructor() {\n    this.REQ_METHODS = ['WS'];\n  }\n\n  requestItem(item) {\n    // ...\n  }\n}\n\n// Durch das externe Konstruieren und das Injektieren unserer Abhängigkeiten könnten wir unser \n// Request-Modul einfach durch ein raffiniertes neues – das WebSockets verwendet – austauschen.\nconst inventoryTracker = new InventoryTracker(['apples', 'bananas'], new InventoryRequesterV2());\ninventoryTracker.requestItems();\n```\n**[⬆ nach oben](#table-of-contents)**\n\n## \u003ca id='testing'\u003eTesting\u003c/a\u003e\nTesting ist wichtiger als das Veröffentlichen von Code. Wenn du keine oder eine unzureichende \nAnzahl an Tests hast, dann wirst du jedes Mal unsicher sein, ob du nicht irgendetwas\nkaputt gemacht hast. Die Entscheidung welche Anzahl angemessen ist, entscheidet dein\nTeam. Aber eine 100%ige Abdeckung (alle Anweisungen und Branches) wird dir ein sehr\nhohes Vertrauen und Seelenfrieden geben. Das bedeutet, dass du als Ergänzung zu einem \nguten Testing-Framework auch ein [gutes Coverage-Tool](http://gotwarlost.github.io/istanbul/) \nverwenden musst.\n\nEs gibt keine Ausrede um keine Tests zu schreiben. Es gibt [zahlreiche gute JS-Test-Frameworks]\n(http://jstherightway.org/#testing-tools). Also finde eines das dein Team bevorzugt.\nWenn du eines gefunden hast, dass für dein Team funktioniert, dann ziele darauf ab, immer \neinen Test für jedes neue Feature/Modul zu schreiben. Wenn deine bevorzugte Arbeitsweise die \ntestgetriebene Entwicklung ist, umso besser. Aber die Hauptsache ist, sicher zu stellen, dass \ndu die Abdeckungsziele erreichst bevor ein Feature veröffentlicht oder vorhandener Code \nüberarbeitet wird. \n\n### Eine Sache pro Test\n\n**Schlecht:**\n```javascript\nimport assert from 'assert';\n\ndescribe('MakeMomentJSGreatAgain', () =\u003e {\n  it('handles date boundaries', () =\u003e {\n    let date;\n\n    date = new MakeMomentJSGreatAgain('1/1/2015');\n    date.addDays(30);\n    assert.equal('1/31/2015', date);\n\n    date = new MakeMomentJSGreatAgain('2/1/2016');\n    date.addDays(28);\n    assert.equal('02/29/2016', date);\n\n    date = new MakeMomentJSGreatAgain('2/1/2015');\n    date.addDays(28);\n    assert.equal('03/01/2015', date);\n  });\n});\n```\n\n**Gut:**\n```javascript\nimport assert from 'assert';\n\ndescribe('MakeMomentJSGreatAgain', () =\u003e {\n  it('handles 30-day months', () =\u003e {\n    const date = new MakeMomentJSGreatAgain('1/1/2015');\n    date.addDays(30);\n    assert.equal('1/31/2015', date);\n  });\n\n  it('handles leap year', () =\u003e {\n    const date = new MakeMomentJSGreatAgain('2/1/2016');\n    date.addDays(28);\n    assert.equal('02/29/2016', date);\n  });\n\n  it('handles non-leap year', () =\u003e {\n    const date = new MakeMomentJSGreatAgain('2/1/2015');\n    date.addDays(28);\n    assert.equal('03/01/2015', date);\n  });\n});\n```\n**[⬆ nach oben](#table-of-contents)**\n\n## \u003ca id='concurrency'\u003eParallelität\u003c/a\u003e\n### Verwende Promises, keine Callbacks\nCallbacks sind keine saubere Lösung und sie verursachen eine übermäßige Verschachtelung.\nMit ES2015/ES6 sind Promises ein integrierter globaler Typ. Verwende sie!\n\n**Schlecht:**\n```javascript\nimport { get } from 'request';\nimport { writeFile } from 'fs';\n\nget('https://en.wikipedia.org/wiki/Robert_Cecil_Martin', (requestErr, response) =\u003e {\n  if (requestErr) {\n    console.error(requestErr);\n  } else {\n    writeFile('article.html', response.body, (writeErr) =\u003e {\n      if (writeErr) {\n        console.error(writeErr);\n      } else {\n        console.log('File written');\n      }\n    });\n  }\n});\n```\n\n**Gut:**\n```javascript\nimport { get } from 'request';\nimport { writeFile } from 'fs';\n\nget('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')\n  .then((response) =\u003e {\n    return writeFile('article.html', response);\n  })\n  .then(() =\u003e {\n    console.log('File written');\n  })\n  .catch((err) =\u003e {\n    console.error(err);\n  });\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Async/Await sind noch sauberer als Promises\nPromises sind eine sehr saubere Alternative zu Callbacks. ES2017/ES8 beinhaltet allerdings \nasync und await, die eine viel sauberere Lösung bieten. Alles was du benötigst ist eine Funktion,\nder das `async`-Keyword vorangestellt ist. Anschließend kannst du deine Logik imperativ ohne eine\nKette von `then`-Funktionen schreiben. Verwende dies, wenn du die Vorteile von ES2017/ES8 jetzt \nschon nutzen kannst!\n\n**Schlecht:**\n```javascript\nimport { get } from 'request-promise';\nimport { writeFile } from 'fs-promise';\n\nget('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')\n  .then((response) =\u003e {\n    return writeFile('article.html', response);\n  })\n  .then(() =\u003e {\n    console.log('File written');\n  })\n  .catch((err) =\u003e {\n    console.error(err);\n  });\n```\n\n**Gut:**\n```javascript\nimport { get } from 'request-promise';\nimport { writeFile } from 'fs-promise';\n\nasync function getCleanCodeArticle() {\n  try {\n    const response = await get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin');\n    await writeFile('article.html', response);\n    console.log('File written');\n  } catch(err) {\n    console.error(err);\n  }\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n## \u003ca id='error-handling'\u003eFehlerbehandlung\u003c/a\u003e\nAusgegebene Fehler sind eine gute Sache! Das heißt, dass die Laufzeitumgebung\nerfolgreich erkannt hat, dass etwas in deinem Programm schiefgegangen ist und lässt\ndich das wissen indem deine Funktion im aktuellen Stack beendet wurde, den Prozess\nzerstört hat (in Node) und dich in der Konsole mit einem Stacktrace darüber benachrichtigt.\n\n### Ignoriere abgefangene Fehler nicht\nMit einem abgefangenem Fehler nichts anzufangen, wird dir niemals die Möglichkeit\ngeben auf diesen zu reagieren oder ihn zu beheben. Den Fehler in der Konsole auszugeben \n(`console.log`) ist nicht viel besser. Er wird oft in den unzähligen Dingen, die \nin der Konsole ausgegeben werden untergehen. Wenn du ein Stückchen Code in einer\n`try/catch`-Anweisung verschachtelst, heißt dass, das du davon ausgehst, dass an \ndieser Stelle ein Fehler auftreten kann und daher solltest du einen Plan haben oder\neine Anweisung schreiben, wenn dieser Fehler erscheint.\n\n**Schlecht:**\n```javascript\ntry {\n  functionThatMightThrow();\n} catch (error) {\n  console.log(error);\n}\n```\n\n**Gut:**\n```javascript\ntry {\n  functionThatMightThrow();\n} catch (error) {\n  // Eine Option (Erweckt mehr Aufmerksamkeit als console.log):\n  console.error(error);\n  // Eine andere Möglichkeit:\n  notifyUserOfError(error);\n  // Eine andere Möglichkeit:\n  reportErrorToService(error);\n  // ODER wende alle drei an!\n}\n```\n\n### Ignoriere zurückgewiesene Promises nicht\nAus dem selben Grund, weshalb du keine Fehler von `try/catch`-Anweisungen \nignorieren solltest.\n\n**Schlecht:**\n```javascript\ngetdata()\n  .then((data) =\u003e {\n    functionThatMightThrow(data);\n  })\n  .catch((error) =\u003e {\n    console.log(error);\n  });\n```\n\n**Gut:**\n```javascript\ngetdata()\n  .then((data) =\u003e {\n    functionThatMightThrow(data);\n  })\n  .catch((error) =\u003e {\n    // Eine Option (Erweckt mehr Aufmerksamkeit als console.log):\n    console.error(error);\n    // Eine andere Möglichkeit:\n    notifyUserOfError(error);\n    // Eine andere Möglichkeit:\n    reportErrorToService(error);\n    // ODER wende alle drei an!\n  });\n```\n**[⬆ nach oben](#table-of-contents)**\n\n## \u003ca id='formatting'\u003eFormatierung\u003c/a\u003e\nFormatierungen sind subjektiv. Wie bei vielen anderen Regeln hier gibt es kein\nRichtig oder Falsch dem du folgen musst. Der Punkt ist, STREITE NICHT wegen \nFormatierungen. Es gibt [unzählige Tools](http://standardjs.com/rules.html) die\ndies automatisieren. Verwende eines! Es ist für Entwickler eine Verschwendung \nvon Zeit und Geld darüber zu streiten.\n\nFür Dinge die nicht in den Bereich der automatischen Formatierung (Einrückungen, \nTabs vs. Leerzeichen, doppelte vs. einfache Anführungszeichen, etc.) fallen schaue \nhier für ein paar Ratschläge.\n\n### Verwende eine einheitliche Schreibweise\nJavaScript hat keine Typen. Die Schreibweise deiner Variablen und Funktionen \nsagt viel über diese aus. Dieses Regeln sind subjektiv, dein Team kann wählen \nwas sie bevorzugen. Die Hauptsache ist, egal was ihr wählt, wendet es konsequent an.\n\n**Schlecht:**\n```javascript\nconst DAYS_IN_WEEK = 7;\nconst daysInMonth = 30;\n\nconst songs = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];\nconst Artists = ['ACDC', 'Led Zeppelin', 'The Beatles'];\n\nfunction eraseDatabase() {}\nfunction restore_database() {}\n\nclass animal {}\nclass Alpaca {}\n```\n\n**Gut:**\n```javascript\nconst DAYS_IN_WEEK = 7;\nconst DAYS_IN_MONTH = 30;\n\nconst SONGS = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];\nconst ARTISTS = ['ACDC', 'Led Zeppelin', 'The Beatles'];\n\nfunction eraseDatabase() {}\nfunction restoreDatabase() {}\n\nclass Animal {}\nclass Alpaca {}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n\n### Funktionsaufrufe sollten nahe an der aufzurufenden Funktion stehen\nWenn eine Funktion eine andere aufruft, halte diese Funktionen im Code \nvertikal nahe beieinander. Behalte idealerweise die Funktion die von einer anderen\nFunktion aufgerufen wird genau über dieser. Wir neigen dazu Code von oben nach unten \nwie eine Zeitung zu lesen. Aus diesem Grund sorge dafür, dass dein Code auf diese Weise \nlesbar ist.\n\n**Schlecht:**\n```javascript\nclass PerformanceReview {\n  constructor(employee) {\n    this.employee = employee;\n  }\n\n  lookupPeers() {\n    return db.lookup(this.employee, 'peers');\n  }\n\n  lookupManager() {\n    return db.lookup(this.employee, 'manager');\n  }\n\n  getPeerReviews() {\n    const peers = this.lookupPeers();\n    // ...\n  }\n\n  perfReview() {\n    this.getPeerReviews();\n    this.getManagerReview();\n    this.getSelfReview();\n  }\n\n  getManagerReview() {\n    const manager = this.lookupManager();\n  }\n\n  getSelfReview() {\n    // ...\n  }\n}\n\nconst review = new PerformanceReview(employee);\nreview.perfReview();\n```\n\n**Gut:**\n```javascript\nclass PerformanceReview {\n  constructor(employee) {\n    this.employee = employee;\n  }\n\n  perfReview() {\n    this.getPeerReviews();\n    this.getManagerReview();\n    this.getSelfReview();\n  }\n\n  getPeerReviews() {\n    const peers = this.lookupPeers();\n    // ...\n  }\n\n  lookupPeers() {\n    return db.lookup(this.employee, 'peers');\n  }\n\n  getManagerReview() {\n    const manager = this.lookupManager();\n  }\n\n  lookupManager() {\n    return db.lookup(this.employee, 'manager');\n  }\n\n  getSelfReview() {\n    // ...\n  }\n}\n\nconst review = new PerformanceReview(employee);\nreview.perfReview();\n```\n**[⬆ nach oben](#table-of-contents)**\n\n## \u003ca id='comments'\u003eKommentare\u003c/a\u003e\n### Kommentiere nur Dinge, die komplexe Anwendungslogik beinhalten\nKommentare sind eine Entschuldigung, keine Anforderung. Guter Code dokumentiert\nsich *meistens* selbst.\n\n**Schlecht:**\n```javascript\nfunction hashIt(data) {\n  // The hash\n  let hash = 0;\n\n  // Length of string\n  const length = data.length;\n\n  // Loop through every character in data\n  for (let i = 0; i \u003c length; i++) {\n    // Get character code.\n    const char = data.charCodeAt(i);\n    // Make the hash\n    hash = ((hash \u003c\u003c 5) - hash) + char;\n    // Convert to 32-bit integer\n    hash \u0026= hash;\n  }\n}\n```\n\n**Gut:**\n```javascript\n\nfunction hashIt(data) {\n  let hash = 0;\n  const length = data.length;\n\n  for (let i = 0; i \u003c length; i++) {\n    const char = data.charCodeAt(i);\n    hash = ((hash \u003c\u003c 5) - hash) + char;\n\n    // Zu einem 32-bit Integer konvertieren\n    hash \u0026= hash;\n  }\n}\n\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Lasse keinen auskommentierten Code in deiner Code-Basis\nVersionsverwaltungen existieren aus einem Grund. Lasse alten Code in der\nHistory deines Repositories.\n\n**Schlecht:**\n```javascript\ndoStuff();\n// doOtherStuff();\n// doSomeMoreStuff();\n// doSoMuchStuff();\n```\n\n**Gut:**\n```javascript\ndoStuff();\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Verzichte auf Journal-Kommentare\nDenke daran, verwende eine Versionsverwaltung! Veralteter Code, auskommentierter\nCode und insbesondere Journal-Kommentare werden nicht benötigt. Verwende `git log`\num vergangen Änderungen einzusehen.\n\n**Schlecht:**\n```javascript\n/**\n * 2016-12-20: Removed monads, didn't understand them (RM)\n * 2016-10-01: Improved using special monads (JP)\n * 2016-02-03: Removed type-checking (LI)\n * 2015-03-14: Added combine with type-checking (JR)\n */\nfunction combine(a, b) {\n  return a + b;\n}\n```\n\n**Gut:**\n```javascript\nfunction combine(a, b) {\n  return a + b;\n}\n```\n**[⬆ nach oben](#table-of-contents)**\n\n### Verzichte auf Positionsmarker\nPositionsmarker sorgen meistens für einen gestörten Lesefluss. Lasse Funktionen \nund Variablen in der korrekten Einrückung und Formatierung stehen. Diese werden \ndeinem Code ausreichend visuelle Struktur geben.\n\n**Schlecht:**\n```javascript\n////////////////////////////////////////////////////////////////////////////////\n// Scope Model Instantiation\n////////////////////////////////////////////////////////////////////////////////\n$scope.model = {\n  menu: 'foo',\n  nav: 'bar'\n};\n\n////////////////////////////////////////////////////////////////////////////////\n// Action setup\n////////////////////////////////////////////////////////////////////////////////\nconst actions = function() {\n  // ...\n};\n```\n\n**Gut:**\n```javascript\n$scope.model = {\n  menu: 'foo',\n  nav: 'bar'\n};\n\nconst actions = function() {\n  // ...\n};\n```\n**[⬆ nach oben](#table-of-contents)**\n\n\n## \u003ca id='translation'\u003eÜbersetzungen\u003c/a\u003e\nDieser Leitfaden ist in den folgenden Sprachen verfügbar:\n\n- ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brasilianisches Portugiesisch**: [fesnt/clean-code-javascript](https://github.com/fesnt/clean-code-javascript)\n- ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Uruguay.png) **Spanisch**: [andersontr15/clean-code-javascript](https://github.com/andersontr15/clean-code-javascript-es)\n- ![en](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags-iso/shiny/24/US.png) **Englisch**: [ryanmcdermott/clean-code-javascript](https://github.com/ryanmcdermott/clean-code-javascript)\n- ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinesisch**:\n    - [alivebao/clean-code-js](https://github.com/alivebao/clean-code-js)\n    - [beginor/clean-code-javascript](https://github.com/beginor/clean-code-javascript)\n- ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Koreanisch**: [qkraudghgh/clean-code-javascript-ko](https://github.com/qkraudghgh/clean-code-javascript-ko)\n- ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polnisch**: [greg-dev/clean-code-javascript-pl](https://github.com/greg-dev/clean-code-javascript-pl)\n- ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russisch**:\n    - [BoryaMogila/clean-code-javascript-ru/](https://github.com/BoryaMogila/clean-code-javascript-ru/)\n    - [maksugr/clean-code-javascript](https://github.com/maksugr/clean-code-javascript)\n- ![vi](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Vietnam.png) **Vietnamesisch**: [hienvd/clean-code-javascript/](https://github.com/hienvd/clean-code-javascript/)\n- ![ja](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanisch**: [mitsuruog/clean-code-javascript/](https://github.com/mitsuruog/clean-code-javascript/)\n- ![id](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Indonesia.png) **Indonesisch**: [andirkh/clean-code-javascript/](https://github.com/andirkh/clean-code-javascript/)\n\n**[⬆ nach oben](#table-of-contents)**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcbruederlin%2Fclean-code-javascript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcbruederlin%2Fclean-code-javascript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcbruederlin%2Fclean-code-javascript/lists"}