Лекцията за втора задача и ОО

  1. Качил съм лекцията за втора задача. Качил съм и решенията, които ви показахме.

    Две неща.

    Първо, зададохте ред въпроси. Иска ми се да продължим дискусията тук. Ако нещо не ви е станало ясно, имате нужда от повторение или прочее - питайте. Искам да опитам да създам дискусия на тази тема тук. Мисля, че ще е полезно за всички ви. И интересно.

    Второ, ако някой от вас си е водил бележки под някаква форма и иска да ги сподели с всички останали - може да го направи тук. Ще има съответното възнаграждение.

  2. Това, което аз си записах :

    • Колкото по-прост (разбираем) код, толкова по-добре (невинаги краткия код е разбираем);
    • Симптоми за codesmell - класове с твърде много код; повторение на код; клас / метод има повече от една отговорност; клас знае твърде много за друг;
    • Когато се чудя дали да направя нов клас, или не, просто да го направя;
    • Класовете трябва да са малки, прости и да изпълняват точно едно определено нещо;
    • Да поставям адекватни имена (на клас, метод, променлива). Ако не мога да измисля такова, трябва да променя нещо;
    • Да изпускам скоби навсякъде, ако няма warning или не са около параметрите при дефиниция на метод;
    • Да подавам ламбда / Proc като блок (в случай, че са само 1).

    Аз се изкефих на първото решение с многото класове. Някой може ли да ми препоръча книга за design patterns с повече задачи/примери?

  3. Аз бих те посъветвал да се зачетеш в GoF. Това е де-факто книгата.

    Тази на Head First не съм я чел (макар че я имам), но подозирам че е добра - те не задълбават в детайли, но обясняват нещата адски добре. Друга добра книга от тази серия е Head First Software Development, която идеално обяснява какво са гъвкави методологии.

    Някой има ли други наблюдения/бележки?

  4. Разкриване на интерфейс

    Едно от твърденията ми бе, че доброто ООП внимателно подбира интерфейса. Нека разгледаме една ситуация.

    Представете си, че имаме нужда да конструираме колекцията на части. За целта решаваме да я направим mutable. Collection#parse ще конструира празни колекции и ще добавя песните една по една.

    Имаме два начина да реализираме това. Първият е като предлагаме масива с песни навън:

    class Collection
      attr_reader :songs
    
      def initialize
        @songs = []
      end
    end
    
    extract_songs(songs_as_text).each do |song|
      collection.songs << song
    end
    

    Вторият е да направим специален метод за целта:

    class Collection
      def initialize
        @songs = []
      end
    
      def add_song(song)
        @songs << song
      end
    end
    
    extract_songs(songs_as_text).each do |song|
      collection.add_song song
    end
    

    Второто е по-добрия интерфейс. Има няколко причини.

    • Скрива вътрешното представяне. Така не е ясно по какъв начин се пазят песните. Може да е масив, може да е структура за по-бързо търсене. Ако трябва да минем от едното към другото, това става без промяна на клиентския код.
    • Предлага по-ограничен интерфейс. Това е хубаво. В първия вариант можем да добавяме песни, да ги трием и да ги сортираме. Това не е нещо нужно - вместо това е инцидентно следствие на реализацията. Ако клиентския код започне да зависи от тези възможности и в последствие решим да променим имплементацията, има възможност да вкараме бъгове.
    • Има по-малко действия, които може да правим с една колекция. Това е хубаво, понеже така колекцията се разбира по-лесно. Отново, много (брой) малки (големина) конкретни абстракции е по-добре в обектно-ориентирана среда.

    Бързодействие и четимост

    Любопитно е да споменем кога първия вариант е за предпочитане. Това са ситуации, в които гоним производимост. Ако имаме нужда да добавяме много песни и overhead-а от извикване на метод/функция е осезаем, излагането на вътрешно представяне може да ускори нещата.

    Два неща, обаче.

    Първо, това е нещо до което кода се развива. Демек, първо го правите работещ, после го правите разбираем и най-накрая, ако и където има нужда го правите бърз. Второ, Martin Fowler казва, че "оптимизацията е обратния процес на рефакторирането". Правим кода бърз, но по-трудно четим. Ще забележите, че ние често ще правим кода по-бавен (маргинално), но по-четим.

    Второ, ако имате такава ситуация в Ruby, тя ще бъде рядка. Едва ли ще ви се случи в рамките на този курс.

    Тук има по-обща мисъл за ценности. Кое е по-важно - четимост или производителност?

    Отговора е: зависи. Трябва контекст. Има проекти, за които производителността е по-важна (search engine, web server, kernel). Има проекто, за които четимостта е по-важна (приложения - например онлайн магазин или дори този сайт). Избора на езика зависи от тези ценности.

  5. Какво разбирате вие.. Skype лог от чат с колега, неуспял да посети лекцията на Браян и Ник:

    [15:19:10] Прохождащ C++ програмист: и кво викат
    [15:19:27] Прохождащ C++ програмист: да си събмитваме кодовете там та сички да ги гледат
    [15:20:59] Прохождащ C++ програмист: той моя код е генийален
    [15:21:13] Прохождащ C++ програмист: и да го гледат няма да го разберат
    [15:21:42] Petko Bordjukov: мда, това е основна характеристика на добрия код
    [15:21:46] Petko Bordjukov: като го гледаш, не можеш да го разбереш
    

Трябва да сте влезли в системата, за да може да отговаряте на теми.