Тази история първоначално се появи вHacker Noon на 10 февруари 2017 г.

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

По времето, когато го написах, вероятно смятах, че кодът ми е красив. Елегантен шедьовър. Трябваше да бъде отпечатано, поставено в рамка и окачено на стената на Залата на славата на програмирането. Колкото и умен да си мислех, че може да съм преди няколко години, рядко успявам да прочета стария си код без да губя сериозно време за отстраняване на грешки.

Този проблем ме измъчваше редовно. Опитах различни техники, за да направя кода си по-лесен за разбиране.

Първо се опитах да добавя коментари към моя код. Доста лесно за изпълнение, но не толкова полезно.

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

Също така се опитах да документирам моя код в отделен файл. Това имаше своите предимства, но също така не реши проблема напълно.

В крайна сметка разбрах какво трябва да направя: трябваше да използвам и трите горни техники, за да напиша наистинакрасив и разбираем код.

Коментари

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

public class Class1
{
  public List<string> DoWork(List<string> a)
  {
    List<string> numbers = new List<string>();
    
    // Loop over data
    for (int i = 1; i < a.Count; i++)
    {
      int s = a[i].IndexOf(" ");
      string num = a[i].Substring(0,s);
      
      // Save data
      numbers.Add(num);
    }
    
    return numbers;
  }
  ...
}

„Обръщане на данни“? „Запазване на данни“? Тези коментари са полезни за разбирането на кода. Мога лесно да разбера, че имам цикъл и че добавям данните си към колекция, защо трябва да губя ценно пространство на екрана с безполезни коментари?

Вместо да казват каквоили как, коментарите трябва да обясняват защо. Програмистът ще види цикъла for и ще знае, че преминава през някакъв тип колекция от Addresses. Програмистът обаче няма да разбере защо започваме нашия брояч с int i = 1 — това е мястото, където добавянето на коментар може да подобри разбирането на кода:

// i = 1 because the view will never display the first address
for (int i = 1; i < Addresses.Count; i++) {...

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

Освен това премахваме напълно коментара // Save data, тъй като той не добавя проницателна стойност.

Самодокументиране

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

public class Class1
{
  public List<string> DoWork(List<string> a)
  {
    List<string> numbers = new List<string>();
    
    // i = 1 because the view will never display the first address
    for (int i = 1; i < a.Count; i++)
    {
      int s = a[i].IndexOf(" ");
      string num = a[i].Substring(0,s);
    
      numbers.Add(num);
    }
    
    return numbers;
  }
  ...
}

Какво точно е Class1? Каква работа вършиDoWork()? Какво ще кажете за използването на int s? Имената на обектите в нашия код не ни помагат да разберем какво прави този код.

Тук идва идеята за самодокументиращ се код: вместо да създаваме обекти с произволни, неинформативни имена („Кълна се, че ще преработя това по-късно“), ние изграждаме описателни обекти. Ако имам клас, името му трябва да ми даде добра представа какви биха могли да бъдат неговите свойства и методи. Името на метода трябва да е достатъчно описателно, за да ми каже какво трябва да очаквам като изход, без да се налага да ровя в подробности какво прави този метод. Променливите трябва да добавят допълнително осветление, което прави коментарите от типа какво и как остарели.

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

Какво ще кажете за името на метода List<string> DoWork(List<string> a)? Е, мога да ви кажа, че този метод се опитва да анализира числовата част от уличен адрес. Така че нека променим името и подписа на метода на нещо по-информативно, като List<string> ParseHouseNumbers(List<String> addresses). Сега можем да направим обосновано предположение, че този метод приема някои адресни низове като вход и ще върне списък с анализирани номера на къщи.

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

public class AddressStandardizer
{
  public List<string> DoWork(List<string> addresses)
  {
    List<string> houseNumbers = new List<string>();
    
    // i = 1 because the view will never display the first address
    for (int i = 1; i < addresses.Count; i++)
    {
      int firstSpaceIndex = addresses[i].IndexOf(" ");
      string houseNumber = addresses[i].Substring(0,firstSpaceIndex);
    
      houseNumbers.Add(houseNumber);
    }
    
    return houseNumbers;
  }
  ...
}

Документация

Нашият код най-накрая започва да се оформя. Имаме коментари, обясняващи защо избрахме да направим нещо и преработихме нашия код, за да има имена на обекти, които са информативни.

Кодът на този етап е добре, но не е перфектен. Ако не разгледаме този код няколко години, вероятно вече имаме достатъчно информация, за да разгледаме кода и да разберем какво прави с относителна лекота.

Голямата част от информацията, която все още ни липсва обаче, е да знаем защо този код е написан на първо място.

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

Това, което обаче би било полезно, е обяснение какво прави нашата програма на високо ниво. Това е целта на официалната документация.

Документацията за тази част от кода може да изглежда по следния начин:

…След като извлече информацията за нашите клиенти от нашия доставчик, програмата обработва данните и ги почиства, за да се зареди в нашия склад за отчети. Почистването на данните означава анализиране на адресите в множество колони, включително номер на къща, име на улица, суфикс на улица, град, щат и пощенски код...

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

Увийте

Всички тези техники са необходими за премахване на главоболията с кода по пътя. Поучете се от моя опит – ако не правите и трите, може да спестите малко време в краткосрочен план, но ще навреди в някакъв момент в бъдеще. След като придобиете навика да пишете и трите вида документация, това ще стане втора природа и ще направи живота ви (и живота на бъдещото ви аз!) много по-лесен.

Коментарите в кода трябва да обясняват защоне как:

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