Как да (не) си изпращаме задачите

Тук ще намерите кратки (или не толкова кратки) инструкции за това как да си изпращате задачите.

Накракто

  • Прочетете си условието внимателно и дори няколко пъти.
  • След като сте написали решение, изпълнете примерния тест.
  • Преди да опитате да изпратите решение през сайта, изпълнете стилистическата проверка на вашия компютър.
  • Не споделяйте решението си с никого.
  • Не гледайте чужди решения.

Преписване и споделяне на решения

Всички решения стават публични след крайния срок на задачата. Преди това всякакво споделяне на решения е забранено.

Това включва:

  • Да пратите решението си на някой друг.
  • Да го покажете на другарче, за да "почерпи идеи".
  • Да го сложите някъде публично преди крайния срок (например GitHub).

Ако хванем, че сте преписвали, ви късаме без много-много обяснения и губите всичките си точки от задачи. Когато се видим през септември, схемата за оценяване продължава да важи за вас и вие продължавате да имате 0 точки от задачи. Това означава, че се борите за 3 или 4. Ако сте много нахални, санкциите могат да бъдат по-тежки.

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

От друга страна, не се притеснявайте да напишете най-простия възможен код, понеже "други хора ще предадат същото решение". Това също се разпознава лесно, и разбира се, няма да сметнем, че сте преписвали. Пишете най-добрия код, на който сте способни, не споделяйте решенията си и няма да има причина да се притеснявате, че ще помислим, че сте преписвали.

От какво имате нужда

Тестовете, с които проверяваме домашните, са написани с RSpec. Това е интересен тестов framework за Ruby. Стиловите изисквания към кода ви се проверяват с библиотека, която е доста популярна в Ruby света - rubocop. Всичко това се случва в Ruby.

Ако пращате задача за първи път, първо се уверете, че използвате последната версия на Ruby, инсталационни инструкции за която сме ви дали. Например:

$ ruby -v
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]

Ако версията ви не е най-новата, е възможно някои неща да не сработят при вас.

След това си инсталирайте нужните библиотеки:

$ gem install rspec rubocop

Ако получите грешка, че не съществува команда gem, значи имате проблем с инсталацията на Ruby. Инсталирайте го отново и този път се уверете, че сте качили RubyGems.

Примерен тест

С всяка задача публикуваме примерен тест в GitHub хранилището. Задължително изтеглете теста и го пуснете. За да го направите, трябва да си качите rspec. След това запишете решението си като solution.rb и изпълнете теста така:

$ rspec sample_spec.rb --require ./solution.rb --colour --format documentation

Обърнете внимание, че трябва да поставите ./ пред файла с решението.

Стилистическа проверка

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

Преди да опитате да изпратите решение на сайта, може да изпълните стилистическата проверка на вашия компютър. В GitHub хранилището можете да намерите инструкции как да го направите.

Ако смятате, че има грешка в примерния ни тест или в rubocop и искате да се свържете с нас, пишете на форумите. В никакъв случай не споделяйте решението си публично. Напишете кратка Ruby програма която пресъздава проблема и споделете нея вместо това. Ако смятате, че няма как да стане без да видим решението ви, пишете ни на fmi@ruby.bg и прикачете решението си. Или още по-добре, направете private gist и ни пратете линк към него. Ако споделите решението си публично (форумите или публичен gist) преди крайния срок, ще смятаме това за преписване.

Обърнете внимание, че е относително лесно да заобиколите ограниченията. Например, ако си кръстите променливите с по една буква, ще се справите лесно с ограничението за дължина на ред. Ако разбиете метода calculate на calculate_1, calculate_2 и calculate_3, които да си общуват с полета, лесно ще заобиколите ограничението за дължина на метод. Ако дефинирате метод с define_method, може да подминете ограничението за брой методи в клас.

Не пасем трева. Ако сте направили така, резултатът ще варира от това да ви вземем няколко точки за стил, до това въобще да не ви дадем точки на задачата. Идеята на тези ограничения е да ви провокират да помислите как да структурирате кода си по-добре и да стане по-четим, а не да измисляте креативни начини да заобикаляте статичния анализ на кода.

Следва списък с ограниченията. Това не е финална версия - с времето ще се изменя. Консултирайте го, ако не разбирате какъв е проблема с кода ви.

Максимално ниво на влагане

Един метод трябва да е прост и лесно да показва какво прави със структурата си. Съответно, всеки метод трябва да има най-много X нива на влагане.

За ниво на влагане се брои:

  • Блокове (each, map и прочие)
  • Условия (if, unless и case във всичките им форми, както и ? :)
  • Ламбди
  • begin/end блокове
  • Цикли (while, until, for)

Тези неща важат в рамките на един метод - class, module и def не се броят за нива на влагане.

Ако метод не отговаря на това ограничение, може да опитате следните неща:

  • Разбийте метода на няколко отделни. Всеки трябва да прави едно нещо и да е относително изолиран от останалите.
  • Използвайте локални променливи за да дадете име на израз, който е в по-дълбоко ниво на влагане.
  • Потърсете дали няма начин да напишете нещо с по-малко нива на влагане. Обикновено има.

Брой редове в метод

Дългите методи са трудни за разбиране. Това обикновено е сиптом, че един метод прави твърде много неща и може да се раздели на няколко. Съответно, всеки метод може да има най-много X реда.

За редове се броят:

  • def-а на метода не се брои.
  • Празни редове не се броят.
  • Редове с коментари не се броят.
  • Редове, на които има само end не се броят.
  • Отделно, няколко екзотични случая не се броят за ред, но тях няма да ви ги казваме.

Ако метод не отговаря на това ограничение, може да опитате следните неща:

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

Брой методи в клас

Един клас трябва да прави точно едно нещо и да има точно една причина да се променя. Дългите класове са трудни за разбиране. Класовете които правят няколко неща са трудни за разбиране. Съответно, всеки клас може да има най-много Х метода.

За методи се броят:

  • Методи на инстанциите класа.
  • Класови методи.
  • attr_accessor, attr_reader и прочее не се броят за методи.

Ако клас не отговаря на това ограничение, може да опитате следните неща:

  • Идентифицирайте няколко неща, които класът прави, и създайте отделни класове за всяко. Създавайте инстанция на новите класове и я ползвайте за да извършите изчислението.
  • Не се притеснявайте да дефинирате повече класове. Повече прости класове е по-добре от по-малко, но сложни.
  • Не създавайте "utility" класове/модули, в които има само класове методи.

Без ; като разделител на изрази

Не ползвайте ; като разделител за изрази. Вместо това, напишете изразите на отделни редове. Така кодът е по-прегледен и е по-ясно какво прави.

Дължина на редове

Дългите редове са трудни за четене. Не могат да се видят ясно на един екран. Често, голямата дължина е признак, че един ред прави твърде много неща. Съответно, всеки ред трябва да е най-много Х символа дълъг.

Ако един ред не отговаря на това ограничение, разделете го на няколко отделни изрази, всеки от който присвоете на променлива. Сведете го до по-кратък израз, който ползва тези променливи.