Инженерия ПО
Что такое Software Engineering
Цели урока
- Понимать разницу между ремеслом программирования и инженерной дисциплиной
- Назвать причины провалов проектов: требования, коммуникация, процессы, не только код
- Знать ключевые роли в команде: PM, dev, QA, DevOps, SRE и зачем они нужны
- Понимать что 70-80% стоимости ПО приходится на поддержку, а не первичную разработку
- Видеть карьерные траектории: IC, lead, staff, principal, manager
Предварительные знания
- Базовый опыт программирования на любом языке
- Понимание что такое функция, переменная, баг
- Желание разобраться, как индустрия делает софт массово, а не только в учебниках
В 1996 году ракета за 370 миллионов взорвалась из-за одной строчки кода. Код был правильным - он просто оказался в неправильной системе. Это не баг программиста, это провал инженерии. Разница между «писать код» и «строить программные системы» - это разница между умением класть кирпичи и проектированием небоскрёба.
- **Стартапы**: 90% проектов провалены не из-за «плохого кода», а из-за хаоса в требованиях и процессах
- **Корпорации**: Amazon деплоит каждые 11.7 секунд - это результат зрелой инженерной культуры, не только хороших программистов
- **Ваша карьера**: разница в зарплате между «кодером» и «инженером» - в 2-3 раза, потому что инженер решает проблемы бизнеса, а не только пишет функции
Инженерия vs Кодинг
В 1996 году ракета **Ariane 5** взорвалась через 37 секунд после старта. Стоимость - 370 миллионов. Причина? Переполнение 16-битного целого числа при конвертации 64-битного float. Код работал идеально - на **Ariane 4**. Его скопировали без анализа новых условий. Программист написал правильный код. Инженер должен был задать вопрос: «А этот код подходит для новой системы?»
**Кодинг** - написание инструкций для компьютера. **Software Engineering** - дисциплина создания программных систем, которые работают надёжно, долго и в команде. Разница - как между укладкой кирпичей и проектированием здания.
Фредерик Брукс в эссе **"No Silver Bullet" (1986)** сформулировал ключевое наблюдение: главная сложность софта - не в синтаксисе языков и не в скорости компиляции. Сложность - в самой **природе задач**: требования меняются, системы растут, люди не понимают друг друга.
Standish Group CHAOS Report
С 1994 года Standish Group публикует отчёт CHAOS о судьбе IT-проектов. Первый отчёт шокировал: **31%** проектов отменены, **53%** превысили бюджет вдвое, лишь **16%** завершены в срок. К 2020-м ситуация улучшилась, но всё ещё **~66%** проектов сталкиваются с серьёзными проблемами. Причина №1 - не «плохой код», а нечёткие требования, отсутствие коммуникации и слабое управление.
| Аспект | Кодинг | Software Engineering |
|---|---|---|
| Масштаб | Скрипт, утилита | Система из сотен модулей |
| Команда | 1 человек | 10–1000 человек |
| Время жизни | Дни–недели | Годы–десятилетия |
| Главный вызов | Алгоритм, синтаксис | Коммуникация, сложность, изменения |
| Цена ошибки | Баг в скрипте | 370M ракета / утечка данных |
Хороший инженер не тот, кто пишет самый умный код, а тот, чей код **другие люди** могут прочитать, изменить и развивать через 5 лет.
Ракета Ariane 5 взорвалась из-за бага в коде. Почему это проблема инженерии, а не кодинга?
Жизненный цикл разработки (SDLC)
Если software engineering - это не просто кодинг, то из чего он состоит? Ответ - **Software Development Life Cycle (SDLC)** - набор фаз, через которые проходит каждый проект. Разные методологии по-разному организуют эти фазы, но сами фазы неизбежны: анализ → проектирование → реализация → тестирование → развёртывание → поддержка.
| Методология | Когда подходит | Сильные стороны | Слабые стороны |
|---|---|---|---|
| Waterfall | Требования фиксированы (госзаказ, hardware) | Предсказуемость, документация | Нет обратной связи до конца |
| V-Model | Safety-critical (медицина, авиация) | Каждый уровень тестируется | Жёсткость, дорогие изменения |
| Agile/Scrum | Стартапы, продукты, неясные требования | Быстрая обратная связь, адаптация | Сложно планировать на год вперёд |
| DevOps | Зрелые команды, cloud-native | Непрерывная доставка, автоматизация | Требует культуры и инфраструктуры |
**Waterfall** (Уинстон Ройс, 1970) - линейная последовательность фаз. Ройс описал эту модель как **анти-паттерн**, но индустрия приняла её буквально. Результат: команды год писали требования, год кодили, а на тестировании обнаруживали, что требования устарели.
**Agile Manifesto (2001)** стал ответом на провалы Waterfall. Четыре ценности: люди важнее процессов, рабочий софт важнее документации, сотрудничество с заказчиком важнее контракта, адаптация важнее следования плану.
**DevOps** (2009+) - следующая эволюция: стена между Dev и Ops разрушается. CI/CD pipeline автоматизирует сборку, тестирование и деплой. Amazon деплоит в production **каждые 11.7 секунд**.
Не существует «лучшей» методологии. SpaceX использует элементы Agile для ПО и Waterfall для hardware. Выбор зависит от контекста: степени неопределённости, цены ошибки и размера команды.
Стартап разрабатывает мобильное приложение. Требования меняются каждую неделю после пользовательского тестирования. Какая методология подходит лучше всего?
Качество ПО: внешнее и внутреннее
Пользователь видит, что приложение **тормозит** (внешнее качество). Разработчик видит, что код - **спагетти из копипасты** (внутреннее качество). Обе проблемы реальны, но решаются по-разному и имеют разную видимость.
| Внешнее качество (видит пользователь) | Внутреннее качество (видит разработчик) |
|---|---|
| UX - удобство интерфейса | Readability - код читается как текст |
| Performance - скорость отклика | Testability - код покрыт тестами |
| Reliability - система не падает | Maintainability - изменения не ломают всё |
| Security - данные защищены | Modularity - компоненты независимы |
| Accessibility - доступна для всех | Consistency - единые паттерны |
Внешнее качество **зависит** от внутреннего. Спагетти-код рано или поздно приведёт к тормозам, багам и падениям. Но внутреннее качество **невидимо** бизнесу - поэтому его часто приносят в жертву срокам.
В 1992 году Уорд Каннингем ввёл метафору **Technical Debt** - технический долг. Как финансовый долг, он позволяет «занять» время сейчас (срезать углы), но требует «процентов» потом (каждое изменение занимает всё больше времени).
**Не всякий долг - плох.** Каннингем различал **осознанный** долг ("знаем, что срезаем, вернёмся и исправим") и **неосознанный** ("написали как смогли, не знаем, что это плохо"). Первый - стратегическое решение. Второй - мина замедленного действия.
Правило бойскаута: оставляй код **чище**, чем нашёл. Не нужен грандиозный рефакторинг - каждый коммит немного улучшает качество.
Команда решает скопировать 200 строк кода вместо рефакторинга, чтобы успеть к дедлайну. Менеджер говорит: «Потом исправим». Что произойдёт?
Сложность: главный враг инженера
Почему софт так сложен? Брукс в «No Silver Bullet» разделил сложность на два вида. **Essential complexity** - неизбежная сложность самой задачи. Налоговый кодекс сложен не из-за плохого кода, а потому что налоги - сложная предметная область. **Accidental complexity** - сложность, которую мы **добавили сами**: неудачная архитектура, плохие инструменты, лишние абстракции.
**Закон Конвея (1967)**: «Организации проектируют системы, которые копируют структуру коммуникации этих организаций.» Если у вас 4 команды - получится 4 сервиса. Если команды не общаются - сервисы не будут хорошо интегрированы.
Как **измерить** сложность? Несколько ключевых метрик:
| Метрика | Что измеряет | Хорошо | Плохо |
|---|---|---|---|
| Cyclomatic Complexity | Количество путей через функцию (if/else/loop) | 1–10 | > 20 |
| Coupling | Зависимость между модулями | Loose (слабая) | Tight (сильная) |
| Cohesion | Связность внутри модуля | High (всё по теме) | Low (каша из функций) |
| Lines per function | Размер функции | < 30 строк | > 100 строк |
| Depth of inheritance | Глубина иерархии классов | 1–3 уровня | > 5 уровней |
**Coupling и Cohesion** - две стороны одной медали. Хороший модуль имеет **высокую cohesion** (делает одно дело хорошо) и **низкий coupling** (минимально зависит от других). Если модуль `UserService` содержит логику отправки email, работы с платежами и генерации PDF - у него низкая cohesion.
Сложность растёт **нелинейно**. Система из 10 модулей может иметь 45 потенциальных связей (n*(n-1)/2). Из 100 модулей - 4950. Каждая новая связь увеличивает когнитивную нагрузку на разработчика.
Хороший код - это максимально короткий код. Меньше строк = меньше багов.
Хороший код - это читаемый и поддерживаемый код. Иногда больше строк делают намерение яснее.
Однострочник `users.filter(u=>u.a>18&&u.s=='active'&&!u.d).map(u=>({...u,r:'premium'}))` - короткий, но непонятный. Развёрнутая версия с именованными переменными и комментариями длиннее, но любой член команды поймёт и изменит её через год. Readability и maintainability побеждают краткость.
Разработчик жалуется: «Наш проект сложный, потому что бизнес-логика запутанная - налоги, скидки, правила.» Это какой тип сложности?
Ключевые идеи
- **Инженерия ≠ кодинг**: код - это ~20% работы. Остальное - требования, архитектура, тестирование, поддержка
- **SDLC - жизненный цикл**: Waterfall → V-Model → Agile → DevOps. Нет «лучшей» методологии - есть подходящая для контекста
- **Качество двойственно**: внешнее (видит пользователь) и внутреннее (видит разработчик). Технический долг связывает их: плохое внутреннее → плохое внешнее
- **Сложность - главный враг**: essential (неизбежна) vs accidental (наша вина). Цель инженера - минимизировать accidental complexity
- Помните Ariane 5? Строчка кода была идеальной. Инженерный процесс - нет. Код без инженерии - ракета без системы управления
Куда дальше?
Software Engineering - фундамент. Теперь разберём конкретные навыки инженера:
- Требования и спецификации — Как превратить идею в точное описание системы
- Архитектурные паттерны — Как организовать код в масштабе
Вопросы для размышления
- Вспомните проект, который «провалился». Это была проблема кода или инженерного процесса?
- Какой технический долг есть в проектах, над которыми вы работаете? Он осознанный или случайный?
- Если бы вы проектировали Ariane 5, какой этап SDLC предотвратил бы взрыв?
Связанные уроки
- prog-01-intro — Базовое программирование - предпосылка для инженерной дисциплины
- se-02 — Следующий урок: практические методологии разработки
- st-01-feedback-loops — Системное мышление - ключевой инструмент software engineer
- db-01-intro — Проектирование данных - первое крупное инженерное решение в любом проекте
- sd-01-intro