Jak pisać kod, żeby chcieć do niego wrócić i wiedzieć co się w nim dzieje

in polish •  7 years ago  (edited)

Cześć,
w tym artykule chciałbym podzielić się z wami moimi przemyśleniami związanymi z pisaniem kodu.
Każdy kiedyś zaczynał naukę pisania programów w danym języku. Na samym początku, nasze programy to były głównie przepisane gotowe formułki, które "działały". Cieszyliśmy się z tego, że pojawiła się konsola i mogliśmy coś sobie tam wpisać.
Z czasem, zaczęliśmy pisać już bardziej świadomie. Używaliśmy dokumentacji, uczyliśmy się nowych instrukcji. Nasz kod wyglądał pewnie tak, że wrzucaliśmy wszystko do jednej klasy/pliku i cieszyliśmy się, że nasz program działa, i że to my go napisaliśmy od zera.
Po pewnym czasie, zobaczyliśmy że nasz kod jest co raz większy i staje się dla nas niezrozumiały już po kilku dniach przerwy. Pewnie wtedy dowiedzieliśmy się, że kod trzeba w pewien sposób wydzielać. Że są metody/funkcje, że są klasy. Oczywiście zaczęliśmy używać tego typu elementów do rozdzielania naszego kodu na mniejsze części.
Było już lepiej, ale wciąż po kilkudniowej przerwie, wciąż te nasze nazwy zmiennych, nazwy metod były słabo zrozumiałe. Zaczęliśmy staranniej nazywać zmienne, metody, klasy, widzieliśmy że już możemy zrobić tydzień przerwy i nasz kod jest zrozumiały. Wielu pewnie czuło satysfakcję.
Nadszedł jednak pewien moment (bądź jeszcze nie), że pomyśleliśmy - "A czemu by tak nie pisać kodu tak, aby można było czytać go jak książkę w języku angielskim?"
Każdy chyba pamięta jak trzeba było czytać lektury. Niektórzy to lubili, niektórzy mniej, ale zawsze po przeczytaniu takiej książki, mieliśmy w pamięci sporo informacji na temat przeczytanej książki.
Na takiej samej zasadzie właśnie można pisać kod. Tak, żeby czytać go jak książkę. W naszym przypadku, książka byłaby połączona w podstrony. Kod czytamy wtedy "wgłąb".
Nie wiem ilu z was miało takie odczucia jak ja je tutaj opisałem, ale taki tok myślenia pozwala na przyjemniejsze powroty do naszego kodu napisanego jakiś czas temu.
Powiem wam właśnie jakie narzędzie może służyć do upiększania naszego kodu.
Jest to zwykły REFACTORING.
Tyle i aż tyle. Dzięki tej opcji, nasz kod może zostać upiększony do wersji jak najbardziej czytelnej. Oczywiście najlepiej sprawdza się przy większej ilości kodu.
Podam wam teraz "wycinek" takiego kodu, gdzie mamy kod bez "upiększaczy" i wersję "książkową".

public class UglyCode {
   
    private int a = 0;
    private int b = 0;
    private static Random r = new Random();

    public UglyCode(int a, int b) {
        this.a = a;
        this.b = b;
        String text = "Szczęśliwe liczby: ";
        text = text + a + ", " + b;
        System.out.println(doStuff(text));
    }

    public String doStuff(String text) {
        int c = r.nextInt(10);
        while(c == 7) {
            c = r.nextInt(10);    
        }
        text = text + ", " + c;

        return text;
     }
}

A teraz, nadajmy temu programowi trochę duszy i zabawmy się w pisarzy :D

public class HappyNumberPrinter {
   
    private int firstTrulyRandomNumberToPrint = 0;
    private int secondTrulyRandomNumberToPrint = 0;
    private static Random randomManWhoWillGiveUsNumber = new Random();

    public HappyNumberPrinter (int firstTrulyRandomNumberToPrint, int secondTrulyRandomNumberToPrint) {
        this.firstTrulyRandomNumberToPrint = firstTrulyRandomNumberToPrint;
        this.secondTrulyRandomNumberToPrint = secondTrulyRandomNumberToPrint;
     }

    public void showMeSomeHappyNumbers() {
        String happyNumbersText = "Szczęśliwe liczby: ";
        happyNumbersText = concatenateMyNumber(happyNumbersText, firstTrulyRandomNumberToPrint);      
        happyNumbersText = concatenateMyNumber(happyNumbersText, secondTrulyRandomNumberToPrint);
        int ourLuckyHappyNumber =  askMenToGiveUsHappyLuckyNumber();
        happyNumbersText = concatenateMyNumber(happyNumbersText, ourLuckyHappyNumber);      
        putOnScreenHappyText(happyNumbersText);
    }
    
    private putOnScreenHappyText(String happyTextToPut) {
         System.out.println(happyTextToPut);
    }

    private String concatenateMyNumber(String currentTextToPrint, int numberToConcatenate) {
        currentTextToPrint = currentTextToPrint + ", " + numberToConcatenate;
        return currentTextToPrint;
    }
    private int askMenToGiveUsHappyLuckyNumber() {
        int luckyNumberCandidate = randomManWhoWillGiveUsNumber.nextInt(10);
        while(isNotOurExpectedLuckyNumber(luckyNumberCandidate)) {
            luckyNumberCandidate = randomManWhoWillGiveUsNumber.nextInt(10);
        } 
        return luckyNumberCandidate;
     }

    private boolean isNotOurExpectedLuckyNumber(candicateToBeLuckyNumber) {
        return candicateToBeLuckyNumber == 7;
    }
}

Uff, to było ciekawe doświadczenie, gdy jedyny kompilator, to twoja głowa :)
Porównajcie sobie klasy, obie robią praktycznie identyczne czynności, jednak nazwy zmiennych, klasy i metod są inne.
Gdyby kod wyglądał tak jak ten drugi przykład, to czytanie kodów źródłowych byłoby czystą przyjemnością.
A wy, jakie macie zdanie na temat pisania kodu "ładnie"?

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Dobrze to napisałeś. Z tego co mi się kojarzy to nawet Sławek Sobótka miał jedną z prezentacji o tytule "Nie koduj, pisz proze!".

Dobór odpowiednich nazw zdecydowanie zwiększa czytelność. Największe wyzwanie to nazewnictwo dla klas. Czasem jest tak, że klasa z zmienia swoją role. Czasem w trakcie trwania projektu okazuje się, że może lepiej było nazwać ją trochę inaczej. Wtedy najlepiej zrefaktorować i zmienić nazwę. Myślę, że nakład czasowy, który wrzucimy w zmianę nazw i tak na końcu się opłaci.

Jeśli chodzi o czytelność to warto wspomnieć o języku Ruby.
W nim nawet osoba która nie jest programistą domyśli się co robi dana funkcja

Widziałem tę prezentację jakiś czas temu na Youtube. Mogła ona się nawet przyczynić po części do napisania tego postu :) Generalnie postanowiłem sobie kiedyś, że będę pisał kod bardziej opisowo, aby każdy kto go zobaczy, mógł prawie od razu coś w nim zmieniać.
Co do Rubiego, to rzeczywiście jego możliwości i składnia są jedne z przyjemniejszych. Kiedyś nawet miałem taki projekt, gdzie musiałem przejść z Rubiego na Javę. Dzięki pisaniu w stylu "javowym" w Ruby, mogłem bez większych problemów przerzucić kod do Javy prawie że 1:1. (Z wyjątkiem takim, że w javie potrzebny był większy boilerplate do napisania identycznej funkcjonalności)

Za przekazywanie poprawnych wzorców pracy na projekcie odpowiadają osoby z największym doświadczeniem. Niestety bardzo często są oni słabymi programistami a stanowisko zawdzięczają innymi umiejętnością. Jak to mówią, ryba psuje się od samej głowy.
W konsekwencji:

  • osoba robiąca code review potrafi zwracać uwagi juniorom jedynie na to czy kod jest zgodny ze standardami klienta a kompletnie olewa jakość
  • na projekcie nie działa continuous integration

Później na projekt przychodzisz TY i próbujesz jakoś przebić się przez ten beznadziejny kod. Tracisz masę czasu na zrozumienie tego całego spagetti w kodzie i przez to sam nie masz czasu na refactoring tego co sam napiszesz. Koło się zamyka. Kolejne linie słabego kodu wpadają do repo :(

Co z tego że ja potrafię tworzyć ładny kod jak jest już za późno na uratowanie całej bazy jaką stworzyli inni :(

Niektórzy kierują się taką zasadą, że przy każdym "spojrzeniu" na pewien kawałek kodu, refaktorujesz go. Wiadomo, jak poprzednicy narobią miesiąc długu technicznego, to ciężko takie coś odrobić. Sam mam styczność z projektem, gdzie język nie jest moim ulubionym i sam projekt ma "ciekawą" strukturę. Ale tam, gdzie ja coś dopisuję, to dbam, aby kod był "fajny". Wiadomo, ratowanie trupa do najłatwiejszych nie należy, ale robiąc coś, nie chce się potem wstydzić za moje "ficzery". Zawsze będzie przynajmniej kawałek "przyjemnego" kodu. Najgorzej jest ruszanie kodu co ma 6 lat, był pisany dorywczo przez studenta, którego już nie ma i dodaj tam teraz coś nowego bez rozwalania całego programu. (Oczywiście null testów) Normalnie jazda bez trzymanki :D

Myślę, żę nigdy nie jest zapóźno. Ale zgadzam się z Tobą. Widzę to sam po sobie. Na projekcie który prowadzę, czepiam się o każdą niepotrzebną spacje. Ale jak czasem muszę popracować na innym porjekcie, który nie jest tak dopracowany, to nie dbam aż tak o jakość kodu.

Podam przykład:

Ostatnio w projeckie edytowałem coś na widoku. Labele zamiast kluczy do translacji miały na sztywno ustawiony polski język. Nie poprawiałem ich. We fragmencie który edytowałem dodałem klucz tranlsacyjny, ale reszte zostawiłem tak jak była.