Решение на Четвърта задача от Нено Ганчев

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

Към профила на Нено Ганчев

Резултати

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

Код

REPOSITORY = 'https://github.com/nenoganchev/ruby-retrospective-1'
Не успях да събера 20 научени неща, може би защото не съм писал първите 3 домашни, или защото Руби не е напълно нов език за мен. Както и да е, ето нещата, които съм записал през тази незабравима нощ:
1. За съжаление, най-много време прекарах докато настроя Вим да работи що-годе читаво с Руби файлове. Знам, че не очаквате да чуете това, но пък както Стефан сам беше казал на една лекция - трябва първо да овладееш tool`овете си за да си щастлив програмист. А не може да пишем на Руби и да не сме щастливи, грехота е.
2. Ограничаването на броя знаци в линия код не води до нищо хубаво. Поне при мен най-честия ефект беше преименуването на сравнително дълга променлива от хубаво описателно име на доста по-мътно такова. Аз лично предпочитам да чета код, който звучи максимално близо до естествен език (което е и една от причините да имам такъв афинитет към Руби - с този език се получава най-четим код), и преименуването от length_difference към len_diff, dlen или dl не помага на каузата ми.
3. Същата работа и с броя редове във функция - даже с по-лоши последици. В една част от случаите жертвах код който проверява за граничните случаи, за да се вместя в броя редове. В друга - трябваше да разделя код, който нагледно се получаваше най-добре ако е на едно място, в няколко отделни функции. Например функцията, която генерира низа за фактурата, изглежда супер когато всичките редове от низа се описват един под друг - можеш директно с един поглед на кода да разбереш как ще изглежда на екрана. За съжаление обаче, фактурата има 3 реда заглавна част, 3 реда опашка, трябва ти поне един ред за вмъкване на всички стоки и още един за вмъкване на купона, или общо 8 реда само за описанието на низа, при ограничение 7. Видях решението ви на лекциите, в което всяко от тези неща става в отделни функции, но аз лично предпочитам варианта в който целия низ се конструира на едно място - по прегледно ми се струва.
4. Все пак, покрай тези ограничения се принудих да проверя как някои Руби класове се справят с гранични случаи. Останах приятно изненадан, че енумераторите на целите числа като #upto и #times се справят доста прилично (и сравнително логично) с отрицателни числа, въпреки че това не е описано никъде в документацията им. Например 0.upto(-2) и -2.times няма да изпълнят блока нито веднъж, така че можеш да пропуснеш проверките дали a > b и директно да пишеш 0.upto(a - b). И все пак, аз бих се придържал към изричната проверка - сигурно ще спести малко време в чудене на следващия човек който гледа кода.
5. Array(a) прави (съвсем очаквано) масив с единствен елемент a, когато a не е масив, но оставя a непроменен когато a е масив. Много приятен начин да си уеднаквиш кода, когато знаеш че даден параметър може да е елемент или масив с единствен елемент.
6. За първи път не мога да намеря метод, който би ми бил от полза - Array няма (или поне не намерих) метод #is_subset, така че трябваше да го емулирам със сечение и сравнение на множества. Не е кой-знае каква драма, но все пак щеше да е по-четимо ако имаше подобен метод. Пропускам ли нещо?
7. Ааааах, да - променянето на подадени аргументи. Вижте това:
def foo(a)
a.select! { |e| e.even? }
end
def bar(a)
a = a.select { |e| e.even? }
end
a = [1, 2, 3, 4]
b = [1, 2, 3, 4]
foo a
bar b
На пръв поглед (поне за лаици като мен) двете функции са идентични и очаквах a и b да имат еднакви стойности. Да ама не - a се променя от foo, докато b остава непроменена. Първо си помислих че процесора ми се е развалил, тъй като Руби със сигурност предава параметрите по reference и b трябва да бъде променена, нали вътре във функцията й се прави присвояване?! Проклет парсер който създава нова локална променлива щом види оператор за присвояване и скрива параметъра. Damn you, I said!
8. Заради горния проблем ми трябваше деструктивна версия на select. Отначало не виждах такава и се отчаях. След известно време я намерих, но в Array, а не в Enumerable. Какво му пречи на всеки Enumerable да има деструктивни операции?
9. Като гледам тестовете ви, писането им сигурно е било поне мааалко тегаво. За сметка на това, писането на код като имаш хубави тестове е песен. В случая не ми липсваше компилатора - тестовете откриха всички глупави дребни грешки.
Наблюдение: все пак с помощта rspec и ruby като цяло тестовете не се пишат толкова трудно. За C++ и особено за C ще ти окапе косата докато напишеш еквивалентни тестове.
Следствие: Писането на C рядко е песен. Жалко, а иначе съм музикално момче :/
10. !Enumerable#first (или в превод от СЕП - съществува метода first от модула Enumerable:) Първо го търсех в Hash и се отказах (вместо него използвах Hash#shift, ама не беше готино да руша хеша като нямах нужда от това). После погледнах някое решение. Да не кажете, че нищо не съм научил!

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

Нено обнови решението на 14.11.2011 11:50 (преди почти 13 години)

+REPOSITORY = 'https://github.com/nenoganchev/ruby-retrospective-1'
+
+Не успях да събера 20 научени неща, може би защото не съм писал първите 3 домашни, или защото Руби не е напълно нов език за мен. Както и да е, ето нещата, които съм записал през тази незабравима нощ:
+
+1. За съжаление, най-много време прекарах докато настроя Вим да работи що-годе читаво с Руби файлове. Знам, че не очаквате да чуете това, но пък както Стефан сам беше казал на една лекция - трябва първо да овладееш tool`овете си за да си щастлив програмист. А не може да пишем на Руби и да не сме щастливи, грехота е.
+2. Ограничаването на броя знаци в линия код не води до нищо хубаво. Поне при мен най-честия ефект беше преименуването на сравнително дълга променлива от хубаво описателно име на доста по-мътно такова. Аз лично предпочитам да чета код, който звучи максимално близо до естествен език (което е и една от причините да имам такъв афинитет към Руби - с този език се получава най-четим код), и преименуването от length_difference към len_diff, dlen или dl не помага на каузата ми.
+3. Същата работа и с броя редове във функция - даже с по-лоши последици. В една част от случаите жертвах код който проверява за граничните случаи, за да се вместя в броя редове. В друга - трябваше да разделя код, който нагледно се получаваше най-добре ако е на едно място, в няколко отделни функции. Например функцията, която генерира низа за фактурата, изглежда супер когато всичките редове от низа се описват един под друг - можеш директно с един поглед на кода да разбереш как ще изглежда на екрана. За съжаление обаче, фактурата има 3 реда заглавна част, 3 реда опашка, трябва ти поне един ред за вмъкване на всички стоки и още един за вмъкване на купона, или общо 8 реда само за описанието на низа, при ограничение 7. Видях решението ви на лекциите, в което всяко от тези неща става в отделни функции, но аз лично предпочитам варианта в който целия низ се конструира на едно място - по прегледно ми се струва.
+4. Все пак, покрай тези ограничения се принудих да проверя как някои Руби класове се справят с гранични случаи. Останах приятно изненадан, че енумераторите на целите числа като #upto и #times се справят доста прилично (и сравнително логично) с отрицателни числа, въпреки че това не е описано никъде в документацията им. Например 0.upto(-2) и -2.times няма да изпълнят блока нито веднъж, така че можеш да пропуснеш проверките дали a > b и директно да пишеш 0.upto(a - b). И все пак, аз бих се придържал към изричната проверка - сигурно ще спести малко време в чудене на следващия човек който гледа кода.
+5. Array(a) прави (съвсем очаквано) масив с единствен елемент a, когато a не е масив, но оставя a непроменен когато a е масив. Много приятен начин да си уеднаквиш кода, когато знаеш че даден параметър може да е елемент или масив с единствен елемент.
+6. За първи път не мога да намеря метод, който би ми бил от полза - Array няма (или поне не намерих) метод #is_subset, така че трябваше да го емулирам със сечение и сравнение на множества. Не е кой-знае каква драма, но все пак щеше да е по-четимо ако имаше подобен метод. Пропускам ли нещо?
+7. Ааааах, да - променянето на подадени аргументи. Вижте това:
+
+def foo(a)
+ a.select! { |e| e.even? }
+end
+
+def bar(a)
+ a = a.select { |e| e.even? }
+end
+
+a = [1, 2, 3, 4]
+b = [1, 2, 3, 4]
+foo a
+bar b
+
+ На пръв поглед (поне за лаици като мен) двете функции са идентични и очаквах a и b да имат еднакви стойности. Да ама не - a се променя от foo, докато b остава непроменена. Първо си помислих че процесора ми се е развалил, тъй като Руби със сигурност предава параметрите по reference и b трябва да бъде променена, нали вътре във функцията й се прави присвояване?! Проклет парсер който създава нова локална променлива щом види оператор за присвояване и скрива параметъра. Damn you, I said!
+8. Заради горния проблем ми трябваше деструктивна версия на select. Отначало не виждах такава и се отчаях. След известно време я намерих, но в Array, а не в Enumerable. Какво му пречи на всеки Enumerable да има деструктивни операции?
+9. Като гледам тестовете ви, писането им сигурно е било поне мааалко тегаво. За сметка на това, писането на код като имаш хубави тестове е песен. В случая не ми липсваше компилатора - тестовете откриха всички глупави дребни грешки.
+Наблюдение: все пак с помощта rspec и ruby като цяло тестовете не се пишат толкова трудно. За C++ и особено за C ще ти окапе косата докато напишеш еквивалентни тестове.
+Следствие: Писането на C рядко е песен. Жалко, а иначе съм музикално момче :/
+10. !Enumerable#first (или в превод от СЕП - съществува метода first от модула Enumerable:) Първо го търсех в Hash и се отказах (вместо него използвах Hash#shift, ама не беше готино да руша хеша като нямах нужда от това). После погледнах някое решение. Да не кажете, че нищо не съм научил!