Качество кода - Критический фактор успеха любого программного проекта. Некорректные наименования сущностей, избыточная сложность методов, противоречивые комментарии и нарушение структурных принципов ведут к существенным проблемам: снижению скорости разработки, росту количества ошибок и сложности поддержки. Роберт Мартин (известный как "Дядя Боб"), один из авторов Agile-манифеста, в своей фундаментальной работе "Чистый код" систематизировал принципы написания эффективного, поддерживаемого кода.

Книга "Чистый код" это детально проработанная методология, основанная на десятилетиях опыта разработки коммерческих систем. Она отвечает на ключевые вопросы:

  • Как создать код, который понятен коллегам через месяцы после написания?

  • Какие паттерны предотвращают накопление технического долга?

  • Как проектировать компоненты для лёгкого тестирования и модификации?

Все примеры в этой статье будут на языке программирования C#. Каждый раздел сопровождается примерами рефакторинга "плохого" кода в "чистый" согласно стандартам Мартина.

Что такое чистый код?

Мартин начинает с фундамента: чистый код - это код, написанный с заботой о читателе (часто будущем вас или коллеге). Этот код:

  • Прямолинеен: Делает ровно то, что ожидается.

  • Лаконичен: Ничего лишнего. Одна операция - одна функция, одна ответственность - один класс.

  • Выразителен: Имена и структура и без комментариев объясняет, что делается и почему.

  • Поддерживаем: Легко изменять и расширять без страха сломать что-то ещё.

  • Проверен: Покрыт осмысленными юнит-тестами.

Основа всего - имена

Правильные названия - 90% чистого кода. Вот основные правила:

  1. Выразительность: Имя должно отвечать на все главные вопросы: Что это? Зачем нужно? Как используется? Избегайте общих слов (data, info, manager), если они не полностью говорят о смысле.

    • Плохо: int d; // elapsed time in days

    • Хорошо: int elapsedTimeInDays;

    • Плохо: List list1;

    • Хорошо: List activeCustomers;

  2. Избегайте дезинформации:
    Не используйте accountList для переменной типа Account[] (это не список). Лучше accounts или accountGroup.
    Не используйте похожие имена: XYZControllerForEfficientHandlingOfStrings и XYZControllerForEfficientStorageOfStrings.

  3. Делайте осмысленные различия:

    • Плохо: ProductProductInfoProductData (что отличает их?).

    • Плохо: a1, a2, ... aN.

    • Хорошо: sourceCustomertargetCustomeroriginalMessageencryptedMessage.

  4. Используйте произносимые имена: genymdhms (generate date, year, month, day, hour, minute, second) - кошмар. Лучше generationTimestamp.

  5. Используйте поисковые имена: Однобуквенные имена (ijk в коротких циклах - исключение) и числовые константы (15) сложно найти в коде.

    • Плохо: if (employee.Flags & 15) ... 

    • Хорошо: const int IsFullTimeFlag = 0x01; const int IsOnProbationFlag = 0x02;

  6. Классы / Типы: Имена существительных или существительных с уточнением (CustomerAddressParserAccountService). Избегайте ManagerProcessorDataInfo.

  7. Методы: Имена глаголов или глагольных фраз (Save(), Delete(), ParseConfiguration(), CalculateTotal()). Геттеры/сеттеры - GetName(), SetName().

  8. Булевы переменные / методы: Используйте префиксы is, has, can, should для ясности: isActive, hasLicense, canExecute, shouldValidate.

Методы и функции

Маленькие, хорошо организованные методы это главное чистого кода!

  1. МАЛЕНЬКИЕ! И ещё раз МАЛЕНЬКИЕ!

    • Идеал: Не длиннее 20 строк. Часто 3-4 строки.

    • Правило экрана: Функция должна полностью помещаться на одном экране без прокрутки.

  2. Делайте одно дело (The Single Responsibility Principle - SRP для функций):

    • Функция должна делать ТОЛЬКО то, что явно следует из ее имени. Если вы можете выделить другую операцию с осмысленным именем - вынесите ее в отдельную функцию.

    • Уровни абстракции: Операции внутри функции должны быть на ОДНОМ уровне абстракции. Не смешивайте высокоуровневую логику (ProcessOrder()) с низкоуровневыми деталями (ParseOrderLineItemString()).

  3. Структура кода (Сверху-Вниз - Stepdown Rule):

    • Код должен читаться как повествование, сверху вниз.

    • На верхнем уровне высокоуровневые функции (шаги алгоритма).

    • Каждый следующий уровень - более детальные функции, реализующие шаги верхнего уровня.

  4. Аргументы Функций (Параметры):

    • Идеал: 0 (niladic) > 1 (monadic) > 2 (dyadic). 3 (triadic) - Избегать! > 3 - Требует исключительного обоснования.

    • Флаги как аргументы - ЗЛО! (Process(bool isAdmin)) - Это явный признак, что функция делает два разных дела! Разбейте на две: ProcessAdmin(), ProcessUser().

    • Output-параметры (out, ref) - Еще большее зло! Они запутывают и нарушают поток чтения. Возвращайте кортежи или маленькие объекты-результаты.

    • Объекты-аргументы: Если нужно много параметров, логически связанных, объедините их в класс/структуру.

      • Плохо: public void CreateReservation(DateTime start, DateTime end, int roomId, string customerName, bool hasPremium)

      • Хорошо:
        public class ReservationRequest
        {
        public DateTime Start { get; set; }
        public DateTime End { get; set; }
        public int RoomId { get; set; }
        public CustomerInfo Customer { get; set; } // CustomerInfo содержит Name и HasPremium
        }
        public void CreateReservation(ReservationRequest request)

  5. Глаголы и ключевые слова:

    • Один аргумент: Имя функции и аргумента должны образовывать естественную пару глагол/существительное: WriteField(name)AssertExpectedEqualsActual(expected, actual).

    • Два аргумента: Порядок должен следовать общепринятому: Point p = new Point(x, y);.

  6. Исключения вместо кодов ошибок:

    • Плохо: Возврат кодов ошибок (int result = Save(); if (result == ERROR) ...) ведет к загромождению кода проверками сразу после вызова.

    • Хорошо: Бросайте исключения (try { Save(); } catch (SaveException ex) ...). Обработка ошибок отделена от основной логики.

    • Try[Операция]Паттерн: Для ситуаций, где ошибка это часть ожидаемого потока (например, проверка пароля), используйте паттерн TryParse:
      if (int.TryParse(input, out int value)) { ... } // Успех
      else { ... } // Ошибка, но не исключение

  7. DRY (Don't Repeat Yourself): Безжалостно устраняйте дублирование кода, выделяя общую функциональность в методы.

Пример рефакторинга функции (C#):
Грязный метод:

Чистые методы:

Комментарии

Лучший комментарий - отсутствующий комментарий. Хороший код объясняет себя сам через имена и структуру. Комментарии часто лгут (код меняется, а комментарии нет) и загромождают. Но есть исключения:

  1. Законные комментарии:

    • Правовые: Лицензии, авторские права.

    • Поясняющие намерение (WHY): Почему код сделан так, а не иначе? Особенно если причина неочевидна (баг в библиотеке, специфичное требование).

    • Предупреждения о последствиях: // Внимание: Этот метод запускает долгую операцию (до 5 мин). Не вызывать из UI-потока!

    • TODO: Краткие заметки о том, что нужно доделать / поправить позже. Обязательно указывайте контекст / причину.

    • Усиление (Amplification): Подчеркнуть важность чего-то неочевидного. // Не изменять порядок инициализации: компонент Y зависит от X!

    • Javadoc в Public API: Для публичных методов/классов библиотек - объяснение, что делает, параметры, возвращаемое значение, исключения.

  2. Недопустимые комментарии:

    • Закомментированный код: Удаляйте его! Системы контроля версий хранят историю.

    • Избыточные:

    • История изменений:

    • Скобочные / позиционные: // Конец метода CalculateTotal ------------------------

    • Комментарии-извинения: // Извините за этот баг...

    • Неясные ссылки: // См. замечание в мануале - Какой мануал? Какое замечание?

Форматирование

Единый стиль форматирования критически важен для читаемости.

  1. Вертикальное форматирование (Длина файла, пустые строки, группировка):

    • Длина файла: Стремитесь к маленьким файлам (200-500 строк). Большие классы — признак нарушения SRP.

    • Пропуски (Пустые строки): Разделяйте логические блоки внутри файла (группы переменных, методы, логические секции внутри большого метода).

    • Вертикальная Близость: Связанные концепции должны быть рядом. Переменная объявляется как можно ближе к месту использования. Вызываемые методы - ниже вызывающих (Правило Stepdown).

  2. Горизонтальное форматирование (Длина строки, отступы, пробелы):

    • Длина строки: 120 символов - разумный максимум. Избегайте горизонтальной прокрутки.

    • Отступы (Indentation): Обязательны! Используйте отступы (обычно 4 пробела) для вложенных блоков (внутри классов, методов, циклов, условий).

    • Пробелы: Используйте для улучшения читаемости:

      • Вокруг операторов (=+-*/%==!=><>=<=&&||): int sum = a + b;

      • После запятых в списках аргументов/параметров: void Print(string name, int age)

      • После ключевых слов (if, for, while, switch, catch): if (condition)

      • Между скобками и содержимым (кроме пустых): list.Add( item ); -> list.Add(item);

      • Не ставьте пробелы между именем методы и открывающейся скобкой: Save() (не Save ()). А также внутри скобок индексатора: array[0] (не array[ 0 ])

    • Выравнивание: Избегайте выравнивания переменных по типу или значению. Оно создаёт ложный акцент и сложно поддерживается.

      • Плохо:

      • Хорошо:

Объекты и структуры данных

  • Абстракция и сокрытие данных: Классы должны скрывать свои данные и предоставлять абстрактные интерфейсы для работы с ними. Не создавайте просто структуру данных с публичными полями (в C# для этого есть struct, но и их поля лучше делать приватными).

    • Плохо (публичные поля):

    • Хорошо (инкапсуляция):

  • Закон Деметера (Principle of Least Knowledge): Метод объекта M объекта O должен вызывать только методы:

    1. Самого объекта O (this).

    2. Объектов, переданных в M в качестве параметров.

    3. Объектов, созданных внутри M.

    4. Компонентов объекта O.

      • Не objectA.GetObjectB().DoSomething(); - Это "поездка по цепочке". Нарушает инкапсуляцию, делает код хрупким.

      • Решение: Делегирование. Пусть objectA предоставит метод, выполняющий нужное действие, скрыв свою зависимость от ObjectB:
        Плохо:


        Хорошо:

Обработка ошибок

Ошибки - часть жизни ПО. Обрабатывайте их чисто:

  1. Используйте исключения, а не коды ошибок.

  2. Сначала пишите Try-Catch-Finally: Обрабатывайте код, который может выбросить исключение, блоком try. Обрабатывайте конкретные исключения в catch. Освобождайте ресурсы в finally.

  3. Не возвращайте null! Это источник NullReferenceException (для C#, аналогично в других языках). Возвращайте пустые коллекции (Enumerable.Empty(), new List()), используйте Nullable<T> для значимых типов, применяйте паттерн Null Object.

  4. Не передавайте null! Это смещает ответственность за проверку на вызывающего. Бросайте ArgumentNullException в начале метода, если null недопустим.

Использование стороннего кода

Работа с библиотеками/API требует аккуратности:

  1. Изолируйте границы: Не позволяйте стороннему коду "расползаться" по всей вашей кодовой базе. Оберните его в адаптер (Adapter или Facade паттерн).

  2. Изучайте через тесты: Напишите небольшие юнит-тесты для сторонней библиотеки перед интеграцией. Это поможет понять её поведение и защитит от неожиданных изменений при обновлении.

Юнит-Тесты. TDD и чистота тестов

Без тестов нет чистого кода. Тесты обеспечивают безопасность рефакторинга.

  1. TDD (Test-Driven Development) цикл:

    1. Красный: Напишите маленький тест для новой функциональности. Он должен упасть (так как функциональности ещё нет).

    2. Зелёный: Напишите минимальный код, чтобы тест прошёл. Можно схитрить.

    3. Рефакторинг (Синий): Улучшите структуру кода (как продакшн, так и тест), удалите дублирование, примените принципы чистого кода. Тесты должны оставаться зелёными.

  2. Правила чистых тестов (F.I.R.S.T.):

    • F (Fast): Тесты должны выполняться мгновенно (секунды, а не минуты). Медленные тесты не запускают часто.

    • I (Independent): Тесты не должны зависеть друг от друга. Порядок выполнения не важен. Сброс состояния перед каждым тестом.

    • R (Repeatable): Результат теста одинаков в любой среде (dev, CI, продакшн) и при любом количестве запусков. Нет зависимостей от сети, времени, случайных чисел.

    • S (Self-Validating): Тест должен выдать бинарный результат: УСПЕХ или ПРОВАЛ. Нет ручной проверки логов.

    • T (Timely): Пишите тесты либо до написания кода (в подходе TDD), либо немедленно после написания рабочего кода. Никогда не откладывайте написание тестов на потом!

  3. Качество тест-кода: Так же важно, как и продакшн код. Применяйте все правила чистого кода: выразительные имена, маленькие функции, минимальные утверждения (Asserts) на тест, отсутствие дублирования (используйте SetUp / TearDown или фабричные методы аккуратно), ясность (Build-Operate-Check паттерн).

Классы

  1. Принцип единственной ответственности (Single Responsibility Principle - SRP): У класса должна быть только одна причина для изменения. Если класс делает слишком много, его нужно разбить.
    Признаки нарушения SRP: Много несвязанных методов/полей, частые изменения в разных местах класса по разным причинам, большой размер.

  2. Инкапсуляция: Скрывайте данные и детали реализации! Делайте поля приватными. Предоставляйте доступ через методы / свойства. Ослабляйте уровень доступа только при явной необходимости.

  3. Композиция прежде наследования (Composition over Inheritance): Наследование создаёт сильную связь между классами. Часто композиция (включение одного класса в другой как поле) + интерфейсы дают больше гибкости.

    • Плохо:

    • Хорошо:

Системы

Чистота на уровне архитектуры.

  1. Разделение забот (Separation of concerns): Система должна быть разделена на слабо связанные модули (например, по слоям: UI, бизнес-логика, доступ к данным). Каждый модуль решает свою задачу.

  2. Чистая архитектура (Clean Architecture/Onion/Hexagonal): Основная идея - зависимости направлены внутрь, к ядру. Бизнес-правила (самые стабильные) в центре. Инфраструктура (БД, UI, фреймворки - часто меняющиеся) на периферии. Ядро не зависит от деталей реализации периферии. Достигается через интерфейсы и DI.

  3. Внедрение зависимостей (Dependency Injection - DI, дополнительно Zenject): Классы не создают свои зависимости, а получают их извне (через конструктор, свойства, методы). Это ослабляет связность, упрощает тестирование и делает код гибче.

  4. Масштабирование: Система должна начинаться с простой, чистой архитектуры. Не добавляйте сложности "на вырост"! Рефакторите и расширяйте архитектуру по мере реальной необходимости.

Пример рефакторинга

Мартин детально разбирает эволюцию небольшой программы (генератор простых чисел) от грязной первой версии до чистого кода. Этапы:

  1. Начало: Рабочая, но ужасно написанная версия.

  2. Написание тестов: Покрытие функциональности тестами для безопасности изменений.

  3. Рефакторинг волнами:

    • Разбиение огромного метода на маленькие.

    • Улучшение имён переменных и функций.

    • Устранение дублирования.

    • Упрощение логики.

    • Улучшение алгоритма.

  4. Результаты: Код становится в разы короче, понятнее, эффективнее и легче для изменения.

Словарик терминов

  1. Чистый код (Clean code) - Код, который легко читать, понимать и изменять. Обладает свойствами: прямолинейность, лаконичность, выразительность, поддерживаемость, проверенность.

  2. Выразительность (Expressiveness) - Свойство кода, при котором имена переменных / методов / классов и структура однозначно передают их назначение и логику без комментариев.

  3. DRY (Don't Repeat Yourself) - Принцип разработки "Не повторяйся". Любое знание или логика должны иметь единственное представление в системе.

  4. SRP (Single Responsibility Principle) - Для функций/классов: Объект должен иметь только одну причину для изменения (выполнять одну обязанность).

  5. Инкапсуляция (Encapsulation) - Сокрытие внутреннего состояния объекта и деталей реализации. Доступ к данным только через публичные методы / свойства.

  6. Закон Деметры (Law of Demetr / Principle of Least Knowledge) - Метод объекта A должен взаимодействовать только с:

    • Самим A

    • Параметрами, переданными в метод

    • Объектами, созданными внутри метода

    • Непосредственными компонентами A. Запрещает цепочки вызовов: objA.GetB().DoC()

  7. Исключение (Exception) - Механизм обработки ошибок, прерывающий нормальный поток выполнения и передающий управление обработчику (catch). Альтернатива кодам ошибок.

  8. Null-объект (Null Object Pattern) - Паттерн, подразумевающий возврат специального объекта с нейтральным поведением вместо null (например, пустая коллекция).

  9. Адаптер (Adapter Pattern) - Паттерн для преобразования интерфейса класса в другой интерфейс, ожидаемый клиентом. Используется для изоляции стороннего кода.

  10. Фасад (Facade Pattern) - Паттерн, предоставляющий простой интерфейс к сложной подсистеме. Скрывает её детали реализации.

  11. Юнит-тест (Unit Test) - Автоматизированный тест, проверяющий корректность работы небольшой изолированной части кода (метода, класса).

  12. TDD (Test-Driven Development) - Методология разработки:
    Red → Написать падающий тест
    Green → Написать минимальный код для прохождения теста
    Refactor → Улучшить код, сохраняя зелёный статус.

  13. F.I.R.S.T. - Принципы чистых тестов:

    • Fast - Быстрые

    • Independent - Независимые

    • Repeatable - Повторяемые

    • Self-Validating - Самопроверяющиеся

    • Timely - Своевременные.

  14. Arrange-Act-Assert (AAA) - Паттерн структуры юнит-теста:

    • Arrange: Подготовка данных и зависимостей

    • Act: Вызов тестируемого метода

    • Assert: Проверка результата.

  15. Внедрение зависимостей (DI, Dependency Injection) - Передача зависимостей объекта извне (через конструктор / свойства) вместо их создания внутри. Уменьшает связанность.

  16. Чистая архитектура (Clean Architecture) - Архитектурный подход, где:

    • Бизнес-логика (ядро) не зависит от деталей (БД, UI, фреймворков)

    • Зависимости направлены к центру системы

  17. Разделение забот (SoC, Separation of Concerns) - Принцип разделения программы на независимые модули, каждый из которых решает отдельную задачу (например: UI, бизнес-логика, БД).

  18. Композиция (Composition) - Построение функциональности за счёт включения одних объектов в другие (предпочтительнее наследования).

  19. Рефакторинг (Refactoring) - Изменение структуры кода без изменения его поведения. Цель - улучшение читаемости и упрощение поддержки.

  20. Непрерывный рефакторинг (Continuous Refactoring) - Практика постоянного улучшения кода в процессе разработки.

  21. Дурной запах кода (Code Smell) - Симптом проблемы в коде (например: длинный метод, дублирование, "божественный класс").

  22. Уровень абстракции (Level of Abstraction) - Степень детализации операций. Код внутри функции должен оперировать на одном уровне (например, только бизнес-логика или только технические детали).

  23. Правило пошагового спуска (Stepdown Rule) - Код должен читаться сверху вниз: высокоуровневая логика -> детали реализации. Каждый уровень раскрывает подробности предыдущего.

  24. Искажение (Misinformation) - Использование имён, вводящих в заблуждение (например: accountList для массива).

  25. Обучающие тесты (Learning Tests) - Тесты, написанные для изучения поведения сторонней библиотеки перед её использованием в проекте.

  26. Границы (Boundaries) - Места интеграции с внешними системами (библиотеки, API, устаревший код). Требуют изоляции.

  27. Модуль (Module) - Логически связанная группа функций / классов (например: компонент, слой, библиотека).

  28. Связанность (Coupling) - Степень зависимости между модулями. Низкая связанность - признак хорошего дизайна.

  29. Зацепление (Cohesion) - Мера связанности обязанностей внутри модуля. Высокое зацепление - все элементы модуля работают на единую цель.

  30. Искажение абстракции (Abstraction Leakage) - Ситуация, когда детали реализации просачиваются через абстракцию, нарушая инкапсуляцию.


Если понравилась статья - рекомендую подписаться на телеграм‑канал NetIntel. Там вы сможете найти множество полезных материалов по IT и разработке!

Комментарии (11)


  1. outlingo
    27.06.2025 08:07

    Прочитал «Чистый код»

    Неть. Не прочитал, а спросил у LLM


  1. DjUmnik
    27.06.2025 08:07

    То есть на Go/Rust чистый код невозможен, там же нет исключений?


    1. Yura_PST
      27.06.2025 08:07

      Ключевой момент чистого кода - это от общего к частному (от высокого уровня абстракции к более низкому).


    1. Alexis_Che
      27.06.2025 08:07

      Тут пожалуй соглашусь. Глава "Обработка ошибок" для Go не очень подходит


  1. avshkol
    27.06.2025 08:07

    Спасибо, что сэкономили время на прочтение [считающейся] обязательной книги)

    Скопировал текст в перплексити с просьбой переписать на python с примерами кода.

    Рекомендую код вставлять не сканами экрана, а через формат кода, с указанием языка.


  1. d_ilyich
    27.06.2025 08:07

    Выравнивание: Избегайте выравнивания переменных по типу или значению. Оно создаёт ложный акцент и сложно поддерживается.

    А мне приятно читать такой код.


  1. JBFW
    27.06.2025 08:07

    По мелочам есть всегда нюансы )

    Читаешь какой-нибудь код, а в нем переменные типа tekushiyGod или perechisleniye. Glazovykolupyvatelnitsa.

    Да лучше бы буквами y & I обозвал...


  1. Lewigh
    27.06.2025 08:07

    Очень занимательно это читать, учитывая что автор книги давным давно полюбил ФП и пишет на Clojure:

    Then, in 2010 or so, I bumped into Clojure. I had just recently read The Structure and Interpretation of Computer Programs and so was interested in playing around with a LISP derivative.

    It has been 11 years now, and I feel no urge to change languages. I reckon that Clojure may be my last programming language. Oh, not that I haven't looked around. I've had some daliances with Golang, Elixr, and Kotlin, and have looked with trepidation at Haskel. I've even played with Scala and F#. I keep looking as new languages arise; but have found nothing that calls me to switch away from Clojure.

    также автор книги раньше утверждал что:

    The first rule of functions is that they should be small. The second is that they should be smaller than that. (…) Every function in this program was just two, or three, or four lines long. Each was transparently obvious. Each told a story. And each led you to the next in a compelling order. That’s how short your functions should be!

    но если зайти к нему на Github то можно увидеть такие функции:

    (defn build-character-display [width]
      (let [{:keys [segment-gap segment-length segment-height segment-width height width margin] :as context} (build-context width)
            hseg (build-horizontal-segment context)
            vseg (build-vertical-segment context)
            backslash-seg (build-backslash-segment context)
            slash-seg (build-slash-segment context)
            right-displacement (+ segment-length segment-gap)
            half-segment-width (* 0.5 segment-width)
            half-height (* 0.5 height)
            vertical-displacement (+ segment-height segment-width)
            s0 hseg
            s1 (translate-segment hseg [right-displacement 0])
            s2 vseg
            s3 backslash-seg
            s4 (translate-segment vseg [right-displacement 0])
            s5 slash-seg
            s6 (translate-segment vseg [(- width margin margin segment-width) 0])
            s7 (translate-segment hseg [0 (- half-height margin half-segment-width)])
            s8 (translate-segment hseg [right-displacement (- half-height margin half-segment-width)])
            s9 (translate-segment vseg [0 vertical-displacement])
            s10 (translate-segment slash-seg [(+ (* -0.5 width) half-segment-width margin) (- (* 0.5 height) half-segment-width margin)])
            s11 (translate-segment vseg [(+ segment-length (* 0.5 segment-gap)) vertical-displacement])
            s12 (translate-segment backslash-seg [(- (* 0.5 width) half-segment-width margin) (- (* 0.5 height) half-segment-width margin)])
            s13 (translate-segment vseg [(- width margin margin segment-width) vertical-displacement])
            s14 (translate-segment hseg [0 (- height segment-width margin margin)])
            s15 (translate-segment hseg [right-displacement (- height segment-width margin margin)])]
        {:context context
         :segments [s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15]}))

    https://github.com/unclebob/skillBoard

    Автор уже давно сам своим рекомендациям не следует но вы разумеется следуйте.


    1. comradeleet
      27.06.2025 08:07

      А в чем проблема? Рекомендации, в большинстве своем, вполне здравые. Естественно без фанатизма нужно использовать


  1. iamkisly
    27.06.2025 08:07

    А можно без спойлеров?


  1. Dhwtj
    27.06.2025 08:07

    Попробую по пунктам

    1Выразительность: Имя должно отвечать на все главные вопросы

    Лучше, чтобы тип (или класс) отвечал на все главные вопросы, а имя (или переменная) отвечали бы на второстепенные.

    Плохо: List list1;

    Плохо: List activeCustomers;

    Хорошо: List<ActiveCustomer> forBilling;

    2 функции.

    Структура кода (Сверху-Вниз - Stepdown Rule):

    • Код должен читаться как повествование, сверху вниз.

    • На верхнем уровне высокоуровневые функции (шаги алгоритма).

    • Каждый следующий уровень - более детальные функции, реализующие шаги верхнего уровня

    "Верхний уровень" кода оркестириует для конкретного случая данные и бизнес правила, описанные для более общих случаев.

    Ну, хватит для начала.