Решение на Пета задача от Милен Мавров

Обратно към всички решения

Към профила на Милен Мавров

Резултати

  • 4 точки от тестове
  • 1 бонус точка
  • 5 точки общо
  • 0 успешни тест(а)
  • 0 неуспешни тест(а)

Код

REPOSITORY = 'https://github.com/MMavrov/ruby-retrospective-3'
#Двадесет неща, които научих:
#
#1. Ясни и стриктни ограничения за форматирането на кода и именуването на променливите са добра практика и също така се набива на очи, дори и на не толкова опитни
# програмисти. Това е може би най-важното и полезно за мен правило, което научих от този курс. По този начин програмиста се старае да осмисли наистина какво точно
# се желае като резултат и да погледне по-от-високо на 'картинката'. Смея да твърдя, че вече ми е навик. Благодаря! :)
#2. Преди да навлизаш в прекалено задълбочени размишления, попитай приятел. Спестява време и усилия. Евентуално довежда до интересни спорове. Също така ако имаш ясни
# цели за това какво трябва да представлява крайния продукт, гониш срок за предаване и няма как да го спазиш, по-добре направи малка, но работеща част от
# изискванията. По такъв начин ще получиш малко по-лош feedback. (Визирам предадената си втора задача, където мислех, че ще получа точки за написани базови класове
# и идея зад тях.)
#3. Използване на неявно извикан self в повечето решения беше интересно и неизползвано от мен свойство на езика. Отне ми известно време докато успея да разбера какво
# става всъщност.
#4. Явно когато се викат методи от друг клас е по-удачно параметрите да бъдат възможно по-базови от гледна точка на йерархия в езика. Това е полезен принцип за
# програмирането като цяло. Визирам 3та задача, където за инициализация на нов обект от тип 'BresenhamRasterization' се използват координатите на крайните точки,
# а не самите точки.
#5. Начина по който се дефинират методи от рода на "def vertical_drawing_direction @drawing_from_y < @drawing_to_y ? 1 : -1 end", които много приличат на променливи ми
# допада и досега не го бях използвал. Наистина разбива кода на малки по-лесно обозрими и уникални по смисъл парчета. Силно ми наподобяват, според мен, properties
# в C#.
#6. Имплементирането на метод с едно и също име ( още познато като override :D ), в случая "rasterize_on" помага за това да не използваме "case" в "draw" на 'Canvas',
# с който да определяме типа на аргумента на "draw" и в съответвствие от това да викаме метод, който да обработва дадената фигура.
#7. Ако имаме често повтарящ се код, като например шаблона за HTML рендерирането в трета задача, е по-удачно да го сложим в замразен обект в класа, отколкото да
# използваме инстанционна променлива и да я инициализираме с няколко метода, всеки от който е по n-на-брой реда. Замразените обекти играят ролята на константи в Ruby.
# П.С. Също така по този начин се отърваваме от ограниченията (в случая Skeptic).
#8. За хеширане на обекти в Ruby можем да използваме "hash"-метода, който връща уникално число, в зависимост от обекта на който е извикан.
#9. Всички 'Enumerable' обекти имплементират min, max, map, drop, find, all и други.
#10. Използване на "map(&:strip)", вместо "map { |element| element.strip }".
#11. Използване на "some_text".lines, вместо 'split'-ването му на символи за нов ред.
#12. Съществуване на метод "uniq" и съответно "uniq!" за създаване на уникални по елементи списъци. Може да се вика с блок и в този случай резултата, върнат от блока
# се приема за сравнение дали два елемента са еднакви.
#13. Цялостния начин по който поредица от символи се обработва до масив от обекти само с помощта на два "map"-a на три реда ми направи огромно впечатление в едно от
# решенията на втора задача (именно това, което съм избрал да предам за пета задача).
#14. Код от рода на:
# "@todo_object = TodoList.new
# @todo_object.fillList todo_string
# @todo_object"
# ефектно може да се замени от по-краткото и прегледно:
# "@todo_object = TodoList.new todo_string", ако вместо допълнителен метод 'fillList', използвам конструктора на класа.
#15. За обекти, които имат структура, подсказваща обхождане (например списък) е по-удобно и силно препоръчително да се имплементира 'Enumerable'.
#16. Можем да наследим "Struct.new(:instructions, :labels, :ax, :bx, :cx, :dx)". Параметрите, указани в конструктора играят роля на полета в наследяващия клас, който
# всъщност е структура. Това е начина в Ruby да създаваме Struct. Предимството пред 'class' е, че съществуват удобни методи за манипулиране на полетата на
# структурата.
#17. Метапрограмиране! Явно не съм обърнал достатъчно внимание на лекцията, свързана с тази част на езика. Дефинирането на методи на класа по този начин ми идва малко
# от въздуха, честно казано, но все пак е полезен похват, за който научих. Както повечето неща в Ruby, и това става доста елегантно (ето, че дойде момента в
# програмистката ми кариера, в който описвам код по този начин).
#18. Създаване на методи чрез 'proc'. Един вид създаване на ламбда функции. Нещо, което до скоро не се срещаше толкова често в останалите езици. Интересна практика е.
# Липсата на възможност за ефективно дебъгване и видимото забавяне в performance-а са едни от основните минуси.
#19. Интересен е начина, по който се разменят стойностите на две променливи без трета! "@drawing_from_x, @drawing_to_x = @drawing_to_x, @drawing_from_x" ... да, това
# работи! Похвата се нарича "Parallel Assignment" и се дължи на паралелното обработване на присвояването в Ruby.
#20. Оператор % на String. Не го бях използвал и честно казано виждал до сега. Според мен става въпрос за някаква форма на интерполация. Правя асоциация със
# String.format в някои езици.

История (2 версии и 2 коментара)

Милен обнови решението на 22.01.2014 15:11 (преди почти 11 години)

+REPOSITORY = 'https://github.com/MMavrov/ruby-retrospective-3'
+
+#Двадесет неща, които научих:
+#
+#1. Ясни и стриктни ограничения за форматирането на кода и именуването на променливите са добра практика и също така се набива на очи, дори и на не толкова опитни програмисти. Това е може би най-важното и полезно за мен правило, което научих от този курс. По този начин програмиста се старае да осмисли наистина какво точно се желае като резултат и да погледне по-от-високо на 'картинката'. Смея да твърдя, че вече ми е навик. Благодаря! :)
+#2. Преди да навлизаш в прекалено задълбочени размишления, попитай приятел. Спестява време и усилия. Евентуално довежда до интересни спорове. Също така ако имаш ясни цели за това какво трябва да представлява крайния продукт, гониш срок за предаване и няма как да го спазиш, по-добре направи малка, но работеща част от изискванията. По такъв начин ще получиш малко по-лош feedback. (Визирам предадената си втора задача, където мислех, че ще получа точки за написани базови класове и идея зад тях.)
+#3. Използване на неявно извикан self в повечето решения беше интересно и неизползвано от мен свойство на езика. Отне ми известно време докато успея да разбера какво става всъщност.
+#4. Явно когато се викат методи от друг клас е по-удачно параметрите да бъдат възможно по-базови от гледна точка на йерархия в езика. Това е полезен принцип за програмирането като цяло. Визирам 3та задача, където за инициализация на нов обект от тип 'BresenhamRasterization' се използват координатите на крайните точки, а не самите точки.
+#5. Начина по който се дефинират методи от рода на "def vertical_drawing_direction @drawing_from_y < @drawing_to_y ? 1 : -1 end", които много приличат на променливи ми допада и досега не го бях използвал. Наистина разбива кода на малки по-лесно обозрими и уникални по смисъл парчета. Силно ми наподобяват, според мен, properties в C#.
+#6. Имплементирането на метод с едно и също име ( още познато като override :D ), в случая "rasterize_on" помага за това да не използваме "case" в "draw" на 'Canvas', с който да определяме типа на аргумента на "draw" и в съответвствие от това да викаме метод, който да обработва дадената фигура.
+#7. Ако имаме често повтарящ се код, като например шаблона за HTML рендерирането в трета задача, е по-удачно да го сложим в замразен обект в класа, отколкото да използваме инстанционна променлива и да я инициализираме с няколко метода, всеки от който е по n-на-брой реда. Замразените обекти играят ролята на константи в Ruby. П.С. Също така по този начин се отърваваме от ограниченията (в случая Skeptic).
+#8. За хеширане на обекти в Ruby можем да използваме "hash"-метода, който връща уникално число, в зависимост от обекта на който е извикан.
+#9. Всички 'Enumerable' обекти имплементират min, max, map, drop, find, all и други.
+#10. Използване на "map(&:strip)", вместо "map { |element| element.strip }".
+#11. Използване на "some_text".lines, вместо 'split'-ването му на символи за нов ред.
+#12. Съществуване на метод "uniq" и съответно "uniq!" за създаване на уникални по елементи списъци. Може да се вика с блок и в този случай резултата, върнат от блока се приема за сравнение дали два елемента са еднакви.
+#13. Цялостния начин по който поредица от символи се обработва до масив от обекти само с помощта на два "map"-a на три реда ми направи огромно впечатление в едно от решенията на втора задача (именно това, което съм избрал да предам за пета задача).
+#14. Код от рода на:
+# "@todo_object = TodoList.new
+# @todo_object.fillList todo_string
+# @todo_object"
+# ефектно може да се замени от по-краткото и прегледно:
+# "@todo_object = TodoList.new todo_string", ако вместо допълнителен метод 'fillList', използвам конструктора на класа.
+#15. За обекти, които имат структура, подсказваща обхождане (например списък) е по-удобно и силно препоръчително да се имплементира 'Enumerable'.
+#16. Можем да наследим "Struct.new(:instructions, :labels, :ax, :bx, :cx, :dx)". Параметрите, указани в конструктора играят роля на полета в наследяващия клас, който всъщност е структура. Това е начина в Ruby да създаваме Struct. Предимството пред 'class' е, че съществуват удобни методи за манипулиране на полетата на структурата.
+#17. Метапрограмиране! Явно не съм обърнал достатъчно внимание на лекцията, свързана с тази част на езика. Дефинирането на методи на класа по този начин ми идва малко от въздуха, честно казано, но все пак е полезен похват, за който научих. Както повечето неща в Ruby, и това става доста елегантно (ето, че дойде момента в програмистката ми кариера, в който описвам код по този начин).
+#18. Създаване на методи чрез 'proc'. Един вид създаване на ламбда функции. Нещо, което до скоро не се срещаше толкова често в останалите езици. Интересна практика е. Липсата на възможност за ефективно дебъгване и видимото забавяне в performance-а са едни от основните минуси.
+#19. Интересен е начина, по който се разменят стойностите на две променливи без трета! "@drawing_from_x, @drawing_to_x = @drawing_to_x, @drawing_from_x" ... да, това работи! Похвата се нарича "Parallel Assignment" и се дължи на паралелното обработване на присвояването в Ruby.
+#20. Оператор % на String. Не го бях използвал и честно казано виждал до сега. Според мен става въпрос за някаква форма на интерполация. Правя асоциация със String.format в някои езици.

Милен обнови решението на 22.01.2014 15:22 (преди почти 11 години)

REPOSITORY = 'https://github.com/MMavrov/ruby-retrospective-3'
#Двадесет неща, които научих:
#
-#1. Ясни и стриктни ограничения за форматирането на кода и именуването на променливите са добра практика и също така се набива на очи, дори и на не толкова опитни програмисти. Това е може би най-важното и полезно за мен правило, което научих от този курс. По този начин програмиста се старае да осмисли наистина какво точно се желае като резултат и да погледне по-от-високо на 'картинката'. Смея да твърдя, че вече ми е навик. Благодаря! :)
-#2. Преди да навлизаш в прекалено задълбочени размишления, попитай приятел. Спестява време и усилия. Евентуално довежда до интересни спорове. Също така ако имаш ясни цели за това какво трябва да представлява крайния продукт, гониш срок за предаване и няма как да го спазиш, по-добре направи малка, но работеща част от изискванията. По такъв начин ще получиш малко по-лош feedback. (Визирам предадената си втора задача, където мислех, че ще получа точки за написани базови класове и идея зад тях.)
-#3. Използване на неявно извикан self в повечето решения беше интересно и неизползвано от мен свойство на езика. Отне ми известно време докато успея да разбера какво става всъщност.
-#4. Явно когато се викат методи от друг клас е по-удачно параметрите да бъдат възможно по-базови от гледна точка на йерархия в езика. Това е полезен принцип за програмирането като цяло. Визирам 3та задача, където за инициализация на нов обект от тип 'BresenhamRasterization' се използват координатите на крайните точки, а не самите точки.
-#5. Начина по който се дефинират методи от рода на "def vertical_drawing_direction @drawing_from_y < @drawing_to_y ? 1 : -1 end", които много приличат на променливи ми допада и досега не го бях използвал. Наистина разбива кода на малки по-лесно обозрими и уникални по смисъл парчета. Силно ми наподобяват, според мен, properties в C#.
-#6. Имплементирането на метод с едно и също име ( още познато като override :D ), в случая "rasterize_on" помага за това да не използваме "case" в "draw" на 'Canvas', с който да определяме типа на аргумента на "draw" и в съответвствие от това да викаме метод, който да обработва дадената фигура.
-#7. Ако имаме често повтарящ се код, като например шаблона за HTML рендерирането в трета задача, е по-удачно да го сложим в замразен обект в класа, отколкото да използваме инстанционна променлива и да я инициализираме с няколко метода, всеки от който е по n-на-брой реда. Замразените обекти играят ролята на константи в Ruby. П.С. Също така по този начин се отърваваме от ограниченията (в случая Skeptic).
+#1. Ясни и стриктни ограничения за форматирането на кода и именуването на променливите са добра практика и също така се набива на очи, дори и на не толкова опитни
+# програмисти. Това е може би най-важното и полезно за мен правило, което научих от този курс. По този начин програмиста се старае да осмисли наистина какво точно
+# се желае като резултат и да погледне по-от-високо на 'картинката'. Смея да твърдя, че вече ми е навик. Благодаря! :)
+#2. Преди да навлизаш в прекалено задълбочени размишления, попитай приятел. Спестява време и усилия. Евентуално довежда до интересни спорове. Също така ако имаш ясни
+# цели за това какво трябва да представлява крайния продукт, гониш срок за предаване и няма как да го спазиш, по-добре направи малка, но работеща част от
+# изискванията. По такъв начин ще получиш малко по-лош feedback. (Визирам предадената си втора задача, където мислех, че ще получа точки за написани базови класове
+# и идея зад тях.)
+#3. Използване на неявно извикан self в повечето решения беше интересно и неизползвано от мен свойство на езика. Отне ми известно време докато успея да разбера какво
+# става всъщност.
+#4. Явно когато се викат методи от друг клас е по-удачно параметрите да бъдат възможно по-базови от гледна точка на йерархия в езика. Това е полезен принцип за
+# програмирането като цяло. Визирам 3та задача, където за инициализация на нов обект от тип 'BresenhamRasterization' се използват координатите на крайните точки,
+# а не самите точки.
+#5. Начина по който се дефинират методи от рода на "def vertical_drawing_direction @drawing_from_y < @drawing_to_y ? 1 : -1 end", които много приличат на променливи ми
+# допада и досега не го бях използвал. Наистина разбива кода на малки по-лесно обозрими и уникални по смисъл парчета. Силно ми наподобяват, според мен, properties
+# в C#.
+#6. Имплементирането на метод с едно и също име ( още познато като override :D ), в случая "rasterize_on" помага за това да не използваме "case" в "draw" на 'Canvas',
+# с който да определяме типа на аргумента на "draw" и в съответвствие от това да викаме метод, който да обработва дадената фигура.
+#7. Ако имаме често повтарящ се код, като например шаблона за HTML рендерирането в трета задача, е по-удачно да го сложим в замразен обект в класа, отколкото да
+# използваме инстанционна променлива и да я инициализираме с няколко метода, всеки от който е по n-на-брой реда. Замразените обекти играят ролята на константи в Ruby.
+# П.С. Също така по този начин се отърваваме от ограниченията (в случая Skeptic).
#8. За хеширане на обекти в Ruby можем да използваме "hash"-метода, който връща уникално число, в зависимост от обекта на който е извикан.
#9. Всички 'Enumerable' обекти имплементират min, max, map, drop, find, all и други.
#10. Използване на "map(&:strip)", вместо "map { |element| element.strip }".
#11. Използване на "some_text".lines, вместо 'split'-ването му на символи за нов ред.
-#12. Съществуване на метод "uniq" и съответно "uniq!" за създаване на уникални по елементи списъци. Може да се вика с блок и в този случай резултата, върнат от блока се приема за сравнение дали два елемента са еднакви.
-#13. Цялостния начин по който поредица от символи се обработва до масив от обекти само с помощта на два "map"-a на три реда ми направи огромно впечатление в едно от решенията на втора задача (именно това, което съм избрал да предам за пета задача).
+#12. Съществуване на метод "uniq" и съответно "uniq!" за създаване на уникални по елементи списъци. Може да се вика с блок и в този случай резултата, върнат от блока
+# се приема за сравнение дали два елемента са еднакви.
+#13. Цялостния начин по който поредица от символи се обработва до масив от обекти само с помощта на два "map"-a на три реда ми направи огромно впечатление в едно от
+# решенията на втора задача (именно това, което съм избрал да предам за пета задача).
#14. Код от рода на:
# "@todo_object = TodoList.new
# @todo_object.fillList todo_string
# @todo_object"
# ефектно може да се замени от по-краткото и прегледно:
# "@todo_object = TodoList.new todo_string", ако вместо допълнителен метод 'fillList', използвам конструктора на класа.
#15. За обекти, които имат структура, подсказваща обхождане (например списък) е по-удобно и силно препоръчително да се имплементира 'Enumerable'.
-#16. Можем да наследим "Struct.new(:instructions, :labels, :ax, :bx, :cx, :dx)". Параметрите, указани в конструктора играят роля на полета в наследяващия клас, който всъщност е структура. Това е начина в Ruby да създаваме Struct. Предимството пред 'class' е, че съществуват удобни методи за манипулиране на полетата на структурата.
-#17. Метапрограмиране! Явно не съм обърнал достатъчно внимание на лекцията, свързана с тази част на езика. Дефинирането на методи на класа по този начин ми идва малко от въздуха, честно казано, но все пак е полезен похват, за който научих. Както повечето неща в Ruby, и това става доста елегантно (ето, че дойде момента в програмистката ми кариера, в който описвам код по този начин).
+#16. Можем да наследим "Struct.new(:instructions, :labels, :ax, :bx, :cx, :dx)". Параметрите, указани в конструктора играят роля на полета в наследяващия клас, който
-#18. Създаване на методи чрез 'proc'. Един вид създаване на ламбда функции. Нещо, което до скоро не се срещаше толкова често в останалите езици. Интересна практика е. Липсата на възможност за ефективно дебъгване и видимото забавяне в performance-а са едни от основните минуси.
+# всъщност е структура. Това е начина в Ruby да създаваме Struct. Предимството пред 'class' е, че съществуват удобни методи за манипулиране на полетата на
-#19. Интересен е начина, по който се разменят стойностите на две променливи без трета! "@drawing_from_x, @drawing_to_x = @drawing_to_x, @drawing_from_x" ... да, това работи! Похвата се нарича "Parallel Assignment" и се дължи на паралелното обработване на присвояването в Ruby.
+# структурата.
-#20. Оператор % на String. Не го бях използвал и честно казано виждал до сега. Според мен става въпрос за някаква форма на интерполация. Правя асоциация със String.format в някои езици.
+#17. Метапрограмиране! Явно не съм обърнал достатъчно внимание на лекцията, свързана с тази част на езика. Дефинирането на методи на класа по този начин ми идва малко
+# от въздуха, честно казано, но все пак е полезен похват, за който научих. Както повечето неща в Ruby, и това става доста елегантно (ето, че дойде момента в
+# програмистката ми кариера, в който описвам код по този начин).
+#18. Създаване на методи чрез 'proc'. Един вид създаване на ламбда функции. Нещо, което до скоро не се срещаше толкова често в останалите езици. Интересна практика е.
+# Липсата на възможност за ефективно дебъгване и видимото забавяне в performance-а са едни от основните минуси.
+#19. Интересен е начина, по който се разменят стойностите на две променливи без трета! "@drawing_from_x, @drawing_to_x = @drawing_to_x, @drawing_from_x" ... да, това
+# работи! Похвата се нарича "Parallel Assignment" и се дължи на паралелното обработване на присвояването в Ruby.
+#20. Оператор % на String. Не го бях използвал и честно казано виждал до сега. Според мен става въпрос за някаква форма на интерполация. Правя асоциация със
+# String.format в някои езици.

В решението на задача 1 не ми харесва името "lpf". В четвърта задача имаш други неспазени skeptic ограничения, като брой методи в клас и дължина на ред. Тестовете ти минават и ще допусна, че си имал проблем с най-новата версия на Skeptic и Aspell и затова ще ти приема решенията.

В някои от решенията си далеч от желаните оптимални решения. Един пример е методът harmonic в първа задача - там ползваш each по неидиоматичен начин и това не е добре. Там се ползва map + reduce. Недобре изчистени решения се наблюдават и в другите задачи (като изключим трета, която май не си я пипал/променял ти.

Имам бележка по употребата на Struct (напр. в четвърта задача при теб). Виждам смисъл в това само ако има нужда да се замести клас, т.е. се спестява дефиницията на отделен клас. Употреба като тази: class Executor < Struct.new(:instructions, :labels, :ax, :bx, :cx, :dx) не намирам за добра. Предпочитам да дефинирам атрибутите с attr_accessor - не само, че е по-кратко, но и е по-праволинейно, просто и ясно. Struct носи допълнителни неща, които в не само, че повечето случаи не са необходими (например, енумерация на атрибутите), ами са и направо излишни.

Това не е съвсем вярно - "Замразените обекти играят ролята на константи в Ruby." Константите в Ruby са си константи, а замразените обекти са нещо съвсем отделно. Спокойно може да имаш замразен обект, присовен на променлива. Добра практика е да се замразяват обекти, които присвояваш на константи, като целта е да се избегне неволно мутиране на обекта зад константата. Например, низове и хешове позволяват мутиране на обекта с методи като upcase!, reject!, []= и прочее. Замразявайки обекта, ще се предпазим от тази програмистка грешка.

fillList трябва да се запише fill_list.

За проблемите с производителността на анонимните функции (lambda & proc) може да се спори.

По т. 20, това се казва "printf/sprintf". В Ruby също се нарича така, понеже String#% вика Kernel.sprintf.

Като цяло ми харесват изводите ти и се надявам, че си доволен от наученото. Съветвам те да си избереш решенията на трима колеги на пета задача, които съм оценил с максимален брой точки и да ги разгледаш, за допълнително вдъхновение :)