Как только вы начали бояться своей технологии, вскоре появятся новые причины для страха.

Петля страха затягивается так:

  1. Небольшие правки приводят к непредсказуемым, пугающим или дорогостоящим последствиям.
  2. Мы начинаем бояться изменений.
  3. Мы стараемся делать все правки как можно более мелкими и локальными.
  4. Кодовая база наполняется заплатками, исключениями и особыми случаями.
  5. Страх усиливается.

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

Возникла такая нервотрёпка, потому что разработчик не смог предсказать все последствия изменения. Возможно, набор тестов был недостаточным. Или всплыл особый случай, который наблюдается только в продакшне. (Например, у единственного клиента, чьи настройки данных отличаются от всех остальных). Какова бы ни была конкретная причина, результат такой: «Я не знал, что это произойдёт».

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

Проблема в том, что у такого поведения будут последствия. Неизбежно начнёт ухудшаться кодовая база, нарастать потребность в крупных изменениях и увеличиваться объём рефакторинга в билдах без релиза.

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

Переломный момент


Это может закончиться тремя способами:

  1. Кардинальный рефакторинг кода (обычно с другой командой) под девизом «уж теперь мы сделаем это правильно!» См. также: синдром второй системы и «Что никогда нельзя делать, часть I».
  2. Масштабный аутсорсинг.
  3. Продажа поражённых активов другой компании.

Как избежать петли


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

Трибунал — худшая реакция на неудачу.

Разница между «техническим спецназом» и трибуналом заключается в том, как конкретные люди подходят к этой проблеме. Чтобы избежать петли страха, требуется мудрое руководство. Ищите людей с опытом работы в DevOps и управлении техническими проектами.

Как разорвать петлю


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

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


  1. Dmitri-D
    15.09.2018 01:40
    -2

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


    1. JustDont
      15.09.2018 02:58
      +2

      Если код покрыт тестами, правки не вызывают страха.

      Тесты совершенно не являются «серебрянной пулей» против непредвиденных проблем.


      1. Dmitri-D
        15.09.2018 08:52

        Не вижу возражения, хотя по тону прозвучало именно как возражение. Вы что хотели сказать? Что тесты не нужно делать? Или рефакторинг не проводить? Или что нужно продолжать бояться вносить правки?


        1. JustDont
          15.09.2018 12:32
          +1

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

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


          1. pdima
            15.09.2018 14:58
            -1

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


            1. JustDont
              15.09.2018 15:04
              +2

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

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

              это что-то не было достаточно покрыто тестами

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


          1. Dmitri-D
            15.09.2018 21:33

            Статья может много чего не иметь, но тезис статьи о страхе перед правками. И лечение этого страха — тесты. Если вы не понимаете связь — то я могу сделать вывод только что у вас нет опыта. Ничего, — это то, что со временем может пройти. А пока — можете принять на веру моё утверждение, как человека имеющего 30 лет опыта разработки и дизайна в т.ч. крупных проектов, как в России, так и в Штатах последние 18 лет, что тесты как раз резко снижают вероятность, да, не исключают, но резко снижают вероятность непредвиденных ситуаций после правок кода. Это происходит прежде всего потому, что вы видите, что ломаются именно стандартные ситуации — покрытые тестами и вы не пустите такую правку в production, а будете разбираться в чем дело и кто неправ — тесты или правки. Если сломалось то, что не покрыто тестами, а такое тоже бывает, то вы улучшаете создаете покрытие — в т.ч. и проактивно, анализируя отчеты о code coverage, _до_ возникновения проблем. Но если у вас нет тестов, то вероятность обнаружения проблем резко ниже, или вообще равна нулю. Всё просто.


            1. JustDont
              15.09.2018 23:29

              Это конечно прекрасно, что у вас такой обширный опыт, но почему-то вы так и не хотите понять, о чём вам пишут.

              Тесты и непредвиденные поломки (и следствия из них) — это две разные, никак не пересекающиеся друг с другом вещи. Я наблюдал и нежелание править нетестируемый код, и точно такое же нежелание ничего особо не трогать при наличии огромной охапки тестов за плечами; и все промежуточные этапы. И то, как до апологетов TDD и прочего тестирования постепенно доходит, что тесты не гарантируют, что у них ничего не поломается (а как максимум не поломается только то, что уже когда-то ломалось или то, где поломки предусмотрели). И в конечном счете стремление решать проблемы через костыли (зато мелкие), чтоб не случилось бы чего страшного непредвиденного из-за больших правок — оно всё опять на месте, тесты or no.


            1. tangro
              16.09.2018 21:24
              -1

              Начинается тут про «30 лет опыта» и т.д. Молодой человек, Вы на Хабре, тут каждый первый такой, никого Вы не удивите.

              Почему же Вы не читаете то, что Вам пишут в комментариях? Тесты — это хорошо, но они не помогут от описанных в статье проблем. Условно говоря, вы можете разработать Отвёртку и сделать для неё прекрасные тесты на то, что она откручивает шурупы. И это НИКАК не защитит вас от случаев, когда вашей отверткой решат забивать гвозди, гнуть трубы или засовывать себе в ухо. И вы никогда не предугадаете и не напишете тесты на все эти случаи заранее.


    1. Druu
      16.09.2018 05:29

      Обычно боятся править те, кто не представляет что такое тестирование и как его принято организовывать в 21м веке. Если код покрыт тестами, правки не вызывают страха.

      Это в теории. А на практике просто к исправлению 1000 строк кода добавляется исправление 2000 строк тестов. Что только снижает желание что-то исправлять.


      1. Dmitri-D
        16.09.2018 21:34

        Нет, это не в теории, это как раз на практике. Если у вас не так, то нужно пересматривать что и как вы тестируете.
        Ниже опишу как и что мы делали на одном примере


    1. Habra_nik
      16.09.2018 11:40

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

      Онтопик: Из моего опыта, вероятность наблюдения предложенному нашему вниманию феномена растет со временем; поэтому, одним из способов избежать петли видется дробление проектов на более мелкие ( без фанатизма, конечно ).


      1. Dmitri-D
        16.09.2018 21:46

        Вот самый последний пример. По ряду причин нужно было перенести кусок кода с серверной части сервиса на клиентскую часть. Код, десятки тысяч строк, чрезвычайно сильно переплетен с кодом, который не должен переноситься. Ситуация усложнялась еще и тем, что сервис очень сильно нагруженный — порядка миллиарда запросов в час в гочее время и до миллиарда запросов в сутки в более свободное. Параллельно работает сотня разнообразных клиентских приложений, которые используют действующий API и таким образом вывести в продакшн новый API невозможно без параллельной поддержки старого. И К тому же весь код на С — старый, разработчики начинали его делать в 92м году и в нынешнем виде он существовал примерно с 2003 года. Сотрудники, которые его писали или уже стали боссами или ушли. Документации никакой.
        Т.е. как видите, по современным стандартам грамотно организованной разработки не было.

        Что мы сделали:
        — до моего присоединения к проекту, уже были написаны интеграционные тесты, которые использовали «эталонное» клиентское приложение, довольно популярное среди сотни клиентских приложений, которые работают с сервисом.
        — мы выбрали второе по популярности и добавили его тоже в тестирование. Таким образом наши тесты охватили примерно 50% всех клиентских приложений по количеству запросов.
        — далее я вычленил код из серверной части сервиса и оформил его в виде библиотеки, без зависимостей от серверного кода. Эту библиотеку могли использовать как клиентские приложения, так и сам сервис. Это трудоемкий и долгий рефакторинг. Как только собранный сервис, с этой библиотекой, прошел тесты, мы выпустили его в продакшн на 1 инстансе из балансируемых 10. Убедились что всё идет как по маслу и сбоев нет. Увеличили охват. Тут обнаружили что некий старый процесс, идущий в фоне по таймеру, работает некорректно. Он один использовал некий функционал, который уже был объявлен deprecated и подлежал переписыванию в любом случае, поэтому ему подняли отдельный выделенный instance со старым сервисным кодом. Эта связка будет продолжать так работать, пока мы не перепишем его.
        — тем временем я переписал эталонные приложения с использованием новой библиотеки. Таким образом получился первый клиент, использующий новый API. Мы запустили все тесты как со старым приложением, так и с новым. Т.о. у нас удвоилось количество тестов. Как только тесты прошли, приложение было установлено для обслуживания 1 pipeline. После положительного отклика от группы, кто работает с этим pipeline мы распространили приложение и на другие pipelines.
        — далее для серверной стороны был разработан вспомогательный процесс, который поддерживал и обслуживал старый API и транслировал его в новый API. Т.о. сервис полностью избавился от старого кода. Теперь мы уже запускали 4 набора конфигураций интеграционных тестов — новый клиент с новым сервисом, новый клиент со старым сервисом (как в продашене), старый клиент с новым сервисом и старый клиент со старым сервисом. Как только все тесты показали добро, новый сервис с вспомогательным процессом для поддержки старого API вышел в продакшн. И новый клиент полностью и окончательно был заменен на всех pipelines в продакшене.
        — тесты сокращены до 1 варианта конфигурации — новый клиент с новым сервисом
        — теперь осталось переписать все 100 клиентских приложений — с использованием библиотеки и затем выбросить вспомогательный процесс на сервере.

        Итог:
        — тесты не переписывались. Они были лишь доработаны, чтобы можно было гибко конфигурировать что собирать и тестировать — разные варианты версий сервера и клиента
        — в любой фазе процесса мы были готовы откатить к предыдущему состоянию, на любое количество шагов назад
        — для перехода на следующий шанг у нас было «добро» от системы тестирования
        — переход на следующую версию осуществлялся плавно, с охватом порядка 10% в начале, и с доведением процента до 100.
        — зафиксировано лишь 2 сбоя, не оказавших существенного влияния. Первый — отказ в работе старого (deprecated) приложения, которое и так подлежало переписыванию. Второй — чуть серьезнее — в эталонном приложении обнаружился функционал, не покрытый тестами, который на первый взгляд выглядел как отладочный, поэтому и не был перенесен в новый код. Инцидент был пофикшен довольно просто — тесты расширены, функционал был перенесен, а на время переноса была предоставлена старая версия.

        Совет — стройте интеграционные тесты. Ведите хорошее ясное логгирование всех внутренних операций как на клиенте, так и на свервере. Логгирование должно быть централизованным и позволять обнаруживать сбои в онлайн. Выводите в продакшн плавно. Плюс — не забывайте про систему мониторинга, которая следит за используемыми ресурсами (нагрузка CPU, дисков, памяти и пр) плюс интенсивность работы сервиса — как каждой ноды кластера, так и аггрегированный кластер.

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

        По поводу разделения — это правильный подход. Чем лучше код разделён на независимые куски, тем легче его сопровождать.


        1. Druu
          17.09.2018 00:56

          Совет — стройте интеграционные тесты.

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


          1. Dmitri-D
            17.09.2018 01:42

            Не вижу противоречия. Code coverage не привязан исключительно к unit tests.
            В тестировании middle layer, да и не только, покрытие можно, и я уверен — нужно, изучать. В самом деле — вы же запускаете клиентский код с разными вариантами входных данных. Как понять, что этих вариантов достаточно, и не пропущено что-то существенное? А вот так — по code coverage. Вы видите куда пошло ветвление и куда не пошло. И аналогично на сервере — не лишне проверить, какие варианты реакции и сколько из них попали в тестирование, или другими словами, покрыты тестами.


            1. Druu
              17.09.2018 05:51

              Как понять, что этих вариантов достаточно, и не пропущено что-то существенное?

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


              вы же запускаете клиентский код с разными вариантами входных данных. Как понять, что этих вариантов достаточно, и не пропущено что-то существенное? А вот так — по code coverage.

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


              1. Dmitri-D
                17.09.2018 06:32

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


  1. arilou_camper
    15.09.2018 15:37
    +1

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

    Сначала пришлось «продать» им идею того, что без отдачи технического долга до клинча осталось не так много времени. Потом договорились, что новые фичи делаем с рефакторингом затрагиваемого кода. Потом доказали, что умеем в рефакторинг.

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

    «Петля страха» — отличное название. Возьму на вооружение)


    1. Newbilius
      15.09.2018 19:09

      А как именно "доказали, что умеете в рефакторинг"?


      1. arilou_camper
        15.09.2018 20:01
        +2

        Детальные code review в режиме презентации, юнит и интеграционные тесты.


        1. Dmitri-D
          16.09.2018 03:32

          А вот юный друг JustDont выше утверждает, что тесты никак не помогут )))


          1. arilou_camper
            16.09.2018 08:17

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


  1. xFFFF
    15.09.2018 17:00

    Было нечто похожее. В итоге завершилось рефакторингом всего кода проекта.


  1. lxsmkv
    15.09.2018 23:40

    Люди боятся того, чего не понимают. Если они не понимают, что делает код приложения они боятся вносить в него изменения. Именно «что делает код», а не «как работает эта языковая конструкция». Конструкцию понимает большинство, а вот как ее изменение повлияет на работу всей системы — в состоянии понять не многие.

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

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

    Все вы видели, и это не легенды, беспорядочно подключенные серверные стойки, рапределительные щитки с клубком проводов внутри — все это пример пофигительского отношения к профессиональным обязянностям. Так не надо так делать. Я понимаю это всегда «кто-то другой» так делает, а мы сами никогда.

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

    Я где-то помниться читал такое, что в НАСА при разработке запрещают определенные языковые конструкции. Отличная практика. Запретить использовать определенных конструкций языка. Вы удивитесь, как это много дает. Всегда хочется впихнуть где нибудь лямбду. Но потом думаешь о тех, кто ее может не понимать — и отказываешься. Всегда хочется назвать переменную X, но подумаешь и называешь по назначению.

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

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

    Короче, будьте менее халатны и будет вам счастье. Основательность в работе занимает не сильно больше времени.


    1. sena
      16.09.2018 00:15

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


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


      1. Dmitri-D
        16.09.2018 04:02

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


        1. sena
          16.09.2018 04:53

          Это большая роскошь — покрывать тестами код, который будет вскоре выброшен или кардинально переделан.


          Нет, мы покрываем тестами то, что необходимо в процессе переработки.


          1. Dmitri-D
            16.09.2018 05:16

            Речь не о unit tests, поэтому не совсем так.
            Вы покрываете use-cases, т.е. варианты использования софта. В новой версии все use cases остаются прежними.


            1. sena
              16.09.2018 10:21

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


              1. Dmitri-D
                17.09.2018 01:55

                ведь тестирвание нужно делать в любом случае

                Вот вам и мне — это очевидно.
                Но посмотрите другие ответы — там уже видно, что это не всем очевидно. И задумайтесь на секунду, откуда страх правок если всё хорошо тестируется? Ну сломали что-то, тесты покажут что сломано. Чего бояться? Продакшн не пострадает.

                покрыть тестами все возможные юзкейсы в нашем случае тоже невозможно

                Все возможные — невозможно, во всяком случае за разумное время. Тут требуется искуство. Расскажу как мы это делаем. Во первых у нас централизованное логгирование. Т.е. мы знаем какие функции когда и кем вызваны. Во вторых — у нас есть аггрегаторы логов, которые позволяют сделать, ну скажем group by, по логам. Сразу видно какие функции наиболее часто используются. Их мы тестируем подробнее в первую очередь. В логгировании есть параметры вызова. Эти параметры тоже аггрегируются и в первую очередь тестируем более частые варианты.
                Разумеется, это не дает покрытие всех возможныйх use-cases, но 90% вызовов попадают в 10% функций и из в этих функциях 90% вызовов попадают с 10% вариантов параметров. Т.е. вся эта беконечность use-cases довольно хорошо коллапсирует на практике. Вот по этой статистике мы и формируем тестирование.
                Это не идеальное решение, всегда есть риск что-то проспустить. Поэтому, кроме тестирования, мы делаем частые релизы. Мы всегда готовы быстро откатить новую версию назад в случае инцидента. После чего вариант создавший инцидент — обязательно попадает в тесты. Да — инциденты неприятны, но по мере роста объма тестов частота инцидентов становится почти ноль.


                1. Druu
                  17.09.2018 05:54

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

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


                1. sena
                  17.09.2018 11:19

                  Вот вам и мне — это очевидно.
                  Но посмотрите другие ответы — там уже видно, что это не всем очевидно. И задумайтесь на секунду, откуда страх правок если всё хорошо тестируется? Ну сломали что-то, тесты покажут что сломано. Чего бояться? Продакшн не пострадает.

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


        1. lxsmkv
          16.09.2018 07:08

          Писать тесты для кода устройство которого мало понятно, вероятно приведет к тому, что тесты будут написаны на те части кода, которые вы понимаете. А труднодоступные для понимания, неочевидные, глубоко лежащие вещи так и останутся вне поля видимости. Это чем-то сродни «систематической ошибке выжившего».

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


          1. Dmitri-D
            17.09.2018 02:14

            тесты будут написаны на те части кода, которые вы понимаете

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

            Сделать так, чтобы разработчикам было удобно его писать

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


          1. guility
            17.09.2018 09:35

            Это, кстати, очень важная штука, о которой повсеместно забывают.
            И тут речь не только о работе архитектора, но и о работе PM-а/TL-а, т.к. разработчик, который пишет код, в достаточно большом проекте единовременно может или охватить головой реализацию конкретной функции, или охватить её смысл в рамках проекта(а иногда в принципе этого не может, т.к. не обладает необходимыми познаниями в части технологического стэка). Точно также, как PM/TL/архитектор не может охватить реализацию конкретной функции.
            В своей работе сейчас сталкиваюсь с этим.
            В идеале, должно получаться разделение труда: Архитектор/PM/TL продумывает разделение решения на модули, каждый из которых решает конкретную задачу. На каждый из этих модулей составляется ТЗ/req.list, после чего разработчик уже не думает о том как этот модуль будет взаимодействовать с остальной системой — он думает о том, как наиболее эффективно и красиво реализовать функционал.

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


  1. dim2r
    15.09.2018 23:44

    Из опыта могу дать такой совет: иметь возможность деактивации правки на проде через настройки.

    if feature_enabled then
    do_new_action;
    end if


    1. Dmitri-D
      16.09.2018 03:58

      Фичи как правило слишком сильно переплетены. Отключение одной может привести к нежелательным накладкам. Поэтому выключение фич — это рискованно, особенно если все варианты перебора включения-выключения не протестированы. К тому же вам нужно держать и новый и старый код, т.е. ваш if совсем не только c then, но и с else. И это довольно сильно загромождает код. Т.е. да, пробовали так, но не удобно.
      Насколько я вижу, в крупных компаниях практика другая. Я опишу с упрощениями, чтобы не загромождать идею слишком большим количетсвом подробностей. Переключают версии. Т.е. kill-switch, о котором вы говорите — да, он есть, он нужен, но реализуют его централизованно и над приложениями, а не внутри них. Если это онлайн сервис, то новую версию вводят постепенно. Это означает, что существует механизм, который делает новую версию доступной только для небольшой части клиентов — например по их IP. Мониторят сбои — как автоматически, например по логам, так и через каналы обратной связи. Если в течение достаточного промежутка времени, а он известен из практики, сбоев нет, то увеличивают процент охвата. И так шаг за шагом вплодь до 100%. Но если есть проблемы — убирают версию, т.е. сокращают ее присутствие до нуля и информируют девелоперов и тестировщиков (девелоперов, пишущих тесты). Это автоматический процесс. Вмешательство человека, если и есть, то минимально. Далее пишут тесты на выявленные недостатки, и ждут девелопмент. Затем выкатывают новую верстю после того как она проходит все тесты, включая новые. Это цикл релизов, если простите мне упрощения, known as CI/CD (continuous integration, continuous delivery). Рекомендую. Почитайте.


      1. dim2r
        16.09.2018 11:22

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


        1. Dmitri-D
          16.09.2018 21:51

          Делайте чаще релизы.
          Тогда в каждый релиз будет попадть меньшее количество правок и а) будет меньше вероятность необходимости отката назад и б) сам откат, в случае необходимости, будет более безболезненный
          CI/CD — это всё вокруг частых релизов. Можно и без полного CI/CD всё сделать. Просто автоматизируйте как deployment новой версии, и так откат на старую. Частые релизы станут менее трудозатратными.


  1. zmejg
    16.09.2018 11:40

    Почему-то все 3 способа, приведённые автором в переломном моменте, подразумевают несчастный финал, особенно если пройти по ссылкам далее. Вывод тоже неутешительный.
    У нас в компании с одним веб-проектом была похожая ситуация, когда код, полученный от аутсорсеров после сдачи бизнесу фактически нельзя было ни развивать ни нормально править на месте.
    Первая реакция местных программистов была именно такая — «выкинуть и всё переписать с нуля», но объём проекта и сроки, данные на исправление от такого шага оградили. Наверное произошло то, что кто-то назвал «масштабным рефакторингом», хотя в нашем случае мы просто «выкинули всё ненужное и непонятное». Сократили в результате код на 25% одновременно улучшив лог и управление исключениями. Всё, что касается бэкенда получилось на мой взгляд неплохо — тесты уже прошли, релиз через 2 дня. Вот с фронтендом ситуация намного хуже. Боюсь, что там придётся таки идти на шаг «переписать всё с нуля» — уж больно динамичен характер мира фреймворков для веба, особенно когда стандартные компоненты типа Vue, VueMaterial смачно сдабриваются сторонними и кастомными компонентами.


    1. JustDont
      16.09.2018 12:43

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

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


      1. zmejg
        17.09.2018 08:07

        Пока не сдался последний разработчик, есть шанс, что плохой финал во всяком случае отодвигается на неопределённо долгий срок. Тут можно подойти с философской точки зрения и подумать о том, что наверняка лет через 10-20, даже при наличии постоянного интереса к продукту, его невозможно будет оставить на той базе и в том виде, что он есть сейчас. Всё равно переписывать :)


  1. dimoff66
    16.09.2018 20:13
    +1

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

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


    1. dimoff66
      16.09.2018 20:22
      +1

      Соответственно ответ на вопрос

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


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


      1. Dmitri-D
        16.09.2018 22:24

        У сотрудников, которые уже давно работают и привыкли работать по-старинке — да, довольно часто распространен синдром страха перед кодом. Но это из-за предыдущих ошибок, которые привели к проблемам в пролдакшене, с кризисами, с прибегающими менеджерами с выпученными глазами (но без слюней и без криков — у нас достаточно просто выпученных глаз), с массивными перелопачиваниями в базах — и всё после работы некорректной новой версии. По-моему все на такое наступают, если нет правильного процесса разработки. Из новичков — тоже вполне бывает что-то разламывают, но скорее по неопытности. Из курьезов — не поверите — но даже в 2001 я влился в один коллектив, где я так и не смог никого убедить что нужен source control. Не говоря о тестах. Правили у себя локально и сразу ручками отправляли в продакшн. Я не смог там задержаться дольше полутора лет.
        Но махать шашкой и увольнять — я как-то не вижу такой практики. Организовать процесс — можно или отправив главных разработчиков на тренинги или наняв консультантов. Чаще вижу второе. Того кто не знает как пользовать гитом — научат пользоваться гитом. Того кто не знает как писать интеграционные тесты — научат писать интеграционные тесты. Того кто не знает что такое скрам и стендапы — научат и этому. Для менеджмента отдельные тренинги. Для разработчиков — уже с оттренированными менеджерами. Это работает хорошо, если конечно консультанты хорошие. Хотя тоже не без курьезов ))) Но они смешные.


        1. dimoff66
          17.09.2018 08:31

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

          У меня нет ощущения, что верные технологии это панацея. Верные технологии в руках неправильных людей будут нести все тот же отпечаток страха, формализма и(или) раздолбайства. Тесты будут писаться на «отвали» и т.д. Про «скрам и стендапы» вообще молчу, подход, который хорош для бойскаутских лагерей, применять в программировании — решение очень незрелых людей или ДЛЯ очень незрелых людей. К сожалению когда болезнь становится массовой, ее начинают считать за норму, лично я никогда в жизни больше не буду работать в компании, где используется скрам и стендапы, при этом у меня нет ни малейшего страха кода, я всегда анализирую существующий код и делаю его рефакторинг, если он не оптимален независимо от наличия-отсутствия тестов. У меня есть глаза, я вижу что делает код, я вижу какие участки он затрагивает и т.д.