Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code Review zur Übungsaufgabe: Countdown #1

Open
wants to merge 1 commit into
base: review
Choose a base branch
from

Conversation

alexanderbazo
Copy link
Collaborator

@alexanderbazo alexanderbazo commented Jun 15, 2020

Code Review zur Übungsaufgabe Countdown

Bitte fertigen Sie ein Code Review für den Lösungsvorschlag in diesem Repository an. Konzentrieren Sie sich auf die qualitativen Aspekte des Quellcodes und des Software Designs. Sie müssen den Code nicht ausführen und keine funktionalen Fehler oder Bugs indentifizieren. Versuchen Sie, konstruktives Feedback zur besseren Gestaltung der Teilkomponenten und Funktionen bzw. zur allgemeine Optimierung der Codeqqualität zu geben. Suchen Sie nach offensichtlichen Verstößen gegen bekannte Regeln zur Gestaltung und Formatierung von JavaScript-Code und identifizieren Sie unsaubere Lösungen, die sich negativ auf den Gesamteindruck auswirken. Vergessen Sie dabei nicht, auch positives Feedback zu geben und gelungene Stellen un Umsetzungen zu kennzeichnen.

Machen Sie sich keine Sorgen über die Qualität Ihres Feedbacks. In der Regel sind alle Hinweise und Ratschläge nützlich. Das Anfertigen des Reviews soll nicht nur den EmpfängerInnen helfen, sonder auch eine Übungsmöglichkeit für Sie selbst darstellen. Nutzen Sie die Chance, wertvolle Erfahrungen für spätere Projekte zu sammeln.

Vorgehen

Sie können das Review vollständig auf der Github-Webseite durchführen. Organisatorische Grundlage ist dieser Pull Request.

  • Im Reiter Files changed sehen Sie eine Übersicht über alle (editierten) Dateien dieses Lösungvorschlags. Sichten Sie den Code in diesen Dateien und versuchen Sie an möglichst viele Stellen Feedback zu geben.
  • Notieren Sie ihre positiven und negativen Anmerkungen, in dem Sie im Code über die enstprechenden Zeile hovern und einen Kommentar hinzufügen. Zum Speichern des ersten Kommentars wählen Sie die Funktion Start Review aus.
  • Ergänzen Sie auf diese Art und Weise an allen relevanten Teile des Codes Kommentare. Seien Sie dabei möglichst präzise und geben Sie zu negativ aufgefallen Stellen auch entsprechende Verbesserungsvorschläge. Versuchen Sie Ihre Einschätzungen immer auch kurz zu begründen.
  • Schließen Sie Ihr Review über den Button Finish your Review ab. Am Ende können Sie auch einen allgemeinen Eindruck zur Qualität des Codes formulieren. Schicken Sie Ihr Feedback mit einem Klick auf die Schaltfläche Submit your Review ab.

Checkliste

Bei der Erstellung des Reviews können Sie sich an dieser einfachen Checkliste orientieren:

  • Wurden bekannte Coding Guidelines eingehalten?
  • Wurden für Variablen und Methoden verständliche und treffend formulierte Bezeichner verwendet?
  • Folgt der Aufbau des Codes einem nachvollziehbaren und sinnvollen Konzept?
  • Wurden die verschiedenen Aufgabenbereiche der Software sichtbar und sinnvoll voneinander getrennt?
  • Wurde auf eine modularisierte Code-Strtuktur, z.B. durch gute Decomposition oder wiederverwendbare Methoden und Prototypen geachtet?
  • Wurde das MVC-Konzept korrekt umgesetzt: Sind Model und UI klar voneinander getrennt?
  • Wurden kritische oder komplexe Stellen im Code ausreichend kommentiert?
  • Wurden alle nicht benötigten Teilbereiche des Codes entfernt? Wurden alle Debug-Ausgaben und -Methoden vor der Abgabe entfernt?

Weitere Hinweise und Hilfestellungen

  • Allgemeine Informationen zur Code Reviews finden Sie auf der Kurswebseite
  • Hinweise zu Pull Requests, der technischen Grundlage für dieses Code Review können Sie auf github.com nachlesen
  • Über die Notwendigkeit qualitiativ hochwertigen Quellcodes schreibt Martin Fowler hier

Copy link
Collaborator Author

@alexanderbazo alexanderbazo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hier ist mein Vorschlag für die Lösung der Countdown-Aufgabe. Bitte teilt mir eure Meinung und eure Verbesserungsvorschläge mit.

Copy link

@AnonymousCodeReviewer AnonymousCodeReviewer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ich habe mir den Code des Lösungsvorschlags angeschaut. Insgesamt geht das meiste schon in Ordnung. An einigen Stellen habe ich Verbesserungsvorschläge notiert. Am wichtigsten sind meiner Meinung nach die folgenden Punkte:

  • Überarbeitung der Event-Generierung (z.B. mit Factory-Methoden)
  • Debugging des LetterGenerators, in dessen Stapel einige Buchstaben nicht vorkommen

Die Qualität des Codes insgesamt ist akzeptabel.

Comment on lines +11 to +14
function broadcastEvent(type, data) {
let event = new Event(type, data);
this.notifyAll(event);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diese Methode, zumindest in dieser Form, verbessert die Übersicht und Lesbarkeit des Codes nicht wirklich. Meiner Meinung nach sollte die Erstellung des Events und der Call von notifyAll direkt an der Stelle im Modul erfolgen, an der das Event kommuniziert werden muss. Diese Form der Dekomposition geht unnötig einen Schritt zu weit. Stattdessen können wir die Generierung der Events auslagern und im Modul Methoden zum Erzeugen der unterschiedlichen Events bereitstellen.

Comment on lines +22 to +26
return {
word: word,
hint: hint,
points: points,
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Statt eines anonymen Objekt-Literals wäre hier möglicherweise ein Prototyp als Grundlage für das Ergebnis-Objekt besser. Das hier zurückgegebene Objekt wird auch außerhalb des Moduls verwendet. Durch einen Prototypen, dessen Struktur App-weit bekannt ist, wird die Arbeit mit dem Rückgabeobjekt für andere ProgrammierInnen erleichtet.

function addChar(char) {
if (currentLetters.length < Config.MAX_CHARS) {
currentLetters.push(char);
broadcastEvent.call(this, "CharAdded", char);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dieser Aufruf setzt voraus, dass addChar selbst im richtigen Objekt-Scope aufgerufen wurden. Statt über mehrere Ecken call zu verwenden, könnte hier auch direkt der Context als zusätzlicher Paramater übergeben werden. Technisch ist das identisch zur Lösung mit call, macht den (intendierten) Ablauf des Programms aber deutlicher bzw. leichter zu erkennen.

Da das Konzept sich durch das ganze Modul zieht: Ich würde die Abhängigkeit zu call insgesamt aus dem Modul entfernen. Dazu kann überall der explizite Kontext übergeben werden.

function addChar(char) {
if (currentLetters.length < Config.MAX_CHARS) {
currentLetters.push(char);
broadcastEvent.call(this, "CharAdded", char);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Die Event-Typen (hier CharAdded) sind an einer zentralen Stelle, z.B. in den jeweiligen Event-Prototypen besser aufgehoben. Dadurch können wir sicherstellen, dass hier keine "falschen" Werte übergeben werden und der gesetzte Typ stets den Erwartungen entspricht. Das gilt auch für die anderen Stellen im Code, die Events erzeugen. Am besten überarbeiten wir dies im Zusammenhang mit der vorgeschlagenen Auslagerung der Event-Erstellung.

function isValidCharCombination(word) {
let result = word.toUpperCase();
for (let i = 0; i < currentLetters.length; i++) {
result = result.replace(currentLetters[i].toUpperCase(), "");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hier wäre vielleicht eine Konstante für den leeren String, z.B. const EMPTY_STRING = "";sinnvoll. Dadurch lassen sich Missverständnisse vermeiden, z.B die falsche Annahme, hier könnte etwas zwischen den Leerzeichen vergessen worden sein.

class LetterGenerator {

reset() {
prepareStacks(Config.LETTER_FREQUENCY);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vielleicht können wir hier die Aufrufe von prepareStacks und shuffleStacks trennen? Wenn wir an dieser Stelle beide Methoden direkt aufrufen, wird - ohne das man dazu weiter in den Code schauen muss - sehr schnell klar, was alles beim Initialisieren des Generators passiert.

Comment on lines +68 to +74
getVowel() {
return selectRandomCharFrom(vowels);
}

getConsonant() {
return selectRandomCharFrom(consonants);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auf die zusätzliche Zufallsauswahl können wir verzichten, wenn die Stapel bereits zu Beginn gemischt werden. Dann könnte die Methode auch passenderweise in getNextVowel umbenannt werden. Beides gilt auch für getConsonant.

Copy link

@AnonymousCodeReviewer AnonymousCodeReviewer Jun 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nachtrag: Der Kommentar bezieht sich vor allem auf die unnötige Implementierung von selectRandomCharFrom.

constructor(el) {
super();
this.setElement(el);
this.clockHand = this.el.querySelector(".hand");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nicht kritisch, aber ggf. für das Refactoring relevant: Die CSS-Klassen könnten an einer zentralen Stelle oder hier im Modul als Konstanten abgebildet werden, statt innerhalb der Methoden hard eincodiert zu werden.

Comment on lines +37 to +39
getUserInput() {
return this.inputEl.value;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wenn wir die Methode in getCurrentUserInput umbenennen wird deutlicher, dass wir den aktuellen Inhalt des Textfelds auslesen und keinen neuen Input von den NutzerInnen anfordern.

Comment on lines +7 to +8
let event = new Event("StartButtonClicked");
this.notifyAll(event);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auch hier könnten wir über die Verwendung von CustomEvents auf Basis eigener Prototypen nachdenken und ggf. deren Erstellung auslagern. Vielleicht benötigen wir für die gesamte Anwendung eine EventFactory?

Comment on lines +63 to +69
function addVowel() {
GameManager.addRandomVowel();
}

function addConsonant() {
GameManager.addRandomConsonant();
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Da die Methoden als Callback für die Events aus dem ControlsView dienen: Können wir die Namen zu onAddVowel oder etwas Ähnlichem ändern? Damit sollte klarer werden, dass es sich hier um eine Callback-Methode handelt, die von außerhalb des Moduls und durch einen Event aufgerufen wird.

Comment on lines +88 to +89
let result = getResultObject(word, Config.INVALID_COMBINATION_RESULT_MESSSAGE, 0);
reject(result);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auch ein fehlerhaftes Wort ist doch ein valides Ergebnis für das Spiel an sich. Sollte dieser Fall (mit entsprechendem Hinweis und null Punkten) nicht auch über das erfolgreiche auflösen des Promise (resolve) kommuniziert werden? Den reject-Callback würde ich für wirkliche "Probleme" beim Validieren reservieren, z.B. wenn keine Verbindung zur Wiktionary-API aufgebaut werden konnte oder die Eingaben der NutzerInnen nicht ausgewertet werden konnten.

}

addLetter(letter) {
let nextLetterElement = this.el.querySelector(".letter.empty");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diese Variable könnten wir vielleicht in nextEmptyLetterElement umbennen, um deutlicher zu machen, dass das nächste freie Element ausgewählt wurde.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants