Эта статья предназначается не только для менеджеров продуктов. Основатели компаний, инвесторы и люди других профессий, которые в достаточной степени заинтересованы в каком-либо цифровом продукте, тоже смогут извлечь из нее пользу. Я так считаю, потому что проблема, которая будет обсуждаться – пересуложнение – одна из наиболее распространенных в разработке. По моему мнению, перусложнение чаще убивает продукты, чем плохие практики программирования.
Прежде чем пускаться в подробности, позвольте сказать пару слов о собственном опыте. До перехода в менеджеры продуктов я работал программистом. Вообще говоря, даже образование я получал по специальности «информатика». По ходу карьеры я держался ближе к управлению, чем к написанию кода, но мне в равной мере приходилось формировать команды как менеджеров, так и программистов и руководить теми и другими.
Так что мои рассуждения о переусложнении – это не взгляд со стороны. Я и сам в этом отношении не без греха, и от чужих ошибок тоже доводилось страдать. Поэтому я хорошо понимаю, что это такое, во что обходится командам и как этого избежать.
Если строго следовать определению из Википедии переусложнение предполагает, что продукт спроектирован с большей сложностью, чем требуется:
Если говорить именно о ПО, мне нравится вот такое определение от Павла Глоговски:
Вы, возможно, подумаете: да кто вообще станет решать проблему, которой по факту нет? Ерунда какая-то, да? Ну, в таком случае усаживайтесь покрепче, потому что после двадцати лет работы в сфере ИТ и многочисленных собственных промахов я могу вас заверить: переусложнение – не исключение, а норма.
Никто не пытается перемудрить назло. Очень часто переусложнение зарождается от того, что мы пытаемся предугадать будущее и подготовиться к неизвестности. Когда проектируешь новую возможность, в голову приходит, что неплохо бы потратить чуть больше времени, чтобы защитить ее от всех будущих невзгод – мало ли что.
В девяти случаях из десяти «что» никогда не наступает. Но по ходу дела мы потратили лишнее время и добавили в продукт лишней сложности, которая останется с нами до самого конца его жизни.
Другая распространенная причина переусложнения – недостаток опыта. Говоря в общем, чем опытнее разработчик, тем менее он склонен к излишней сложности, потому что у него за плечами уже много случаев, когда искусственная сложность провоцировала взрыв.
График зависимости уровня сложности от опыта можно переложить в слова примерно таким образом:
Очень простой код > Cплошное ООП > Паттерны проектирования > Абстракции, интерфейсы, «А вдруг потом пригодится», «Так эксперты делают» > Очень простой код
Расплывчатые требования тоже могут усугубить проблему. Не имея четкого представления о том, какую именно проблему решает, разработчик с большей вероятностью начнет переусложнять, чтобы подстраховаться.
К переусложнению может привести скука. Если разработчику не достается сложных и интересных задач, он будет мудрить над теми, которые есть, просто чтобы попробовать что-то новое.
Я не шутил, когда говорил, что переусложнение убивает стартапы. Оно имеет два губительных для любых систем последствия.
С одной стороны, оно повышает затраты на разработку. Если для устранения проблемы программисты выбирают не самое простое решение, времени и денег расходуется больше, а процесс итерирования замедляется.
С другой стороны, затраты на поддержку тоже возрастают. Простой код легче писать, тестировать и редактировать. Когда начинаешь добавлять в него лишнее, сложность возрастает по экспоненте, что, опять же, влияет на темп итерирования.
Так что повторю свое исходное утверждение: переусложнение убивает продукты. В большей степени, чем отсутствие хороших практик написания кода. Так получается, потому что, чтобы от практик был толк, сначала нужно добиться соответствия продукта рынку, а с излишней сложностью можно вообще к этому не прийти.
Первое, что приходит здесь на ум – это микросервисная архитектура. Несколько лет назад этот тренд накрыл разработку волной и, вероятно, погубил больше продуктов, чем усовершенствовал.
Я привожу микросервисы как пример переусложнения, потому что в 99% случаев в них нет необходимости. В первую очередь это относится к стартапам, которые еще не нашли свое место на рынке и больше бы выгадали от менее навороченного паттерна, например «великолепного монолита».
Если вам посчастливится вписаться в рынок и вы поймете, что нужно переходить на микросервисы, чтобы справиться с масштабированием – ну, о такой проблеме можно только мечтать.
Преждевременная оптимизация – еще один типичный пример переусложнения. Нередко можно наблюдать, как систему готовят к поглощению огромных объемов трафика, снабжают хитровывернутой архитектурой, хотя пользователи-то еще и не пришли. В большинстве случаев для проверки бизнес-модели достаточно монолитной системы, которая работает на одном сервере.
Одна из худших форм преждевременной оптимизации – трата времени, чтобы в будущем не пришлось делать какую-то работу на второй раз или удалять что-то уже готовое. Никакие совершенства в проектировании или имплементации не будут иметь ни малейшего значения, если вы так и не увидите их в деле, потому что разорились до запуска. Худший в мире код, который позволит провести валидацию гипотезы – и то лучше, чем топтаться на месте из страха где-нибудь повториться.
В том же ключе, переписывание кода – очевидный пример переусложнения. Разработчикам, как правило, не нравится работать с унаследованным кодом. Возникает естественное побуждение переделать всё с нуля. Но, как писал Джоэл Спольски еще двадцать лет назад, полное переписывание системы редко дает ожидаемый эффект и может стоить компании жизни.
Я говорю самоочевидные вещи, но клиенту нет дела до того, насколько элегантно ваша система смотрится изнутри. Ему важно только одно: решается ли его проблема. Всё время, которое не служит созданию чего-то ценного для него, уходит впустую.
На мой взгляд, самый лучший способ предотвратить переусложнение – превратить коллег из абстрактных разработчиков в разработчиков продукта. Этого можно добиться, держа их в курсе бизнес-процессов изо дня в день, объясняя истоки той или иной инициативы с приложением ссылок на метрики, важные для компании. Нужно сократить дистанцию между пользователями и разработчиками, сводить их на опросах и встречах с обсуждением продукта. Команде должны быть знакомы и близки проблемы пользователя, чтобы они могли сразу же отказываться от усилий, которые не будут способствовать эффективному решению этих проблем.
Не ждите, что у разработчиков появится желание избегать переусложнения, если вы воспринимаете их просто как прод-ресурс, единственная задача которого – брать пользовательские истории из бэклога и реализовывать. Им должен быть понятен ход мысли, стоящий за каждым решением.
Продолжая тему, формулируйте проблему ясно, не оставляя места неопределенности. Причины важны, но и ожидания тоже требуют внимания. Чем уже вы очертите проблему, тем меньше у разработчиков будет оснований искать опоры в переусложненных решениях. Хороший способ обозначить требования к системе – использовать показатели SLI и SLO.
Разработчики, как правило, относятся к самым творческим сотрудникам в компании. Если ваши критерии вызывают у них доверие, возможно, в ходе повседневной работы у них будут возникать идеи и предложения, основанные на каком-то гипотетическом сценарии из будущего. Если интуиция вам подсказывает, что это как раз тот случай, задайте вопросы: «Как это поможет нам решить проблемы пользователей на текущем этапе? Что будет, если мы этого не сделаем?». Так вам будет проще определить, замешано здесь переусложнение или нет.
Наконец – этот совет предназначен в основном для основателей компаний – старайтесь в первую очередь нанимать сениоров, у которых уже есть опыт работ в продуктовых компаниях. На собеседованиях высматривайте боевые шрамы. Расспросите о том, какие задачи были самыми мучительными и как они выходили из положения. Выбирайте тех, кто обращает внимание не только на техническую сторону, но также на пользователей, и ценит простоту.
YAGNI
Проблема переусложнения так часто встречается в индустрии, что у программистов есть особое выражение для ситуаций, когда код пишется из соображений «а вдруг» — YAGNI. Это акроним, который расшифровывается как You are not going to need it («Вам это не понадобится»).
Принцип YAGNI служит тому, чтобы предотвратить добавление чего-то не вполне необходимого для решения проблемы, которая перед вами стоит – в реальности это, скорее всего, действительно «не понадобится».
KISS
Акроним KISS (Keep it simple stupid, «Делай всё просто, придурок») указывает на то, что простые системы легче чинить, развивать и поддерживать. Соответственно, простота всегда должна быть одной из целей при проектировании, а лишней сложности нужно избегать.
Чем хуже, тем лучше
Этот принцип подчеркивает, что начиная с определенного этапа предпочтительнее иметь меньше возможностей, а не больше. Причина здесь в том, что продукт с меньшим набором функций легче использовать, что делает его привлекательным для более обширного сегмента рынка.
Иными словами, это подталкивает нас к тому, что поддерживать минимум самых важных функций продукта и обходиться без воды, которая добавит системе сложности.
Обобщая сказанное: переусложнение потенциально способно погубить ваш стартап. Оно может:
К сожалению, переусложнение является нормой, а не отклонением от нее. Исходя из этого, крайне важно понимать, что к ней относится, и стараться устранить эти практики, ближе знакомя разработчиков с проблемами пользователей. Время, которое не служит разрешению этих проблем, тратится зря.
Не попадайтесь в ловушку «мало ли что». Кладбища полнятся безупречно продуманными стартапами и продуктами, рассчитанными на миллионы пользователей, которые так и не привлекли к себе никакого внимания. Не следуйте по их стопам.
Прежде чем пускаться в подробности, позвольте сказать пару слов о собственном опыте. До перехода в менеджеры продуктов я работал программистом. Вообще говоря, даже образование я получал по специальности «информатика». По ходу карьеры я держался ближе к управлению, чем к написанию кода, но мне в равной мере приходилось формировать команды как менеджеров, так и программистов и руководить теми и другими.
Так что мои рассуждения о переусложнении – это не взгляд со стороны. Я и сам в этом отношении не без греха, и от чужих ошибок тоже доводилось страдать. Поэтому я хорошо понимаю, что это такое, во что обходится командам и как этого избежать.
Что такое переусложнение?
Если строго следовать определению из Википедии переусложнение предполагает, что продукт спроектирован с большей сложностью, чем требуется:
Переусложнение – это действия, связанные с созданием продукта или решением проблемы чересчур сложным путем, в то время как существует более простое решение и можно продемонстрировать, что оно обладает той же эффективностью, как и исходный проект.
Если говорить именно о ПО, мне нравится вот такое определение от Павла Глоговски:
Это код или дизайн, который решает несуществующую проблему.
Вы, возможно, подумаете: да кто вообще станет решать проблему, которой по факту нет? Ерунда какая-то, да? Ну, в таком случае усаживайтесь покрепче, потому что после двадцати лет работы в сфере ИТ и многочисленных собственных промахов я могу вас заверить: переусложнение – не исключение, а норма.
Причины переусложнения
Никто не пытается перемудрить назло. Очень часто переусложнение зарождается от того, что мы пытаемся предугадать будущее и подготовиться к неизвестности. Когда проектируешь новую возможность, в голову приходит, что неплохо бы потратить чуть больше времени, чтобы защитить ее от всех будущих невзгод – мало ли что.
В девяти случаях из десяти «что» никогда не наступает. Но по ходу дела мы потратили лишнее время и добавили в продукт лишней сложности, которая останется с нами до самого конца его жизни.
Другая распространенная причина переусложнения – недостаток опыта. Говоря в общем, чем опытнее разработчик, тем менее он склонен к излишней сложности, потому что у него за плечами уже много случаев, когда искусственная сложность провоцировала взрыв.
График зависимости уровня сложности от опыта можно переложить в слова примерно таким образом:
- Сначала разработчик пишет предельно просто.
- Разработчик знакомится с какой-нибудь парадигмой – скажем, объектно-ориентированным программированием – и присоединяется к сообществу.
- Разработчик начинает читать про разные паттерны проектирования и рвется применять их по поводу и без.
- Через несколько лет страданий от излишней сложности разработчик возвращается к предельно простому коду.
Очень простой код > Cплошное ООП > Паттерны проектирования > Абстракции, интерфейсы, «А вдруг потом пригодится», «Так эксперты делают» > Очень простой код
Расплывчатые требования тоже могут усугубить проблему. Не имея четкого представления о том, какую именно проблему решает, разработчик с большей вероятностью начнет переусложнять, чтобы подстраховаться.
К переусложнению может привести скука. Если разработчику не достается сложных и интересных задач, он будет мудрить над теми, которые есть, просто чтобы попробовать что-то новое.
Последствия переусложнения
Я не шутил, когда говорил, что переусложнение убивает стартапы. Оно имеет два губительных для любых систем последствия.
С одной стороны, оно повышает затраты на разработку. Если для устранения проблемы программисты выбирают не самое простое решение, времени и денег расходуется больше, а процесс итерирования замедляется.
С другой стороны, затраты на поддержку тоже возрастают. Простой код легче писать, тестировать и редактировать. Когда начинаешь добавлять в него лишнее, сложность возрастает по экспоненте, что, опять же, влияет на темп итерирования.
Так что повторю свое исходное утверждение: переусложнение убивает продукты. В большей степени, чем отсутствие хороших практик написания кода. Так получается, потому что, чтобы от практик был толк, сначала нужно добиться соответствия продукта рынку, а с излишней сложностью можно вообще к этому не прийти.
Примеры переусложнения
Первое, что приходит здесь на ум – это микросервисная архитектура. Несколько лет назад этот тренд накрыл разработку волной и, вероятно, погубил больше продуктов, чем усовершенствовал.
Я привожу микросервисы как пример переусложнения, потому что в 99% случаев в них нет необходимости. В первую очередь это относится к стартапам, которые еще не нашли свое место на рынке и больше бы выгадали от менее навороченного паттерна, например «великолепного монолита».
Если вам посчастливится вписаться в рынок и вы поймете, что нужно переходить на микросервисы, чтобы справиться с масштабированием – ну, о такой проблеме можно только мечтать.
Преждевременная оптимизация – еще один типичный пример переусложнения. Нередко можно наблюдать, как систему готовят к поглощению огромных объемов трафика, снабжают хитровывернутой архитектурой, хотя пользователи-то еще и не пришли. В большинстве случаев для проверки бизнес-модели достаточно монолитной системы, которая работает на одном сервере.
Одна из худших форм преждевременной оптимизации – трата времени, чтобы в будущем не пришлось делать какую-то работу на второй раз или удалять что-то уже готовое. Никакие совершенства в проектировании или имплементации не будут иметь ни малейшего значения, если вы так и не увидите их в деле, потому что разорились до запуска. Худший в мире код, который позволит провести валидацию гипотезы – и то лучше, чем топтаться на месте из страха где-нибудь повториться.
В том же ключе, переписывание кода – очевидный пример переусложнения. Разработчикам, как правило, не нравится работать с унаследованным кодом. Возникает естественное побуждение переделать всё с нуля. Но, как писал Джоэл Спольски еще двадцать лет назад, полное переписывание системы редко дает ожидаемый эффект и может стоить компании жизни.
Я говорю самоочевидные вещи, но клиенту нет дела до того, насколько элегантно ваша система смотрится изнутри. Ему важно только одно: решается ли его проблема. Всё время, которое не служит созданию чего-то ценного для него, уходит впустую.
Как предотвратить переусложнение?
На мой взгляд, самый лучший способ предотвратить переусложнение – превратить коллег из абстрактных разработчиков в разработчиков продукта. Этого можно добиться, держа их в курсе бизнес-процессов изо дня в день, объясняя истоки той или иной инициативы с приложением ссылок на метрики, важные для компании. Нужно сократить дистанцию между пользователями и разработчиками, сводить их на опросах и встречах с обсуждением продукта. Команде должны быть знакомы и близки проблемы пользователя, чтобы они могли сразу же отказываться от усилий, которые не будут способствовать эффективному решению этих проблем.
Не ждите, что у разработчиков появится желание избегать переусложнения, если вы воспринимаете их просто как прод-ресурс, единственная задача которого – брать пользовательские истории из бэклога и реализовывать. Им должен быть понятен ход мысли, стоящий за каждым решением.
Продолжая тему, формулируйте проблему ясно, не оставляя места неопределенности. Причины важны, но и ожидания тоже требуют внимания. Чем уже вы очертите проблему, тем меньше у разработчиков будет оснований искать опоры в переусложненных решениях. Хороший способ обозначить требования к системе – использовать показатели SLI и SLO.
Разработчики, как правило, относятся к самым творческим сотрудникам в компании. Если ваши критерии вызывают у них доверие, возможно, в ходе повседневной работы у них будут возникать идеи и предложения, основанные на каком-то гипотетическом сценарии из будущего. Если интуиция вам подсказывает, что это как раз тот случай, задайте вопросы: «Как это поможет нам решить проблемы пользователей на текущем этапе? Что будет, если мы этого не сделаем?». Так вам будет проще определить, замешано здесь переусложнение или нет.
Наконец – этот совет предназначен в основном для основателей компаний – старайтесь в первую очередь нанимать сениоров, у которых уже есть опыт работ в продуктовых компаниях. На собеседованиях высматривайте боевые шрамы. Расспросите о том, какие задачи были самыми мучительными и как они выходили из положения. Выбирайте тех, кто обращает внимание не только на техническую сторону, но также на пользователей, и ценит простоту.
Образ мышления, который спасает от переусложнения
YAGNI
Проблема переусложнения так часто встречается в индустрии, что у программистов есть особое выражение для ситуаций, когда код пишется из соображений «а вдруг» — YAGNI. Это акроним, который расшифровывается как You are not going to need it («Вам это не понадобится»).
Принцип YAGNI служит тому, чтобы предотвратить добавление чего-то не вполне необходимого для решения проблемы, которая перед вами стоит – в реальности это, скорее всего, действительно «не понадобится».
KISS
Акроним KISS (Keep it simple stupid, «Делай всё просто, придурок») указывает на то, что простые системы легче чинить, развивать и поддерживать. Соответственно, простота всегда должна быть одной из целей при проектировании, а лишней сложности нужно избегать.
Чем хуже, тем лучше
Этот принцип подчеркивает, что начиная с определенного этапа предпочтительнее иметь меньше возможностей, а не больше. Причина здесь в том, что продукт с меньшим набором функций легче использовать, что делает его привлекательным для более обширного сегмента рынка.
Иными словами, это подталкивает нас к тому, что поддерживать минимум самых важных функций продукта и обходиться без воды, которая добавит системе сложности.
В заключение
Обобщая сказанное: переусложнение потенциально способно погубить ваш стартап. Оно может:
- Сделать систему запутанной
- Повысить расходы на разработку и поддержку
- Снизить темп итерирования
- Не дать продукту найти свое место на рынке
К сожалению, переусложнение является нормой, а не отклонением от нее. Исходя из этого, крайне важно понимать, что к ней относится, и стараться устранить эти практики, ближе знакомя разработчиков с проблемами пользователей. Время, которое не служит разрешению этих проблем, тратится зря.
Не попадайтесь в ловушку «мало ли что». Кладбища полнятся безупречно продуманными стартапами и продуктами, рассчитанными на миллионы пользователей, которые так и не привлекли к себе никакого внимания. Не следуйте по их стопам.