Неконтролируемая сложность

Contents

Неприятная статистика

Самое неприятное, что может произойти с проектом — это его конец. Я не имею в виду конец на его финальной стадии, хотя совершенству предела нет и стадию поддержки также необходимо учитывать. Куда хуже ситуация, когда программный проект больше не может продолжаться, не достигнув успешного результата. Это происходит достаточно часто. Если посмотреть статистику провальных стартапов, то можно увидеть в списке частых причин нехватку ресурсов в виде инвестиций, а также проблему человеческих ресурсов. В частности, достаточно высокий коэффициент провалов или остановок по причине “Not the Right Team”. Идея продукта может меняться вместе с рынком, но люди должны быть надёжными и, самое главное, предсказуемыми.

20 biggest reasons why startup companies fail

https://medium.com/r/?url=https%3A%2F%2Fwww.marketwatch.com%2Fstory%2F20-biggest-reasons-why-startup-companies-fail-2015-06-16

Насколько я могу видеть, то в open-source проектах часто встречается ситуация, когда проект перестает поддерживаться, когда у автора пропадает интерес к изначальной идее, не хватает времени или разработка заходит в тупик. У разработчиков может размыться видение линии развития проекта. Или например не хватает терпения поддерживать ошибки в проектировании системы. Или вовсе не хватает сил менять решение, которое требует изменений в архитектуре. Такое происходит даже с востребованными и уникальными проектами, имеющих пользовательскую базу. И несмотря на популярность и востребованность проекта достаточно сложно найти человека, который будет продолжать и развивать идею. зачастую из-за высокго порога вхождения в изучении системы или высокой стоимости внесения изменений.

Главный Технический Императив

Программные проекты редко терпят крах по техническим причинам. Чаще всего провал объясняется неадекватноий выработкой требований, неудачным планированием или неэффективным управлением. Если же провал обусловлен все-таки преимущественно технической причиной, то очень часто ею оказывается неконтролируемая сложность. Иначе говоря, приложение стало таким сложным, что разработчики перестали по-настоящему понимать, что же оно делает. Если работа над проектом достигает момента, после которого уже никто не может полностью понять, как изменение одного фрагмента программы повлияет на другие фрагменты, прогресс прекращается. -- Стив Макконнелл, Совершенный код, 2010

Эту цитату хорошо подсуммирует фраза:

…programming is a desperate losing battle against the unconquerable complexity of code… -- Beautiful Code by Jonathan Edwards

Можно сказать, что борьба со сложностью является непрерывным процессом.

Бертран Мейер в своей книге “Основы объектно-ориентированного программирования” вводит ряд критериев, определяющих качество системы. Среди них “расширяемость” —  легкость адаптации ПО к изменениям спецификации. Также присутствует “простота использования” — это легкость, с которой люди с различными знаниями и квалификацией могут научиться использовать ПО и применять его для решения задач. Сюда же относится простота установки, работы и текущего контроля.

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

Управление сложностью – самыий важныий техническиий аспект разработки ПО. По-моему, управление сложностью настолько важно, что оно должно быть Главным Техническим Императивом Разработки ПО." -- Стив Макконнелл, Совершенный код, 2010

Контролируемая сложность

Но как же сделать систему более простой? Ответ очевиден — нужно ее упрощать. Этот процесс может происходить как на стадии проектирования, так и на стадии разработки.

Упрощение на стадии проектирования

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

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

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

Разработчик каждого модуля должен выбрать некоторое подмножество свойств модуля в качестве официальной информации о модуле, доступной авторам клиентских модулей. Применение этого правила означает, что каждый модуль известен всем остальным (то есть разработчикам других модулей) через некоторое официальное описание, или так называемые общедоступные (public) свойства. -- Бертран Мейер. Основы объектно-ориентированного программирования, 2016

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

Еще один спооб контролировать сложность — использовать стандартные методики проектирвоания модулей и применять проверенные шаблоны проектирования.

Writing Software Patterns

На стадии разработки

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

The only valid measurement of code quality: WTFs/minute

Одним из симптомов того, что вы погрязли в чрезмерно̆й сложности, является упрямое применение метода, нерелевантность которого очевидна по крайней мере любому внешнему наблюдателю. При этом вы уподобляетесь человеку, который при поломке автомобиля в силу своеий некомпетентности не находит ничего лучшего, чем заменить воду в радиаторе и выбросить окурки из пепельниц. -- Ф. Дж. Плоджер (P. J. Plauger)

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

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

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