Глубинные преступления против проекта
Jun. 8th, 2023 05:06 pmОдно из самых сложных и повреждающих действий в проекте - повышение сложности проекта без должной отдачи.
Когда человек сталкивается с новым требованием в проекте, он открывает код, ищет, куда что дописать. Находит. Дописывает. Фича готова. Если проект достаточно покрыт тестами, то старые фичи/юскейсы не сломаны. Задача сделана, можно сказать, на отлично.
... Но в глубине...
В каждом месте, где он дописал, изменение, грубо говоря, можно свести к:
* всегда делать что-то (добавлять timestamp к сообщению). Сложность не изменилась, точнее, изменилась на несколько строчек. С точки зрения необоснованной сложности вопросов нет. Могут быть вопросы по дублированию кода (если одна и та же строчка получения/форматирования времени появилась в нескольких местах).
* Делать что-то по условию (если у нас есть фичефлаг 'timestamp', добавлять timestamp). Был линейный код, теперь у нас ветвление. Маленькое или большое - но ветвление. В декартовом произведении состояний приложения всё удвоилось.
* Делать что-то по условию в ветвях условий. Если это одно и то же, то это просто дублирование кода и предыдущий случай, если же это разные действия, то мы получаем нарушение инварианта, в котором, возможно, есть не покрытые тестами ветки.
* Добавить трекинг фичефлага или "режима", или "глобальной переменной". Теперь весь (или существенная часть) кода параметризирована, и, возможно, имеет необходимость отвечать на вопрос "что делать в этой ситуации" даже там, где фича не нужна или не имеет смысла.
* Вызывать распространяющиеся изменения (например, фичефлаг - линейный код в месте использования, но новый код вызывает расползающиеся изменения в компонентах, которые зависили от старого кода, включая "накладывание" эффектов идущих по разным ветвям кода на другой код, который вынужден вместо одного "да/нет" уметь реагировать на комбинацию действий разных ветвей кода (А: да, Б: нет; А: да, Б: да, А: нет, Б: да, А: нет, Б: нет).
* Вызвать появление нескольких версий интерфейсов или нарушение контрактов интерфейсов из-за появления вариантивности из-за фичи, включая необходимость думать о ковариантности или контр-вариантности (паталогический случай: когда в код передают сущность (коллбэк, замыкание), ожидающую объект с фичей или без фичи как параметр); особо тут обстоит вопрос с контрактами для внешних потребителей.
* Вызывать нелинейные сайд-эффекты, проявляющиеся через нетипизированные изменения среды исполнения (блокировки из-за чрезмерно активной записи, переполнения, etc).
И всё это выглядит как feature done, но последствия для проекта совершенно разные.
А вот заметить это глубинное преступление очень трудно. Feature done? Ну да, пришлось добавить matrix, ну да, мы теперь с помощью if'а вычисляем зависимости вместо линейного списка, у нас появилась ещё одна переменная, которую по Глубокой Причине надо выставлять в явном виде и помнить про её существование всем остальным вокруг.
Если это всё немного обобщить, то преступления тут нескольких видов:
* Повышение цикломатической сложности
* Нарушение инвариантов
* Добавление паталогических связей (с особым преступлением, когда оказываются связаны вместе два компонента, которые раньше были независимы)
* Экспозиция сложности в контракты
* Повышение нестабильности сайд-эффектов.
... И я не имею ни малейшего представления как это можно заметить, кроме как на интуиции, и то, не всегда.
Когда человек сталкивается с новым требованием в проекте, он открывает код, ищет, куда что дописать. Находит. Дописывает. Фича готова. Если проект достаточно покрыт тестами, то старые фичи/юскейсы не сломаны. Задача сделана, можно сказать, на отлично.
... Но в глубине...
В каждом месте, где он дописал, изменение, грубо говоря, можно свести к:
* всегда делать что-то (добавлять timestamp к сообщению). Сложность не изменилась, точнее, изменилась на несколько строчек. С точки зрения необоснованной сложности вопросов нет. Могут быть вопросы по дублированию кода (если одна и та же строчка получения/форматирования времени появилась в нескольких местах).
* Делать что-то по условию (если у нас есть фичефлаг 'timestamp', добавлять timestamp). Был линейный код, теперь у нас ветвление. Маленькое или большое - но ветвление. В декартовом произведении состояний приложения всё удвоилось.
* Делать что-то по условию в ветвях условий. Если это одно и то же, то это просто дублирование кода и предыдущий случай, если же это разные действия, то мы получаем нарушение инварианта, в котором, возможно, есть не покрытые тестами ветки.
* Добавить трекинг фичефлага или "режима", или "глобальной переменной". Теперь весь (или существенная часть) кода параметризирована, и, возможно, имеет необходимость отвечать на вопрос "что делать в этой ситуации" даже там, где фича не нужна или не имеет смысла.
* Вызывать распространяющиеся изменения (например, фичефлаг - линейный код в месте использования, но новый код вызывает расползающиеся изменения в компонентах, которые зависили от старого кода, включая "накладывание" эффектов идущих по разным ветвям кода на другой код, который вынужден вместо одного "да/нет" уметь реагировать на комбинацию действий разных ветвей кода (А: да, Б: нет; А: да, Б: да, А: нет, Б: да, А: нет, Б: нет).
* Вызвать появление нескольких версий интерфейсов или нарушение контрактов интерфейсов из-за появления вариантивности из-за фичи, включая необходимость думать о ковариантности или контр-вариантности (паталогический случай: когда в код передают сущность (коллбэк, замыкание), ожидающую объект с фичей или без фичи как параметр); особо тут обстоит вопрос с контрактами для внешних потребителей.
* Вызывать нелинейные сайд-эффекты, проявляющиеся через нетипизированные изменения среды исполнения (блокировки из-за чрезмерно активной записи, переполнения, etc).
И всё это выглядит как feature done, но последствия для проекта совершенно разные.
А вот заметить это глубинное преступление очень трудно. Feature done? Ну да, пришлось добавить matrix, ну да, мы теперь с помощью if'а вычисляем зависимости вместо линейного списка, у нас появилась ещё одна переменная, которую по Глубокой Причине надо выставлять в явном виде и помнить про её существование всем остальным вокруг.
Если это всё немного обобщить, то преступления тут нескольких видов:
* Повышение цикломатической сложности
* Нарушение инвариантов
* Добавление паталогических связей (с особым преступлением, когда оказываются связаны вместе два компонента, которые раньше были независимы)
* Экспозиция сложности в контракты
* Повышение нестабильности сайд-эффектов.
... И я не имею ни малейшего представления как это можно заметить, кроме как на интуиции, и то, не всегда.
no subject
Date: 2023-06-09 07:48 pm (UTC)Но для этого надо, чтобы программисты работали в гильдиях, цехах, вроде ныне существующих медиков или юристов.
no subject
Date: 2023-06-12 11:00 am (UTC)В смысле, отказ что-то писать? Или я тебя не понял.
no subject
Date: 2023-06-12 12:30 pm (UTC)no subject
Date: 2023-06-12 12:44 pm (UTC)Ну, занимать позицию ты можешь любую, но в целом, в коммерческой разработке ценность ПО - вообще говоря, величина, зависящая от того, где этот софт будут применять. Если идеальную архитектуру не задеплоят, то грош цена этой архитектуре. Если лапша, от которой кровавые слёзы, делает своё дело, она работает, и ценна.
Дальше тут вопрос комфорта разработки и качества разработки, то есть профессиональный конфликт между разработчиками и менеджментом, который решается путём переговоров (у каждой стороны есть существенные и несущественные требования и между ними нужно найти компромисс).
Разработчики, посылающие менеджеров нахер, имеют возможность продолжать разработку только если им это позволяют. Менеджеры (как представители компании), которые срали на мнение разработчиков, имеют возможность продолжать использовать и развивать продукт, только если разработчики это поддерживают.
Каждая из сторон имеет свою правду и свой интерес, находящийся вне интереса другой стороны, и поиск компромисса - основа для успешной совместной работы.
Если одна сторона идёт на баррикады, то всё ломается. Всё, включая продуманную архитектуру и время на рефакторинг (которого остаётся 0, потому что отдел расформировали).
no subject
Date: 2023-06-13 11:00 am (UTC)Проблема с обоими вариантами в том, что требования будут реализованы силами других людей. Быстро, без переработки архитектуры и с ещё бо́льшим накоплением техдолга.