Ваше проектирование -- отстой

Перевод статьи Мэтта Траута (Matt S. Trout, mst) "Your design sucks"

26 Jan 2016


Мой перевод статьи “Your design sucks” http://shadow.cat/blog/matt-s-trout/your-design-sucks/

Перевод также опубликован на Хабрахабре: http://habrahabr.ru/post/275231/

Об авторе: Мэтт Траут (Matt S. Trout, mst) – Perl-разработчик, сооснователь и техлид компании Shadowcat Systems Limited (консультирование в области разработки ПО), автор ORM DBIx::Class, один из ментейнеров веб-фреймворка Catalyst, автор многих модулей на CPAN.


Ваше проектирование – отстой

… но это нормально. Любое проектирование отстой. И всегда будет отстоем.

Если вы мне не верите, давайте объясню…

Ни один проект не переживает встречи с реализацией

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

Данные, которые вы ожидали как обязательные в ответе внешнего сервиса, могут отсутствовать (или быть невалидными). Ожидаемая уникальность может оказаться совсем не уникальной на практике (даже в sha1 когда-нибудь случаются коллизии). Процессы, которые предполагались надежными, будут падать гораздо чаще, чем вы ожидали.

Это нормально.

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

Недостающие данные могут быть сделаны опциональными или заменены умолчальными.

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

Ограничение уникальности можно отменить, или смержить данные, или выбрать одну из версий.

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

Считать ли нарушение ваших предположений ошибкой, добавлять ли промежуточный слой или исправить концепцию системы для большего соответствия реальности – решать надо в каждом случае отдельно. Это всегда решение о справедливом компромиссе: стоит ли обработка бардака во внешнем мире усложнения вашей системы?

Ни один проект не переживает встречи с настоящими пользователями

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

Люди будут искать по неожиданным параметрам (“да, я знаю, что могу поискать по client_id, но гораздо проще посмотреть, с какого телефона мне звонят, и поискать по нему”).

У людей будут появляться суеверные привычки – ожидайте, что функции типа “погасить все и перестроить заново” будут использоваться гораздо чаще, чем предполагалось, потому что пользователи воспримут ее как “выключить и включить” и отнесутся соответственно.

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

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

Когда встречаетесь с суевериями, вы или ограничиваете доступ к неправильно используемым функциям (снова жалобы), или изменяете интерфейс, чтобы привести пользователя к функции, которую он на самом деле должен был бы использовать, или добавляете хитрую логику по определению ситуаций, когда на самом деле достаточно более простых действий.

Обнаружив непредвиденные варианты использования, вы либо объявляете их неправильными (жалобы… и, возможно, обходные пути, которые добавят вам проблем одного из двух других типов), либо реализуете их поддержку, несмотря на то, что это не планировалось изначально, либо интегрируетесь с другим сервисом, который предоставляет такую функциональность.

Еще раз: это все компромиссы; и становится заметно, что есть три основных варианта действий.

Три Типичных Ответа

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

Приспособиться, что покрывает “ослабить ограничения” и “добавить индексы” – то есть подправить дизайн, чтобы проблемный сценарий обрабатывался бы хорошо. Это лучший умолчальный вариант для сценариев, которые “почти подходят”, то есть когда невелики расхождения между “что есть” и “что требуется”.

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

Ни один проект не переживает встречи с будущим

Даже учитывая все изложенное выше, только две вещи можно сказать наверняка: по крайней мере часть вашего проекта – отстой; и спустя полгода вы осознаете, что эта часть больше, чем вы думаете сейчас.

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

И что со всем этим делать? Лучшая идея, которую мне до сих пор удалось найти, довольно простая: проектируйте в предположении, что все пойдет не так, и постарайтесь сделать, чтобы фиксить последствия этих “не так” было бы настолько легко, насколько возможно.

На самом деле, все базовые принципы хорошего программирования можно рассматривать как следствия этого подхода.

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

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

Разделение ответственности означает, что детали реализации не “утекут” во внешний мир, потому что когда внешний мир не полагается на конкретную реализацию, а вы вдруг понимаете, что ваша реализация отстойная, вы можете переделать или даже заменить ее и не заботиться о переделывании кода вне этой части системы (или: компартментализация – это первичная экстернализация в рамках аггрегирующей системы).

Итого

Ваше проектирование – отстой.

И всегда будет отстоем.

Если ваш проект сейчас не кажется отстоем, это потому, что вы что-то упускаете.

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

Проектируйте в предположении, что позже вы определенно, совершенно точно, обязательно будете перепроектировать.

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

А самое главное: не переживайте слишком из-за этого. Звук “рука-лицо” – это не признание некомпетентности, это – шум, издаваемый проблемой, превращающейся из неразрешимой в тривиальную.

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

Так что это нормально, что ваше проектирование – отстой.

Продолжайте отстойничать. Продолжайте отстойничать чуть меньше. Продолжайте отстойничать по-другому. Продолжайте учиться.

И помните – выпустить что-то отстойное на 100% лучше, чем не выпустить вообще ничего.

Удачного хакинга.