David Farley - Modern Software Engineering

David Farley - Modern Software Engineering

Прочитал книгу David Farley “Modern Software Engineering”, 2022 год. Эту книга рекомендуется в числе прочих в курсе “Системная инженерия” в ШСМ. Кроме того мне независимо посоветовал ее прочитать коллега. Двойное попадание, хорошо. Автор книги являлся руководителем разработки биржи LMAX, а в свое время библиотечка LMAX Disruptor мне прям очень зашла, там были очень интересные вещи про то как устроено конкурентное программирование, например, концепт Mechanical sympathy.Получил несколько важных инсайтов. Пересмотрел, как надо программировать.В книге рассказывается про программную инженерию с упором именно на инженерию. Под этим автор понимает в первую очередь нацеленность на результат, на то чтобы “получать более качественный продукт быстрее”. Далее предлагаются несколько сильно связанных между собой практик, помогающих этому. Контринтутивно, но оказывается, что нет компромисса между “лучше” и “быстрее”, это ложный компромисс. В реальности команды, которые следят за качеством получают и результат качественнее.Вводятся две метрики: стабильность (stability) и пропускная способность (througput). Оказывается достаточно следить за этими двумя метриками в контексте поставки фич и это позволит улучшить качество продукта и ускорить разработку. Инженерия противопоставляется ремеслу. Ремесленный способ деятельности неточный и его невозможно масштабировать, поэтому важно, в том числе и при создании софта мыслить инженерно. Например, это о том, чтобы стараться автоматизировать все, что можно автоматизировать, о том, чтобы увеличивать точность измерений.Объясняется несколько важных практик: для более быстрого и качественного познания предметной области и для борьбы со сложностьюБыстрое познание

  • итеративная разработка
  • обратная связь
  • инкрементальная разработка
  • эмпирицизм
  • опора на эксперименты

Борьба со сложностью

  • Модульность
  • Связность (cohesion)
  • Разделение интересов (separation of concerns)
  • Сокрытие деталей реализации (information hiding and abstraction)
  • Сцепление (coupling)

Магистральной линией с точки зрения конкретных практик в книге является стимулирование использования TDD и Continous Delivery, использование которых поддерживают указанные выше практики.

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

Про Continuous Delivery тоже очень интересно. Вообще автор написал еще несколько книг, где тема непрерывной поставки разобрана более детальна, но и здесь про это немало сказано. Например, автор предлагает релизится несколько раз в день, оптимальная частота по его словам новый релиз каждый час. Также поясняется разница между trunk based development и feature branching development с объяснением почему именно первый хорош.

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

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

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

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

Итеративность работает на уровне всей системы, например, метод прогрессивного джипега Артемия Лебедева § 167. Метод прогрессивного джипега ровно об этом. Инкрементальность работает на уровне деталей. Это два разных принципа, использовать надо оба. И оба они про быструю обратную связь.

Понравился автор, также подписался на его youtube-канал Continuous Delivery https://www.youtube.com/@ContinuousDelivery, хорошие и понятные видосы о том, как устроены разные аспекты программирования.

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

Текст также опубликован в личном блоге Telegram: Contact @burganov

4 лайка

Спасибо за пост! Натолкнул на размышления.

1 лайк

Тоже очень люблю метод джипега, но в последнее время кажется, что суть Continuous delivery не в том, как картинку увидеть целиком, а в том, как быстрее понять что пора рисовать новую картинку.

И в этом смысле итерации – дорисовывание детально, но по чуть чуть более дают простоту манёвра/pivot, но инкременты – дают возможность быстрее необходимость этого манёвра увидеть.

2 лайка

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

TDD - для меня было главное откровение понять что нужно тестировать, а именно что брать за понятие “unit” (так как TDD говорит про “unit test”). Правда, когда начинаешь понимать что имел ввиду Kent Beck под понятием “unit”, когда ввел TDD, сама практика уxодит на задний план…

Спасибо за дополнительную мотивацию достать это книжку с полки! (Уже пол года лежит)

1 лайк

Мне нравится понятие Test Driven Development, т.е. разработка которая направляется тестами. Когда мы говорим о Unit Testing, там этого акцента нет. Итог - можно получить разработку, в которой много кода, который тестирует функциональность, но где разработка направляется не тестами, где тесты пишутся постфактум. Оказывается это совершенно другая история. В Modern Software Engineering все это очень подробно разбирается, почему это важно и почему обратная история не работает.

Для меня как разработчика это было прям открытием.

1 лайк

Придётся обе книги читать)

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

И в своей повседневной работе некий test first я использую в двух случаях. Первый - когда задача супер простая и подробно описана. Например, у меня есть контракт и мне нужно подписаться на событие с таким контрактом. Всё здесь понятно, что тестировать, как тестировать. Второй - когда я кусок решения проверяю. Есть задача, она не простая. Но я часть понятную могу выделить, решить её каким-то способом. И тогда red, green, refactoring. Как короткий цикл обратной связи вполне себе. Но полную работоспособность отдельное тестирование кусков не гарантирует.

Интересно, как у вас получится применить в работе. С какими сложностями столкнетесь. Ждём ещё постов!

самому интересно :grin: как бы это совсем другой майндсет

Еще как точечный вариант когда пишешь тест первым и потом уже меняешь код что бы этот тест удовлетворить - это когда у тебя есть баг (описанный в достаточных деталях что бы можно было повторить этот сценарий подготовкой и самим тесто). Очень приятно и легко исправлять ошибки.
Я сам так не делал, но читал что когда начинаешь новый проект (новую “code base”) еще сам не знаешь чего xочешь и поэтому сложно писать тесты вначале. А вот уже потом начинаешь внедрять TDD и тесты для багов.

1 лайк

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

Естественно 100% покрытие не означает что софт работает без багов)))

2 лайка

Ты реально каждый раз, как в книге написано, сначала пишешь падающий тест на пустой модуль?

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

1 лайк

Не прям каждый, но довольно часто.

1 лайк