WTF Code Andrei Solntsev jug.lv Riga, Latvia May 2011
Обо мне http://asolntsev.livejournal.com http://asolntsev. blogspot .com
Agenda Классический говнокод Моя коллекция Кто виноват и что делать
WTFC Весь правильный код похож друг на друга, каждый кривой код крив по-своему. Перефразируя Достоевского
Классика «Лучшие» с сайта  govnokod.ru Например, см. исходники  EHCache : net.sf.ehcache.store.MemoryStore.findEvictionCandidate()
Классика « true »  - 4  символа « false »  -  5 символов
Классика
Так что же такое говнокод? Говнокод – это код, который явно можно написать проще и быстрее. А.Солнцев
Моя коллекция По колено в коде!
Масло масляное form.set Application Parent Template( form.get Parent Application Template());  ... потому что масло!
Чистый профит try  {    Object o = null;    o.foo();    //200 строк кода } catch(NullPointerException e) {    //200 строк кода }
Константы public class Field  { private final static String  ID_APPLY_FORM_TYPE_ID_5_LABEL  =  "applyFormTypeID_5" ; private final static String  ID_APPLY_FORM_TYPE_ID_22_LABEL  =  "applyFormTypeID_22" ; }
Ещё константы public class GapsResolver { /** Quantity of milliseconds in day. */ private final static long  MILLISECONDS_PER_DAY  = (long) 24 * 60 * 60 * 1000; Проблема 2012 года.     /** Quantity of milliseconds in month. */ private final static long  MILLISECONDS_PER_MONTH  = MILLISECONDS_PER_DAY  * 31 ; /** Quantity of milliseconds in year. */ private final static long  MILLISECONDS_PER_YEAR  = MILLISECONDS_PER_DAY  * 365 ; ... }
Be expressive Объясняйте свой код: Имя переменной Имя метода Имя класса Имя юнит-теста (в последнюю очередь!)  комментарий
Обработка ошибок class  LoginException  extends Exception { static final  LoginException   PASSWORD_EXPIRED   = new LoginException("Password expired"); static final  LoginException   INVALID_LOGIN_NAME   = new LoginException("Invalid login name"); static final  LoginException   INVALID_PASSWORD   = new LoginException("Invalid password"); } Сюрприз №1:  Exception ’ы объявлены как константы!
Обработка ошибок public User login(String  username , String  p assword) { … if (result == AUTH_RESULT. PASSWORD_EXPIRED ) { throw  PASSWORD_EXPIRED ; // WTF! } else if (result == AUTH_RESULT. INVALID_PASSWORD ) { throw  INVALID_PASSWORD ; // WTF! } else { throw  new LoginException ("Unkown …" + result); } } Сюрприз № 2 : У них неправильный  stack trace
Обработка ошибок public class  Login Controller { … catch (LoginException e)    { if ( e   ==   LoginException. PASSWORD_EXPIRED )  // WTF^2! { return  loginNotSucceededExpiredUserPassword (…); } } return loginNotSucceeded(… ); } Сюрприз № 3 : аццкая обработка
XML Builder private final void init() { m_sResponseTemplate =  new StringBuilder (&quot;<response>&quot;) .append(&quot;<dttm>&quot; +  LBL_TO_REPLACE_DTTM  + &quot;</dttm>&quot;) .append(&quot;<status>&quot; +  LBL_TO_REPLACE_STATUS  + &quot;</status>&quot;) .append(&quot;<reason>&quot; +  LBL_TO_REPLACE_REASON  + &quot;</reason>&quot;) .append(&quot;<requestID>&quot; +  LBL_TO_REPLACE_REQID  + &quot;</requestID>&quot;) .append(&quot;</response>&quot;) . toString() ; } Part 1/2 LBL_TO_REPLACE_DTTM  = &quot;%DTTM%&quot;; LBL_TO_REPLACE_STATUS  = &quot;%STATUS%&quot;; LBL_TO_REPLACE_REASON  = &quot;%REASON%&quot;; LBL_TO_REPLACE_REQID  = &quot;%REQID%&quot;;
XML Builder public final String initSuccessful(String sReqID) { init(); return StringUtils. replace ( StringUtils. replace ( StringUtils. replace (   StringUtils. replace   (   m_sResponseTemplate,   LBL_TO_REPLACE_DTTM , nvl(new Date())   ) ,   LBL_TO_REPLACE_STATUS , STATE_SUCCESS ) , LBL_TO_REPLACE_REQID , nvl(sReqID) ) , LBL_TO_REPLACE_REASON , REASON_NO ) ; } Part 2/2 Красиво!
XML Builder public final String initSuccessful(String sReqID) { return &quot;<response>&quot; + &quot;<dttm>&quot; +  new Date()  + &quot;</dttm>&quot; + &quot;<status>&quot; +  STATE_SUCCESS  + &quot;</status>&quot; + &quot;<reason>&quot; +  REASON_NO  + &quot;</reason>&quot; + &quot;<requestID>&quot; +  sReqID  + &quot;</requestID>&quot; + &quot;</response>&quot;; } Part 2/2 Просто! Строк кода:  58 -> 15
Искусство программирования заключается в том, чтобы не писать Огюст  Роден всё, что только можно не писать. Мессага Спроси себя: Можно ли сделать это проще ?
Динамика развития boolean  l icenseIsMandatory =  (mvr instanceof MvrDACService) ; if ( l icenseIsMandatory && isEmpty( l icense)) { … } Всё было хорошо, пока девелопер не закоммитил такой фикс:
Динамика развития -  boolean  l icenseIsMandatory =  (mvr instanceof MvrDACService) ; +  boolean  l icenseIsMandatory =  !(mvr instanceof MvrDACService) ; if ( l icenseIsMandatory && isEmpty( l icense)) {   … } Всё было хорошо, пока девелопер не закоммитил такой фикс:
Страшные фиксы try   { nFFAddress = new Integer(sAddressID); }
Страшные фиксы try   { -  nFFAddress = new Integer(sAddressID); +  nFFAddress = new Integer(sAddressID .substring(8) ); +  // remove ADDRESS_ prefix }
Откуда берётся говнокод? (студенты, индусы, спешка, демотивация, …) Руки впереди головы Привычки Стремление написать красиво
Мессага Не бывает  красивого  или  некрасивого   кода! От эстетства до педерастии – один шаг. Гоблин
Чем плох говнокод? Написание кода 20% Чтение  кода 80% review эволюция отладка Работа программиста
Мессага «Пишем быстро и плохо, чтобы сэкономить время» - это САМООБМАН! * Экономите лишь 20%, а нагружаете 80%
Средства борьбы с говнокодом Self-review Ctrl+K (IDEA) № 1 Юнит-тесты  & TDD http://asolntsev.livejournal.com/46049.html   № 2 Парное программирование online code review № 4 Code review Слишком поздно; ругать != учить NO Автоматическое  code review FindBugs, PMD, IDE inspections № 3
The best of protected void parseSummaryLines() { ... // NOTE: First letters are ommited in order to  // support capitalized words as well    String RESULT_GOOD_TEXT_1 = &quot; othing &quot;; //  Nothing    String RESULT_GOOD_TEXT_2 = &quot; uccessful &quot;;//  Successful    String RESULT_BAD_TEXT_1 =  &quot; assword “; //  Password    String RESULT_BAD_TEXT_2 =  &quot; failed &quot;; //  Failed    ... }  Этот код спустился с небес ! какмеч? жопослово?
W hat T he F aerie Code!
Любите говнокод! Серьёзное лицо – ещё не признак ума. Весь говнокод на земле  пишется  именно с этим выражением лица. Григорий Горин Улыбайтесь!
http://www.govnokod.ru   http://lurkmore.ru/ индусский_код   http://funny-java.blogspot.com/ http://community.livejournal.com/programmers_fun   http://community.livejournal.com/code_wtf   http://indiacodingpatterns.unkur.com/   Попробуйте только  не прочитайте:

WTF Code @ jug.lv

  • 1.
    WTF Code AndreiSolntsev jug.lv Riga, Latvia May 2011
  • 2.
    Обо мне http://asolntsev.livejournal.comhttp://asolntsev. blogspot .com
  • 3.
    Agenda Классический говнокодМоя коллекция Кто виноват и что делать
  • 4.
    WTFC Весь правильныйкод похож друг на друга, каждый кривой код крив по-своему. Перефразируя Достоевского
  • 5.
    Классика «Лучшие» ссайта govnokod.ru Например, см. исходники EHCache : net.sf.ehcache.store.MemoryStore.findEvictionCandidate()
  • 6.
    Классика « true» - 4 символа « false » - 5 символов
  • 7.
  • 8.
    Так что жетакое говнокод? Говнокод – это код, который явно можно написать проще и быстрее. А.Солнцев
  • 9.
    Моя коллекция Поколено в коде!
  • 10.
    Масло масляное form.setApplication Parent Template( form.get Parent Application Template()); ... потому что масло!
  • 11.
    Чистый профит try {    Object o = null;    o.foo();    //200 строк кода } catch(NullPointerException e) {    //200 строк кода }
  • 12.
    Константы public classField { private final static String ID_APPLY_FORM_TYPE_ID_5_LABEL = &quot;applyFormTypeID_5&quot; ; private final static String ID_APPLY_FORM_TYPE_ID_22_LABEL = &quot;applyFormTypeID_22&quot; ; }
  • 13.
    Ещё константы publicclass GapsResolver { /** Quantity of milliseconds in day. */ private final static long MILLISECONDS_PER_DAY = (long) 24 * 60 * 60 * 1000; Проблема 2012 года.  /** Quantity of milliseconds in month. */ private final static long MILLISECONDS_PER_MONTH = MILLISECONDS_PER_DAY * 31 ; /** Quantity of milliseconds in year. */ private final static long MILLISECONDS_PER_YEAR = MILLISECONDS_PER_DAY * 365 ; ... }
  • 14.
    Be expressive Объясняйтесвой код: Имя переменной Имя метода Имя класса Имя юнит-теста (в последнюю очередь!) комментарий
  • 15.
    Обработка ошибок class LoginException extends Exception { static final LoginException PASSWORD_EXPIRED = new LoginException(&quot;Password expired&quot;); static final LoginException INVALID_LOGIN_NAME = new LoginException(&quot;Invalid login name&quot;); static final LoginException INVALID_PASSWORD = new LoginException(&quot;Invalid password&quot;); } Сюрприз №1: Exception ’ы объявлены как константы!
  • 16.
    Обработка ошибок publicUser login(String username , String p assword) { … if (result == AUTH_RESULT. PASSWORD_EXPIRED ) { throw PASSWORD_EXPIRED ; // WTF! } else if (result == AUTH_RESULT. INVALID_PASSWORD ) { throw INVALID_PASSWORD ; // WTF! } else { throw new LoginException (&quot;Unkown …&quot; + result); } } Сюрприз № 2 : У них неправильный stack trace
  • 17.
    Обработка ошибок publicclass Login Controller { … catch (LoginException e)   { if ( e == LoginException. PASSWORD_EXPIRED ) // WTF^2! { return loginNotSucceededExpiredUserPassword (…); } } return loginNotSucceeded(… ); } Сюрприз № 3 : аццкая обработка
  • 18.
    XML Builder privatefinal void init() { m_sResponseTemplate = new StringBuilder (&quot;<response>&quot;) .append(&quot;<dttm>&quot; + LBL_TO_REPLACE_DTTM + &quot;</dttm>&quot;) .append(&quot;<status>&quot; + LBL_TO_REPLACE_STATUS + &quot;</status>&quot;) .append(&quot;<reason>&quot; + LBL_TO_REPLACE_REASON + &quot;</reason>&quot;) .append(&quot;<requestID>&quot; + LBL_TO_REPLACE_REQID + &quot;</requestID>&quot;) .append(&quot;</response>&quot;) . toString() ; } Part 1/2 LBL_TO_REPLACE_DTTM = &quot;%DTTM%&quot;; LBL_TO_REPLACE_STATUS = &quot;%STATUS%&quot;; LBL_TO_REPLACE_REASON = &quot;%REASON%&quot;; LBL_TO_REPLACE_REQID = &quot;%REQID%&quot;;
  • 19.
    XML Builder publicfinal String initSuccessful(String sReqID) { init(); return StringUtils. replace ( StringUtils. replace ( StringUtils. replace ( StringUtils. replace ( m_sResponseTemplate, LBL_TO_REPLACE_DTTM , nvl(new Date()) ) , LBL_TO_REPLACE_STATUS , STATE_SUCCESS ) , LBL_TO_REPLACE_REQID , nvl(sReqID) ) , LBL_TO_REPLACE_REASON , REASON_NO ) ; } Part 2/2 Красиво!
  • 20.
    XML Builder publicfinal String initSuccessful(String sReqID) { return &quot;<response>&quot; + &quot;<dttm>&quot; + new Date() + &quot;</dttm>&quot; + &quot;<status>&quot; + STATE_SUCCESS + &quot;</status>&quot; + &quot;<reason>&quot; + REASON_NO + &quot;</reason>&quot; + &quot;<requestID>&quot; + sReqID + &quot;</requestID>&quot; + &quot;</response>&quot;; } Part 2/2 Просто! Строк кода: 58 -> 15
  • 21.
    Искусство программирования заключаетсяв том, чтобы не писать Огюст Роден всё, что только можно не писать. Мессага Спроси себя: Можно ли сделать это проще ?
  • 22.
    Динамика развития boolean l icenseIsMandatory = (mvr instanceof MvrDACService) ; if ( l icenseIsMandatory && isEmpty( l icense)) { … } Всё было хорошо, пока девелопер не закоммитил такой фикс:
  • 23.
    Динамика развития - boolean l icenseIsMandatory = (mvr instanceof MvrDACService) ; + boolean l icenseIsMandatory = !(mvr instanceof MvrDACService) ; if ( l icenseIsMandatory && isEmpty( l icense)) { … } Всё было хорошо, пока девелопер не закоммитил такой фикс:
  • 24.
    Страшные фиксы try { nFFAddress = new Integer(sAddressID); }
  • 25.
    Страшные фиксы try { - nFFAddress = new Integer(sAddressID); + nFFAddress = new Integer(sAddressID .substring(8) ); + // remove ADDRESS_ prefix }
  • 26.
    Откуда берётся говнокод?(студенты, индусы, спешка, демотивация, …) Руки впереди головы Привычки Стремление написать красиво
  • 27.
    Мессага Не бывает красивого или некрасивого кода! От эстетства до педерастии – один шаг. Гоблин
  • 28.
    Чем плох говнокод?Написание кода 20% Чтение кода 80% review эволюция отладка Работа программиста
  • 29.
    Мессага «Пишем быстрои плохо, чтобы сэкономить время» - это САМООБМАН! * Экономите лишь 20%, а нагружаете 80%
  • 30.
    Средства борьбы сговнокодом Self-review Ctrl+K (IDEA) № 1 Юнит-тесты & TDD http://asolntsev.livejournal.com/46049.html № 2 Парное программирование online code review № 4 Code review Слишком поздно; ругать != учить NO Автоматическое code review FindBugs, PMD, IDE inspections № 3
  • 31.
    The best ofprotected void parseSummaryLines() { ... // NOTE: First letters are ommited in order to // support capitalized words as well   String RESULT_GOOD_TEXT_1 = &quot; othing &quot;; // Nothing   String RESULT_GOOD_TEXT_2 = &quot; uccessful &quot;;// Successful   String RESULT_BAD_TEXT_1 = &quot; assword “; // Password   String RESULT_BAD_TEXT_2 = &quot; failed &quot;; // Failed   ... } Этот код спустился с небес ! какмеч? жопослово?
  • 32.
    W hat The F aerie Code!
  • 33.
    Любите говнокод! Серьёзноелицо – ещё не признак ума. Весь говнокод на земле пишется именно с этим выражением лица. Григорий Горин Улыбайтесь!
  • 34.
    http://www.govnokod.ru http://lurkmore.ru/ индусский_код http://funny-java.blogspot.com/ http://community.livejournal.com/programmers_fun http://community.livejournal.com/code_wtf http://indiacodingpatterns.unkur.com/ Попробуйте только не прочитайте:

Editor's Notes

  • #27 1. Про фортран и Яву; можно ещё про «через 20 лет» и Бритни 2.Если будет время – видео про числа Фибоначчи («ну, я... Эээ.... Наверное... Типа того... »)
  • #28 Код может быть: Читаемый/нечитаемый, громоздкий/лаконичный, эффективный/неэффективный, НО НЕ красивый/некрасивый!
  • #30 Спешка – формулировка от Гоблина « Работать быстро - значит делать медленные движения без перерывов »
  • #31 Попить кофе, вернуться и взглянуть ещё разок на своё творение 2. 3. FindBugs, PMD, jlint , встроенные в IDE.