8 апреля 2019 г.

Разбитые окна

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

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

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

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

Причем (это уже я рефлексирую про себя) это работает на полу-автоматическом уровне: не только я сознательно выбираю “аккуратные” решения, а еще на стадии бессознательного поиска мозг уже чаще подсовывает решения соответствующего типа. Если вокруг все сделано аккуратно, изящно и продумано — кривые решения просто реже приходят в голову, и наоборот.

(Это, конечно, статистическое утверждение — кривые решения реже приходят в голову в хорошем окружении, но все-таки приходят)

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

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

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

  1. Согласен. Сам наблюдаю это в ежедневной практике. Как кто то небрежно закоммитил код с варнингами компилятора так после него и понеслось. И через неделю в коде уже 1000 ворнингов

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

      Удалить
  2. "Without refactoring, the internal design—the architecture—of software tends to decay. As people change code to achieve short-term goals, often without a full comprehension of the architecture, the code loses its structure. It becomes harder for me to see the design by reading the code. Loss of the structure of code has a cumulative effect. The harder it is to see the design in the code, the harder it is for me to preserve it, and the more rapidly it decays. Regular refactoring helps keep the code in shape." Martin Fowler

    ОтветитьУдалить
    Ответы
    1. Да, это близкие вещи. Вообще, я этот пост давно хотел написать, но все откладывал, именно потому, что казалось, что это настолько тривиально, что любому человеку с опытом хотя бы в несколько лет это должно быть очевидно.

      Но во-первых регулярно оказывается, что -- нет, не очевидно.

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

      Удалить
  3. Мы побеждаем это так:
    - в IDE включены все warnings компилятора и нельзя коммитить код в ветку, если есть warnings
    - в gradle прописан плагин spotless, который проверяет стиль, согласно шаблона
    - при коммите Jenkins тоже запускает этот spotless плагин и если spotless замечает несоответствеи билд фейлится и значит ветка при ревью считается не готовой к слияню в главную ветку
    - в Jenkins есть еще FindBugs плагин, который делает статический анализ кода на элементарные и не очень ошибки. если он что то находит в ветке, билд фейлится и ветка не готова к коммиту
    - то же самое насчет compiler warnings - если их количество превышает порог - то билд фейлится. мы предпочитаем zero tolerance - и поэтому билд фейлится даже при 1 warning
    - ну и конечно время от вермени чисткой занимаемся по принципу скаутов - "оставь место привала чище, чем ты его нашел до привала"

    ОтветитьУдалить
    Ответы
    1. Вот интересно, что в статье про теорию разбитых окон как раз подчеркивают, что посыл broken window часто воспринимают как призыв к zero tolerance: все наглухо запретить, и жестко карать.

      И это (с точки зрения авторов) неверно: ТРО фокусирует внимание на том, что бы транслировать (через среду обитания) сообщение "у нас тут сплоченное сообщество, следящее за своей средой обитания и члены сообщества добровольно соблюдают принятые нормы поведения".

      А zero tolerance транслирует сообщение "у нас тут жесткое сообщество, со своими правилами, и если вы не согласны, то лучше сразу идите нахуй, а то будет хуже"

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

      То, что ты описываешь -- больше похоже на второй вариант. Я сам, честно говоря, больше склонен к первому. То есть вот "после меня лучше чем до меня" -- это да, это я тоже стараюсь постоянно делать. А вот остальное надо пристально смотреть (хотя FindBugs у нас тоже включен)

      Удалить
    2. Мне кажется пример с разбитыми окнами полезен но имеет свои границы аналогии. Если уже применять его к разработке по то лучше подойдет аналогия со строительством: ведь в обычном коммьюнити вы не выбираете кто там живет и бьет окна и бросает окурки. А в программерской команде как и в строительной бригаде все же людей отбирают по каким тотправилам. Так вот если на стройке кругом мусор инструмнт не на месте раствор замешивают не по технологии плюют на кривую кладку кирпича лазают по лесам без касок и работают без страховок то не удивительно что дом такой пойдет трещинами и рухнет еще на стадии строительства. Соотвественно на стройке всегда присутствует техника безопасности культура производства и контроль без которых просто нельзя построить качественный дом. Именно здесь работает такое: не хочешь работать в каске и со страховкой - вали со стройки, не желаешь пользоваться визиром и класть кирпичи по веревочке - иди на улицу мести тротуары.

      Zero tolerance в нашем проекте обеспечивается автоматически: никто не стоит над душой программиста и не корит его что вот тут у тебя косяк а вот тут ты null pointer exception вставил. Весь код проверяется автоматически и у всех кто коммитит код - без перехода на личности. Это ка во властелине колец You shall not pass! Накосячил - исправь сам облегчи работу своим коллегам и тем кто будет делать ревью. По-моему справедливо и не обидно.

      Вам в статью надо ссылку на книгу Clean Code поставить. В качестве рекламного баннера. И вам профит и люди почитают где ваша справедливая мысль красной строкой через все главы проходит

      Удалить
    3. Если говорить в терминах примера со стройкой, то мой поинт вот про что: если на стройке кирпичи свалены кучей, и строительный мусор валяется -- то на такой стройке _вероятнее_ будут и технику безопасности нарушать (хотя как раз на такой-то стройке она особенно важна!). И раствор не по нормативам замешивать (хотя казалось бы -- как связь между технологией замешивания раствора -- и грудой кирпичей?). Вот в этом состоит утверждение ТРО (как я его понимаю).

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

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

      А clean code, мне кажется, и так все знают -- кому вообще эта тема хоть чуть-чуть интересна. Нет смысла мне его рекламировать

      Удалить
  4. Написано хорошо. В комментариях почему-то ударились в частности - FindBugs, etc. Код может проходить проверку FindBugs, но быть костыльным.

    ОтветитьУдалить
    Ответы
    1. Да, мне тоже кажется, что несколько не в ту сторону дискуссия пошла. Наверное, я все-таки плохо раскрыл тему.

      Удалить