Comments 10
Мелко-декомпозированный код не является качественным, он является мелко-декомпозированным и только
И эти молекулы тестятся независимо, и реализации каждой заменяются и расширяются при необходимости, а YAGNI портянки, в большинстве случаев - нет. Это и дает значительный прирост в долгосрочной поддерживаемости. Эту долгосрочность очень трудно продавать, как менеджменту, так и технарям, даже демонстрируя ретроспективно где и как эти решения сработали: они живут здесь и сейчас, зашорившись текущим спринтом/таской.
Вопли про оверинжиниринг понятны, все это дико субъективно.
Другой вопрос, что сейчас часто выбирают быстро написать портянку, никаких тестов к портянке не пишется (цена за скорость), а затем, если будет нужно, выбросить целиком и написать заново.
Вопли про такие портянки понятны, все это точно также субъективно.
Выбор в том, что ты хочешь обслуживать на ежедневной основе: портянки с непредсказуемыми сайдэффектами без тестов, или сложные покрытые тестами компоненты.
Кто-то не вырастает из портянок, пушто и так норм. Кто то вырастает, но порой делает выбор в их пользу при выборе решения, по разным причинам. Кто то преимполняется, и радикально отказывается от написания портянок, или наоборот только их и пишет, но осознанно.
И у всех этих подходов есть плюсы и минусы, выбор строго субъективен. Хорошо, когда этот выбор есть.
Последняя версия - все еще Хреново задизайнено:
Метод Send у Api вызывает метод Add у BatchCollector-а.
А почему я должен искать непосредственно сам этот метод Send (в этом стектрейсе Send-Add нету никакого Send-а - той ключевой логики, о которой клиентский код попросил)
А если размер передаваемой коллекции в метод Add меньше размера batch-а? То никакой отправки и не будет. Ответственность не исполняется.
Параметр items в методе Add вообще не используется.
Люди не могут проверить код, который публикуют на всеобщее обозрение.
Я уж молчу про код, который нигде не публикуется.
Вот почему так трудно найти нормальных архитекторов - многие начитались SOLID, и решив, что все поняли, начинают писать статьи на хабре.
А те кто умеют в дизайн - они не пишут никакие статьи.
HINT: Если не умеете в SOLID, то вот вам совсем детская формулировка:
Любой код должен быть спроектирован так, чтобы его было ОЧЕНЬ ЛЕГКО использовать правильно, и
ОЧЕНЬ СЛОЖНО использовать неправильно.
Спасибо! Поправил параметр, но в остальном не стал. Код тут не главное все-таки. И так очень много кода получилось и он забрал существенную меру внимания от основной мысли. Хотя конечно стоило помнить специфику читателя (=
---
С вашего позволения прихвачу правило, себе на будущее. Отличная формулировка!
Если дальше копать - вот метод Add своим именем говорит нам о том, что будет просто добавлен некий диапазон значений в коллекцию. А зачем метод Add возвращает Task-у тогда? Ведь просто добавить в коллекцию это же в чистом виде CPU-bound работа. Где здесь преимущество от использования асинхронности? Ага, оказывается, что добавление сопровождается отправкой. Вот это нарушение SRP.
Очень много ХАОСА в таком маленьком фрагменте кода.
Здесь скорее не ловушка конкретно SRP, а ловушка излишнего перфекционизма.
Он проявляется много где, не только при декомпозиции. Например при использовании паттернов. Многие программисты (даже опытные), порой любят "пихать" паттерны туда, где это вообще не нужно, что только усложняет код без какого-либо решения конкретной проблемы.
Мне кажется, понимание рамок перфекционизма приходит только с опытом. Потому что, нужно искать индивидуальный подход под разные размеры, типы проектов, учитывая например скорость их развития/масштабируемости и т.д.
Мне понравилась мысль, что "декомпозированный код не всегда является качественным кодом". На самом деле, тоже самое можно сказать про любое проявление перфекционизма в разработке. Имхо, но мысли в статье описаны правильные, просто на одном из примеров.
«Наука начинается с тех пор, как начинают измерять. Точная наука немыслима без меры».
Д. И. Менделеев
К SRP есть вопросы:
• как измерить ответственность?
• как измерить единичную ответственность?
• как измерить причины для изменений? (что-бы выявить что она только одна для данной ответственности)
Т.е. это вопросы о метрологической состоятельности терминов этого принципа.
Термин "метрологическая состоятельность" — один из ключевых в инженерном деле. Но его понимание может быть расширено по отношению к тому, как он понимается в инженерном деле, и при этом он должен стать общенаучным: "метрологическая состоятельность" в наиболее широком понимании этого термина выражается в том, что:
выявив явление в природе (а равно в обществе), ему дóлжно поставить в соответствие определённый набор признаков, каждый из которых доступен восприятию людей либо непосредственно через их органы чувств, либо опосредованно через приборную и эталонную базу, порождённую культурой (собственно в построении такого набора признаков и состоит акт выявления в природе объективно наличествующего в ней явления);
выявленные признаки могут быть сведены:
либо в описание, на основе которого независимый наблюдатель способен выявить в среде его обитания это же явление либо однородное ему (по составу набора признаков) явление, если оно объективно наличествует в среде обитания во время наблюдения;
либо в модель, на основе которой можно вести прогностику в отношении развития этого явления либо однородных ему (по составу набора признаков) явлений.
на основе метрологически состоятельных описаний и моделей (при условии, что они адекватны) человек (общество) может выработать своё отношение к явлению:
игнорировать;
приспособиться к нему;
предпринять попытку управления явлением;
однократно или многократно порождать аналогичные явления искусственно, ориентируясь на достижение каких-то своих целей.
Иначе говоря, метрологическая состоятельность деятельности, если она обеспечена, выражается в успешном прохождении последовательности: "объективно наличествующее в среде обитания явление => описание либо модель явления => деятельность, на основе описания или модели явления, связанная с этим явлением и приводящая к ожидаемым (запроектированным) результатам".
А кто для этого кода Вас является actor-ом - источником изменений?
Вы меня извините, но у Вас так и не получилось SRP. АПИ-клиент это инфраструктурный компонент, отвечающий за работу с внешним миром, это его задача, которую нужно было выделить. Только отправка данных вовне. Написали, протестировали и забыли до изменений во внешнем АПИ. Т.е. если не произошло изменений на внешнем сервере, Вам клиент трогать НЕ НУЖНО! Нет никаких затрат на поддержку. С батчКоллектором и таймером еще лучше - они от внешнего мира не зависят, если не делать в них зависимостей на АПИ или друг на друга, то Вы их больше не будете исправлять НИКОГДА! И появляется отдельный класс (или два декоратора поверх АПИ-клиента), который все это вызывает, но знает только по интерфейсам. Тогда, если требуется добавить таймер, Вы тестируете только таймер и вызывающий весь процесс компонент. При изменении в АПИ, тестируете ТОЛЬКО клиент и т.д.
Смысл СРП в этом - при одном логическом изменении исправлять надо только в одном месте. Это снижает затраты на поддержку.
Другое дело, декомпозицию надо начинать тогда, когда понятны оси уже случившихся или вероятных изменений.
Да, конечно! Если разделить клиента на, например, IMyApi и IBatchedMyApi можно будет и решить те проблемы, о которых рассказал ryanl. Тут в коде на самом деле полно недостатков, но совершенно не хочется перегружать статью кодом - затеряется мысль. А идеального кода все-равно не получится, даже если мы соберем тут самые лучшие умы скорей всего мы выработаем только компромисс.
Путь программиста: в ловушке SRP