Как стать автором
Обновить

Почему разрабатывать ПО действительно сложно?

Время на прочтение5 мин
Количество просмотров4.3K
Всего голосов 17: ↑15 и ↓2+16
Комментарии11

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

Давайте начнем с тривиального, но неоспоримого факта: программное обеспечение постоянно развивается… Заметным исключением является наборная система TeX, разработанная Дональдом Э. Кнутом.

Что-то вы неправду пишете. TeX постоянно развивается, получая дополнительные функции. Буквально каждый пользователь развивает его своими функциями (командами), а число добавочных надстроек (пакетов) растёт с каждым годом.

TeX развивается, или LaTeX, XeLaTeX и тд?

Действительно, вы правы. MS Office 2003 достиг полного совершенства и больше не развивается.

Надстройки (LaTeX), инструменты - да. Но не сам TeX. Его смысл наоборот, в том чтобы быть стабильным. Это не случайность что версия TeX сходится к pi: 3.141592653 - текущая, если верить Википедии.

Пожалуй, надо ответить на это отдельной статьёй. Постараюсь сделать.

Ответ на заголовок статьи можно сформулировать одной фразой - потому что сложность разработки ПО не может быть меньше сложности решаемой им бизнес-задачи. С ростом сложности задач растет и сложность ПО.

Да, но. Это задача архитектуры (системной архитектуры, если быть точным) влиять на подход к решению бизнес задач. Если просто добавлять ещё и ещё - сложность будет неизбежно рост вплоть до момента стагнации, когда ничего полезного за разумные время/деньги в систему уже не добавить.

Разделение продукта на bounded contexts позволяет снизить сложность за счёт того что каждый такой домен ограничен. И это работает.

Однако, такой подход приводит к тому что не все становится возможным сделать "как хочется", что может вызывать критику и сопротивление. Также, это долгосрочная история, что усложняет дело ещё сильнее.

Я долго пытался бороться со сложностью, но на данный момент несколько опустил руки.

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

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

Для проектов, где я являюсь единственным программистом, я использую другой подход: стараюсь, чтобы объёмная сложность кода перевешивала концептуальную. Т.е., если сложно написать какой-то универсальный компонент, который придётся отлаживать год, и он всё равно будет багать, лучше я обойдусь без него, даже если это приведёт к большему объёму кода. Пусть лучше будет три разных неуниверсальных компонента, но понятно, как работающих.

Хочется немного дополнить, к тому что вы говорите.

Мне кажется что следующая модель роста сложности и борьбы с ней может быть релевантной.

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

Решение: а давайте организуем код по модулям и как то его упорядочим.

Второе: модульный монолит можно развивать еще какое то время, прежде чем возникнет вторая проблема, трудоемкость изменений (это тоже своего рода сложность, сложность тестирования). Если приложение -- достаточно крупный монолит, количество изменений в единицу времени будет только увеличиваться и также будет увеличиваться время необходимое на тестирование. В итоге процесс выпуска новых релизов начинает болезненно буксовать.

Решение: Микросервисы. То что раньше было (или могло быть) модулями теперь становятся отдельными приложениями (взаимодействующими через API, который нужно разрабатывать дополнительно, что overhead, но оправдано). Таким образом объем тестирования сокращается до отдельного сервиса и его связей (а не всего приложения целиком). Да, разрабатывать микросервисы немного более трудоемко чем модульным монолит (за счет API overhead), но это окупается на большой дистанции.

Третье: как я говорил в статье, модульность вообще (и микросервисы в частности) не снижают общую сложность приложения. Это способ лучше организовать связи и облегчить тестирование и раскатывание изменений. Однако, с ростом приложения общая сложность продолжает возрастать и в какой то момент его развитие стопорится потому что "все слишком сложно", и просто чтобы понять какие и где нужно сделать изменения нужно долго разбираться (иногда месяцами).

Решение: bounded contexts (собственно о чем в бОльшей степени статья). Нужно менять системную архитектуру приложения, вводить границы (ограничивающие сложность) и это уже не может быть сделано только на техническом (инженерном уровне), сам продукт нужно менять что бы такой подход к уменьшению сложности сработал. И добиться этого становится действительно тяжело :)

Когда я был молодым и глупым, то пытался в своих пет-проектах делать все по "большому", по тем же принципам, что использовал в рабочем процессе. Это в итоге приводило к переусложнению когда и большинство этих проектов так и не было доведено до конца.

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

Даже позволяю дублирование кода. Правда когда код дублируется больше трех раз вывожу его отдельно.

И реализацию стал делать начиная с UI. Все API и данные мокаются в изолированном классе(-ах) на UI стороне. И когда становится понятно каким всё таки должен быть API и когда фронтом уже можно пользоваться почти как полноценным приложением - ввожу backend с БД и прочими прелестями.

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

Кстати. Этот подход также использую и при старте написания новых компонент/микросервисов в обычном рабочем процессе. Правда сначала пришлось немного побуждать команду, что это даст пользу. Начальству не нравилось в этом:

  • рефакторинг здесь всё, а это по их мнению лишние траты (см.след.пункт)

  • ты же архитектор. а тут, по сути своей, никакой изначально архитектурой и не пахнет. значит не отрабатываешь свои деньги, халтуришь

Но после нескольких успешных релизов все подуспокоились.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий