вторник, 20 февраля 2018 г.

Как именовать множество классов

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

Его ответ: большое количество классов - это вовсе не недостаток объектно-ориентированного кода. Проблема не в ООП. Рост сложности будет только, если мы бездумно начнем заменять наш старый код объектами, не задумываясь на его объектной архитектурой.
    Ранее упоминалось несколько «правил», которые, если они применяются, явно приведут к большому количеству классов, в том числе: а) все общедоступные методы должны быть объявлены в интерфейсах; б) объекты не должны содержать более четырех атрибутов; c) статические методы не допускаются; d) конструкторы должны быть без кода; e) объекты должны выставлять менее пяти общедоступных методов.
Самой большой проблемой того как программисты пишут код является его поддерживаемость (maintainability). Если вместо 50 более длинных классов у нас будет 300 гораздо более коротких, то код явно станет более читабельным. Обратное же произойдет, если вы начнете создавать классы неправильно.
    Типы в ООП составляют ваш словарь, который объясняет мир вокруг кода.
    Типы (или классы) в ООП составляют ваш словарь, который объясняет мир вокруг вашего кода - мир, в котором живет ваш код. Чем богаче лексика, тем сильнее ваш код. Чем больше у вас типов, тем лучше вы можете понять и объяснить мир.
    Если ваш словарный запас достаточно велик, вы скажете что-то вроде:
      Прочтите книгу, которая находится на столе.

    С гораздо меньшей лексикой такая же фраза звучит так:
      Сделайте это с тем, что есть на этом.

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


Эта статья о том, как называть свои классы

К сожалению, Java и многие другие языки не разработаны с учетом концепции большого количества классов. Пакеты, модули и пространства имен действительно не помогают, и мы обычно заканчиваем такими именами, как:
AbstractCookieValueMethodArgumentResolver (Spring)
или CombineFileRecordReaderWrapper (Hadoop).
    Мы пытаемся собрать как можно больше семантики в имена классов, чтобы программисты читающие код не сомневались ни на секунду. Затем мы пытаемся под эти имена собрать как можно больше методов в одном классе. Нам кажется, что это делает жизнь проще для пользователей: класс.метод, .метод… .метод (в крайнем случае можно будет воспользоваться подсказками IDE, чтобы найти нужный).
Если мы увеличим количество классов их имена станут еще более длинными и еще более заковыристыми - это совсем не элегантное решение.

Еще больше поддает жару то требование, что имена всех классов должны быть  существительными, а имена методов выражаться одним словом.

Приехали, как говорится! С одной стороны у нас требование увеличить количество классов, а с другой сделать их имена максимально простыми…

Префикс:

Классы всегда должны реализовывать интерфейсы и благодаря этому они всегда являются запросами, директивами или доменами. Например, RqBuffered - это буферный запрос (Buffered Request), RqSimple - простой запрос, RqLive - это запрос, который представляет «живое» HTTP-соединение, а RqWithHeader - это запрос с дополнительным заголовком.

Альтернативный подход - использовать имя типа, как центральную часть имени класса и добавить префикс, который объясняет детали реализации. Например, DyDomain - это домен, который сохраняет свои данные в DynamoDB. Как только вы знаете, для чего предназначен этот префикс Dy, вы можете легко понять, что такое DyUser и DyBase.

В приложении среднего размера или в библиотеке должно быть от 10 до 15 префиксов, которые вам нужно запомнить, не более того. Например, в Takes Framework имеется 24 000 строк кода, 410 файлов Java и 10 префиксов: Bc, Cc, Tk, Rq, Rs, Fb, Fk, Hm, Ps и Xe. Не так сложно вспомнить, что они означают, верно?

Среди всех 240 классов самым длинным именем является RqWithDefaultHeader.

Такой подход к присвоению классов довольно удобен. Он использован в таких проектах с открытым исходным кодом (в GitHub), как: takes (10 префиксов), jare (5 префиксов), rultor (6 префиксов) и wring (5 префиксов).

http://www.yegor256.com/2017/02/28/too-many-classes.html


Префикс является видом дополнительного имени пакета, но префикс более полезен для использования в диалоговом окне поиска класса IDE; и Префикс - способ уменьшить имена классов.

Критика от сообщества:
  • Я обнаружил, что префиксы классов большую часть времени похожи на головоломку. Я трачу время, чтобы попытаться угадать, что означают эти префиксы. Я помню свое первое впечатление от структуры Takes: «Если мне нужно время, чтобы понять, что означает каждый префикс, я даже не хочу продолжать это». Я до сих пор не знаю, что означает префикс Tk, например. Когда я открыл страницу Wring, я нашел «AgGithub», и я не представляю, что это значит? Agile? Скорее всего, это нечто другое.
  • Классы с префиксом! Это единственное, что я категорически против и не люблю в вашем коде! Я считаю, что имя пакета должно использоваться для дифференциации классов. Я всегда использую классы с таким же именем в моем проекте, но их другое название пакета имеет смысл для меня.
  • Поскольку код читается чаще, тогда вы пишете его, вы не должны использовать аббревиатуру вообще. Аббревиатуры всегда могут означать слишком много разных вещей. Экономия времени также совершенно глупа. Ваш самый длинный класс: «RqWithDefaultHeader» или 19 символов. В этом случае важно, чтобы вы сохранили 5 символов из «Запроса»? Сколько времени вам нужно, чтобы написать 5 символов? Полсекунды?
  • Если вы только застряли и забыли одну аббревиатуру, и вы должны искать определение где-то в документации, вы почти теряете впустую огромное количество времени
  • аббревиатуры - это отсутствие 

    LegoNamingClassesAreASignThatYouLackAbstraction
.
  • Lego Naming - это просто признак того, что вы добавляете поведение, вместо того, чтобы действительно думать о том, что вы делаете. Например в Game Of Life вам обычно нужно определить количество живых клеток. Вы можете создать функцию / класс, например 
    GetCellsAroundCellOnlyKeepAliveCellAndCountThem (клетка)

    Но вы также можете назвать его:
    AmountOfLiveCells (клетка)

    Вся фильтрация и то, как вы приобретаете живые клетки, неважны. Важно только то, что вы каким-то образом получаете живые клетки. Итак, вы абстрагируетесь (другими словами) удаляете детали, которые не важны, и создавайте новый словарь вместо поведения LegoBuilding вместе.

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

    RectangleWithTextThanCanBeClickedByAMouse, мы изобрели новую лексику и дали ей название Button. В этом суть абстракции. Если у вас есть правильная абстракция, вам также не нужны префиксы или нужно сокращать материал.

  • `RqWhDefHr` звучит как классное научное заклинание для химии из периодической таблицы,
  • Префиксы - одна из причин, по которой я не мог придерживаться концепции EO. В мире сложных IDE и мощных компьютеров совсем не сложно использовать полные названия вместо сокращений. Сокращения должны быть оставлены низкоуровневым языкам.
  • Пакеты, разделение пространства имен и д.р. специально существуют именно для того чтобы не использовать префиксы,. Если они вам все же нужны, значит вы делаете это неправильно.
  • Если у вас есть интерфейс `Request` и вы называете такие классы, как` RqBuffered`, `RqLive`,` RqWithHeader`. В будущем вы можете найти лучшее имя для своего интерфейса и переименовать `Request` в` Whatever`. Это означает, что вам нужно переименовать `RqBuffered` ->` WhBuffered`, `RqLive` ->` WhLive`, `RqWithHeader` ->` WhWithHeader` соответственно. И эта ошибка склонна, поскольку люди склонны забывать переименовать вещи.
  • Префексы делают код более читаемым в начале (когда вы их все знаете) - но они не работают, если проект становится больше. Например, новый программист в команде не будет знать, что означает «Cc» или «Dy». Новый программист не будет знать, какой префикс использовать для новой группы классов.
  • Иногда префикс представляет интерфейс, иногда он представляет собой технологию, такую ​​как DynamoDB. Эта путаница смущает.
  • 2 ~ 3-буквенные префиксы не работают в сложных системах.
  • Хорошая вещь с префиксами заключается в том, что вы всегда знаете, что этот конкретный класс реализует этот интерфейс! И легко запомнить 10-20 префиксов.
  • FbChain реализует Fallback (расширение FbWrap) -> "Fb" == "Fallback"
  • Префиксные сокращения - уменьшают читаемость. И они уродливые: hrdr wk fr th rdr. 1) вы можете легко использовать завершение кода (просто напишите Request и Ctrl + SPACE, чтобы увидеть все классы, реализующие интерфейс Request); 2) см. Все классы, реализующие интерфейс (как показано в (1)).
  • Теряется семантический смысл названий. Нет никакой проблемы, чтобы написать полное имя интерфейса в качестве префикса.
  • «Bc, Cc, Tk, Rq, Rs, Fb, Fk, Hm, Ps и Xe» - это похоже на периодическую таблицу из химии :)
  • Действительно ли это экономит несколько нажатий клавиш,? В современных IDE нет необходимости вводить полное имя при поиске класса / создания ссылки на него. При поиске вы можете нажать CTRL + N (IntelliJ IDEA), затем начните вводить Re..., и вы найдете все Запросы (Requests). Или вы можете ввести Re * Domain и RequestDomain. Таким образом, когда вы используете возможности IDE для упрощения своей работы. Фактически, полное имя класса вы вводите только один раз (при создании).
  • Префиксы затрудняют понимание кода, особенно новеньким в проекте (или тем, кто работает над несколькими проектами сразу, или тем, кто возвращается к проекту после паузы). Я не уверен, и я определенно не буду использовать префиксы. Возможно, раньше без хорошей IDE это было нормально (10 лет назад java IDE были медленными и громоздкими . В настоящее же время я предпочитаю понятные имена, а не короткие.
  • Многие разработчики борются с чрезмерным разнообразием классов, потому что они постоянно переключаются между ними. И им трудно получить целостную картину  в сильно разветвленных кодах. Они не находят или теряют логику приложения во множестве мелких классов. Я также заметил, что большинство из них редко используют интерфейсы (или делают это бессмысленно: MyService / MyServiceImpl), и чтобы понять код прежде всего смотрят реализацию…
  • Мы разрабатываем инструмент тестирования нагрузки - код почти в 2000 классов и 60K строк кода (и только 10K операторов). Каждый отдельный класс делает одну вещь и делает ее хорошо. После того, как вы начнете тестировать все, что вы пишете, вы будете склонны к такой же системе - просто потому, что она делает тестирование намного проще.

Комментариев нет:

Отправить комментарий