понедельник, 13 июня 2011 г.

Эффект второй системы

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

И хотя в классическом понимании «эффект второй системы» немного отличается от паталогической нелюбви к чужому коду и постоянному его переписыванию, оба эти случая имеют и что-то общее, так что имеет смысл оба эти симптома рассмотреть совместно.

Классический эффект второй системы

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

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

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

Все эти проблемы описаны еще Фредериком Бруксом в его «Мифическом человеко-месяце», где помимо описания этой проблемы даются и рекомендации по ее решению. И хотя она вышла задолго до другой замечательной книги Энди Ханта и Дэйва Томаса «Программист-прагматик», Брукс дает тот же самый совет, что и постоянно звучит в книге прагматиков: не нужно крайностей, и побольше прагматизма и самодисциплины.

Синдром «А не переписать ли все нафиг»

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

Однако проблема заключается в том, что большинство людей с некоторым высокомерием смотрит на неудачи других людей, близоруко считая, что они бы справились лучше. 87,5 процентов программистов считают, что они бы эту работу сделали лучше, и лишь 2,5 процента (**) из них сделали бы ее лучше на самом деле. Остальные же просто сделали бы ее «по своему», правда с тем же успехом в плане сроков, качества и функциональности.

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

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

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

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

--------------------------------------

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

(**) Научно доказано, что 78,5% статистических данных берутся с потолка:)

5 комментариев:

  1. Это все хорошо, а как бороться?

    ОтветитьУдалить
  2. Серебренной пули нет! Надо просто думать не о том, как пректрасен мог бы быть мой код ,если бы это делал я, а о той пользе, которую система приносит бизнесу заказчик здесь и сейчас и какую будет приносить после того как ее перепишут(или отрефакторят). Если изменений положительно скажутся на бизнесе, то смысл в изменениях есть.

    ОтветитьУдалить
  3. Спасибо за статью, имменно такие мысли меня и посещают когда открываю проект написанный не мною... но опыт и рефлексия теперь заставляют задуматься, а стоит ли.... ваша статья даёт понять что я на верном пути....

    ОтветитьУдалить
  4. @gandjustas: рад видеть еще одного rsdn-ера!

    В целом смысл этой серии статей (в которую входит текущая статья, а также Технический долг и Синдром рефакторинга) заключается в желании показать типовые паттерны поведения команды разработчиков в ходе работы над проектом. Смысл этих статей в чем-то схожий с основной идеей последней книги Демарко, Листера и компании под названием "Adrenaline Junkies", в которой они прежде всего хотели обобщить некоторые паттерны поведения и придать им пригодную для повторного использования форму. Т.е. ты работаешь над проектом и вместо смутного предчувствия, типа че-то с этим проектом не так, ты легко можешь выразить это словами. "А... дело все в том, что "технический долг" слишком велик", или "да у нас тут, батенька, классический эффект второй системы". Как мне кажется, увидеть существование подобной проблемы является первым и главным этапом на пути ее решения.

    Теперь что касается решения. Как мне кажется, есть несколько ключевых идей, способных если не устранить, то, по крайней мере, существенно снизить риск подобных проблем. Во-первых, стараться не высекать решения в камне, а давать возможность от них отказаться за разумное время и количество усилий. Очень часто бывает, что вот, приняли решение использовать СОМ, и запихнули это дело в каждую дырку. Или взяли какую-то библиотеку и размазали ее использование тонким слоем по всей системе. Понятное дело, что от всего абстрагироваться нельзя (более того, это не нужно), но разумным образом минимизировать зависимости – просто необходимо.

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

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

    З.Ы. хз, стало ли понятнее, но в, в общем, где-то так.

    ОтветитьУдалить
  5. тут принцип Парето (80/20) то же будет кстати :)

    ОтветитьУдалить