Димитър обнови решението на 27.01.2016 17:24 (преди около 9 години)
+REPOSITORY = 'http://github.com/dimitaruzunov/ruby-retrospective-2015-1'
+
+# Двадесет неща, които научих.
+#
+# Първа задача
+# 1. Оставяне на празни редове в методи с цел разделяне на логически различните
+# части от кода на метода е добра практика. Например, в първа задача, сложих
+# празен ред преди стойността на връщане от функцията compare_prices.
+# По този начин кодът стана по-четим.
+#
+# Втора задача
+# 2. В move функцията за премахване на опашката на змията използвам Array#drop
+# метода вместо копиране на змията (при grow), Array#shift и накрая връщане
+# на преместената змия. Така кодът става по-кратък (от 3 на 1 ред), но и
+# по-четим и разбираем. От тук научих, че е хубаво да се чете документацията
+# с цел да се намери най-подходящата функция за решаването на даден проблем.
+# 3. В new_food метода промених начина, по който взимам всички x координати
+# (и съответно същото и за y координатите). Замених
+# xs = *(0...dimensions[:width]) с xs = (0...dimensions[:width]).to_a,
+# от което става ясно, че стойносттва на xs ще бъде масив, докато от splat-а
+# не се разбира веднага какво се случва. От това научих, че е по-добре да
+# се използват възможно най-простите и разбираеми конструкции, когато може,
+# а не нещо изглеждащо 'fancy' като например splat-а, но същевременно и
+# неразбираемо за дадената ситуация.
+# 4. Използването на паралелно присвояване прави кода по-прост и четим,
+# когато например елементите на даден масив са свързани логически и искаме
+# да им дадем имена. Във функцията snake_ahead_position взимам x и y
+# координатите на главата на змията чрез head_x, head_y = snake.last (по
+# същия начин и координатите на посоката).
+# 5. Сложни конструкции като zip -> map -> reduce не са подходящи за прилагане
+# при решаването на проста задача като например сумирането на два 2D вектора,
+# както е в snake_ahead_position функцията. Вместо zip -> map, имаме просто
+# [head_x + direction_x, head_y + direction_y].
+# 6. Не е смислено да се дефинира метод, който е 'синоним' на друг метод, и
+# единственото нещо, което прави втория метод, е да извика първия. Например,
+# метода not_in_bounds? е 'синоним' на wall_ahead? (wall_ahead? извиква
+# not_in_bounds?). За да подобря това, преместих кода от not_in_bounds? в
+# wall_ahead? и изтрих not_in_bounds? метода.
+#
+# Трета задача
+# 7. Научих какво е Enumerator в Ruby и че при извикване на методи от
+# Enumerable без подаване на блок тези методи връщата Enumerator и по този
+# начин може да се chain-ват методи от Enumerable.
+# 8. Научих за метода enum_for, чрез който можем да конструираме Enumerator от
+# метод, който yield-ва стойности. И този Enumerator обхожда точно
+# yield-натите стойности от подадения метод.
+# 9. Научих за цикъла loop do ... end и използването и за конструиране на
+# безкраен поток от стойности, като се използва заедно с enum_for. Цикълът
+# може да бъде прекратен при възникване на StopIteration изключение, което
+# се хвърля, когато Enumerator-ът обходи всички стойности.
+# 10. Научих за lazy метода в Enumerable, който връща lazy_enumerator. Това е
+# Enumerator, при който методи като map, select, take, drop, take_while,
+# drop_while обхождат стойностите само при необходимост. Тоест при подаване
+# на блок на някой от тези методи, съответния израз няма да бъде оценен
+# веднага, а само при нужда или при изпълнение на force метода. По този
+# начин може да се chain-ват map, select, take с подадени блокове без да
+# се оценяват. Това е доста полезно при конструирането на безкрайни потоци.
+# 11. Паралелното присвояване помага, когато искаме да вземем елементите от
+# масив с дължина 2 и да им дадем имена, като по този начин кодът става
+# по-разбираем. Така, например, във функцията meaningless от partition
+# се получава масив от два елемента -- двете групи, на които е разделен
+# входния масив. В старото решение бях дал името groups на тези две групи,
+# което по никакъв начин не дава информация какви са тези групи. И за
+# взимането на всяка група поотделно използвах индексиране, което също
+# намалява разбираемостта на кода.
+# 12. За рефакторирането на функцията aimless научих, че при подаването на масив
+# като аргумент на блок можем да използваме паралелно присвояване и по
+# този начин да избегнем индексиране, с което да направим кода по-четим.
+# 13. Научих, че параметър на блок може да има стойност по подразбиране.
+# Например, във функцията aimless сложих стойност по подразбиране на
+# параметъра second 1, с което си спестих 1 проверка
+# (pairs.last << 1 if n.odd?).
+# 14. Научих за метода take_while (използван във функцията worthless)
+# 15. При рефакторирането на метода prime? разбрах за метода all?, който в
+# комбинация с upto метода доста опрости кода на функцията, като замени
+# изцяло while цикъла.
+#
+# Четвърта задача
+# 16. Научих, че не трябва да забравям да имплементирам each метода в клас,
+# който включва Enumerable модула (в случая класа Deck)
+# 17. Научих, че с влагане на клас в друг клас може да се постигне по-добра
+# и интуитивна подредба на кода. Например при влагането на класа Hand в Deck
+# и съответно на клас Hand във всеки от видовете тестета.
+# 18. Хубаво е при моделирането на дадения проблем чрез средствата на ООП да
+# се изгради изчистена и консистентна йерархия от класове.
+# 19. Научих, че може да използваме splat вътре в дефиницията на масива, за да
+# 'разгърнем' интервал от стойности:
+# [:ace, :king, :queen, :jack, *(10.downto 2)]
+# 20. Научих за ключовата дума next и използването и за прекратяване на текущата
+# итерация, като може да се даде и стойност на връщане на блока. Например:
+# next false if cards_of_suit.size < card_count в n_consecutive_cards?