Пользователь
0,0
рейтинг
19 апреля 2012 в 16:04

Разработка → Сложности многоэтажного программирования

Здравствуйте дорогие Хабрачитатели и программисты!

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

Многие годы я мечтал и продолжаю мечтать до сих пор создавать качественные приложения. Каждый раз, когда я начинал писать свою новую программу, я был на 100% убежден, что это будет самая лучшая программа в своем роде. Начало любого приложения было воодушевляющим, восхитительным и внушающим надежды на большие перспективы. В такие дни я был погружен в работу с головой, забывая обо всем на свете. Каждый день появлялись новые функции, применялись и новые удачные решения, всё сулило небывалый прогресс и золотые горы, если бы все продолжалось в том же темпе. Хотелось мысленно продлить этот график роста, и казалось, ничего не могло ему помешать. Думаю у каждого из нас такое бывало.

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

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

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

Со временем стало понятно, какая часть кода сможет прожить долго, а какая умрет через несколько попыток её доработать. Достаточно взглянуть на наполненный условиями участок кода, не вмещающийся ни на экран монитора, ни в мозг человека, и становится понятно что этот код близок к тому, чтобы быть заброшенным. Он конечно может работать. И если он работает хорошо, в нем нет ошибок и производительность не вызывает проблем, то лучшее что можно сделать — не трогать его. Можно посмотреть на класс, имена методов которого говорят что он является смесью каких-то разнородных понятий, и становится понятно, что использовать второй раз его не хочется. Он достиг предела своей сложности, здание выросло до такой высоты, что еще этаж и основание не выдержит и все завалится. Не выдержит мой мозг, в попытках обрисовать все множество комбинаций состояний этого объекта, понятие становится слишком сложным для понимания. Это хорошо проявлялось когда я расследовал причины неправильного поведения таких классов. Нужно было что-то менять.

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

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

Условно можно выделить три фазы положения дел в программе:
  1. Зеленая фаза или детство проекта. Код кажется простым, его не много, руки развязаны и хочется программировать. :)
  2. Желтая фаза или трудовые будни. Проект большой, работа над ним трудна, но кажется вполне оправданной. Новый функционал добавляется осторожно, но регулярно. Многие были бы довольны оставаться в этой фазе навсегда, но ведь нет. :|
  3. Коричневая фаза или катакомбы. В проекте много непонятного. Одни и те же вещи делаются несколькими разными путями. Переписывать отдельные части не хватает духа, так как непонятно на что это может повлиять. Слишком много неудачных решений, всего не изменить, и стоит ли ввязываться? Переделка отдельных участков влечет за собой долгий период отлавливания ошибок в самых разных участках программы. Вставляются костыли. Количество затраченных сил намного превышает результат. Развитие программы не представляется возможным. Появляется желание заняться чем-то другим. :(

У меня есть пример из жизни. Я знаю одну фирму, которая программирует всегда в зеленой фазе. Программисты в этой фирме кажутся довольными и оптимистичными, не видавшими трудностей людьми. Такое впечатление, что им море по-колено. Чудесно, не правда ли? В чем же дело? Её смекалистый руководитель давно понял о закономерной смене фаз в процессе разработки и продает проект каждый раз, когда начинает чувствоваться накопление сложности. Он продает стартапы. Графики роста прилагаются. Отчеты о проделанной работе отличные. Срок выполнения завораживает. Перспективы кажутся внушительными. Наивные инвесторы полагают что программа это товар, как любой другой обычный бизнес, купил, поставил на места продавцов и бухгалтеров и получай себе прибыль. Они часто не понимают, что покупают себе головную боль замедленного действия, которую они выбросят через год, когда программисты начнут лезть на стены, лишь бы все стояло на месте. Все проблемы коричневой фазы остаются на долю покупателя, а фирма продавшая стартап чувствует все прелести и оптимизм зеленой.

Выход конечно оригинальный, но, очевидно не единственный. Существуют ведь Microsoft, Apple, Oracle которые умеют преодолевать эти трудности роста. Как они это делают? Какие есть методы сохранить зеленую зону?

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

Спасибо вам за ваши комментарии.
Олег Дубров @Oleg_Yozhik
карма
33,5
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (126)

  • +22
    На протяжении 3 лет я занимался разработкой нового функционала и починкой багов в системе, которую писали на протяжении последних 20 лет. Естественно, пользуясь вашей терминологией, находилось всё в районе конца жёлтой фазы и начала коричневой. Чтобы не скатиться в коричневую, как мне кажется, больше всего помогало следующее:

    1. Никакого agile, ни в какой в форме. Только faterfall, только предварительное проектирование на протяжении 4-6 месяцев. Непосредственно на стадию написание кода при этом приходилось около 2 месяцев, и около 4 на тестирование.

    2. Жёсткие гайдлайны, как именно можно писать код. Система была в основном на С, при этом никакой адресной арифметики, никакого динамического выделения памяти. Указатели использовались только для передачи параметров в функции. Нативные типы данных не использовались, только домены, при этом работа с доменами через автоматически генерируемые макросы, особенно со строками.

    3. Документация. Каждое изменение в коде комментируется, кто, когда, и в рамках какого Change Request или бага менял код. На каждый Change Request — документы, описывающие изменения словами и отдельные документы о том, что и как конкретно меняется в коде, какие поля добавляются или изменяются в базе.

    В итоге всё программирование сводится к поиску места, где надо изменить, и отслеживанию, что и где ещё могло бы из-за этого поломаться. Результат такого программирования — документ, по которому уже собственно пишется код. Код уже могут писать кодеры-индусы, это уже больше механическая работа. Да, это вам не в стартапе с нуля программы писать. Все челленджи переносятся на уровень выше — как именно реализовать хотелки заказчика в продукте, и при этом не сильно просесть в производительности, не поломать старый функционал и т.д.
    • +1
      Пару лет назад что единственная команда где такой подход к проектированию — NASA, ПО для шатлов. Вы не оттуда случаем? :)
      И да, там есть 20+ летняя база всех багов с кусками кода до\после. По ней пытаются строить всякий статистический анализ.
      • +10
        Да ну бросьте, это обычный большой энтерпрайз, их таких много. В последние лет 10 они переползают на жаву, но принципиально ничего не меняется.
    • +5
      > Никакого agile, ни в какой в форме. только предварительное проектирование.
      Вообще-то agile ничего не имеет против предварительного планирования. Также agile не запрещает иметь жёсткие guidelines. документировать любое изменение в коде и ссылаться на Change Request.

      Так что на agile вы зря наехали, стоит узнать про него поподробнее.

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

      А на тестирование у нас точно никогда не уходит 4 месяца, потому что по ходу разработки пишем автоматические тесты. Таким образом, когда код готов, он тут же и протестирован.

      Так что да, проект всегда зелёный, ибо тесты зелёные.
      • +5
        юнит тесты != тестирование
        • 0
          Это к чему? Я так и сказал, что этап тестирования не занимает так много времени, потому что по ходу разработки мы пишем автоматические тесты (как юнит-тесты, так и приёмочные тесты).
          Это и означает, что тестирование != юнит-тесты. Но благодаря последним этап тестирования не занимает так много времени, не находит так много багов и не требует так много исправлений.
          • 0
            Может быть я Вас не так понял, т.к. из предыдущего Вашего комментария не совсем ясно, что у вас включают «автоматические тесты». Мне, например, показалось, что Вы говорите только о юнит-тестах («по ходу разработки», «когда код готов, он тут же и протестирован»).
      • 0
        Я же не утверждаю, что agile в принципе не работает. Просто когда Change Request — это 1-8 человекомесяцев разработки — смысл agile немножно теряется. Особенно если учесть тот факт, что разные Change Request в одной версии продукта бывают друг на друга завязаны. Побить один большой Change Request на много маленьких независимых часто не представляется возможным, т.е. итерации в 1-2 недели сделать не получится. Итерация — 6 месяцев, включая тестирование :)

        Автоматические тесты были у заказчика. Они тестировали основные flow за несколько суток, но на их поддержание у них был выделенный сотрудник, который занимался только автотестами, и он не всегда успевал внести все изменения, чтобы начать тестировать новую версию. Что характерно, опытные тестировщики находили после этих автотестов мелкие баги. Опять же, это особенности больших систем.
        • 0
          Да бросьте! Change Request длиной 8 месяцев невозможно разбить на части?
          Ерунда! Конечно можно. Может, стоит этому где-то поучиться, книжки какие почитать, с людьми опытными посоветоваться?
          • 0
            Во-первых, 8 человеко-месяцев, т.е. реально затрачено будет 2 месяца работы 4 человек.

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

            Вот принципы agile из википедии:
            Личности и их взаимодействия важнее, чем процессы и инструменты; — в крупном бизнесе личности разработчиков никого не интересуют. Рядовые разработчики имеют очень ограниченные возможности общения с представителями заказчика, в идеале — вообще никакого общения.

            Работающее программное обеспечение важнее, чем полная документация; — заказчик не примет продукт без документации. Это — условия контрактов. Более того, функциональность системы должна соответствовать спецификациям, которые тоже являются документацией.

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

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

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

            Вопрос: зачем agile?

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

              Проблема в том, что вы считаете неизменными вещи, которые как раз стоит поменять в первую очередь. Например:
              1. «заказчик не примет продукт без документации. Это — условия контрактов.»
              Поменяйте это! Договоритесь с заказчиком по-другому. Напишите контракт по-другому.

              2. «в крупном бизнесе личности разработчиков никого не интересуют. „
              Это не так. Ровно наоборот, заказчику очень хочется пообщаться напрямую с разработчиками и узнать, как дела на самом деле, а не на бумаге.

              3. “специальные представители компании общаются с представителями заказчика,»
              Поменяйте это! Разрешите разработчикам общаться с заказчиком. Как я уже упомянул выше, заказчик сам тоже хочет этого.

              4. «Временные рамки заранее ограничены, скоуп работ изменяться не может»
              Это не так. Точнее, зависит от заказчика. Мой опыт говорит, что НИ ОДИН заказчик не может заранее точно описать, чего он хочет. Есть только некоторые идеи, наброски. И он хочет сделать первую версию, посмотреть, как это работает. привлекает ли клиентов, и тогда уже решать, что делать дальше. И это абсолютно нормально, бизнес так и должен развиваться. Вот тут аджайл и приходит на помощь. Если ты такому клиенту отвечаешь: «Не, друг, так не пойдёт, у нас скоуп не может меняься и временные рамки заранее ограничены», ты думаешь, он будет доволен?

              Одним словом, аджайл начинается с «тесного сотрудничества с клиентом». Это значит, что клиент должен постоянно с вами встречаться, просматривать промежуточные результаты, выдвигать новые идеи т т.д. Если ваш заказчик не такой, если ему не хочется впрягаться, если он говорит: «Вы начинайте делать, а мы через полгода посмотрим, что у вас там получилось» — тогда никакого аджайла не получится. Что поделать, этот клиент не заинтересован в том, чтобы проект получился быстро и качественно. Да, таких клиентов много — как правило, это государственные предприятия, большие закостенелые монополисты и пр, у которых много денег и которых не заботит эффективность. В такой ситуации аджайл действительно не поможет.

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

              Да, у меня есть опыт работающего agile в больших проектах. В них так и было, что приходилось сначала заказчику объяснять, что теперь придётся работать немного по-другому. И это вполне работает — с кем-то проще, с кем-то сложнее, но работает.
              • 0
                Простите, вы издеваетесь?

                1. Стоимость 1 версии от $1m. Система — ключевая для заказчика, она ему бабло приносит. Если она что-то не так посчитает, и нету спецификаций — кто крайним окажется? А как без документации получить сертификат на софт? Попробуйте предложить банку сделать процессинг без документации и итерациями по 1 неделе, расскажете потом, куда они вас пошлют.

                2. Тому, кто подписывает контракты со стороны заказчика, на разработчиков глубоко покласть. Он никогда не будет вникать в технические детали, потому что для этого у него есть бизнес-аналитики. Впрочем, их, аналитиков, сами программисты тоже интересуют мало. Как дела на самом деле они узнают на User Acceptance Test, + есть SLA на новую версию и на поддержку. Этот тест, кстати, тоже не 1 день занимает.

                3. Разрешить общаться с кем именно? С бизнес-аналитиками? Ну так с ними наши архитекторы общались много. Но только сначала общение, потом подсчёт денег, потом подписание контракта на новую версию. Если заказчику очень хочется — то он может пообщаться с менеджером проекта, разработчики же вообще в другой стране могут находиться. И, самое главное, разработчики обычно не в курсе политических интриг.

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

                Это я к чему: есть проекты, где agile работает, а есть такие, где он не работает, это не серебряная пуля. Шуруповёрт и саморезы — отличные штуки, удобно пользоваться, можно на ходу что нибудь по-другому прикрутить, даже дырки сверлить не надо. Но прикручивать саморезами обшивку самолёта к фюзеляжу вам никто не разрешит, там можно использовать только старомодные заклёпки.

                А на тестирование у вас не уходит 4 месяца потому, что у вас наааамного меньше тестовых сценариев.
                • 0
                  Я не издеваюсь, я поясняю базовые принципы аджайл. Я отвечаю на ваш вопрос, знаю ли я реальные примеры, где это работает. Я знаю, и это в том числе банки и другие серьёзные финансовые системы.

                  А вы не хотите услышать. Вы пытаетесь донести до меня гениальную мысль о том, что аджайл не серебряная пуля. Это банально: все и так понимают, что серебряных пуль не бывает. Я ведь и сказал, что для аджайла должен поменяться заказчик — но похоже, вы и сами не очень-то торопитесь меняться.
                  • 0
                    Давайте подведём итог, всё таки. Автор топика спрашивал, как большие корпорации борются с описанным им эффектам в своих больших проектах. Я описал, как одна конкретная компания борется с ними в одном из своих больших проектов, сравнимых по объёму кода с RDBMS от Oracle. И в ней не будет работать эджайл по целому ряду причин, основная из которых: рядовые разработчики, проработавшие с ней меньше 5-7 лет, просто не могут хорошо знать систему и не могут начинать делать фичи без документа, как именно их реализовывать, от архитектора. Она тупо слишком большая, чтобы разобраться быстро. Те разработчики, которые разобрались — становятся архитекторами, если захотят, конечно же. Ещё agile вряд ли примут в mission critial проектах, слишком высоки риски.

                    Вы всё никак не поймёте ту мысль, что я хочу донести до вас: возможности применения agile ограничены не только заказчиком, но и самим проектом. Agile — для небольших и средних, где один человек через небольшое время работы в команде легко ориентируется, что и как можно менять, может сходу сказать, как имплементить фичу и т.д. Я знаю несколько банков, где всё это успешно применяется во всяких интернет-банках, внутренних шинах между приложениями, CRM и т.д. Банков, которые применяют agile в разработке процессинга или клиринга, т.е. mission critical — не знаю.

                    И, кстати, отдельный вопрос: как решается с SLA на баги? Методики agile позволяют в середине итерации бросить всё и чинить злобный баг?
                    • 0
                      С чего вы взяли, что я не понял какую-то мысль?
                      Я ведь и сказал, что аджайл начинается с тесного сотрудничества с клиентом. Если подходящий клиент есть, встаёт ещё ряд условий: в первую подходящая команда, и — теоретически — подходящий проект. Хотя я не встречал ни одного проекта, в котором аджайл был бы неприменим. Из-за клиента или команды — да, из-за самого проекта — не встречал.

                      Те причины, по которым в вашем проекте не подошёл бы аджайл, я засчитать не могу.
                      1. «рядовые разработчики не могут хорошо знать систему и не могут делать фичи без документа от архитектора».
                      Аджайл не запрещает использование документов и архитекторов. Мы на работе тоже читаем документы и пишем иногда. Аджайл просто предлагает вместо документов более простые и эффективные возможности, там где это уместно. Например, потрясающая практика — парное программирование. Посадить молодого программиста в пару с опытным, и он очень скоро будет знать систему и легко менять её. Гораздо быстрее, чем при чтении огромных документов.

                      2. «Agile — для небольших и средних»
                      Применение аджайл никак не зависит от критичности проекта или объёма кода. Я видел примеры применения аджайл в разных проектах — и больших и маленьких, и критичных и не очень.

                      3. Ваш вопрос насчёт багов забавный. Вы же сами в начале процитировали: «Реакция на изменения важнее, чем следование плану». Именно так. Аджайл заточен под то, чтобы в любой момент времени можно было поменять планы. Если в середине итерации заказчик решил, что исправление такого-то бага важнее, чем новые фичи — да, бросаем всё и исправляем баг. Именно так это и делается. Я не очень понимаю, в чём вопрос-то.
      • 0
        >>по ходу разработки пишем автоматические тесты. Таким образом, когда код готов, он тут же и протестирован.

        Очень опасное допущение.
        • 0
          Нет, конечно, это не исключает необходимости ручного тестирования.
          Просто оно находит гораздо меньше багов и не занимает 4 месяца.
  • +4
    когда мы добавляли последние десять новых фич, мы уже говорили себе, что каждая из этих фич будет последней

    Никогда они не бывают последними.
  • +9
    Unit-тесты должны спасти отца русской демократии. Идеальной архитектуры не существует на то она и идеальная, всегда есть компромисс, недостаточное понимание, ошибки, лень… Unit-тесты позволяют не перепроверять не сломали ли изменения функционал совсем в другом месте, осталось только найти время/желание и начать их применять… ))
    • +2
      Хотя сам люблю тесты и TDD, но всё же они (особенно если только юнит-тесты использовать) не панацея. Способны отдалить наступление коричневой фазы, но вряд ли помогут её избежать.
      • +1
        Более того они сами по себе могут добавить проблем. Но что немаловажно для того, чтобы применять тесты код должен соответствовать определенным требованием — как правило это «автоматически» улучшает архитектуру.
        А в целом согласен с вами, только опыт(!), комплексный подход и чувство меры может помочь. Это и отличает плохого программиста от хорошего (архитектора?).
        • +1
          Вот насчёт архитектуры согласен на все 146%. Даже если тесты не писать, но просто думать перед написанием метода/функции: «а как я её тестировать буду, если заставят» :), уже архитектуру заметно улучшает.
  • +18
    Странное ощущение когда текст полностью описывает положение дел в моей жизни. Много нас таких? Читал «дежавируя», спасибо :)
    • +5
      Да и у меня те же были чувства. Особенно касательно «маленьких уютненьких домашних проектов».
  • +3
    Чтобы код всегда оставался простым, нужно добавлять каждую новую фичу так, чтобы он и дальше оставался простым. То есть нужно избегать компромиссов, которые приводят к усложнению кода (например таких, что наполненный условиями участок кода не вмещается ни на экран, ни в мозг). Это, естественно, возможно при адекватной (простой и понятной) архитектуре проекта.

    При таком подходе может потребоваться больше времени на добавление каждой фичи, но это время никогда не сравнится со временем полного переписывания всего проекта.

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

      Проблема не в коде, а в том, что изначальная архитектура уже не решает текущую задачу.
      • 0
        Вот именно, что проблема как раз в коде. Код должен оставаться простым при любых изменениях — это главное правило.

        Если изначальная архитектура не позволяет коду сохраниться простым — то нужно сразу же внести в нее изменения, а не усложнять код. Как раз это я имел в виду, когда написал о том, что может потребоваться больше времени на добавление конкретной фичи.
        • 0
          Речь о другом: когда изначальная архитектура перестаёт эффективно решать текущую задачу. (Поскольку текущая задача уже отличается от изначальной довольно сильно)
          • +2
            В этом случае есть 2 решения:

            1) изменить изначальную архитектуру таким образом, чтобы она позволяла решать текущую задачу, не усложняя код. Это, кстати, не означает, что нужно переписать весь проект с нуля, в большинстве случаев нужно просто внести некоторые изменения в архитектуру;

            2) усложнить код, не изменяя архитектуру.

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

            Требование к адекватности первоначальной архитектуры конечно же остается.
            • 0
              Макконел смотрит на вас укоризнено=) Он так много написал про жуткую дороговизну латания ошибок в архитектуре.
              Да и по сути допилиьт архитектуру — это долго и не факт, что получился лучше=(
              • 0
                А можно ли считать ошибкой то, что архитектура не удовлетворяет новым требованиям?
              • +1
                А Фаулер сидит и ухохатывается в сторонке :) Он где-то писал, что если под архитектурой понимать какие-то решения, которые дорого пересмотреть в будущем, то нужно уничтожать такое явление вообще :)
                • 0
                  И как, интересно, хотя бы гипотетически возможно уничтожить такое явление вообще? Когда заказчики все поголовно станут суперасами в проектировании и ясновидцами своих будущих запросов?
                  • 0
                    Мне может быть везло с заказчиками, но я солидарен с Ериком Евансом — бизнес (в том числе и его изменение) есть логически обоснованная деятельность, а создатели бизнеса являются бизнес-архитекторами, таким образом никакой сложности как в реализации бизнес-модели, так и в ее изменении нет. Ну то есть если изменение бизнес-модели логически обоснованно, то и рефакторинг автоматически получается логически обоснованным, единственная сложность с которой я тут сталкивался — миграция продакшен базы данных, которой на ранних этапах разработки нет. Тут нужно быть осторожным: бизнес-модель — это не архитектура.

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

                    Что касается архитектуры, то я под ней понимаю выбор языка, фреймворка, сетевую архитектуру и тому подобное. Согласитесь, что наврятли изменения требований могут привести к изменению чего-то подобного.
                    • 0
                      1. Мы сейчас совсем не про логическую обоснованность/необоснованность рефакторинга говорим. Зачем вы мне об этом говорите — совершенно непонятно и нелогично. Я где-то утверждал обратное?

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

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

                        Вот мой опыт это не подтверждает, в этом и моя основная мысль.
                        • 0
                          Ничего, когда-нибудь встретитесь и с этим. ;)

                          А пока попробуйте прикинуть, могут ли хотя бы теоретически быть такие изменения хотелок заказчика, которые затронут состав компонентов и связей между ними?
                          Ответ очевиден: конечно могут быть!
                          А теперь следующий вопрос: А какие вселенские законы мироздания ограждают мозги заказчиков от подобных изменений хотелок? ;)
            • 0
              > Это, кстати, не означает, что нужно переписать весь проект с нуля, в большинстве случаев нужно просто внести некоторые изменения в архитектуру;

              Это смотря какие новые требования появились к уже устаревшей архитектуре. Иногда эти требования приводят к таким изменениям, которые далеко не просто внести. Вписаться новым требованиям в существующий код — часто задачка та еще.
  • +4
    есть куча полезных практик чтобы избежать скатывания в…

    DRY, KISS, рефакторинг, минимальная связность модулей (чему помогает TDD) и тп

    практикуйте их и ваш код будет чистым и шелковистым :)
    • +1
      Описание практики это тоже своего рода не более чем человеческая мораль: вместо ответа на твой вопрос задаёт тебе кучу новых, дополнительных вопросов :)
  • +1
    Сам сейчас нахожусь в ситуации, по-сути аналогичной той что вы описали. Пока-что спасает то, что в архитектуре проекта изначально начал не «фигли думать, надо решать задачу», а старался сделать всё правильно.

    Конкретно: проект под Zend Framework + PostgreSQL +ExtJs. На начальной стадии проекта я долго сам себя крыл чуть ли не матом за то, что моя архитектура выглядела как:
    (
    представления не использую, поскольку ответы идут в json-виде.
    Плюс к этому использую вызов одного действия Контроллера из другого путём перехвата вывода
    )

    Прототип Контроллера с базовыми механизмами ->Прототип Контроллера в обобщённом виде -> Прототип Контроллера для класса сущностей ->Контроллер для конкретной сущности

    Прототип Модели с базовыми механизмами -> Прототип Модели с «виртуальными полями» -> Прототип Модели для общего вида -> Прототип Модели конкретного класса сущностей -> Модель конкретной сущности

    Прототип Маппера с базовыми механизмами -> Прототип Маппера в общем виде -> Конкретный Маппер

    Класс ДбТайбл

    Как я дико плевался на всю эту иерархию когда её делал. Но сейчас она, порой, меня самого вытаскивает из задницы…

    Пусть и индийский говнокод порой присутствует — он по крайней-мере локализован, и не расползается из одного уровня иерархии по всему проекту… Архитектура делает вирусное поражение «индийским кодом» достаточно cложным
  • –7
    Человечество уже давно нашло решение тех проблем, что вы описываете.
    • +2
      Хасель никак не избавляет от потребности от правильной декомпозиции. Обычно самые серьезные проблемы лежать на более высоком уровне, нежели на уровне реализации.
      • +1
        Подозреваю, что комментатор хотел рассказать про то, что функциональное программирование даёт нам несколько интересных свойств, которые окажутся полезными при исправлении ошибок проектирования. Если программа состоит из чистых функций, то любую из них можно переписывать, не беспокоясь испортить другую за счёт влияния её на глобальное состояние среды исполнения в целом.
        • 0
          К примеру ява-приложение обычно состоит из кучки stateless сервисов, гоняющих тупые сущности, состоящие из одниз геттеров-сеттеров. Вобщем этот подход уже сто лет как используется еще со времен процедурного программирования и хаскель тут особо ничего нового не приносит.
          • 0
            Ничто не помешает внести в такое Java-приложение кривой код, добавляющий сущностям состояние. Например, счётчик покупателей, чтобы каждому десятому выдавать скидку. Его можно положить в статическое поле класса, а можно сделать хорошо, придумав лучший способ, вписывающийся в архитектуру приложения. В большом проекте наверняка найдётся хотя бы один разработчик, который добавит такой костыль для экономии времени решения какой-нибудь мелкой задачи. Т.е. у языка нет механизма, который бы вызывал трудности (например имел высокий порог вхождения или требовал использования необычного синтаксиса) у человека, пытающегося испортить проект.
            • 0
              >Т.е. у языка нет механизма, который бы вызывал трудности (например имел высокий порог вхождения или требовал использования необычного синтаксиса) у человека, пытающегося испортить проект.

              Вопрос: а надо ли? Если есть такой горе-разработчик, то я думаю хаскель не спасет. Но это уже совсем другая тема. Мой основной посыл в том, что чисто практически профит от stateless уже давно используется. Да хаскель делает это лучше, я не спорю, но он не может перевернуть представления о разработке.
    • +9
      Очередной мессия со своим «единым истинным знанием»?
  • 0
    Просто нужно разделять всё аккуратно — декомпозировать. Протоколировать обмен данными между подсистемами, и никогда не нарушать жесткую инкапсуляцию… Лучше меня вам всё расскажет книга «Совершенный код»
    • +1
      Точнее — нужно не забывать периодически производить декомпозицию заново :)
      • 0
        Ну или композицию… Ну не важно, просто нельзя допускать энтропию… все должно быть четко разделено.
        • 0
          Ну не допустить этропию вы не можете из-за её сущности. :) Можете лишь более-менее эффективно сдерживать её рост.

          Не забывайте что проект может стать не только неуправляемым из-за того, что «приделано много подпорок», но и наоборот: когда всё раздробленно на слишком уж много уровней, где ты попросту теряешься…
          • 0
            Суть декомпозиции в иерархичности, помимо всего прочего.
            Ну нужно еще выявлять места вероятных изменений… еще много чего нужно… это не легко, но возможно. У меня сейчас в 300 000 строк кода (10 лет софту) — все прекрасно.
        • +1
          Так легко скатиться в оверинжиниринг, а это тоже плохо. Все должно быть в свое время, в том числе и правильная декомпозиция.
          • 0
            Легко, нужна итерационность…
            Это все эвристика, эмпиризм и прочие умные слова. Суть в том, что нужен опыт, а панацеи действительно нет. Но есть несколько эвристических правил, которые сильно уменьшают сложность разработки и устранения ошибок.
            • 0
              Итерационность нужна безусловно. Но не всегда ее можно обеспечить (заказная разработка такая заказная, да).

              Но IoC, стопицот фабрик в модуле, который никогда не будет расширяться… или сложная cms или фреймворк для говновизитки, когда можно обойтись генератором статики…
  • +8
    Всегда, ВСЕГДА оплачивать технический долг, ибо как и любой другой долг он выдается под проценты, и накапливаясь эти проценты хоронят ваш проект.
  • +2
    Я для себя уже достаточно давно нашел ответ на ворос как оставаться в «зеленой фазе». Нельзя писать плохой код. Никогда. Тут есть хорошая новость и плохая. Хорошая в том, что почти все интуитивно понимают когда код нуждается в доработке. Плохая в том, что не всегда очевидно как сделать код лучше. Корни того, что не понятно как сделать лучше обычно находятся в том, что либо требования не очень сами по себе, либо мы эти требования не очень хорошо понимаем, а то и то и другое вместе. С первым можно бороться вводя практики управления требованиями, гибкий анализ и так далее. Что бы бороться со вторым нужно побороть себя, свою лень и с головой окунуться в предметную область. Когда все правильно декомпозировано, код писать легко и приятно. А при реализации новых фич код наоборот подталкивает к быстрому и правильному кодированию.
    • 0
      > Нельзя писать плохой код. Никогда.

      Код, который сегодня был очень хорошим, завтра в один момент может стать очень плохим из-за того, что у заказчика вдруг поменялись требования. Т.е. оставаться всё время в режиме «хороший код» в общем случае невозможно. Ну разве что наплевав на неудобные вам хотелки заказчика. ;)
      • 0
        Код может стать плохим в один момент, только если мы не отрефакторили код под новые требования, а сразу влепили костыль, собственно а чего еще можно ожидать в таком случае? :) Если вы не можете быстро отрефакторить код, ищите проблемы, по своему опыту могу сказать, что все реально, код можно и нужно сохранять в чистоте.
        • 0
          > Код может стать плохим в один момент, только если мы не отрефакторили код под новые требования...

          А в тот момент, когда эти новые требования появились, но код под них еще не отрефакторили, этот код какой? Хороший или плохой? Плохой. Хотя вчера был еще хорошим. Об этом-то и речь.
          Код в один момент может стать плохим и будет таким оставаться до тех пор, пока его не отрефакторят (а это может быть очень длительным процессом). Отсюда следует, что мое утверждение верно: оставаться всё время в режиме «хороший код» в общем случае невозможно.
  • +2
    Об этом уже много писали как и о методах противодействия.

    Юнит-тесты и рефакторинг вас спасут. Плохой менеджмент («Нет времени, нужны новые фичи!!!111адинадинадин») слабый архитектор («Все и так работает, зачем что-то еще?..») вас убьют.
  • +3
    Наличие «желтых» и «коричневых» фаз говорит о том, что сами вы пока в «зеленой» фазе.
    Это пройдет, если стремиться.
  • +2
    Я задам вопрос сразу всем, кто писал про рецепты: как можно удержать проект, сравнимый по объёму хотя бы с ядром линукса, в «зелёной» фазе? Даже с более мелкими типа MySQL, Apache HTTPD, X.Org — и то проблема, они далеко в «жёлтой» фазе.

    Никакого крупного рефакторинга уже быть не может. 100% покрытие юнит-тестами невозможно. Код в принципе не может остаться простым, потому что он делает сложные вещи. Функция не может поместиться на 1 экран, потому что бить на части функцию, если никакая из частей не будет больше нигде применяться, глупо, неэффективно и путает ещё больше, чем написанное 1 куском.
    • +1
      Легко и ненапряжно — правильное разбиение на модули и правильные интерфейсы между ними (и да, правильный waterfall на уровне проектирования модулей). Тогда каждый модуль превращается в маленький ненапряжный проектик.
      • +2
        То есть вы сейчас легко и ненапряжно готовы написать простенькую файловую систему в линуксе? Или сделать новый движок базы данных в MySQL? Если нет — то готовы показать проект с >1млн строк кода, где время входа в строй нового программиста, не знакомого с проектом ранее, займёт меньше пары недель? Да в том же любимом многими nginx'е всего чуть больше 100к строк кода, а новый модуль, который сложнее обычного фильтра, добавить не так уж и тривиально. Вот хотя бы SSI взять, сходу в коде не разберёшься.

        И, кстати, в том же линуксе от версии к версии надо править исходники, чтобы они собирались. Сделаете модуль под 3.0 — он под 3.1 уже может и не собраться. Это всего лишь минорная версия меняется. И это при том, что там с правильными интерфейсами всё довольно таки неплохо.
        • 0
          Про линукс давайте не будем. Срач про архитектуру линукса длится уже очень долго и проблем там из-за монолитности очень много.

          Про MySQL и nginx ничего не знаю.
          Но вот к ASP.NET и IIS, например, модули добавляются элементарно и знать их внутреннюю архитектуру для этого не обязательно, достаточно изучить 1 (один) интерфейс.
        • 0
          Проекты с низким уровнем вхождения — любая enterprise-система с вменяемой архитектурой и менеджментом. Хороших и плохих примеров много в книжках и статьях Мартина Фаулера.
          • +2
            Таки любая? :) Я несколько систем щупал, везде порог вхождения высокий был. И это системы от одного из лидеров на рынке, довольно популярные в мире.
            • +2
              Лидерство на рынке говорит только об успехах продажников и абсолютно ничего — о качестве кода.
        • 0
          А еще можно почитать про организационную структуру мелкомягких в книжке «I. M. Wright's Hard Code».
        • 0
          Если нет — то готовы показать проект с >1млн строк кода, где время входа в строй нового программиста, не знакомого с проектом ранее, займёт меньше пары недель?

          Маленький пример. Мой знакомый, который работает над оптимизатором в MySQL, рассказывал что «входил в строй» около года, сейчас software architect.
    • +2
      Функция не может поместиться на 1 экран, потому что бить на части функцию, если никакая из частей не будет больше нигде применяться, глупо, неэффективно и путает ещё больше, чем написанное 1 куском.

      Не согласен, разбивать код на функции нужно не только из соображений DRY. Иногда нельзя этого делать в критически важных частях из соображений эффективности использования ЦПУ (может и других ресурсов), но это именно иногда. Да и в таких случаях даже исходя из DRY часто всё равно нельзя. Будет два куска одинакового кода и надо будет с этим жить.
      • +1
        Допустим, есть функция на 1000 строк. Сначала будет строк 30 объявления переменных (структур всяких), из остального кода 10-15% занимают комментарии, 70% заполнение структур, остальное — собственно логика, всякие if-ы и вызовы функций, для которых собственно структуры заполняли. И как её такую разбивать на части, и, главное, зачем?

        Это я не про какую-то абстрактную функцию говорил, во всяких больших энтерпрайзных системах такое сплошь и рядом.
        • +2
          Если у вас в начале 30 объявлений переменных, то это говорит, что вы не знаете про правило «объявляй переменную там где она используется». Если ему следовать, то ваша функция сама структурно распадется на отдельные блоки.
          • –1
            Она в любом случае распадётся на них. Вопрос то в другом был: зачем каждый блок выделять в отдельную функцию, если он больше никогда нигде не будет использоваться?
            • +4
              Очевидно, для того, чтобы обозвать кусок кода коротким именем объясняющим суть, повысив общую читаемость и поддерживаемость кода. Про самодокументируемый код слышали?
              • –1
                Допустим, функция примерно такая:
                create_customer() {
                create_in_db();
                set_priceplan();
                add_priceplan_options();
                add_funds();
                apply_offers();
                activate_customer();
                }

                Т.к. каждая из вызываемых внутри функций имеет свои параметры, то всё это растянется на 1000 строк. И всего таких функций, как create_customer, тысячи. Как вы предлагаете это разбивать? И, главное, за счёт чего читаемость то повыситься может, если тут линейный порядок действий, без извращений? Короткие имена закончатся очень быстро. Суть и так будет видно по комментарию к исходной функции create_customer(), т.к. там будет написано, что она делает и в каком порядке.
                • +3
                  В вашем примере отчетливо нужно выделять даже не функции, а классы.
                  • 0
                    Т. е. вопрос в адекватном построение domain model.
                  • –3
                    Какие именно классы, чем это может помочь? Логика работы каждой из функций типа add_funds() довольно нетривиальна и включает в себя десятки бизнес-кейсов. Соответственно, она требует довольно много входных параметров, которые надо заполнять. Какая разница, заполнять поля структуры или дёргать сеттеры классов? Или предлагаете написать пару десятков конструкторов, по одному на каждое место, где могут вызвать ту же add_funds()?
                    Поверьте, ту систему проектировали далеко не дураки, и она реально работала, её можно было поддерживать и развивать.

                    Вы сейчас говорите постулаты из книжек, которые, возможно, хорошо работают в маленьких проектах. Скажите, у вас есть опыт работы в больших проектах, где данные советы (разбиение больших функций на много небольших, использование интерфейсов в ядре системы, сильная изолированность кода, юнит-тесты, рефакторинг) применялись на практике и работали, или вы теоретизируете? Если нет — то попробуйте представить себе, что такое 50 тысяч функций, около 20 лет разработки, несколько сотен (если не тысяч) разработчиков, которые приложили свою руку и около гигабайта исходного кода, и попробовать переосмыслить мои посты.
                    • +3
                      У вас уже из названия функций четко видно, что priceplan, funds, offers — это все отдельные сущности и отдельные таблички в БД, а в аргументах функций вы видимо передаете их атрибуты. В нормальной системе их вполне можно подтягивать из модели или DAL, создавать фабриками итд.

                      Такое как раз и получается, когда разработка идет по принципу «а мне быстрее тут добавить аргумент к функции, а рефакторить долго, а менеджмент не ждет».

                      > Скажите, у вас есть опыт работы в больших проектах, где данные советы
                      > (разбиение больших функций на много небольших, использование интерфейсов в
                      > ядре системы, сильная изолированность кода, юнит-тесты, рефакторинг)
                      > применялись на практике и работали, или вы теоретизируете?


                      Да нет. Я вчера досмотрел курс Попова по ПХП и уже СОЗДАЛ свой ПЕРВЫЙ САЙТ.


                      А если серьезно, самое большое над чем работал и работаю сейча — полтора года работы над ИС организации из примерно 10000 человек, которую до этого несколько лет писали именно так как вашу, и ее активный рефакторинг параллельно с разработкой и переработкой. Устроит?
                      • +1
                        P.S. Хабр странно обработал тэг «сарказм».
                        • 0
                          очевидно же, что вы вчера не сделали свой первый сайт, хабр дал возможность адекватным самим догадаться, что это сарказм)
                      • +2
                        У вас уже из названия функций четко видно, что priceplan, funds, offers — это все отдельные сущности и отдельные таблички в БД, а в аргументах функций вы видимо передаете их атрибуты. В нормальной системе их вполне можно подтягивать из модели или DAL, создавать фабриками итд.

                        А с чего вы взяли, что это не нормальная система? За каждой из этих функций стоит много кода и по несколько табличек, из которых там, внутри функций, данные вытягиваются. И ещё в несколько записываются. И естественно DAL тоже есть, который даже полуавтоматически генерируется. priceplan, funds — это действительно отдельные сущности, которые живут каждая в своей директории проекта, по несколько файлов с кодом в каждой.

                        Скажем, платежи: можно платить наличкой, можно картой, можно банковским переводом, всё это может быть в разной валюте и даже за разные даты (всяческие batch-операции)! При этом могут работать всякие штуки, типа «заплатил 1000р — получил 100р на счёт в подарок». Если клиент был заблокирован за просроченные платежи — его надо включать обратно. В прайсплане могут включаться какие нибудь опции в зависимости от размера платежа. Может быть вообще работа в кредит, и тогда от платежа может меняться кредитный лимит. На каждый платёж надо создавать платёжные документы. Заполнение структур аргументов, про которое я писал, — это именно заполнение параметров конкретного платежа.

                        С прайспланами и доп. опциями к ним всё ещё сложнее.
                        • 0
                          Тогда я без конкретно кода не могу о чем-либо судить.

                          Но:
                          — В случаях когда много входных данных их как правило легко раскидать по набору вспомогательных объектов.
                          — Сложная логика легко разруливается через IoC на отдельные модули.
                          • +2
                            С IoC надо быть осторожным, очень легко попасть в ситуацию «наш софт настолько гибкий, что не встаёт». Были прецеденты :)
                            • 0
                              Согласен.
                            • 0
                              Просто не надо воспринимать IoC как средство достижения гибкости. IoC — это средство управления зависимостями, и его вполне можно (и нужно) использовать даже в тех проектах, где никакая гибкость не нужна, исключительно ради упрощения тестирования.
                              • 0
                                Лично моё мнение: подгонка кода под тестирование в проектах с высокой нагрузкой приводит к падению производительности. В той системе проблема усугублялась тем, что она масштабировалась только вертикально, и под неё использовали уже очень взрослые железки типа здоровенных санов.

                                Кмк именно IoC везде, где только можно, приводит к крайне неповоротливым и прожорливым энтерпрайз приложениям на жаве, у которых стектрейс занимает 3 экрана.
                                • 0
                                  «Лично моё мнение: подгонка кода под тестирование в проектах с высокой нагрузкой приводит к падению производительности. [...] Кмк именно IoC везде, где только можно, приводит к крайне неповоротливым и прожорливым энтерпрайз приложениям на жаве, у которых стектрейс занимает 3 экрана. „
                                  Эмм. А вы можете чем-то аргументировать свое мнение?

                                  Потому что лично я не очень понимаю, каким образом код
                                  class A {
                                  private IB _b;
                                  public A(IB b) {_b = b;}
                                  public void Do() {_b.DoOther();}
                                  }
                                  [...]
                                  b = B();
                                  a = A(b);
                                  a.Do();

                                  может быть медленнее, чем

                                  class A {
                                  private IB _b;
                                  public A() {_b = new B();}
                                  public void Do() {_b.DoOther();}
                                  }
                                  [...]
                                  a = A();
                                  a.Do();
                                  • +1
                                    В таком виде не будет. Но вы же не будете передавать в конструктор, скажем, 10 зависимостей, правда? Начнёте использовать фабрику, которая ещё будет читать из какого нибудь xml конфига. А вам всего то надо было положить клиенту денег на счёт. Если хотите — я готов попробовать вспомнить и описать в личке алгоритм работы какой нибудь не очень тривиальной функции, а вы попробуете разорвать зависимости.
                                    • 0
                                      «Но вы же не будете передавать в конструктор, скажем, 10 зависимостей, правда?»
                                      Почему нет? Это, конечно, неудобно, но если это одно место в коде, то я переживу.

                                      «Начнёте использовать фабрику, которая ещё будет читать из какого нибудь xml конфига.»
                                      Почему сразу xml-конфига? Xml-конфиг появляется тогда, когда нужна гибкая настройка во время выполнения, а она-то как раз не нужна. Я же говорю — не надо путать IoC, DI-контейнеры и гибкую настройку.

                                      (при этом надо отметить, что DI-контейнер мне может дать кучу приятных мелочей навроде автоматического управления жизненным циклом и неявных синглтонов, за счет чего я в производительности выиграю, но это так, мелочи)

                                      «А вам всего то надо было положить клиенту денег на счёт.»
                                      А зачем для этого десять зависимостей?

                                      «Если хотите — я готов попробовать вспомнить и описать в личке алгоритм работы какой нибудь не очень тривиальной функции, а вы попробуете разорвать зависимости. „
                                      Ну давайте попробуем, хотя мне кажется, что делать это в паблике интереснее.
            • +1
              А если функция в коде вызывается всего один раз, то правильный компилятор ее все равно заинлайнит и потери производительности не будет, если что.
            • +3
              Исследование, проведенное в IBM, показало, что максимальный уровень ошибок был характерен для методов, размер которых превышал 500 строк кода.
              При дальнейшем увеличении методов уровень ошибок возрастал пропорционально числу строк (Jones, 1986a)

              С.Макконел. Совершенный код
            • +4
              Зачем бить 1000-строчную функцию на 30 одноразовых подфункций? Ответ простой, на самом деле. В любой точке любой области видимости должно быть доступно как можно меньше переменных — этим достигается значительное упрощение кода. Не возрикает желание в том или ином месте использовать то, что к этому месту отношения не имеет.

              Например, есть у вас большая функция и в ней 6 переменных. Функция распалась на 2 логических блока, в Первом используются первые 3 переменные, во втором — последние три. Вот чтобы явно это выделить, чтобы кто-нибудь в будущем не залез шаловливыми ручками во второй блок и не добавил в него зависимость от первых трех переменных, и надо это все разбить на 2 функции.

              Это простая минимизация связности и лишних зависимостей. А в качестве бонуса — еще и необходимость в комментариях почти отпадает, потому что названия функций — это и есть комментарии. Попробуйте, я обещаю, вам такой подход понравится!
              • 0
                вы абсолютно (на мой взгляд) правы — сам использую такую «технику», код становится максимально понятным
              • +1
                То есть вы предлагаете сделать из 50 000 простых с точки зрения логики функций 1 000 000 (один миллион)? Не надоест названия придумывать? :) Опять же, вот в примере выше есть функция, предложите свои варианты названий её кусков.

                И да, на 1000-строчную функцию пришлось бы максимум 5 вызовов других функций, на экран бы всё равно не помещалось.

                От шаловливых ручек спасает доменная модель данных и отсутствие переменных нативного типа. Так же число логически внутри 1 функции обычно не может быть много объектов одного и того же типа, т.к. не может быть такого бизнес-кейса. Вот в примере, который я описывал выше, каждая функция принимает на вход свою структуру, больше переменную такого типа приткнуть просто негде.

                Бонус же ваш нифига не бонус, потому что наличие комментариев прописано в гайдлайне. Без «шапки» функции в виде коммента, описывающего её работу, такая функция code review не пройдёт.

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

      Не вижу противоречия. Код бьется на части не только из-за повторного использования.
  • +3
    Как они это делают? Какие есть методы сохранить зеленую зону?


    Это complexity problem, она стара как само программирование и уже давно все обсуждено. Основные методы борьбы — это наличие архитектуры :). Почему-то большинство разработчиков считают, что их начальные три класса программы и «вот тут у нас очередь в которой мы делаем во-о-о-от так» — это архитектура О_О.
    • 0
      Для тех из нас, кто ещё не знает — что читать про правильную организацию архитектуры?
      • 0
        Вы будете долго смеяться — а я не знаю :). Ни разу не встречал книгу/статью/информацию по архитектуре, которая бы содержало что-либо кроме общих слов вида «архитектура должна быть, иначе все будет плохо» и конкретных примеров вида «мы тут десять лет назад писали драйвер, сделал вот такую архитектуру — так в ней потом столько косяков было, не делайте так».
        • +1
          Потому что архитектура софта — это, во-первых, очень общая, абстрактная проблем; во-вторых — для нее пока нет такого строгого математического аппарата типа «возьмем вещественное R такое, что для любого N…»
          Поэтому да, очень общо. Единственные более-менее достоверные метрики — цикломатическая сложность и, как бы это ни было смешно — среднее количество строк кода в отдельном методе/классе.
      • 0
        Книги Мартина Фаулера в первую очередь.

        martinfowler.com/books.html
  • 0
    Перед мерджем в транк делается ревью кода ответственным за это сотрудником. Самому себе может и простишь фигню, но она просто не пройдет проверки.

    Побольше тестов.

    Проверка стиля кодирования при коммите. Коммиты с плохим стилем не проходят.

    Как-то так, пока не знаю решения лучше :)
  • +1
    > Достаточно взглянуть на наполненный условиями участок кода, не вмещающийся ни на экран монитора

    Ну лично для себя я уже экспериментально выяснил как держаться в зелено-желтом участке. Да и вы в одном(!) предложении ответили на два(!) вопроса сразу:
    во-первых, уменьшать количество условий всеми возможными способами
    во-вторых, не иметь сложных сущностей, не умещающихся на экран монитора (простые сущности могут быть сколь угодно длинными)
  • +6
    Во-первых понимать полностью как это работает.
    Не должно быть «магии».
    Лучший способ этого достичь — конспектирование.
    Открываете libre office writer и записываете много-много связанных с задачей вопросов «почему?», «как?», «зачем?».
    Потом записываете ответы никуда не подглядывая. Пробелы, неглубина всплывут сразу.
    Записанное должно быть логически (с вашей позиции) безупречным. Ощущение «Придраться не к чему».
    Такой текст не стыдно выложить в сеть подписавшись своим именем.
    Реализовав фичу, вы должны быть способными объяснить, допустим, своей маме что происходит при выполнении первой строки кода «int n = 5;» и ответить не все встречные вопросы. И так по всем строчкам.
    Поначалу это сложно и долго, т.к. поверхностных знаний море, а на уровне ждедая вы, как выяснится, знаете грёбаное нихрена, и для объяснения «int n = 5;» вам придётся прочитать, скажем, целую книгу «КОД» Пецзольда и потом ещё проработать её конспектами.

    Во-вторых сразу делать настолько хорошо, насколько можно.
    Это значит смотря на решение нет даже намёка на чувство «что-то здесь не то». И уж тем более никаких «Сойдёт».
    Такое решение не стыдно выложить в сеть и подписаться своим именем.
    Это несложно, главное контролировать чувство жажды «ещё фичу!». Долго в краткосрочной перспективе, но не в долгосрочной.

    Практикуя предложенное, границы между зеленой-желтой-коричневой зонами будут размываться, а в момент, когда они станут одной, вы услышите хлопок одной ладони.
    • 0
      … хлопок одной ладони… по лбу и восклицание: «Какой же я был дурак, всю жизнь потратив на это!».
  • +7
    Сейчас реже бываю в таких ситуациях, чем пару лет назад. Что мне в этом помогло:
    KISS Если можно использовать максимально простой интерфейс — использую его, без всяких затычек на будущее.
    Постоянный рефакторинг. Рефакторинг провожу мелкими частями, редко затрагивая за раз больше 2-3 связанных мест. При этом этот процесс идет практически неприрывно, так как сразу спроектировать идеальную архитектуру при решении новых задач почти никогда не удается.
    Модульные тесты. При постоянном рефакторинге незаменимое средство. Покрываю тестами меньшую часть кода, но стараюсь обеспечить достаточное покрытие тех мест, которые подвергаются рефакторингу.
    Готовые решения. Раньше, при использовании готовых решений часто старался кастомизировать их. Не для изменения функционала, а для удобства использования. Потом обязательно натыкался на какие-нибудь грабли. Сейчас стараюсь по максимуму следовать принятым соглашениям, даже если не все они мне нравятся. И выходит лучше, и сопровождать другим мой код намного легче.
    Спрятать запах. Когда какая-то часть системы уже почти целиком дурно пахнет, стараюсь максимально изолировать ее за симпатичным интерфейсом, а уже потом производить рефакторинг. Очень полезно во время дедлайна, в этом случае дальнейший рефакторинг можно отложить на некоторое время.

    В целом, все довольно стандартно и уже не раз было описано во многих источниках, но чтобы полнолстью принять прочитанное, часто приходится самому сначало шишки набить.
  • +1
    Попробуйте познать подход "Getting Real". (:

    Отказываться от лишнего функционала, придерживаться строгой архитектуры, документировать код и, конечно же, Keep It Simple!

    … я, конечно же, не имею права давать советы, ибо у самого мало опыта. Сам забросил несколько, кажущихся невероятно хорошими, проектов. Но в последнее время — всё-таки довёл одно из дел до конца, первый раз в жизни и…. Хотя, быть может, ~14k строк — это не так уж и много, но ощущение от запуска собственного проекта — совершенно невероятные, неописуемые!
  • +1
    есть проект с 30 тыс. строк кода, написан исключительно мною. Находится в последней фазе, поэтому я принял решение полностью переписать.

    Одно могу сказать: невозможно изначально хотя бы приблизительно спрогнозировать правильную архитектуру ибо в бою все приоритеты меняются с ног на голову. Я сейчас пришел к такому варианту: пишется минимально рабочий вариант, на котором оттачиваются концепции и подходы, затем на основе всего этого добра пишется окончательное решение. Важно не бояться переписать в n-й раз, удалить целый модуль, для которого целый день писал документацию. Если выудить из репозитория первые варианты моего проекта и сравнить с текущим — вряд ли насоберется хотя бы 5% совпадений
    • +1
      Переписывать лучше постоянно и понемногу, то есть рефакторить, а не весь проект переписывать. Почему вы только на 30 тысячах строк решили переписывать? Наверняка же были «запахи» и на 5 тысячах и на 10.

      С прототипированием никогда не получается до конца. Прототип позволяет заложить хоть какую-то изначально правильную декомпозицию. Но все равно со временем код начнет протухать и придется рефакторить.
      • +1
        проект был внедрен в очень многие предприятия, под него написаны модули иными разработчиками (вне этих 30 тыс), поэтому единственным вариантом было довести все до более-менее законченного состояния, после чего с громадной базой знаний переписать с нуля. Самое интересное, что качество кода никого не интересует, главное чтоб багов не было. Однако же, удовлетворяя требования многих заказчиков, система обрасла миллионом сущностей, которые разрулить просто крыша едет
        • +1
          перечитал, и понял, что причина в сообщении незаметна. Проект писался очень долго и важна была совместимость со всеми предыдущими версиями. В конце концов снежный ком набрал очень много веса и требовалось все переосмыслить
  • +2
    Покажите этот текст и 2-3 людей хорошему киносценаристу. Может быть, родится идея и вырастет фильм «Коричневый закат» о программных проектах и специфических трудностях поддержания их жизни.

    (Проблема в том, что для фильма денег нужно немало, а донести мысль до зрителя в образах — где вы видели аналоги такого фильма? Это даже не «Социальная сеть» и не про хакеров. Это материя, которую не понимают половина программистов, пока не насмотрятся коричневых фаз.
  • –1
    В книжках старины МакКоннелла есть ответы. (Не «Совершенный код», в других в основном).
  • +1
    Чтобы не скатиться к описанной Вами коричневой стадии необходимо вовремя отдавать технический долг.

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

    Также необходимо всегда помнить о принципе разбитых окон.

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

    Но многое, к сожалению, зависит от людей.

    У нас было несколько человек, которые обрабатывали багрепорты следующим образом:
    Они чинили симптомы, в основном по методу добавления костылей в слое пользовательского интерфеса.
    Притом никогда не задумываясь о том, что этот багрепорт может быть симптомом настоящей ошибки.
    Чинить нужно настоящую проблемму, а не симптомы.
    И по мере возможности избавляться от говнокодеров.
    Я говорю о людях, которые принципиально не хотят научиться,
    и как следствие никогда не будут работать правильно.

    Очень важно иметь на проекте хотябы несколько первоклассных программистов.
    Таких, как описано в книге Программист-прагматик. Путь от подмастерья к мастеру.
    • +1
      Еще нужно применять обязательное проведение Code Review.
  • 0
    Я для себя заметил, что хорошая изначально архитектура сваливается в лапшу при недостаточно детальном проектировании. Т.е. проектируешь основные главные фичи, все ровно и красиво, но какая-то мелочь не очень вписывается. Откладываешь её на стадию реализации и в момент когда уже 90% готово, оказывается что эта мелочь не очень-то ложится на архитектуру. Делаешь конечно небольшой костылик (мелочь же) а со временем эта мелочь разрастается в опухоль. Так что мелочей при проектировании нет.
  • +1
    В принципе правильный подход к решению описанной проблемы уже несколько раз в комментариях описывался — постоянно поддерживать простоту кода. Подходы как именно это делать на практике бывают разные, некоторые из них упомянуты в предыдущих комментариях. Я практикую довольно жёсткий подход: даже не пытаться писать сложные задачи. Это не означает что нельзя браться за большие сложные проекты, это означает, что в коде можно воплощать только маленькие простые проекты (обычно их реализация вместе с тестированием, документированием и релизом занимает 2-3 дня, неделю максимум).

    Изначальный большой сложный проект нужно дробить на тривиальные мелкие проектики, изолировать их друг от друга за максимально простыми интерфейсами, и только после успешного завершения этого этапа можно начинать эти мелкие проектики реализовывать. Если в процессе реализации одного из проектов становится понятно, что не такой уж он и простой, и за 2-3 дня его написать не получится — повторить дробление этого проекта на несколько ещё более тривиальных и мелких, точно так же изолированных за простыми интерфейсами. Аналогичный процесс происходит если в процессе добавления новых фич и развития проекта какой-то из мелких проектиков слишком разрастается и усложняется.

    Что прикольно, описанные выше «мелкие проектики» могут быть реализованы в любой форме — как отдельные консольные утилиты, или как сетевые сервисы, или как библиотеки/модули, или как отдельные нити, или как классы… главное, чтобы каждый был реализован простым кодом и изолирован от других «проектиков» максимально простым интерфейсом.
    • 0
      Отдельно хочу добавить по поводу архитектуры проекта — в комментариях выше разгорелся традиционный спор на тему важности правильной архитектуры и невозможности достичь этого на практике.

      При описанном мной подходе с мелкими проектами с простыми интерфейсами архитектура в традиционном понимании практически отсутствует — точнее, она получается очень гибкой и развивается сама собой вместе с проектом. Можно провести аналогию: описываемые мной мелкие проектики это сотни консольных утилит *nix, а проект в целом это большой навороченный конвейер на sh включающий в себя эти утилиты. Когда возникает необходимость изменения проекта в целом, в том числе довольно значительная и не предусмотренная при изначальной разработке архитектуры, это выражается в том, что некоторые проекты выкидываются, некоторые добавляются, некоторые соединяются друг с другом новым образом. Фактически, это довольно сильно изменяет общую архитектуру проекта, но при этом не происходит реального (и обычно очень дорогого) «перепроектирования» архитектуры — она просто динамически подстраивается под изменившиеся требования.
  • –3
    Вот они какие страдания быдлокодера…
    Эх а в универах нет кафедр «софтверинжиниринга»?
    Не учат больше:
    butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod?

    Ставьте Continous integration настраивайте автоматические тесты,
    пишите под тесты. Поставьти метрки качества кода, смотрите на них исправляйте.
    Всегда думайте о структуре пакетов, модулей.
    Не проходите мимо плохого кода, рефакторити его… (хорошие тесты предовратят ошибки).
    Поменайте язык програмирование в конце концов ;)

    Большеи фирмы подходят к этому «профессионально». ;)

    П.С. попрограмируйте на пару с опытным в хорошем дизайне другом. Я знаю не проста таких найти…
    • 0
      ох, не проста…

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.