Про Agile на пальцах. Путь к быстрой разработке.

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

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

Мое первое знакомство с Extreme Programming

На одном из проектов, в одну из наших бэкенд-команд пришел новый парень. Он взял себе тикеты, которые позволяли ему в определенной мере абстрагироваться от унаследованной кодовой базы, сколотил свою собственную небольшую кодовую базу, и в одиночку начал работать в два раза быстрее, чем работала команда из трех человек. Почти в 6 раз быстрее любого другого разработчика. И это при том, что у нас работали далеко не последние разработчики, и компания была достаточно известной. А поскольку, как говорил Martin Fowler, экономика всегда побеждает, пришлось разбираться в причинах такого отрыва.

Этот парень использовал на то время лишь ограниченный сегмент практик Extreme Programming (XP) - наиболее эффективной и одной из первых Agile-методологий. Все что он использовал - TDD, Evolutionary Design, принципы SOLID, из которых особый упор был на Single Responsibility Principle (SRP), а также активно использовал Type Hinting для автоматического рефакторинга, поскольку язык был с динамической типизацией.

Именно так я и познакомился впервые с Extreme Programming, вернее, с его неоспоримым превосходством даже в столь урезанном виде. Под настоянием этого парня я прочитал свою первую книгу в области качества кодирования - Clean Code, и с этого началось мое становление специалиста в области проектирования программного обеспечения.

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

Итак, как нам это удалось, и почему до этого мы не могли работать эффективно?

Умственная природа человека

Кент Бек как-то сказал, что труднее всего работать в Agile-разработке докторам наук. Причина в том, что чем выше интеллект человека, тем больше ему свойственно продумывать всю задачу наперед, охватывать умом всю реализацию, от начала до конца (upfront thinking), еще до начала ее реализации.

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

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

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

  • Single Responsibility Principle (SRP)
  • Качественное проектирование кода, позволяющее отложить решение о конкретной реализации. Декларирование качественных интерфейсов важнее конкретной реализации.
  • Обеспечение автоматического рефакторинга: расстановка Type Hinting для динамических языков программирования, покрытие кода тестами, использование средств автоматизированного рефакторинга.
  • YAGNI - реализация только того, что требуется текущей задачей, без предположений о том, что нам потребуется в будущем, т.е. ничего не реализуется “впрок”. Существует простая лакмусовая бумажка принципа YAGNI: “выделение лишних абстракций (и любое другое усложнение) оправдано лишь в том случае, если стоимость их выделения в будущем будет существенно дороже, чем сейчас”.

Из перечисленного, второй принцип “Качественное проектирование” очень важен, и ниже я расскажу почему. Но сперва об Agile-разработке.

Смысл Agile-разработки

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

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

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

Суть Agile-разработки заключается в том, чтобы изменить этот экспоненциальный график стоимости изменения кода на плоский и горизонтальный (насколько это возможно), приближенный к горизонтальной асимптоте. Если проект равно одинаково легко изменить в любой момент независимо от объема кодовой базы, то это значит, что нам не нужно проектировать его заранее (т.е. нет необходимости в upfront design)! Вот в чем заключается смысл слова “гибкий” (agile)!

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

В свое время Кент Бек сказал, что если плоский график стоимости изменения кода делает XP возможным, то крутой график делает его невозможным.

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

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

Как вы думаете, каким вопросам посвящена книга “Agile Software Development. Principles, Patterns, and Practices.”, написанная в 2002 году Robert C. Martin, который в 2001 году организовал встречу группы, подписавшей Agile Manifesto? Сколько в составе этой группы было выдающихся архитекторов того времени? Какую основную проблему подчеркивает Dave Thomas, автор “The Pragmatic Programmer” и один из создателей Agile Manifesto?

Изначально Scrum содержал технические практики заимствованные из XP. Однако, позже решение о выборе конкретного набора технических практик было отдано на откуп самим разработчикам. Они считали, что это сдерживает проникновение Scrum в массы. Именно поэтому, Scrum - это не методология, а framework (каркас, скелет), на который еще необходимо нарастить практики. К сожалению, из Scrum удалили именно то, что поддерживает стоимости изменения программы низкой и делает Agile-разработку возможной. Одним из вариантов решения этого вопроса является комбинация Scrum и XP. На практике же разработчики не уделяют этому вопросу должного внимания, и часто вообще не используют никаких технических практик, превращая Scrum в обычный Waterfall с итеративным планированием, но при этом рост стоимости изменения кода не позволяет сделать разработку гибкой.

Нужно заметить, что разработчики редко получают правильное представление о Scrum из первоисточника. Поэтому я здесь приведу несколько жизненно-необходимых ссылок:

На Русском:

Очень хорошая интерактивная шпаргалка: Subway Map to Agile Practices.

Причины возникновения Agile-разработки

Возникновение Agile-разработки обусловлено стечением ряда факторов.

Во-первых, обрели популярность объектно-ориентированные языки, предоставляющие более высокие возможности по управлению сложностью кода. Ключевую роль здесь сыграл Smalltalk.

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

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

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

В-пятых, начала вызревать архитектура приложения. Большое влияние оказали работы Bertrand Meyer, Ivar Jacobson, Martin Fowler и др. Вскоре после подписания Agile Manifesto, вышло в свет наиболее полное руководство по архитектуре приложения - “Patterns of Enterprise Application Architecture” by Martin Fowler. Как сказал Ralph Johnson, архитектура - это коллективное понимание устройства системы. И это был, наверное, самый серьезный удар по стоимости изменения программы. Оценить коллосальное влияние этой книги в масштабах индустрии можно на примере web-framework Ruby on Rails, созданным David Heinemeier Hansson на ее основе. На то время Ruby on Rails произвел революционный скачок темпов разработки в 5-6 раз (несмотря на то, что архитектура этого web-framework содержала определенные спорные и критикуемые решения). Мгновенно появилось множество его клонов на различных языках программирования.

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

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

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

Я намеренно не затрагивал многие исторические моменты, чтобы выделить важное. Если интересна более подробная история развития итеративной разработки (начиная с 1930 года), то вы можете посмотреть ее в статье “Computer Iterative and Incremental Development: A Brief History” by Craig Larman.

Качество проектирования

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

Проектирование диктуется психологией, законом магического числа семь плюс-минус два , согласно которому кратковременная человеческая память, как правило, не может запомнить и повторить более 7 ± 2 элементов.

Еще во времена процедурного программирования возник принцип Low Coupling & High Cohesion, нацеленный на то, чтобы снизить концентрацию сложности кода и удовлетворить закон магического числа семь, т.е. исключить переполнение мозга.

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

Coupling (Сопряжение, Зацепление) - это показатель того, насколько класс осведомлен о стороннем поведении.

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

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

Подробнее смотрите в статье “Coupling And Cohesion”.

Именно для снижения Сопряжения и предназначены многие паттерны проектирования. Хорошая новость заключается в том, что паттерны проектирования предназначены для снижения сложности программы, и именно так их и следует использовать. Этому вопросу посвящена статья “Is Design Dead?” by Martin Fowler. Качество программного кода измеряется именно уровнем его сложности, а не изобилием паттернов проектирования (что является частым заблуждением новичков, которым нетерпится продемонстрировать свои новые навыки). Плохая новость заключается в том, что паттерны знать нужно, и паттернов очень много - Design Patterns, PoEAA, DDD Patterns, Cloud Design Patterns, Service Design Patterns, Enterprise Integration Patterns, Analysis Patterns, Concurrency Patterns, POSA, DSL Patterns, Microservices Patterns, Architectural Patterns, XUnit Test Patterns, TDD Patterns, и другие.

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

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

А во-вторых, помните что Дейкстра говорил о строго ограниченных размерах человеческого черепа? Воспроизвести в одиночку эволюцию целой индустрии - это весьма самонадеянно. Жизни не хватит. Можно, конечно, попытаться изобрести колесо, и в одиночку обобщить и систематизировать весь совокупный опыт индустрии, и, если человек обладает умом Эриха Гаммы или Мартина Фаулера, и посвятит этому вопросу половину жизни, то у него может даже и получиться. Вот только совокупный опыт индустрии выражается, опять же, в литературе. Так что - никак.

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

Игнорирование теории по сути является проявлением “Культа Карго”. Еще одним ярким примером игнорирования теории является эпизод о том, как нарисовать 7 перпендикулярных линий игнорируя геометрию, из известной короткометражки “The Expert” (оригинал).

Теория также играет важную роль в формировании коллективного понимания того, как устроена система, что существенно снижает порог вхождения нового разработчика в проект, смягчая негативное воздействие Закона Брукса.

Другая крайность при работе с литературой заключается в чрезмерном перегибе, который приводит к подсознательному отторжению этого процесса. Чтобы стать хорошим специалистом, достаточно читать 5 страниц в день, по крайней мере так говорит один из известнейших авторитетов в области IT-индустрии Steve McConnell. И желательно работать с первоисточниками. Если Design Patterns - значит GOF. Если рефакторинг - значит Martin Fowler. И т.д.

Сегодня в мире ООП принцип Low Coupling & High Cohesion известен благодаря принципам GRASP, однако его функции в значительной мере взяли на себя такие понятия как Абстракция и Инкапсуляция.

Удивительно, но большинство разработчиков не понимают этих базовых вещей, что приводит к написанию tricky code и Big Ball of Mud. Именно поэтому, я рекомендую начинать путь специалиста в области проектирования не с книги “Clean Code”, а с книги “Code Complete” 2-d edition by Steve McConnell, которая дает глубокое понимание базовых фундаментальных понятий.

В наши дни базовые принципы качественного проектирования хорошо известны под акронимом SOLID.

Заимствование проблем

Разработчикам свойственно “брать в долг” проблемы, т.е. решать проблемы полагаясь на предположение о том, что это решение когда-нибудь понадобится в будущем. На самом деле, очень часто такие решения остаются невостребованными, и просто потребляют ресурсы на разработку, сопровождение и понимание возросшей сложности программы. Математическое обоснование этой проблемы (с приведением к процентной ставке) Kent Beck приводит в книге Extreme Programming.

Решением этой проблемы является уже упомянутый ранее принцип YAGNI.

Кто будет читать код?

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

Истина в том, что при написании кода, разработчик 90% времени именно читает код, и только 10% времени он вводит символы с клавиатуры. Пишет код он в одиночку и лишь единожды. Зато читают код все разработчики команды и много раз. Таким образом, плохо написанный код на 90% влияет на снижение темпов разработки всей команды.

Хорошая программа должна читаться, а не пониматься. Если Вы вынуждены изучать реализацию программы - то у программы есть проблемы. А если Вы не можете понять реализацию программы без помощи отладчика - то у программы серьезные проблемы.

В хорошей программе достаточно открыть файл с декларацией публичных интерфейсов (даже если используется язык с динамической типизацией), и этого должно быть достаточно, чтобы понять что делает программа. Если этого не понятно, то интерфейсы следует улучшить. Программа должна выражать “ЧТО” она делает, а не “КАК” она делает непонятно что.

Самотестируемый код

На самом деле, без тестирования просто невозможен рефакторинг, а значит, невозможен и Evolutionary Design. А без Evolutionary Design разработчик возвращается к засасывающей воронке времени под названием upfront thinking.

Однако, есть и другие причины использовать тестирование, причем, желательно в стиле TDD.

  1. Тестирование повышает качество кода, т.к. разработчику легче изначально написать слабо сопряженный код (Low Coupling), чем ломать голову над тем, как протестировать код с высоким сопряжением (High Coupling). С целью достижения наибольшего эффекта, желательно ограничить использование автоматизированных средств создания Mock-объектов, так как они упрощают тестирование плохо спроектированного кода.
  2. TDD повышает качество интерфейсов, т.к. мы продумываем интерфейс изначально с точки зрения его использования, и используем этот интерфейс еще до реализации. Вы, наверное, обращали внимание на то, что, при итеративной разработке, представитель бизнеса всегда получает более ясное представление об User Interface после того, как впервые попробует его использование. Здесь то же самое, только интерфейсы программные.
  3. Тестирование устраняет страх очищать кодовую базу и исправлять ошибки в коде. Т.е. придает уверенность разработчику. Без этого просто невозможен процесс Model Distilling, т.е. улучшение качества бизнес-моделирования по мере переработки знаний. Подробнее этот вопрос раскрывается в DDD.
  4. TDD устраняет засасывающую воронку времени под названием перфекционизм, т.к. существует очевидное условие, выполнение которого свидетельствует о решении задачи.
  5. Тестирование исключает использование отладчика. А отладчик отнимает значительно больше времени, чем написание тестов. К тому же, в отличии от использования отладчика, время для написания тестов прогнозируемо.
  6. Тесты - один из лучших способов документации кода.
  7. Инверсия стресса, что увеличивает работоспособность.
  8. TDD концентрирует внимание на решении только одной осязаемой обязанности. Снижает нагрузку на мозг и обеспечивает более высокие темпы разработки.

Несмотря на то, что при TDD разработчик пишет больше кода, он имеет более высокие темпы разработки. Основное время занимает не сам ввод символов с клавиатуры, а обдумывание предстоящей структуры кода. TDD вырабатывает привычку изолировать в голове только одну осязаемую обязанность кода в единицу времени, и думать только о ней вплоть до момента ее реализации. Как песочные часы.

Это можно сравнить с работой хирурга, проводящего операцию. Фактически все тело оперируемого пациента укрыто специальной простыней, за исключением того места, в котором осуществляется операция. Внимание хирурга должно быть сфокусировано, чтобы он имел дело с фиксированным набором переменных. Хирург не должен думать о всех органах одновременно (смотрите главу “Isolate Change” of “TDD by Example” by Kent Beck).

Т.е. эта методика учит не загружать в голову сразу много. Учит управлять сложностью. Благодаря такому снижению нагрузки на мозг, разработка продвигается в разы быстрее, особенно в сочетании с Помидорным Методом.

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

К тому же, тестирование практически полностью исключает из рабочего процесса такого монстроидального пожирателя времени как “отладчик”.

Оценивание задач

Многие разработчики не понимают разницы между оценкой (estimate) и обязательством (commitment). А также не понимают разницы между планированием и предсказанием. Это приводит к стрессу. Разработчик боится плохо выглядеть, и врет про estimates. Затем боится не выполнить estimates, и работает сверхурочно (что, кстати, претит Agile практикам). Работает сверхурочно - теряет работоспособность, не развивается, и совершает много проектных ошибок, которые с эффектом “положительной обратной связи” (т.е. “вразнос”) ухудшают прогнозирование estimates, что, как снежный ком, ведет к экспоненциальной эскалации напряженности.

Истина в том, что рост стоимости оценки имеет экспоненциальную зависимость от ее точности, а рост бизнес-выгоды от точности оценки - линейную зависимость. Все дело в соблюдении баланса выгоды от точности оценки и затрат на нее. Как правило, на оценку отводится не больше 5% от времени итерации. И точность здесь не критична. Задача планирования - помочь бизнесу грамотно управлять бизнес-рисками. И чем раньше бизнес будет осведомлен об отклонении от плана, тем раньше он сможет принять бизнес-меры. Вот почему честность - ключевой критерий профессионального разработчика.

Именно поэтому в Planning Poker обычно используется ряд Фибоначчи - нет смысла оценивать предмет с точностью выше, чем погрешность оценки. А погрешность тем выше, чем выше объем задачи.

Более подробно эта тема раскрывается в книге “Clean Coder” by Robert Martin. Эта книга сложна для чтения в оригинале, и многим будет легче читать ее русский перевод (который достаточно качественный) под названием “Идеальный Программист”. Также будет полезным этот видеоролик “Effective Estimation (or: How not to Lie)”.

Существует несколько превосходных книг, посвященных вопросам estimates. Например:

  • “Software Estimation: Demystifying the Black Art (Developer Best Practices)” by Steve McConnell (я встречал в интернете краткий конспект)
  • “Agile Estimating and Planning” by Mike Cohn

Но я не вижу смысла уделять внимания изучению оценки предмета больше, чем изучению самого предмета. Лаконичной информации, предоставленной Robert C. Martin, вполне достаточно для большинства разработчиков.

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

А между тем, четырехкратная оптимистичность ошибки оценки, по статистике приводимой Steve McConnell, является среднестатистической. Ошибаться - это нормально. Единственный способ получить точную оценку - это реализовать задачу.

Искусственно завышая сложность проекта, разработчик ставит сам себе же ловушку в будущем, запуская процесс с “положительной обратной связью”. Из-за чего прогнозируемость оценок стремительно падает.

Преждевременная оптимизация

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

В общем, оптимизировать нужно исключительно в соответствии с Законом Парето (80/20) и только то, что измерено профайлером и представляет собой реальную проблему. И желательно делать это на уже стабилизированной кодовой базе, чтобы потраченные усилия не оказались выброшенными из кода через пару недель.

Сражения мнений

Code Review - мощный инструмент, который часто используется далеко не на полную силу.

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

Если вы уже знакомы с Agile-разработкой, то понимаете, что без Collaborative Development не может быть и речи о Collective Ownership. К первому относятся Парное Программирование, Формальные Инспекции (Formal Inspections), Анализ Кода (Walk-Throughs) и Чтение Кода (Code Reading). Чтение Кода похоже на Code Review, но ориентировано на распространение знаний, поэтому является коллективным мероприятием, и должно вовлекать хотя бы 2-3 человека помимо автора. Кроме того, около 90% ошибок обнаруживается самим автором на этапе подготовки к Чтению Кода. Часто это единственная доступная форма of Collaborative Development, так как заказчик не часто соглашается на Парное Программирование.

Во всех случаях нам удавалось перевернуть отношение к Code Review, и впоследствии обиду вызывало уже не Code Review, а, наоборот, нежелание коллег ревьюировать Pull Request. По мере роста участников команды в вопросах проектирования, Code Review стало своего рода площадкой для демонстрации достижений. Обычно после создания Pull Request каждый разработчик просил в командном чате о проведении Code Review, и если находилось мало желающих, то это воспринималось как то, что разработчик никого не заинтересовал своим кодом. Для мержа Pull Request требовалось минимум 2 одобрения.

Для этого переворота было достаточно решить 2 проблемы.

1. Сражения мнений (или даже ЧСВ). Это невероятный пожиратель времени и отравитель морального климата. Мы решили эту проблему тем, что ввели в обиход каталоги Code Smells. Есть три популярных каталога.

  • Chapter 17: “Smells and Heuristics” of the book “Clean Code: A Handbook of Agile Software Craftsmanship” by Robert C. Martin
  • Chapter 3. “Bad Smells in Code” of the book “Refactoring: Improving the Design of Existing Code” by Martin Fowler
  • Каталог Code Smells на сайте of Ward Cunningham

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

2. Вторая проблема - это большой расход времени на объяснения и обучения в процессе Code Review. Решили эту проблему просто - заставили работать книгу вместо себя. На Code Review вместо длительных разъяснений просто бросали ссылку на нужный метод рефакторинга по каталогу рефакторингов:

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

Code Review, которое раньше могло длиться весь день, теперь сжалось до 10 минут. Буквально за пару месяцев качество кода и квалификационный уровень команды поднялись в разы, как и общекомандный velocity.

Также полезны каталоги для рефакторинга БД:

В итоге Code Review стало вполне приятной процедурой, которая повышала темп разработки, а не тормозила его.

Баланс бизнес и технических интересов

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

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

Страхи

Еще одним из ключевых поедателей времени являются страхи. Разработчики боятся показаться некомпетентными, и боятся спрашивать, расходуя кучу времени на неудачные решения. Разработчики боятся показаться медлительными и обманывают с estimate. Разработчики боятся нарушить план разработки и приносят в жертву внутреннее качество программы, тем самым еще больше затягивая петлю. В общем-то, страхи являются одной из основных решаемых задач Agile-разработки, о чем свидетельствует сам факт использования слова “манифест”. Подробно эту тему раскрывают Kent Beck и Martin Fowler в книге “Planning Extreme Programming”.

Страх - всегда от незнания. И лучшей пилюлей от него являются уже упомянутые ранее методики распространения опыта - Collaborative Development.

Профессиональная этика

Важность этой темы саркастически раскрыта в статье “Рик, ты уволен: мы избавились от нашего лучшего сотрудника и не пожалели об этом” (оригинал “We fired our top talent. Best decision we ever made.”).

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

К сожалению, описанная ситуация, когда целый проект становится жертвой некомпетентности и самоутверждения единственного человека - не такая уж и редкость.

Хороший специалист всегда заботится об интересах дела, а не о своем положении в этом деле.

Хороший специалист не проявляет нетерпимости к технологиям и инструментам. Во-первых, у него нет необходимости в самоутверждении. Во-вторых, он понимает, что если инструмент диктует условия, то проблема не в инструменте, а в качестве проектирования. Это как в пословице про плохого танцора… Подробно этот вопрос рассмотрел Robert Martin в статье “The Clean Architecture” (в 2017 вышла его одноименная книга). Даже если инструмент перестал устраивать вовсе, то хорошая архитектура обеспечивает заменяемость и адаптируемость. Один из сильнейших специалистов, с которым мне доводилось работать, мог вполне спокойно поработать и с PHP и с, Django, и с Active Record, и с MySQL и т.п. В-третьих, хороший специалист способен иногда и сам создавать хорошие инструменты, если это требуется.

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

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

Хороший специалист не ищет виноватых, потому что умеет не попадать в такие ситуации.

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

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

Вопросам профессиональной этики, soft skills и поведению в конфликтных и стрессовых ситуациях много внимания уделяет Robert C. Martin в книге Clean Coder.

Заключение

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

Updated on Nov 15, 2019

Comments

comments powered by Disqus