Критерии Простоты

Львиная доля программистов с чистой совестью скажут, что предпочитают решать задачи просто, руководствуясь прежде всего здравым смыслом.

Но это «просто» у каждого разное и, как правило, не похожее на других.

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

Это не привело к немедленному соглашению, но позволило понять логику друг друга и свести к минимуму ненужные дискуссии.



Первый критерий

Особенности человеческого мозга таковы, что он плохо запоминает и различает более 7–9 элементов в одном списке, оптимальное количество – 1–3. Отсюда рекомендация — в идеале иметь не более трёх членов в интерфейсе, трёх параметров в методе и так далее, и не допускать увеличения их количества за пределы девяти.

Этот критерий можно реализовать с помощью инструментов статического анализа.



Второй критерий

Самое важное находится в первых двух строках любого класса.

  1. Имя, тип параметров, реализованные интерфейсы.

  2. Параметры конструктора.

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

И этот критерий можно реализовать с помощью статического анализа.



Третий критерий

Один тип – одна задача.

Контракты — интерфейсы, реализации — классы, алгоритмы — методы! Мультитулы хороши только в том случае, если под рукой больше ничего нет. Благодаря первым двум критериям писать такие типы несложно.

Да, это принцип единой ответственности разделение интерфейса до кучи) Но здесь статический анализ придется доверить человеку.



Четвертый критерий

Ограничения — такая же юридическая часть контракта, как и сигнатуры методов.

И поэтому.

  1. Комментарии в контракте почти всегда полезны, комментарии в коде реализации почти всегда вредны.

  2. DTO — это полноценные объекты, примитивное поведение которых вознаграждается автоматической сериализацией.

  3. Неизменяемые объекты вознаграждают за удобство проверки, отсутствие гонок и ненужного копирования.

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

  5. Анонимные делегаты и лямбды заменяют комбинацию интерфейс-класс одним методом, позволяя выкинуть два лишних типа и продемонстрировать сигнатуру вызова прямо в коде.

  6. Добавляйте другие «фальшивые объекты» по своему вкусу.

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

Пятый критерий

Максимальная простота повторного использования.

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

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

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

Да, это Принцип замены Лискова в самой простой и практичной форме.

Статический анализатор может сообщить об использовании нежелательного наследования реализации.

Кроме того, не скрывайте типы или методы «на всякий случай».

Все должно быть общедоступным, за исключением того, что необходимо скрыть как детали реализации.



Шестой критерий

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

Если предыдущие критерии соблюдены, добиться этого несложно.

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

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

Да, это принцип открыт-закрыт .

Нет, статический анализ здесь не сильно поможет

Седьмой критерий

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

Например:

  1. IService — сервис, необходимый для реализации
  2. Ленивый — это служба, которая может отсутствовать при запуске; чтобы начать его использовать, нужно прочитать свойство Value; при первом звонке может быть пауза.

  3. Задача — ресурс, который получается асинхронно
  4. Функ - фабрика параметризованных ресурсов
  5. Годный к употреблению - ресурс, который необходим до определенного момента; об окончании использования можно сообщить, вызвав метод Dispose.
К сожалению, статический анализ здесь мало поможет.

Восьмой критерий

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

Большое количество мелких типов само по себе не является фатальной проблемой, поскольку типы — это не список, а граф.

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



Девятый критерий

Зависимости между типами должны быть ограничены.

  1. Циклов в графе типов следует избегать.

  2. Также следует избегать прямых ссылок реализаций друг на друга.

  3. Крайне желательно использовать шаблоны разделения типов на слои, добавляя ограничение на зависимости типов разных слоев друг от друга.

Цель состоит в том, чтобы максимально упростить граф зависимости типов.

Это помогает как при навигации по коду, так и при определении возможного влияния тех или иных изменений.

Да, этот критерий включает принцип инверсии зависимостей .

Да, здесь может помочь статический анализ.



Десятый критерий

То же, что и девятый критерий, но для сборок.

Это значительно упрощает жизнь и ускоряет сборку, особенно если сразу проектировать с учетом этого.

Для сборок с контрактами проще поддерживать обратную совместимость (опубликованные контракты не изменяются).

Сборки с реализациями можно заменить целиком — они всё равно напрямую друг от друга не зависят. Инструменты статического анализа могут помешать некоторым сборкам ссылаться на другие.



Одиннадцатый критерий

Все предыдущие критерии могут быть нарушены, если необходима оптимизация.

Но одно, на мой взгляд, всегда работает: Легче оптимизировать правильный код, чем исправлять оптимизированный код. Полученные результаты Письменное изложение моих собственных идей многое для меня прояснило.

Хотелось бы увидеть ваши критерии простоты в комментариях.

Упоминания о статическом анализе означают возможность реализации, а не его текущую доступность.

Дополнения и критика традиционно приветствуются.

Теги: #простота #программирование #.

NET #проектирование и рефакторинг #C++ #ООП

Вместе с данным постом часто просматривают: