Tech Talk
5.47M
Категория: ПрограммированиеПрограммирование

TechTalk

1. Tech Talk

MODERN SOFTWARE ENGINEERING FOR YOUR NEEDS
Tech Talk
«Принципы хорошего кода:
Основные паттерны проектирования»
Артём Янченко
January
2025

2.

Содержание
Что такое «хороший код»
Принципы простоты: KISS, YAGNI, DRY, APO, Бритва Оккама
SOLID
BDUF
Выводы

3.

Что такое «хороший код»
Читабельность > Креативность
Код читают в 10 раз чаще, чем пишут. Он должен быть понятен другому
разработчику с первого взгляда.
Предсказуемость
Изменение в одном месте не ломает функционал в другом.
Тестируемость
Хороший код легко покрыть юнит-тестами. Если его трудно тестировать —
с архитектурой что-то не так.
Минимальная сложность
Отсутствие «Over-engineering». Простое решение всегда лучше сложного.
Выражает намерение
Названия переменных и функций отвечают на вопрос «Зачем?», а не только
«Что делает?».

4.

Принципы простоты: YAGNI, KISS, DRY

5.

Принципы простоты: YAGNI, KISS, DRY
YAGNI — You Aren't Gonna Need It
Основная мысль:
Не пишите код, который вам не нужен прямо сейчас.
Проблема:
Предвосхищение будущего. «А вдруг, через год, понадобится гибкая система оплаты
криптовалютой?»
Реальность:
В 99% случаев этого «потом» не наступает, либо требование меняется так сильно, что
запасной код становится бесполезным.
Решение:
Пишите только под текущие требования. Если функциональность понадобится —
проще дописать её потомe - factor, чем поддерживать мертвый код сейчас.

6.

Принципы простоты: YAGNI, KISS, DRY
YAGNI — You Aren't Gonna Need It
Сценарий:
❌ Код "с запасом на
будущее"
Нужно написать сервис для отправки
уведомлений по email.
Требование:
Пока только отправка обычного текстового
письма.

7.

Принципы простоты: YAGNI, KISS, DRY
YAGNI — You Aren't Gonna Need It
✅ Хорошая реализация
Правильный подход
Код по требованию

8.

Принципы простоты: YAGNI, KISS, DRY
KISS — Keep It Simple, Stupid
Основная мысль:
Простота и читаемость важнее показного «крутого» синтаксиса.
Проблема:
Разработчик использует сложные конструкции: вложенные стримы, тернарные
операторы, битовые сдвиги, чтобы уместить логику в одну строку. Код выглядит
«умно», но его невозможно быстро прочитать и понять.
Реальность:
Код читается людьми в 10 раз чаще, чем пишется. Сложная логика в одну строчку
значительно увеличивает время на поиск багов и введения в контекст проекта.
Решение:
Используйте простые циклы и явные проверки. Не стесняйтесь писать «длинный» и
понятный код. Лучше 5 строк примитивного кода, чем 1 строка гениального, но
непонятного.

9.

Принципы простоты: YAGNI, KISS, DRY
KISS — Keep It Simple, Stupid
Сценарий:
Нужно написать проверку данных формы
регистрации пользователя перед сохранением в
базу данных.
❌ Код переусложнен
Требование:
Email должен содержать символ @, а пароль
должен быть длиннее 8 символов. Если что-то
неверно — вывести конкретную ошибку.

10.

Принципы простоты: YAGNI, KISS, DRY
KISS — Keep It Simple, Stupid
✅ Хорошая реализация
Правильный подход:
Понятная структура
Быстрое чтение
Удобная отладка

11.

Принципы простоты: YAGNI, KISS, DRY
DRY — Don't Repeat Yourself
Основная мысль:
Логика в системе должна иметь единственное место хранения — Single Source of Truth.
Проблема:
Разработчик копирует одинаковые проверки, вычисления или блоки кода в нескольких методах или
классах: «быстрее скопировать, чем выносить».
Реальность:
Когда бизнес-правило меняется, приходится искать все места, где оно используется. Пропустишь одно —
получишь баг в продакшене. А таких мест со временем становится всё больше.
Решение:
Выносите повторяющуюся логику в отдельный метод, утилиту или сервис. Даже если повторение пока
только в двух местах — сделайте это сейчас. Один источник истины = меньше ошибок, проще
поддержка, выше надёжность.

12.

Принципы простоты: YAGNI, KISS, DRY
DRY — Don't Repeat Yourself
❌ Код дублируется
Сценарий:
Нужно реализовать два эндпоинта:
Регистрация нового пользователя.
Обновление профиля существующего
пользователя.
Требование:
Email должен содержать символ @.
Пароль должен быть длиннее 8 символов.
Если данные неверны — вернуть HTTP
400 с понятной ошибкой.

13.

Принципы простоты: YAGNI, KISS, DRY
DRY — Don't Repeat Yourself
✅ Хорошая реализация
Правильный подход:
• Единая точка валидации
• Понятная структура
• Быстрое чтение
• Удобная отладка и изменение

14.

Принципы простоты: APO, Бритва Оккама
APO — Avoid Premature Optimization
Основная мысль:
"Преждевременная оптимизация — корень всех зол". Не оптимизируйте код до того, как
вы измерили, где именно тормозит система.
Проблема:
Разработчик тратит часы на написание сложного, нечитаемого кода ради экономии
миллисекунд, которые никто не заметит. При этом реальная проблема
производительности, например: медленная база данных, остается нерешенной.
Реальность:
80% времени выполнения программы тратится в 20% кода. Оптимизируя оставшиеся
80%, вы просто усложняете себе жизнь без реального профита.
Решение:
Сначала пишите чистый и понятный код. Если есть жалобы на скорость — используйте
профайлер, найдите "узкое горлышко" и оптимизируйте только его.

15.

Принципы простоты: APO, Бритва Оккама
APO — Avoid Premature Optimization
❌ Код переусложнен
Сценарий:
Нужно получить имя пользователя
по ID для отображения в логах.
В системе пока 50 пользователей.

16.

Принципы простоты: APO, Бритва Оккама
APO — Avoid Premature Optimization
✅ Хорошая реализация
Правильный подход:
• Легко тестировать и читать
• Работает сейчас, без излишеств

17.

Принципы простоты: APO, Бритва Оккама
Бритва Оккама
Основная мысль:
Не вводите сущности и уровни абстракции, которые не нужны для решения текущей
задачи.
Проблема:
Архитектурное переусложнение. «Сделаем сразу универсальную, расширяемую, суперабстрактную систему на все случаи жизни».
Реальность:
Лишние уровни и сущности усложняют понимание кода. Стоимость изменений растёт.
“Гибкость” существует только на бумаге — реальным задачам всё равно придётся
подстраивать код заново.
Решение:
Сначала выбирайте самое простое решение, которое покрывает реальные требования.
Усложняйте архитектуру только тогда, когда появились конкретные причины: новые
сценарии, нагрузка, ограничения.

18.

Принципы простоты: APO, Бритва Оккама
Бритва Оккама
Сценарий:
Нужно реализовать создание
пользователя в системе: проверить
данные, сохранить в БД, записать лог.
❌ Код переусложнен
Требование:
Пока есть только одна операция —
создать пользователя. Других
операций: обновление, удаление и т.п.
не планируется в ближайшее время.

19.

Принципы простоты: APO, Бритва Оккама
Бритва Оккама
✅ Хорошая реализация
Правильный подход:
Реализовать логику создания пользователя
прямо в методе сервиса, без промежуточных
абстракций.

20.

Принципы SOLID
Набор принципов, которые помогают писать код, который проще менять и
тестировать

21.

Принципы SOLID
S — Single Responsibility Principle
Основная мысль:
У класса должна быть только одна причина для изменения.
Проблема:
В один класс «сваливают» всё подряд: и сохранение в базу, и отправку писем, и
логирование. Из-за этого класс становится огромным «God Object» и хрупким.
Реальность:
Если нужно изменить формат текста письма — вы открываете класс с логикой
пользователя и рискуете сломать сохранение в базу. Изменения в одной сфере ломают
другую.
Решение:
Разделяйте ответственности. Класс должен заниматься только одним делом, например,
только работой с БД или только отправкой email.

22.

Принципы SOLID
S — Single Responsibility Principle
❌ Неправильный подход
Сценарий:
Нужно реализовать регистрацию нового
пользователя в системе.
Требование:
Сохранить пользователя в базу данных.
Отправить приветственное письмо на
email.
Записать событие в лог.

23.

Принципы SOLID
S — Single Responsibility Principle
✅ Хорошая реализация
Правильный подход
Разделить обязанности:
• UserService — только координирует
процесс (бизнес-логика регистрации).
• UserRepository — работа с БД.
• EmailService — отправка писем.
• AuditService — логирование событий.

24.

Принципы SOLID
S — Single Responsibility Principle

25.

Принципы SOLID
O — Open/Closed Principle
Основная мысль:
Программные сущности должны быть открыты для расширения, но закрыты для
модификации.
Проблема:
Когда появляются новые требования, мы открываем уже написанный и
протестированный класс и начинаем менять его логику.
Реальность:
Каждое изменение старого кода рискует сломать то, что уже работало (регрессия). Код
становится запутанным набором условий.
Решение:
Создавайте абстракции: интерфейсы. Новую функциональность добавляйте через
наследование или создание новых классов, не трогая старый код.

26.

Принципы SOLID
O — Open/Closed Principle
❌ Неправильный подход
Сценарий:
Нужно реализовать обработку платежей
в интернет-магазине.
Требование:
Поддерживать разные способы оплаты:
картой и наличными. В будущем могут
добавиться Apple Pay, PayPal и другие.

27.

Принципы SOLID
O — Open/Closed Principle
✅ Хорошая реализация
Правильный подход
Выделить интерфейс PaymentMethod, а каждый
способ оплаты — отдельная реализация.
PaymentService принимает любую реализацию
через конструктор.

28.

Принципы SOLID
O — Open/Closed Principle

29.

Принципы SOLID
L — Liskov Substitution Principle
Основная мысль:
Объекты базового класса должны быть заменяемы объектами производного класса без
нарушения корректности программы.
Проблема:
Наследник переопределяет поведение родителя так, что это ломает логику работы
программы. Свойства, обещанные родительским классом, не выполняются наследником.
Реальность:
Если вы проверяете тип объекта instanceof перед его использованием, чтобы программа
не упала — скорее всего, принцип LSP нарушен. Это ведет к запутанному коду с кучей
проверок.
Решение:
Убедитесь, что наследник не расширяет класс так, чтобы это противоречило
контракту родителя. Если поведение сильно отличается — возможно, лучше не
использовать наследование, а создать отдельный класс.

30.

Принципы SOLID
L — Liskov Substitution Principle
❌ Неправильный подход
Сценарий:
Нужно реализовать работу с
прямоугольниками. Позже появляется
требование — добавить квадраты.
Требование:
Квадрат — это частный случай
прямоугольника, поэтому логично
сделать Square extends Rectangle.

31.

Принципы SOLID
L — Liskov Substitution Principle
✅ Хорошая реализация
Правильный подход
Не наследовать Square от Rectangle,
если поведение отличается.
Лучше выделить общий интерфейс или
использовать композицию.

32.

Принципы SOLID
L — Liskov Substitution Principle

33.

Принципы SOLID
I — Interface Segregation Principle
Основная мысль:
Много специализированных интерфейсов лучше, чем один универсальный Fat Interface.
Проблема:
Создается огромный интерфейс "Бог-интерфейс", который заставляет реализовывать
методы, которые конкретному классу не нужны.
Реальность:
Классы реализуют методы "заглушки", которые либо ничего не делают, либо
выбрасывают исключение UnsupportedOperationException. Это путает разработчиков и
нарушает логику.
Решение:
Разбивайте крупные интерфейсы на маленькие, специфичные для определенной группы
действий. Клиент должен зависеть только от тех методов, которые он реально
использует.

34.

Принципы SOLID
L — Liskov Substitution Principle
❌ Неправильный подход
Сценарий:
Разрабатывается система управления
сотрудниками: есть менеджеры и
разработчики.
Требование:
Все сотрудники могут работать work()) и есть
eat().
Только разработчики пишут и обозревают код.

35.

Принципы SOLID
L — Liskov Substitution Principle
✅ Хорошая реализация
Правильный подход
Разделить интерфейсы по ролям:
• Workable — может работать,
• Feedable — может есть,
• Codeable — умеет писать код, расширяет
Workable.
Каждый класс реализует только то, что ему
нужно.

36.

Принципы SOLID
I — Interface Segregation Principle

37.

Принципы SOLID
D — Dependency Inversion Principle
Основная мысль:
Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа
модулей должны зависеть от абстракций.
Проблема:
Бизнес-логика, верхний уровень, напрямую зависит от конкретных реализаций
технических деталей, нижний уровень, например, конкретной базы данных или сервиса
отправки.
Реальность:
Если вы захотите сменить базу данных, например, с MySQL на PostgreSQL, или заменить
библиотеку отправки email, вам придется переписывать классы бизнес-логики. Это
делает систему жесткой и трудной для тестирования.
Решение:
Зависите от интерфейсов/абстракций. Конкретные детали: MySQL, SMTP
подставляются через конструктор извне, например: Dependency Injection.

38.

Принципы SOLID
D — Dependency Inversion Principle
❌ Неправильный подход
Сценарий:
Нужно реализовать сервис генерации
отчётов по продажам.
Требование:
Получать данные о продажах и
выводить их количество.
Источник данных — PostgreSQL, но в
будущем могут понадобиться Excelфайлы или API.

39.

Принципы SOLID
D — Dependency Inversion Principle
✅ Хорошая реализация
Правильный подход
Ввести абстракцию IDataSource, а все
источники — реализовывать её.
ReportService зависит только от
интерфейса.

40.

Принципы SOLID
D — Dependency Inversion Principle

41.

BDUF — Big Design Up Front

42.

BDUF — Big Design Up Front
Основная мысль:
Прежде чем строить дом, нужно иметь проект. Крупные системы требуют серьезной
архитектуры до старта разработки.
Проблема:
Начинать писать код "на лету" без четкого плана. Это приводит к хаосу, когда части
системы не стыкуются, а база данных спроектирована неправильно.
Реальность:
Если вы не продумаете архитектуру заранее, вы потратите на refactoring в разы больше
времени, чем на первоначальное проектирование. Исправлять ошибки в фундаменте
системы дорого и больно.
Решение:
Инвестируйте время в анализ и проектирование до написания кода. Четко определите
модули, интерфейсы взаимодействия и схему данных.

43.

Спасибо за внимание!
English     Русский Правила