[СМИ-2024] Modern software engineering

В рамках прохождение курса “Системная инженерия” прочитана книга Дэвида Фарли “Современная программная инженерия.” (288 стр., план 5 часов, факт 5,5 часов).

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

И там получается, что инженерный подход - это обучение (познание, хех) по спирали проблема - гипотеза (некое объяснение за ней кажется всё равно прячется) - эксперимент - обратная связь + уточнение или замена гипотезы. Но всё это ради получения пользы в реальности с оговоркой, что экономическое обоснование (хотим быстрее и точнее получать полезные результаты, т.е. это эффективность).

Интересный ход на то, что надо менять мышление, а не инструменты. Пока мы продолжаем холиварить по чатикам, какой язык программирования самый лучший или в каком редакторе программировать, особо ничего не меняется. Т.е. даже эти фокусы с ускорением работ, когда тебе ИИ-друг побыстрее нагенерит бойлерплейт, не то о чём стоить думать. А о чём думать? Модульность, тестируемость, обратная связь (непременно быстрая), непрерывная доставка. Архитектурные характеристики того кода, который ты пишешь. И если одним словом то развиваемость. Потому что фрактал. Если на каждом уровне думаем про развиваемость шансы сделать систему, которая сможет достаточно быстро меняться повыше. А если не думаем, то наверно теория разбитых окон.

Вводятся понятия coupling (связанность/сцепление) и cohesion(связность). А с ними и trade-offs. Как в учебнике, всё сложно, рецептов не будет. Надо бы чтобы внутри модуль связность была повыше (всё что нужно под рукой), а наружу поменьше (каскад изменений зависимых частей). Но без крайностей и текущий уровень/баланс думайте сами, решайте сами. Да и опять же, всё развивается. Что было хорошо вчера, может оказаться плохо сегодня.

TDD! От части вся книжка ода TDD. И не знаю, как вы, а я неправильно понимала что это такое. Но тут опять этот фокус мышление vs инструменты. Автор уточняет unit-testing и TDD это разное. Чего это вдруг? А того, test first. Если не пишешь тест сначала, а пишешь тест после кода, то поздравляю, ты подтверждаешь своё решение и ничего более. А ещё когда ты кодил, ты не думал о концепции системы с точки зрения тех самых характеристик (тестируемость, модульность и прочее). Хорошо, что были примеры кода. И он там “вот так пишут код все”, и к сожалению, да. Мы выносим конечно в модули всякие штуки. Но там очень контринтуитивная штука.

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

Да, строк-то ладно. У меня как раз сейчас перевод расчётного мероприятий на пайплайны. И я прохожу стадии принятия. Хотя это оно и есть. В голове было только низкоуровневое различие модульности. Т.е. вот мы посчитали (что-то полезное, бизнес операция) и это конечно хотим сохранить (служебная операция). Но у меня ж сохранение это две обертки. Первая обертка (модуль) это как раз бизнес (по крайней мере выглядит как бизнес сущность), вторая уже непосредственно фреймворк (модуль) для работы с разными БД внутри языка программирования. И там внутри реализация, конкретного адаптера для PostgreSQL. Вот я была уверена, что все нужные разделения сделаны! А то, что на уровне абстракции сохранение результатов привязанное к получению результатов это та самая сцепка, кто бы мог подумать.

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

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

Да в начале работы никто не знает, что делать. Если “там” говорят, что знают, в действительности “там” не знают ничего.

Мы знаем, что ничего не знаем. И это нормально. Это тоже трудно принять. Потому что “ну кто-то же должен знать!”. В голове снова начинается “разбор ролей” и вопросики, а кто что делает. Ладно, допустим пользователи не знают, что им надо. Но мы вроде как отображаем реальность (домен) в информационную систему. Кто-то должен знать как эта реальность в предметной области устроена? Она ж не вчера появилась. Эксперты из предметной области должны бы знать. А дальше мы ищем, кто ж у нас там с ними общается. И как бы он донёс информацию, не наврав по дороге. А ещё сакральное знание “как делать” и навык “придумать как делать” содержит в себе методолог. У нас вроде даже выделанная роль есть. Очень интересно чем там люди занимаются на самом деле. В моём понимании в сложном домене верхнеуровневая гипотеза “как делать” должна быть от методолога. А дальше пусть инженеры изобретают.

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

Метрики! Это тоже про обратную связь, скорость, точность.

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

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

Стабильные команды с высокой пропускной способностью определяются как высокопроизводительные.

Метрики стабильности:

  • change failure rate (частота отказов) это доля случаев, когда изменение приводит к ошибке в определённой точке процесса
  • recovery failure time (время восстановления) сколько времени занимает восстановление после сбоя

Метрики пропускной способности:

  • lead time (время на реализацию) оценка эффективности процесса разработки, сколько времени занимает путь от идеи до рабочего продукта
  • frequency (частота) оценка скорости, как часто осуществляется доставка/ввод в эксплуатацию

Красивое, но эти метрики опять раскладывать надо. И да то, как всё у вас устроено, в том числе влияет на то насколько (не)удобно эти метрики собрать.

Обратная связь очень важна для процесса разработки

И shift left. Падай раньше, падай чаще. Думаю как падать и что проверять на этапе discovery (эти все штуки, кто-то что хочет, как оно вроде бы должно работать). Они же приносят что-то, а выяснить что что-то потеряли или что-то не так, как надо мы сможем когда? Когда что-то целое запрограммируют. Медленно. Но опять большой вопрос, где тут граница из “окей, мы узнали что-то новое и доделаем в следующий заход” и “что за фигню вы сделали, всех надо разогнать”. И процесс с его скоростью максимально влияет (медленный релизный цикл обратная связь далеко).

CI это практика слияния всех работающих копий в общую основную ветвь разработки несколько раз в день.

Приехали. Я писала уже где-то. Если вы считаете, что знаете что такое CI/CD, пойдите почитайте внимательнее. Вдруг, вы как я, только слышали слухи.

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

Изменяемость как характеристика. И там непрерывный рефакторинг тоже в книге. Если давно не меняли этот кусок кода - подозрительно. Никто не знает как он работает, все боятся его трогать? Тоже на уровне мышления странная штука.

DDD позволяет перенести модульность, связность и разделение ответственности из реальности предметной области в код. Книжку надо прочитать по DDD.

Чтобы код работал быстро, он должен быть простым и легко понятным.

Тоже вроде расхожая фраза. Насколько простым, насколько понятным? И там автор напоминает, что код должен быть понятен человеку. И желательно действительно быстро, что-то в районе пары секунд. И мы снова возвращаемся к модульности и называйте функции человекопонятно. Забавно, я когда в позапрошлый раз переходила с языка на язык и радовалась, что циклы исчезли. Т.е. для того, чтобы применить функцию к коллекции не надо писать for(i=0;i++). Появились в моём мире Collection.each(do_something()). Большой шаг в человекопонятности. Но манера решать задачи это всё превращает в пачку малопонятных манипуляций, что-то с чем-то сравнивается, что-то удаляется по какому-то признаку. По функциям с нормальными бизнесовыми названиями раскладывать или некогда, или уже неохота. И в итоге ты сидишь смотришь на код и не то, что за две секунды и за 15 минут не особо можешь понять, что же это всё значит. А если ещё комментариев/документации нет… Рассказывайте пожалуйста кодом историю на естественном языке. Свои технические особенности прячьте под ковёр. Любой язык программирования позволяет так или иначе добавить нужных абстракций. Книжка “Код, который умещается в голове: эвристики для разработчиков” у меня в заначке ждёт своей очереди. Но идея понятна.

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

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

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

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

6 лайков

просто есть какие-то модули которые, уже оттестированы и стабильны, если они выполняют свою функцию - зачем менять?

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

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

так процесс это люди. Люди строят люди же и разрушают. Процесс может добавить инерции, но и только

1 лайк

Эволюция, непрерывное всё) Непрерывный рефакторинг.

Если набросы отложить. То у меня такая картина: 1) бизнес логика (а мы максимально сильно завязаны именно на бизнес логику) продолжает меняться постоянно (не скажу что я в восторге при этом) 2) баги/уточнение кейсов 3) техдолг 4) потребность перерабатывать архитектуру под новые нагрузки/потребности.

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

Мусорка накапливается сама по себе. А чтобы было чисто, приходится прибираться. У нас был файл с интеграционным тестом на 1500 или 2000 строк. Никто ж не парится, просто дописываешь тест в середину. Ну простынь, ну и что. Тесты запускаются асинхронно, но на уровне файлов. Т.е. если у меня 50 файлов тестов и 16 ядер на ноуте, они пойдут в 16 потоков. Но в каждом файле сколько-то тест кейсов. И этот гигантский файл все преимущества асинхронного запуска внутри себя съедает. Пайплайн замедляется. Разбила файл на куски, стало получше.

Я не про техническое быстродействие. Там про скорость внесения изменений вся книжка. Если код простой, когнитивная нагрузка меньше (его быстрее поймёшь). Если код простой, его проще тестировать (это модульность опять, тест написать легче, тест проще понять, тест меньше, выполняется быстрее). TDD нам говорит разбивайте на изолированные части, которые легко тестировать (single responsibility). Потом из этих частей собирайте конструктор. Необходимая сложность против навязанной. В целом это уже архитекторы против разработчиков.

Сто процентов! Особенно когда я фразу не разворачиваю) Но там коротко не перескажешь. Примерно то же самое, что я выше написала. “Качественное мышление” способствует скорости внесения изменений. Всё таки скорость везде это lead time, release cycle и вот это всё. Насколько мы быстро можем один модуль заменить на другой. Или даже одну подсистему на другую. Или сервис. И так до бесконечности, разработчика, стек технологий, отдел, архитектуру (это уже в следующей книжке).

Люди + метод + инструменты. И строит и ломает каждая составляющая. Если всё вместе это инженерный процесс. То хорошо настроенный = управляемый. И понятное дело непрерывно развиваемый инженерный процесс должен давать антихрупкость (способность к эволюции).

2 лайка