Dobre praktyki programowania #1 - kiełkowanie metody

07/25/20192 min czytania — w Programowanie

Jak dodawać nowy kod?

Podstawą czynnością programisty jest pisanie kodu. Należy to robić bardzo starannie. Co z tego że będzie działać, jeśli nie będziemy mogli tego łatwo rozwijać. Na początku w ogóle nie jesteśmy uczeni jak kod powinien powstawać. W jakiej kolejności i w jakich miejscach należy dodawać nowe rzeczy. Przychodzi to dopiero z doświadczeniem.

Po prostu pisanie

Spójrzmy na ten kod:

function mineNewBlock() {
const previousHash = this.getLatestBlock().hash;
const index = this.blockchain.length;
const timestamp = new Date().toISOString();
const data = this.getTransactionsToBlock();
if (data.length === 0) {
return null;
}
let newBlock = new Block(index, previousHash, timestamp, data);
newBlock = Miner.mine(newBlock, this.difficulty);
return newBlock;
}

Załóżmy, że chcemy dodać zapisywanie dat transakcji wchodzących w skład danego bloku.

function mineNewBlock() {
const previousHash = this.getLatestBlock().hash;
const index = this.blockchain.length;
const timestamp = new Date().toISOString();
const data = this.getTransactionsToBlock();
if (data.length === 0) {
return null;
}
// NEW CODE
const dates = data.map(d => d.date);
Logger.save('TransactionDates', dates);
// NEW CODE
let newBlock = new Block(index, previousHash, timestamp, data);
newBlock = Miner.mine(newBlock, this.difficulty);
return newBlock;
}

Ogromny błąd

Na początku swojej podróży z programowaniem zrobiłbym tak bez większego zastanowienia. Dzisiaj napisałbym to w ten sposób.

// NEW CODE
function logTransactionDates(data) => {
const dates = data.map(d => d.date);
Logger.save('TransactionDates', dates);
}
// NEW CODE
function mineNewBlock() {
const previousHash = this.getLatestBlock().hash;
const index = this.blockchain.length;
const timestamp = new Date().toISOString();
const data = this.getTransactionsToBlock();
if (data.length === 0) {
return null;
}
// NEW CODE
logTransactionDates(data);
// NEW CODE
let newBlock = new Block(index, previousHash, timestamp, data);
newBlock = Miner.mine(newBlock, this.difficulty);
return newBlock;
}

Niewielka zmiana. Prawda? Zamknąłem wszystko w nowej funkcji i tylko tyle.

Moim zdaniem, aż tyle.

  • Po pierwsze jeśli jest napisana jakaś funkcja, to pewnie spełnia swoje zadanie i powinniśmy dodać jak najmniejszą ilość kodu.
  • Po drugie nie powinniśmy zwiększać odpowiedzalności. Kod z pierwszego sposobu zwiększa zakres funkcji, dodaje logowanie, mapowanie. W drugiej opcji odpowiedzialność jest przeniesiona na zewnątrz. To inna funkcja ma za zadanie logować i wydostać co jest potrzebne. To bardzo ważne.
  • Szczególnie jak zaczniecie pisać testy. Jak je dodacie w pierwszej opcji? Musicie modyfikować kod testów, dopisywać przypadki do całości. Jak wykiełkujemy metodę to będziemy dodawać tylko do tych dwóch linijek kodu testy. Potem dodamy tylko sprawdzenie czy funkcja się wywołuje i to tyle. Kod funkcji będzie przetestowany na zewnątrz.

Małe rzeczy robią dużą różnicę

Doświadczenie nauczyło mnie, że raz napisana funkcja robi swoje. Jeśli wchodzę i próbuję coś dopisać to znaczy, że robię jakiś błąd. Powinienem utworzyć nową funkcję na daną funkcjonalność i tylko zrobić wywołanie w tamtej funkcji.

Będzie ciut więcej kodu, bo trzeba napisać nową funkcję zamiast wprowadzać zmiany w istniejącej. Czasami trzeba przerobić kod, żebyśmy mogli nasz wyrzucić na zewnątrz (szczególnie przy pętlach albo złożonych warunkach). Ale czy to źle? Nadejdzie wyczekiwany refactor i kod będzie wyglądał lepiej. Do tego dojdą testy, które nie tylko sprawdzą czy nie zepsuliśmy czegoś, ale też przetestujemy w izolacji nasz nowy kod. Potem będziemy mogli dopisać testy do całości i sprawdzić wszystkie zależności.

Korzyści i wady

  • czytelniejszy kod
  • łatwiej testować
  • funkcje najczęściej robią tylko jedną rzecz
  • rozdzielamy odpowiedzialność na kilka miejsc
  • nie mamy single point of failure (kiedy przestaje działać jedna rzecz nie działa wszystko)
  • musimy napisać więcej kodu
  • czasami trzeba się nagimnastykować
  • mamy dużą ilość małych funkcji w kodzie

To już od Ciebie zależy co uznasz za wadę a co za korzyść. Pomyśl następnym razem jak będziesz dopisywał nowy kod. Czy na pewno nie mogę tego wyrzucić do innej funkcji? Czy nie łatwiej mi będzie to przetestować? Czy kod będzie czytelniejszy?

Patryk Szczygło
Programista w Netguru. Bloger od 2017 roku. Miłośnik podróży, książek i elektroniki. Stworzył własny blockchain w JavaScript. Marzy o automatyzacji i robotyce w życiu.