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

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

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

Его ответ: большое количество классов - это вовсе не недостаток объектно-ориентированного кода. Проблема не в ООП. Рост сложности будет только, если мы бездумно начнем заменять наш старый код объектами, не задумываясь на его объектной архитектурой.
    Ранее упоминалось несколько «правил», которые, если они применяются, явно приведут к большому количеству классов, в том числе: а) все общедоступные методы должны быть объявлены в интерфейсах; б) объекты не должны содержать более четырех атрибутов; c) статические методы не допускаются; d) конструкторы должны быть без кода; e) объекты должны выставлять менее пяти общедоступных методов.
Самой большой проблемой того как программисты пишут код является его ремонтопригодность. Если вместо 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 и мощных настольных компьютеров вы хотите сказать мне, набрав несколько букв, тогда CTRL + SPACE слишком сложно. Давай, человек! Сокращения должны быть оставлены на языках низкого уровня.
  • Пакеты, или пространства имен, или что-то еще, существуют именно по этой причине. Если вам нужны префиксы, вы делаете это неправильно.
  • Если у вас есть интерфейс `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 нет необходимости вводить полное имя при поиске класса или создании ссылки на exting class. При поиске вы можете нажать CTRL + N (IntelliJ IDEA), затем начните вводить Re..., и вы найдете все Запросы (Requests). Или вы можете ввести Re * Domain и RequestDomain. Таким образом, когда вы используете IDE (вы должны), и вы знаете свою среду IDE (вы должны ее окупить, чтобы узнать ее), вам нужно ввести полное имя класса один раз. Когда вы его создадите.
  • Префиксы затрудняют понимание кода, особенно для кого-то нового для проекта (или того, кто работает над многими проектами, или кто-то, кто возвращается к проекту после паузы). Я не уверен, и я определенно не буду использовать префиксы в мои проекты. Возможно, в 2000 году, без хорошей IDE, это было нормально (я помню, что java IDE были медленными и громоздкими 10 лет назад). В настоящее время я предпочитаю понятные имена над короткими.
  • Многие разработчики борются с разнообразием классов, потому что они постоянно переключаются между классами, чтобы понять код. Они не могут получить целостную картину в сильно развязанных кодах. Они не находят или теряют, логику приложения во множестве мелких классов. Я заметил, что большинство из них редко используют интерфейсы (или бессмысленно их используют: MyService и MyServiceImpl), и всегда смотрят на реализацию…
  • Мы разрабатываем инструмент тестирования нагрузки - код почти в 2000 классов и 60K строк кода (и только 10K операторов). Каждый отдельный класс делает одну вещь и делает ее хорошо. После того, как вы начнете тестировать все, что вы пишете, вы будете склонны к такой же системе - просто потому, что она делает тестирование намного проще.

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

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