2011. április 26., kedd

Clean Coding Technikák : A funkciók megvalósítása

A fejlesztés során az egyik legfontosabb szempont, hogy olyan kódot adjunk ki a kezünkből, amit bármely más programozó azonnal átlát és képes módosítani vagy továbbfejleszteni. A Clean Coding technikák használata pontosan ebben lesz majd a segítségünkre, azáltal hogy a kódunk öndokumentálóvá válik!

Jómagam elkötelezett híve vagyok ezen elveknek, így ebben a cikkben a funkciók megvalósításához ajánlott Clean Coding technikákat fogom pár példával ismertetni.

  1. Fejlesszünk úgy minden egyes metódust mintha egy történetet akarnánk elmesélni az adott domain kifejezéseit használva.
  2. Az alábbi metódusok működése egyszerűen kiolvasható a kódból, így bármely fejlesztő számára könnyen módosíthatóvá válik.
    private void loginUser(){
        checkUserCredentials();
        setupUserWebSessionInformations();
        modifyUserLastLoggedInTime();
        redirectUserToLoginPage();
      }
    
    private void makeTea(){
        if(kettle.isEmpty()){
         fillKettle(Liquid.Water);
        }
        plugTheKettleIntoThePowerPoint();
        switchTheKettle(Switch.On);
        placeTeaLeavesInTheTeapot();
        waitUntilTheWaterIsNotBoiling();
        switchTheKettle(Switch.Off);
      }
    
    
  3. Készítsünk rövid metódusokat. (max. 20-25 sor hosszú metódusok)
  4. Az if, else, for, while, try blokkok legyenek rövidek, kb. 1-3 sor hosszúak. Az ennél hosszabb kódrészeket szervezzük ki külön private metódusokba.
  5. A metódus mindig csak 1 dolgot csináljon, de azt jól!
  6. A funkción belüli műveletek mindig ugyanahhoz az absztrakciós szinthez tartozzanak. Az eltérő absztrakció szinthez tartozó kódrészt szervezzük ki külön osztályba ill. metódusba.
  7. Az alábbi példánál az incrementVideoViews() metódusnak nem kellene a HttpServletResponse-al és Cookie kezeléssel foglalkoznia, mivel ez már egy alacsonyabb szintű dolog. Az incrementVideoViews() szintjén csupán annyit kellene tudni, hogy a cookieManager szolgáltatását igénybevéve az addNewCookie() ezt majd elvégzi valahogyan, a konkrét megvalósítás azonban már a CookieManager felelőssége.
    public void incrementVideoViews(Video video){    
      ...
      Cookie cookie = new Cookie(
        video.getName(), video.getId() .toString());
      cookie.setMaxAge(cookieAge);
      cookie.setPath("/xyz");
      ((HttpServletResponse) facesContext
        .getExternalContext().getResponse())
        .addCookie(cookie);
    }
    
    A fenti kód helyett, inkább használjuk ezt:
    public void incrementVideoViews(Video video){
      ...
      cookieManager.addNewCookie(
        video.getName(),video.getId().toString(),cookieAge);
    }
    
  8. A metódus neve pontosan mutasson rá hogy mit is csinál.  Ha nem sikerül kifejező nevet adni, akkor rossz úton járunk. Ha csak hosszú nevet tudunk adni, akkor valószínűleg kisebb részekre kell bontatnunk a metódust.
  9. A metódusok névadásánál legyünk konzisztensek a domain fogalmaival és az eddig használt elnevezéseinkkel.
  10. Metódus argumentumok számának minimalizálása. Törekedjünk minél kevesebb argumentum használatára mivel rontják a kód olvashatóságát.
  11. public void createUser(String firstName, String lastName, int age, String address);
    
    Helyett:
    public void createUser(User newUser);
    
  12. Side Effectek elkerülése: Olyan műveletet ne végezzen a metódus, ami a metódus nevéből nem következik!
  13. A checkPassword() metódus nevéből senki sem gondolná, hogy akár egy session inicializálás is lefuthat.
    public boolean checkPassword(String userName, String password) {
       User user = findUserByName(userName);
       if (user != null) {
        if(PasswordHandler.checkPasswordMatch(
          password,user.getPassword()))
         Session.initialize();
         return true;
        }
       }
       return false;
      }
    
  14. Command And Query Separation: A metódus vagy változtassa meg az objektum állapotát vagy kérdezzen le valamit az objektumtól, de a kettőt ne tegye egyszerre.
  15. Az alábbi metódusnál vajon egyértelmű a visszatérési érték jelentése?
    public boolean reportError(Error error,List<User> admns);
    
    Sikerült a hibát bejelenteni? Legalább 1 adminisztrátort értesítettek? Minden adminisztrátort értesítettek? Javításként válasszuk szét a Command és a Query funkciókat:
    public void reportError(Error error,List<User> admns);
    public boolean isSuccessfulErrorReport();
    
  16. Kód duplikációk szigorú elkerülése.
  17. A kommentek számának minimalizálása! A sok komment használata rossz kódot jelent, mivel a kód ilyenkor nem önleíró. Törekedjünk arra, hogy maga a kód legyen a dokumentáció!

Ha tetszett a bejegyzés, akkor ne hagyd ki Robert C. Martin előadását sem a Clean Coding technikákról!



Amennyiben szeretnél többet megtudni a tiszta kódolásról, ajánlom az erről szóló könyvet is!  A véleményem szerint olyan időtálló gondolatokat tartalmaz, hogy egy fejlesztőnek sem hiányozhat a virtuális könyvespolcáról!