Статьи

Назад к основам — хорошие комментарии — это целевые комментарии

Я не могу думать об одном человеке, который любит писать комментарии в коде. Нет, мои друзья и коллеги не знают, и я почти уверен, что для фанатов этого мероприятия нет группы встреч. Помимо кода, который я пишу для сообщений в блоге, я могу в значительной степени гарантировать, что в интерфейсах есть только место, где я пишу комментарии.

Простая причина этого заключается в том, что а) интерфейсы должны быть явными, а б) реализации должны быть самодокументируемыми.

Причина этого поста в том, что в данный момент я вижу много кода, который попадает в одну из двух ловушек — либо все задокументировано, либо ничего не задокументировано.

Все задокументировано

Найдите, что не так с этим кодом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
 * The foo class represents blah blah blah...and so on, describing the
 * class in such detail it's a pity the code couldn't be generated from it
 */
public class Foo {
 
    /** The name */
    private String name;
 
   /**
    * Do something with this instance.
    */
   public void doSomething() {
      // Get the name
      String localName = this.getName();
 
      // munge the local name
      localName.munge();
   }
 
   /**
    * Get the name.
    * @return the name
    */
   public String getName() {
      // return the name
      return this.name;
   }
 
   /**
    * Set the name.
    * @param name the name
    */
   public void setName(String name) {
      // set the name
      this.name = name;
   }
}

Или, другими словами, определите, что с этим правильно. Это гораздо более короткий ответ. Код полон ненужных комментариев — например, getName () получает имя — и код, который, кажется, был написан только для того, чтобы его можно было прокомментировать — например; Строка localName — this.getName (); Имена были изменены, чтобы защитить виновных, но это реальный код, который я видел в живой кодовой базе.

Что касается меня, реализации не нуждаются в комментариях на уровне кода, потому что это то, что делает код в любом случае .

Ничего не задокументировано

На другом конце шкалы находится этот маленький драгоценный камень:

1
2
3
public interface Parser {
    void parse(InputStream is) throws IOException, SQLFeatureNotSupportedException
}

Интерфейсы, с другой стороны, должны иметь четкую документацию, которая определяет, что входит, общее описание того, что должно произойти, и четкое описание того, что выходит и какие исключения могут быть выброшены. Информация на этом уровне должна указывать, допустимы ли, например, нулевые аргументы, можно ли возвращать нулевое значение, обстоятельства, при которых могут возникать определенные исключения, и так далее.

Интерфейсы должны быть явными

Интерфейсы, по моему мнению, являются контрактами, а контракты — как скажет любой кровососущий юрист — существуют, чтобы их уважали. Они не могут быть выполнены, если условия явно не установлены.

В Бельгии нет Burger Kings, поэтому, если я нахожусь в Великобритании или Нидерландах, я обычно испытываю желание иметь один. Во время моего последнего визита я заметил это в нижней части квитанции:

«Бесплатный напиток с любым гамбургером для взрослых с этой квитанцией, исключая сделку с гамбургерами, чизбургерами или королями или любые рекламные предложения»

Или, говоря по-другому …

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
/**
 * Get the free drink promised by the receipt.  This is valid for any burger.
 * @param burger the burger
 * @param receipt the receipt
 * @returns the free drink
 * @throws InvalidBurgerException if the burger doesn't qualify for a free drink
 */
public Drink getFreeDrink(Burger burger,
                          Receipt receipt) throws InvalidBurgerException {
    if (MealType.HAMBURGER == meal.type()
        || MealType.CHEESEBURGER == meal.type()
        || MealType.KING_DEAL == meal.type()
        || meal.isPromo()) {
        throw new InvalidBurgerException();
    }
    return new Drink();
}

На мой простой ум, это чертовски запутанно и противоречиво. Ваш API должен быть четким и (как мои преподаватели университета бьют меня) однозначно — например, слова «любой» и «кроме» не должны появляться в одном и том же предложении. Стремитесь к ясности — если вам кажется, что ваш API слишком сложен для четкого документирования, есть большая вероятность, что его будет раздражать. В случае выше, улучшение будет что-то вроде

01
02
03
04
05
06
07
08
09
10
/**
 * Get the free drink promised by the receipt.  Not every burger qualifies for a free drink.
 * @param burger the requested burger.  This may or may not qualify for a free drink
 * @param receipt the receipt containing the offer
 * @returns the free drink. May be null, depending on the burger
 */
public Drink getFreeDrink(Burger burger,
                          Receipt receipt) {
    // implementation
}

Обратите внимание, что я также избавился от исключения из-за того, что был более явным.

Вывод

Как ни раздражает, документация чрезвычайно важна в правильном месте и совершенно бесполезна везде. Если все сделано правильно, они сделают ваш API более простым в использовании и обслуживании, что, как правило, хорошо.

Ссылка: Назад к основам — хорошие комментарии — это целевые комментарии от нашего партнера JCG Стива Чалонера в блоге Objectify .