Комментарии по умолчанию и метаинформация в классах / интерфейсах Java - PullRequest
0 голосов
/ 30 января 2011

В некоторых кодовых базах я видел комментарии, которые можно описать как комментарии по умолчанию . Эти комментарии вы обычно найдете в каждом файле проекта, и, я полагаю, в большинстве случаев они автоматически генерируются с помощью IDE. Мета-информация немного отличается. На самом деле это часть кода. Я думаю, мне лучше показать это на примере. Это наш тестовый объект (взят из реальной жизни и упрощенный):

public class UserServiceImpl implements IUserService {

    ////////////////////////////////////////////////////////////////////////
    // Constants
    ////////////////////////////////////////////////////////////////////////

    /** Logger for this class */
    @SuppressWarnings("unused")
    private static final Log LOG = LogFactory.getLog(UserServiceImpl.class);

    ////////////////////////////////////////////////////////////////////////
    // Attributes
    ////////////////////////////////////////////////////////////////////////

    /** User DAO */
    private IUserDao userDao;

    ////////////////////////////////////////////////////////////////////////
    // Constructors
    ////////////////////////////////////////////////////////////////////////

    /**
     * Default constructor
     */
    public UserServiceImpl() {
    }

    public UserServiceImpl(final IUserDao userDao) {
        this.userDao = userDao;
    }

    ////////////////////////////////////////////////////////////////////////
    // Getter and Setter methods
    ////////////////////////////////////////////////////////////////////////

    /**
     * @return value of {@link #userDao} field
     *
     */
    public IUserDao getUserDao() {
        return userDao;
    }

    /**
     * Sets {@link #userDao} field
     *
     * @param userDao User DAO
     */
    public void setUserDao(final IUserDao userDao) {
        this.userDao = userDao;
    }

    ////////////////////////////////////////////////////////////////////////
    // Implemented/Overridden methods
    ////////////////////////////////////////////////////////////////////////

    /**
     *
     * @see IUserService#saveUser(User)
     */
    @Override
    public void saveUser(final User user) {
        fillMissingFields(user);
        userDao.saveUser(user);
    }

    /**
     *
     * @see IUserService#getUserById(Integer)
     */
    @Override
    public List<User> getUserById(final Integer id) {
        return userDao.getUserById(id);
    }

    /**
     *
     * @see IUserService#getUserList(IEnvironmentContext)
     */
    @Override
    public List<User> getUserList(final @SuppressWarnings("unused") IEnvironmentContext context) {
        return userDao.getUserList();
    }

    ////////////////////////////////////////////////////////////////////////
    // Helper methods
    ////////////////////////////////////////////////////////////////////////

    private void fillMissingFields(final User user) {
        user.setLastUpdated(new Date());
    }

    ////////////////////////////////////////////////////////////////////////
    // toString() method
    ////////////////////////////////////////////////////////////////////////

    /**
     *
     * @see Object#toString()
     */
    @Override
    public String toString() {
        return "UserServiceImpl {...}";
    }
}

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

1) Комментарии к разделу по умолчанию - для каждого раздела класса есть один трехстрочный комментарий (например, константы, конструкторы, ...). Обратите внимание, что я не говорю о логических разделах класса (например, // user managenet или // Account Balance calculation).

2) Комментарии Getter и Setter по умолчанию - комментарии для методов set / get, которые просто сообщают, что соответствующие наборы методов возвращают значение поля.

3) Мета-комментарии - комментарии, описывающие значение некоторых конструкций языка Java. Примеры сверху: @see IUserService#saveUser(User) - сообщает, что метод переопределен / реализован, и местоположение родительского метода, Default constructor - сообщает, что это конструктор по умолчанию класса Java, Logger for this class.

4) @SuppressWarnings ("unused") - в моем конкретном примере говорилось, что LOG не используется в классе (LOG действительно никогда не используется в классе, но IDE не будет отображать предупреждение) и аргумент context не используется, но это нормально (при условии, что context - это некоторая общая информация, и она обычно полностью нормальная, если реализации не используют ее).

5) I префикс для интерфейсов - префикс сообщает, что это интерфейс.

6) final для аргументов метода - запрещает коду в теле метода изменять его значение

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

+ 5 - я думаю, что необходимо , и это должно быть сделано каждым Java-разработчиком и даже должно обеспечиваться инструментами (такими как checkstyle)
...
0 - Мне все равно. Если кто-то скажет мне сделать это, я буду - эти комментарии не принесут никакой положительной или отрицательной ценности.
...
-5 - Я настоятельно рекомендую всем делать это. Такие комментарии / метаинформацию по умолчанию следует удалить из класса, как только вы это увидите.

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

Я приму ответ с большинством ТАК примерно через неделю.

PS.: Некоторые из вас могут подумать, что ответ очевиден, но, поверьте мне, каждый из нас очень отличается, и что-то само собой разумеющееся для вас может быть неожиданностью для меня и порока наоборот. Поэтому я призываю вас принять участие в этом обсуждении в любом случае. (Я буду признателен за это)

Ответы [ 2 ]

3 голосов
/ 30 января 2011

Цель документации кода - помочь любому, кто читает код, понять его. Это и не более того. Это цель, на которую вы должны обратить внимание и убедиться, что никогда не потеряете ее. Ценность документации может быть выражена как (<the time it would take me to read the code without the documentation> - <the time it takes me to read the code with the documentation>) * <my salary>). Вычтите из нее время, которое потребовалось вам для написания документации, умноженной на вашу зарплату, и вы получите чистую стоимость. Если это число может быть отрицательным, не беспокойтесь о его написании. Эти формулы, очевидно, являются чисто теоретическими, но они позволяют нам построить несколько вопросов.

Помогли ли мне комментарии в примере кода понять код? Ни одного бита. Информация в них должна быть ослепительно очевидна для любого, кто имеет небольшой опыт работы с Java.

Они мешали мне? Да, поскольку мне понадобилось в три раза больше времени, чтобы просмотреть его, чем это было бы без комментариев.

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

В общем, документация ради документации неверна. Когда вы взвешиваете свой выбор документации, вы всегда должны иметь в виду читателя: как этот кусок документации пойдет им на пользу? Если вы будете помнить об этом, вы сделаете правильный выбор.

1 голос
/ 30 января 2011

Я думаю, что я не боюсь задавать этот вопрос и не высказываю своего мнения по этому вопросу :). Вот мои голоса.

Короче говоря, я против стандартных / автоматически сгенерированных комментариев. Я считаю, что комментарии не должны описывать очевидные вещи, объяснять конструкции языка Java / соглашения о коде или содержать информацию, которую можно легко получить с помощью IDE.

1) -5 (Раздел комментариев по умолчанию)

Эти комментарии, с одной стороны, пытаются описать соглашения Java-кода (или пытаются навязать макет пользовательского класса, поскольку они не следуют соглашениям), а с другой стороны, нарушают их - например, давайте возьмем раздел // Helper methods: он принудительно размещает все приватные методы в этом разделе в конце файла. Это противоречит соглашениям по коду Java ( раздел 3.1.3 ):

Эти методы должны быть сгруппированы по функциональности, а не по объему или доступности. Например, метод закрытого класса может находиться между двумя открытыми методами экземпляра. Цель - облегчить чтение и понимание кода.

Очень легко ошибочно поместить метод в неправильный раздел - в этом случае они могут стать очень загадочными.

Хуже всего, когда кто-то решает иметь это во ВСЕХ классах, несмотря ни на что. Маленькие классы длиной 10 строк станут классами более 50 строк (см. Сам пример)

2) -5 Комментарии по умолчанию для получателя и установщика

Я нахожу это даже хуже беспорядка. Я полагаю, что они фактически пропускают информацию о внутренних классах. Весь смысл методов set / get состоит в том, чтобы скрыть тот факт, что они просто устанавливают и возвращают значение поля.

Эти комментарии самоочевидны и не добавляют никакой полезной информации - только беспорядок в исходном коде.

Мы также должны учитывать, как работает наш мозг. Со временем он действительно научится игнорировать эти комментарии. В этом случае мы можем упустить что-то важное или полезное.

3) -5 Мета-комментарии

Комментарии типа // Logger for this class или // Default constructor очевидны и не приносят никакой полезной пользы. Если кому-то действительно нужны такие комментарии, чтобы лучше понять или прочитать код, то я думаю, что пришло время ему прочитать какую-нибудь Java-книгу или учебник для начинающих.

@see IUserService#saveUser(User) не имеет никакого смысла для меня (учитывая все усилия по обслуживанию, которые должны быть предприняты, чтобы эти комментарии были актуальными). Все основные Java IDE могут предоставить вам эту информацию - они дают видимые признаки того, что метод переопределяет / реализует что-то, что вы можете перейти с помощью ярлыка, обычно вы также можете увидеть, какой метод был переопределен в подсказке, если хотите.

Теперь рассмотрим возможность того, что метод в родительском классе (который вы переопределили) был удален (но в родительском классе родительского класса все еще есть метод, у которого все еще есть метод). В этом случае вы должны обновить эти комментарии во всех подклассах, чтобы синхронизировать их. И я могу сказать вам по опыту, что в какой-то момент большинство этих комментариев будут не синхронизированы и будут служить только двум целям: 1 - загрязнять код и 2 - озадачивать и вводить в заблуждение других разработчиков.

Теоретически вы можете найти способы синхронизировать их (написать плагин IDE, создать сложный код, переписывать во время сборки и запускать его каждую ночь и т. Д.), Но я твердо верю, что это просто трата времени.

4) -3 @SuppressWarnings («не используется»)

Я думаю, что @SuppressWarnings("unused") имеет место в некоторых обстоятельствах, но не в примере, показанном в вопросе. LOG комментируется, потому что никогда не используется. Но если он никогда не используется, то IMO LOG следует удалить из класса. Это закрытое статическое поле, поэтому оно может использоваться только текущим классом. Если класс не использует его, то это беспорядок.

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

И лично мне трудно читать сигнатуры методов со всеми этими @SuppressWarnings("unused") аннотациями (особенно, если их несколько).

5) -4 I префикс для интерфейсов

Лично я нахожу это уродливым и неестественным.Если я хочу интерфейс для пользователя, я назову его User, а реализация будет иметь имя UserImpl.Я думаю, что это можно сравнить с Единый принцип доступа .Пока он называется User, мне все равно, является ли он интерфейсом абстрактного класса или конкретным классом.Если автор интерфейса User в какой-то момент решит сделать его абстрактным классом - мне не следует вносить изменения в мой код, потому что, скорее всего, он не изменит имя.Но это не относится к IUser.

С другой стороны, IDE дает нам более чем достаточно подсказок, чтобы различать классы и интерфейсы.

Насколько я знаю, это наименование происходит от Microsoft COM .В C ++ они не имеют интерфейсов, поэтому они ставят префикс конкретных классов C (например, CUser) и интерфейсные классы I (например, IUser).В Java у нас есть интерфейсы и Соглашения об именах .И я думаю, что мы должны следовать им, если у нас нет действительно веских причин не делать этого.

6) -1 final для аргументов метода - запрещает коду в теле метода изменять его значение

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

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

Я думаю, что можно обеспечить соблюдение этого правила с помощью инструментов (таких как FindBugs или CheckStyle).И я думаю, что это лучший способ сделать это.Часто люди не пишут все эти final сами, но позволяют IDE добавлять их при сохранении файла (например, eclipse может создать).Но если вы действительно изменили значение аргумента (случайно), то IDE просто не вставит final для вас.

...