В зависимости от личных предпочтений и потребностей, от уровня абстракций, на котором моделируется мир, а также от места в спектре между идеализмом и цинизмом, можно с полным правом сказать, что работа разработчиков ПО заключается в следующем:
- написание кода;
- создание и поддержка качественного ПО;
- создание и поддержка достаточно хорошего ПО экономически выгодным образом;
- управление сложностью;
- удовлетворение потребностей пользователей;
- решение задач;
- удовлетворение потребностей заказчиков;
- зарабатывание денег для организации-работодателя или для её заказчиков;
- зарабатывание денег (для себя).
Разумеется, этот список далеко не полный. Некоторые из этих задач можно абстрагировать, редуцировать или вывести из других. Некоторые из них фундаментально несовместимы между собой или противоречат друг другу и могут сосуществовать с другими в конфликте. Например: допустим (в определённой мере), что качественное ПО порадует наших пользователей и заработает денег работодателю. Но в то же время нам нужно жертвовать качеством, чтобы оставаться в рамках бюджета, или добавлять функции, которые надоедают пользователям, но генерируют прибыль.
Каждая цель проистекает из определённого способа моделирования мира и наших действий. Как и в случае с любой абстракцией, они выполняют свою задачу в подходящем контексте и становятся ложными вне этого контекста; многие проблемы в разработке ПО могут быть объяснены такой искажённой перспективой, о чём я говорил в своём предыдущем посте. В этой статье мы будем считать, что основная задача разработчика ПО — это управление сложностью.
Сложность — это всё то, что усложняет понимание и изменение системы. В своей книге Философия разработки ПО Джон Оустерхаут объясняет, почему это должно стать для нас самым важным:
Если мы хотим упростить написание ПО, чтобы можно было создавать более мощные системы с меньшими затратами, нам нужно найти способы сделать ПО проще. (…) Основная часть кода любой системы пишется при помощи расширения существующей кодовой базы, поэтому ваша самая важная задача как разработчика — упростить это расширение в будущем. То есть мы должны считать основной целью не «работающий код», хотя, разумеется, код должен работать. Вашей основной целью должно быть создание отличной архитектуры, которая в то же время работает. Это и есть стратегическое программирование. (…) Если разработчики ПО всегда должны думать об проблемах проектирования, а снижение сложности — это самый важный элемент проектирования ПО, то разработчикам всегда следует думать о сложности.
Уртекстом рассуждений о сложности ПО можно считать книгу Фрэда Брукса No Silver Bullet. Брукс разделяет в ПО неотъемлемое и привнесённое, утверждая, что сложность — это неотъемлемая проблема программных систем; это одна из тех вещей, которые ограничивают сейчас нашу производительность. В книге Out of the Tar Pit Мосли и Маркс развивают идеи Брукса, определяя более известные (и удобные) типы сложности:
- Неотъемлемая сложность — это врождённая суть проблемы (воспринимаемая пользователями).
- Привнесённая сложность — это всё остальное: сложность, с которой в идеальном мире команда разработчиков бы не столкнулась (то есть сложность, возникающая из-за проблем с производительностью и из-за субоптимального выбора языка и инфраструктуры).
Самое важное в различии заключается в точке зрения пользователя:
Если у команды существует какой-то возможный способ создать систему, которую пользователи признают корректной, без необходимости беспокоиться об определённом типе сложности, то эта сложность не относится к неотъемлемым. (…) Из этого определения можно сделать вывод, что если пользователь не знает какой-то концепции (например, «пул потоков» или «счётчик цикла»), то она по нашему определению никак не может быть неотъемлемой.
Разумеется, в любой реальной реализации системы вынужденно появляется некоторая привнесённая сложность. Цель разработчика ПО при этом — минимизировать привнесённую сложность и помочь с неотъемлемой сложностью.
Несмотря на мелкие семантические отличия, авторы No Silver Bullet и Out of the Tar Pit соглашаются с тем, что в проблеме существует неотъемлемое: то, чего инженеры не могут изменить, то, чему должна соответствовать система и то, что вносит вклад в тип сложности, которого невозможно избежать. Цитата из No Silver Bullet:
Основная часть сложности, с которой должен справляться разработчик ПО — это сложность, привносимая человеческими организациями и системами, с которой должен согласоваться интерфейс. (…) Во многих случаях ПО должно подчиняться, потому что оно появилось в этой среде последним. В других случаях оно должно подчиняться, потому что воспринимается наиболее удобным для изменений. Но во всех случаях большая часть сложности возникает из-за подчинения другим интерфейсам; это нельзя упростить перепроектированием только лишь одного ПО.
Я хочу подвергнуть сомнению мнение о том, что неотъемлемой сложности нельзя избежать. То, что мы не можем устранить его при помощи изменения ПО, не значит, что мы не можем вообще ничего с этим сделать. Что, если мы нападём на саму суть? Что, если бы определение проблемы не находилась вне нашей компетенции? Что, если бы могли бы заставить мир подчиняться ПО, а не наоборот? Брукс уже намекал на такую возможность:
Покупатель машины за $2 миллиона в 1960 году считал, что может позволить себе потратить ещё $250 тысяч на специализированную программу расчёта зарплат, которая бы без проблем интегрировалась во враждебную компьютерам социальную среду. Покупатели офисных машин за $50 тысяч сегодня [1986 год], предположительно, не могут позволить себе покупку подстроенных под них программ расчёта зарплаты; поэтому они адаптируют свои зарплатные процедуры к доступным программным пакетам. Компьютеры сейчас настолько повсеместны, если не сказать любимы, что адаптации воспринимаются как нечто само собой разумеющееся.
Это не удивляет нас: мы десятками лет наблюдали, как поведение людей (и ожидания пользователей) могут формироваться ПО: мессенджеры, социальные сети, потоковая передача контента — всё это существенно изменило повседневные привычки. Если мы признаем, что пользователей можно принудить подстраиваться под систему и что ПО имеет потенциал менять людей и организации, то можно изменить определение задач, которые для них решает ПО: неотъемлемость не высечена в камне, но открыта к дискуссиям, это часть того, с чем может работать инженер.
Таким образом, мы можем упростить цель разработчика ПО, минимизирующего привнесённую сложность и помогающего с неотъемлемой сложностью, до минимизации сложности любого типа. В эссе «No Silver Bullet» Refired Брукс цитирует читателя, идеально формулирующего эту точку зрения:
По моему опыту, основная часть сложностей, которые встречаются в работе систем — это симптомы неправильной работы организаций. Попытки моделировать эту реальность при помощи столь же сложных программ — это, на самом деле, попытка законсервировать беспорядок вместо того, чтобы решать проблемы.
Изменение определения задачи походит на жульничество, но привычно для сеньор-инженеров: Почему мы над этим работаем? Действительно ли нам это надо? Какую задачу мы пытаемся решить? Кто выиграет от того, что мы её решим? Что, если вместо X мы сразу выпустим X1, который потребует от нас 20% усилий, но обеспечит 80% функциональности?
Строго по определению Мосли и Маркса, то, что мы можем убедить пользователя (или заказчика, или владельца продукта) принять изменение требований, подразумевает, что сложность, от которой мы избавились, вообще не была неотъемлемой. Вместо этого мы совершили прогресс в раскрытии истинной сути проблемы. Смысл в том, что для этого прогресса нужно, чтобы инженеры подвергали сомнениям допущения и разубеждали стейкхолдеров; без их участия ненужные функции станут частью спецификации задачи, «окаменев» в её сути.
В целом, с точки зрения комплексной составляющей программной системы (или организации) может выясниться следующее:
- сложность привнесена, так что от неё можно избавиться;
- сложность неотъемлема, и мы должны сохранить её;
- сложность неотъемлема, но мы можем устранить её, изменив определение спецификации задачи;
- знание, позволяющее понять, неотъемлемо что-то или нет, утеряно, заказчик или владелец продукта не могут этого сообщить, или нет лица, имеющего полномочий принять решение.
Последнюю из ситуаций я часто встречаю при работе с легаси-системами, когда единственная спецификация — это сама система с её багами и неизвестными, а любая наблюдаемая фича является де-факто функциональным требованием, неотъемлемым для задачи. Консервативный подход к поддержке таких систем сводится к внутренним рефакторингам; более разрушительный подход «снизить сложность любой ценой» может подразумевать, что всё должно быть устранено, если не доказано иное. В книге Kill It with Fire Марианна Беллотти описывает проектирование устойчивости так:
Когда мы встречаем системы, о которых забыли, и непонятно, что они делают, мы обычно просто выключаем их и смотрим, что произойдёт. (…) Когда мы отключали систему, то ждали, пока кто-нибудь не начнёт жаловаться. Этот человек будет или владельцем системы, или владельцем подчинённой ей зависимости, но в любом случае мы завершили эксперимент с бо́льшим объёмом информации, чем начинали. (…) Если никто не жаловался, то мы обычно оставляли систему отключенной и двигались дальше.
Даже если системы невозможно устранить, новая информация улучшает организационное понимание, что снижает сложность.
Можно довести этот аргумент до крайности: инженеры могут планировать упрощённые реализации систем, а затем убеждать организации подстраивать их процессы под эти реализации в попытке сделать с пользующейся системой организацией то, что Inverse Conway Maneuver пытается сделать с организацией, разрабатывающей её. Предоставленные сами себе, разработчики ПО могут действовать как бритва Оккама, устраняя из мира сложность; автоматизируя работу сотрудников и даже самих разработчиков, чтобы вытеснить их с работы; упрощая системы вместе с организациями, которые ими владеют, вплоть до их уничтожения.
Разумеется, этот reductio ad absurdum возник из-за того, что мы расширили первоначальную предпосылку за разумные пределы. Мы начали с допущения о том, что единственная цель разработчика ПО — минимизация сложности, среди прочего проигнорировав экономические интересы, определяющие нашу работу. Это может служить напоминанием о том, что поскольку наша работа действительно может влиять на людей и организации, мы не можем распоряжаться ею безотчётно, спрятавшись в комфорте абстракции. Время от времени нам нужно выходить за рамки нашего интерфейса в неструктурированный хаос, которым является наш мир.
Telegram-канал со скидками, розыгрышами призов и новостями IT 💻