Неужели нужно придерживаться ослабления предусловий в каждой функции?
Зачем мы продумываем систему типов, если мы должны ослаблять предусловия?
Есть ответы на вопросы.
Этот подход критически важен на границах системы или модулей. Там, где я не контролирую вызывающий код.
1. Публичные библиотеки и утилиты:
- Функции типа
formatDate, parseJson, safeDivide.- Почему: Ими пользуются разные части системы. Если утилита падает от
null, это заставляет каждого потребителя писать проверки. Лучше один раз обработать null внутри утилиты.2. Обработчики данных из внешних источников (API, User Input):
- Парсеры ответов бэкенда, валидаторы форм.
- Почему: Мы не доверяем внешнему миру. Соседний микросервис может прислать мусор. Пользователь может ввести что угодно. Код на границе должен быть готов принять "любой" вход и безопасно его обработать (или отвергнуть с понятной ошибкой).
(Вспоминаем подход Parse, don't validate, о котором писал выше)
А вот внутри ядра системы, где я полностью контролирую потоки данных, лучше использовать сильные предусловия (Design by Contract).
1. Бизнес-логика и ядро (Domain Model):
- Методы сущностей (
Order.calculateTotal(), User.changePassword()).- Почему: Если метод
calculateTotal вызван для заказа без товаров - это баг в логике программы, а не "допустимый случай". Здесь лучше упасть (fail fast) или выбросить исключение, чтобы разработчик сразу нашел ошибку. Замалчивание проблемы (возврат 0) может привести к потерям.2. Приватные методы и внутренние хелперы:
- Функции, которые вызываются только из одного-двух мест, которые вы контролируете.
- Почему: Лишние проверки замусоривают код и снижают производительность. Если вы гарантируете (через типы или логику), что
null сюда не придет - не надо его обрабатывать.Есть еще правило "Баррикады"
(погуглите или спросите у LLM)
1) Стены замка (Границы):
Здесь стоят стражники (ослабленные предусловия). Они проверяют всех входящих, отсеивают врагов, чистят грязные ботинки (нормализуют данные).
2) Внутри замка (Ядро):
Все доверяют друг другу. Не нужно носить оружие и проверять документы на каждом шагу (сильные предусловия). Они ожидают, что стража на входе уже сделала свою работу.
Итого:
- На границах (UI, API, Utils):
Нужно быть либеральным (принимать многое - "слабые предусловия").
- В ядре (Domain):
Нужно быть строгим (требовать валидных данных - "сильные предусловия").
Не зря же я тратил время и продумывал систему типов))