Comments 87
Статья очень даже кстати.
Многие до сих пор не знают.
Ума не приложу впрочем, как мне это может пригодиться в моей предметной области и более чем уверен что через пару дней придёт
Иногда мне кажется, что собеседования разработчиков превратились в экзамен на китайского чиновника, на котором нужно периодически демонстрировать владение оторванными от жизни глубокомысленными мудростями с блестящими этикетками вроде SOLID, И-дзин, KISS, Ши-дзин, DRY, чтобы потом всю жизнь считать мешки с рисом ворочать джейсоны.
Забавный комментарий, а ситуация страшная.
"Можно не учить ПДД, потому что потом всю жизнь машинку вперёд просто катать"
Хотя, с другой стороны в этом комментарии зарыт и OCP, зачем знать детали реализации, когда нужно только JSON-получить?)
У него на первом же слайде написано: «How can you predict what is going to change?»
И это действительно так! Никто не может!
И, насколько я помню, в книжке про SOLID написано, что нам часто нужно проинтуичить, а как же будет меняться код в будущем. И проектировать в зависимости от предсказанного.
(И если честно, в учебнике по психологии говорят: «если кто-то пытается предсказать будущее — сдайте его в дурку».
;)
Кажется, этот ваш учебник по психологии отрицает даже *использование опыта* (это ведь тоже некоторого рода предсказания), не говоря уже о, например, предсказаниях с помощью математических моделей. Вдвойне забавно, если вспомнить, что животному разум нужен в том числе для предсказания последствий действий.
Иногда из ТЗ (или опроса заказчика) ясно, какая часть будет изменяться. Иногда тот самый опыт говорит, что именно придётся менять. А достаточно большой опыт как раз говорит *делать проще, а то получится фигня как в тот раз*.
Но что делать со случаями, которые от нас не зависят? Их же 100500! Вот сидим мы и пишем код… А завтра оказывается, что у фирмы кончились деньги, проект закрыт, и этот код больше никому не нужен! Поможет ли в этом случае наш опыт? Не факт.
Или, например, bus factor. Думаешь, что завтра будешь писать код, а по факту — не будешь.
Понимаю, что примеры иллюстрируют совсем уж редкие случаи. Но уверен, что есть и другие варианты, когда опыт не очень то помогает :)
ЗЫ: никогда не работал в стартапах, но кажется, что они отлично подходят для иллюстрации, кхм, неопределённости. Во-первых, выживает их — 5%. Во-вторых, из того, что я слышал — ТЗ может вообще не быть, зато может быть так, что на завтра приходит идея «мы всё делаем не так, пользователю нужно совсем другое» и красивую архитектуру проекта нужно менять.
Опыт помогает в части случаев, не в 100% случаев, чтобы безоговорочно ему верить, но и не в 0%, чтобы верить было нельзя. Грубо говоря, чем больше опыт, тем достовернее предсказания.
Закрытие проекта иногда можно "предсказать" по слухам и новостям из курилки, а bus factor - настолько известное явление, что в критических местах его просто необходимо учитывать. Но всё-таки это редкие события, которые предсказываются плохо, но тем не менее предсказываются.
Вообще-то Ден Норс прав.
У него на первом же слайде написано: «How can you predict what is going to change?»
И это действительно так! Никто не может!
И, насколько я помню, в книжке про SOLID написано, что нам часто нужно проинтуичить, а как же будет меняться код в будущем. И проектировать в зависимости от предсказанного.
(И если честно, в учебнике по психологии говорят: «если кто-то пытается предсказать будущее — сдайте его в дурку».
;)
Не совсем он прав. Это как раз-таки задача архитектора и/или старшего разработчика, определить возможные точки изменения и предусмотреть там необходимый и достаточный уровень гибкости. Я тут специально хочу подчеркнуть, что это должен быть опытный человек, который уже и проектированием успел заниматься, и на разные грабли понаступать, и книжек умных почитать. Ну или просто талант с даром предвидения (таких я правда не встречал, но какая-то вероятность наличия таких кадров, думаю, присутствует).
Ну а готовые рецепты вроде паттернов, SOLID, других умных аббревиатур, они созданы в помощь менее опытным разработчикам, или людям, которые не слишком заинтересованы в своём развитии и просто ходят на работу. Таких подавляющее большинство, и если они хотя бы просто банально следуют таким рекомендациям, то всё получается не так уж и плохо. А вот когда они превращаются во всяких "Дэнов Норсов", то становится немного хуже, если они потом не эволюционируют :) А уж совсем плохо, если они начинают пытаться учить других тому, в чём сами не разбираются.
Да, архитектор/разработчик может предположить, что будет меняться. Но! Только при определённых условиях. Если же его работа зависит от внешних факторов, то нет, он не может. Поэтому правильный ответ — мы не можем предсказывать будущее!
Ну и по поводу SOLID, и желания следовать рекомендациям… Есть такая штука — over-engineering. Имхо, жесткое следование принципам — отличный путь в этот самый over-engineering скатиться.
Например, когда мы едем на машине, мы непрерывно предсказываем, что будет если остаться в своей полосе или перестроиться. Когда мы выбираем работу, мы предсказываем, как нас примут в коллективе, насколько респектабельна контора.
Точно также мы можем и предсказывать возможное будущее каких-то систем, просто поговорив с их разработчиками, посмотрев на рынок, на поведение игроков на нём. Например, сейчас можно предсказать, что RISC-V, скорее всего, заменит MIPS, а SPARC окончательно умрёт. Поэтому разумно глянуть на статьи по ассемблеру RISC-V. Банальности? Но это же предсказания.
Про «когда мы едем на машине» — отличный пример. Потому что если посмотреть на количество ДТП, то можно заметить, что предсказание порой оказывается ошибочным. И происходит это потому, что кроме нас на дороге есть и другие машины. Ок, допустим я — профи с 20 летним стажем. Но позади меня может ехать человек, который путает педали и приедет мне в корму. И что толку с моей способности предсказывать?
Ну и если вернуться назад к программированию…
1. Вот мы предсказали какое-то будущее и нарисовали идеальную структуру классов. Но завтра пришёл продакт и сказал, что будущее будет совсем другое. И что нам делать с нашими идеальными классами? Всё равно придётся переделывать проект в соответствии с новым планом.
2. Допустим, мы пишем браузер на базе Хромиум. Какую-нибудь фичу для него. (В этом положении находится сейчас 90% рынка. Даже монстры типа Microsoft, Яндекс, ...)
Какова вероятность того, что завтра мы всё ещё сможем пилить фичу для него? Правильный ответ — никто не знает. Потому что завтра Гугл зарелизит очередную версию Хромиума/Хрома. И никто, абсолютно никто не знает, что именно они там поменяют. Они вполне могут отрефакторить здоровенный кусок своего кода. Именно того, который лежит в основе *нашей* фичи. Или могут отрезать другой кусок кода, потому что «не пригодился». И т.п. Говорить в этих условиях, «да! я знаю, что будет завтра» по меньшей мере самонадеянно. Потому что окружающая действительность зависит не от нас.
Про RISC-V я не готов спорить, ибо специализируюсь на Intel-овских архитектурах.
И что толку с моей способности предсказывать?
В старых книжках по вождению рекомендуют включать стоп-сигнал по-возможности заранее. Уменьшая таким образом вероятность наезда сзади.
И только если это будущее зависит от нас.
Ну если вы видите человека, который пьёт из бутылочки с надписью «Яд», вы понимаете, что рано или поздно ему будет не очень хорошо. А ведь его будущее целиком в его руках. :-)
1. В программировании мы точно также, как и в вождении, можем уменьшать вероятность переделки всего и вся. Понимая, что PM может придти с разными, но всё-таки, ограниченными идеями, мы можем закладывать страховку в архитектуру, делая её менее эффективной, но более гибкой. Это искусство, элемент творчества в нашей работе.
2. Хромиум имеет довольно стабильный план релизов, у него есть beta channel. Ну и вообще, если вы держите руку на пульсе, вам более-менее понятно направление моды в Web. Вот тут пробежала статья про желание переходить на Canvas. Где-то вы знаете, что для вашего рынка, который очень мал для Google, контора не будет ничего пилить.
Конечно, вы абсолютно правильно подразумеваете, что рыночная экономика — это хаос, мешающий планировать в долгую. Но что-то же делать надо, хотя бы до той поры, как мы перейдём всем миром на пятилетки вслед за Китаем. :-)
«Но что-то же делать надо» — имхо, иногда лучшая стратегия — не делать ничего! Чем меньше мы потратим сил на суету, тем больше останется сил на разгребание последствий неожиданных изменений!
Если заглянуть в википедию, то там есть отличная табличка:
«Оправдываемость прогнозов тем ниже, чем выше заблаговременность. Оправдываемость СКПП составляет приблизительно 95-96 %[2], КПП 85-95 %, СПП 65-80 %, ДПП 60-65 %, прогнозов климата — около 50 %.»
Понимаю, что последний пункт — это «угадай, что будет через два года». Но 50% — это же пальцем в небо?
В общем, предсказывать они, конечно, могут. Но не со 100% точностью.
Ну и конечно они сильно ограничены средствам сбора первичной информации и вычислительными мощностями, а уже во вторую очередь — методиками прогнозирования.
Прогноз либо сбылся, либо нет.
Где б найти эксперта…
Просто программистам сейчас слишком мало платят, поэтому их многомесячную работу можно просто так взять и спустить в унитаз. Смотрите, в том же геймдеве это сплошь и рядом — люди работали, им платились деньги, а результат выбросили. Во многих статьях описывается.
Современный сеньор может зарабатывать по 200к (вилка 100-200).
Учитывая, что работодатель кроме денег сотруднику оплачивает ещё и налоги и т.п., с точки зрения работодателя может получиться уже 400к (половину отдал сотруднику, остальное государству и т.п...).
В общем, не так уж и мало :)
У него на первом же слайде написано: «How can you predict what is going to change?»
И это действительно так! Никто не может!
Я больше скажу — код непременно будет меняться везде
И, насколько я помню, в книжке про SOLID написано, что нам часто нужно проинтуичить, а как же будет меняться код в будущем
Нет, книжка по солид говорит, что код обязательно будет меняться, и лучше бы вам писать так, чтоб эти изменения можно было легко вносить
книжка по солид говорит, что код обязательно будет меняться, и лучше бы вам писать так, чтоб эти изменения можно было легко вносить
Логично так поступать в большинстве проектов. Но сверхмалые "кодовые базы", где-то десятки-сотни строк, наподобие несложных скриптов, будет проще и разумнее переписать, чем закладывать в них гибкость.
Попытки заменить if/switch на разные классы приведут к увеличение кол-ва классов и усложнению логики. Считаю это вредным советом, всё зависит от проекта и программистов, чистая субъективщина.
Забавно, что некоторые принципы описаны в новой трактовке, по смыслу сильно отличающейся от предыдущих. Может быть, чтобы нас запутать?
Код пишется так, чтобы его мог понять другой человек. Чем больше абстракций и классов нагородим, тем сложнее разбираться. Не надо идеализировать SOLID, всему своё место.
if (var == const)
return true;
else
return false;
Но главное — это нарезанные по-живому сильносвязанные «микро» сервисы, и много-много слоёв абстракций. Вот с фронта приходят запрос, вот уходит неправильный ответ. Открытие всей цепочки, по которой проходит запрос — десятки вкладок, причём большинство — фасады, обёртки, фабрики и т.п.
Ну хотя бы то, что условный оператор тут вообще не требуется, как и тернарный.
По-нормальному такой код пишется вот так:
return var == const;
Даже в js операция сравнения всегда имеет булев тип результата, который не требует дополнительного оборачивания в условный оператор чтобы вернуть true или false.
В итоге примерно через год код был приведён в нормальное состояние (то есть переписан ))), и, насколько мне известно, мой бэк работает вот уже 6й год без переделок. Для крупного интернет-магазина — это показатель.
Ну, типа, надо было return var == const
.
Напомнило рекомендацию PEP8 (общепринятый стайлгайд по Пайтону) использовать if list: ...
вместо if list == []: ...
(ну и для всех других "булеабельных" типов). Я, конечно, понимаю, стандарт и всё такое, но второе мне нравится больше.
Забавно, что эти принципы каждый трактует по-своему, причём даже простейшие, вроде DRY и KISS.
Simple для кого? для того, кто пишет, или того, кто будет читать? Don't repeat — то есть вместо того, чтобы скопировать слегка отличающуюся функцию, стоит сделать одну монструозную? Ой, нет, она же тогда не Simple!
Всё это напоминает возню вокруг церковных текстов. Как бы пришли к "celebrate, not celibate!!!"
Или какое-нить E=mc2 это тоже священный текст?
Здесь конечно важно не увлечься и не превратить программу в фреймворк.
Если привести образный пример из математики — однажды разработав метод решения квадратных уравнений вы всегда и везде его можете использовать. Вам не нужно бояться, что в какой-то задаче этот метод придется менять — мы будем только композировать его с другими. И это потому, что мы нашли абстрактный метод решения абстрактной задачи.
Подобный навык абстрагирования, если он отработан, как раз полностью решает те проблемы, для которых придуман SOLID.
Если модуль рассматривает некий понятный абстрактный класс задач, то у него естественным образом будет одна ответственность (этот конкретный класс задач). Не нужно заранее гадать что и как будет изменяться — абстрактный класс решаемых задач останется таковым при любых изменениях в общей постановке.
Принципы SOLID попросту логически описывают некоторые признаки подобных удачно найденных универсальных абстрактных модулей, но просто формальное соблюдение SOLID не придаст модулю эту самую полезную абстрактность и даже скорее все запутает. Эффект получается именно от самой абстрактности (универсальности) каждого модуля а не от соблюдения SOLID.
Потому что я читаю ваш комментарий и у меня перед глазами встает типичный код начинающих мидлов с хорошей базой, которые любят воротить абстракцию над абстракциями и пытаться решить универсальную задачу за пару месяцев, хотя им надо решать конкретную за неделю.
Мне кажется, что аналогия с «методом решения квадратных уравнений» из математики, которую Вы привели — порочна. Именно потому что программирование сейчас — это близко не наука, это основном инженерия. Тебе надо не научиться решать класс уравнений, а надо научиться решать конкретное, может быть плюс минус пару похожих. Аналогией из математики были бы численные методы решения дифуров.
Поэтому я чаще сталкиваюсь на практике, что от излишнего абстрагирования наоборот надо отучать. Действительно хорошее универсальное решение — это очень высокий класс мастерства, большинству неподвластный.
программирование сейчас — это близко не наука, это основном инженерия.
Скорее ремесло, поэтому хороший разработчик интуитивно, в результате проб и ошибок, понимает принципы хорошего дизайна кода, но наизусть их не знает.
А те кто выучили их, и думают что стали инженерами, часто применяют эти принципы неверно
Обычно в коде не лишние абстракции, а неправильные и в этом проблема. Самая распространённая ошибка не заметить очевидной абстракции которую, кстати недорого реализовать.
Например видел код специализированного хранилища сертификатов, хотя можно было также просто реализовать или использовать kv storage. Видел kv storage с интерфейсом открытия специфичным для драйверов фильтров фс. По сравнению, со всем остальным выделение интерфейса ничего не стоило. По поводу не повторяй это вообще огонь. Я в одном проекте насчитал не менее 20 реализаций encoder/decoder base64.
При этом не нужно забывать, что код пишут люди. И это все просто ошибки.
Потому что я читаю ваш комментарий и у меня перед глазами встает типичный код начинающих мидлов с хорошей базой, которые любят воротить абстракцию над абстракциями и пытаться решить универсальную задачу за пару месяцев, хотя им надо решать конкретную за неделю.Да, конечно. Поэтому я и написал «Здесь конечно важно не увлечься и не превратить программу в фреймворк».
Но печальную лапшу от хорошо сопровождаемого кода отличает именно это — легкий уклон в абстрактность а не соблюдение неких формальных правил. Естественно абстрактность должна быть настоящей и важной а не выдуманной и для галочки.
И что еще важно — эту найденную абстрактность совсем не обязательно отражать в коде совершенно явным образом с помощью разного рода паттернов проектирования. Достаточно, чтобы эта абстрактность явным образом присутствовала в голове программиста, когда он пишет код и отразилась в коде минимально, лишь набросками, основными чертами.
С кодом без тестов, будь он хоть 100 раз написан по идеальному SOLID — работать совершенно не хочется — потому что это «хрупкий» код, который ломается на раз.
Тесты тоже бывают разными. Можно написать 100% юнит тестов, которые намертво прибиты к реализации и не позволяют ничего рефакторить. Можно переборщить и в обратную сторону – написать интеграционных тестов, по которым совсем непонятно, что именно было протестировано.
Истина, как всегда, где-то посередине. А где конкретно – это может быть очень долгая дискуссия.
Так уж в мире повелось, что каждый пришедший в мир (IT, или любой другой индустрии) во первых хочет изменить мир к лудшему, во вторых не обладает всеми знаниями и опытом, поэтому "к лучшему" сводится к "попроще", ведь трудности возникают в основном с изучением старых, протертых до дыр принципов и алгоритмов. Поэтому и появился новый Ден Нолан, который решил отправить в топку устаревшие отголоски прошлого. От себя могу сказать, что не нужно создавать приложение невероятной архитектуры, чтобы напороться на грабли расставленные теми, кто принципы SOLID попросту проигнорировал. Достался пне по наследству микросервис, который необходимо было немного дописать и переписывать пришлось многое. В одном плассе было собрано все на свете, методы на 200 строк, в которых только разбираться нужно мин 30-40, а в процессе кто-то в параллельной ветке решил расширить интерфейс еще одним методом, и смерджил все в девелоп. Вывод один - если что - то не знаешь или не понимаешь это не значит что принципы или постулаты устарели, и еще одно - не учи других говнокодить, они этому сами научатся.
Особенно забавно работает DRY в примерно таких ситуациях:
«о да тут же одинаковая задача в разных микросервисах — хранение настроек»
Уровень ужаса №1 — давайте запилим отдельный микросервис хранения настроек для всего
Уровень ужаса №2 — давайте запилим единый подход и библиотеку, по дороге выпуская релизы с breaking changes из-за того что нужно новые фичи добавить для каких-то отдельных пользователей настроек (нужные только 1-2 микросервисам).
Он наврядли работал с аутсорсинговыми IT конторами из условной Индии, с сотнями коллег, которым в целом абсолютно все равно на код который они пишут. Тут уже аксиомы на которых они строят свои рассуждения (пример “Пишите простой код”) совсем не очевидны, к примеру чем сложнее и запутаннее код вы напишите, тем больше вероятность заработать больше на его поддержке
И по текущей практике как раз такой подход и нужен бизнесу, рынок не обманешь
Мыть руки не обязательно, 5g нами управляет, земля плоская.... Вот, что я слышу когда люди спорят нужно ли использовать SOLID или нет. Для меня это как маркер - разработчик или кодер. К сожалению встречаю кучу людей которые, либо не читали вообще, либо не разобрались, либо верхушечники, либо любят тупо спорить и порой искренне не понимают этих принципов.
А у людей есть свои вполне физические ограничения — на восприятие числа строк, количество одновременно удерживаемых в памяти концепций и прочее.
Кроме того, есть вполне определенные законы развития легаси софта и т.н. технического долга — они уже столько раз со всех сторон обсосаны, что и говорить неохота
Так что с какой стороны не подходи, в результате придешь к одному и тому же. Называть это можно по разному, а суть одна
А то стартаперы-то, напишуть прототип в лоб, и продадут за мильены, и руки уже умывают
А одно из условий продажи, например — поддержка и обучение, на пару лет. И начинается…
Это только нетфликс потом может взять, и все переписать. А если не нетфликс — то так такие решения в лоб и остаются, и портят кровь последующим когортам девов
Принципы SOLID не стали менее актуальны, просто на практике они никогда сильно актуальными не были. Каждый из этих 5 принципов может применяться к конкретному примеру архитектуры кода разными программистами с точностью до наоборот, имея при этом хорошую аргументацию. Что означает single responsibility? Разные программисты оценивают по разному (должен ли метод, сохраняюший в базу, посылать письма?). Нарушает ли класс принцип Лисков? Зависит от того как мы трактуем контракт базового типа, который явно не прописан (или прописан недостаточно точно)
Проще говоря, если вам надо поменять метод, сохраняющий в базу, это делается в одном модуле, а если надо написать отсылку письма — то в другом
Как его можно по-разному применить-то?
Когда вы строите хоть сколько-нибудь нетривиальную систему, декомпозируя задачи на подзадачи, у вас никогда не будет элементарного понятия «одна ответственность». Она всегда будет иерархическая — ответственность разбивается на «подответственности». Мой аргумент состоит в том, что у вас никогда не будет единственного правильного способа такого разбиения — разные программисты зачастую по-разному видят то, в каком модуле и на каком уровне должно делаться то или иное действие. Соответственно они по-разному будут понимать что есть «единственная ответственность» и «единственная причина изменить код».
«Пишите простой код!»
Ха. У меня как-то был менеджер, который говорил — просто пишите код без багов, и все!
Актуальность принципов SOLID