Комментарии 93
Я каждый раз забываю про SOLID пройдя интервью и получая жопофер. и каждый раз читаю про него, когда меняю работу.
ИМХО, что если принципы сформулированы так, что их нифига непонятны — это фиговые принципы. Для «простой» архитектуры невозможно использовать сложные принципы, которые нихрена не понять. Простая архитектура — «контроллер-логика-DAO», например, один раз прочитал — никогда не забудешь, или MVC или flux.
SOLID — как библия или Коран, каждый объясняет по-своему. То «не убий», то «сжечь ведьму»)
Для "простой" архитектуры не нужны принципы, это ещё php показал завоевав популярность всем кодом в одном файле.
Конечно не нужно цитировать solid с точностью до буквы, нужно их понять. А когда понял причины понимаешь когда следовать, а когда нарушать.
ИМХО, что если принципы сформулированы так, что их нифига непонятны — это фиговые принципы.
Есть мнение на этот счет:
Эта статья про то, что он может применяться намного шире, чем многие привыкли думать. А в целом является достаточно универсальной инженерной концепцией. Возьмите какую-нибудь гайку, там будет практически весь SOLID. Если вы не начинаете создание какого-то программного артефакта с понимания и выделения его зоны ответственности (SRP или "крепёжный элемент" на примере гайки), не вводите абстрактных интерфейсов (DIP или "метрическая резьба", "шестигранная" опять же для гайки) и т.п., то у вас есть проблемы. Вам так понятен MVC поскольку он — результат применения SRP.
Если вы к токарю придете и скажете ему сделай мне гайку М6 со стандартной резьбой. Он вам ее просто сделает. Не подохревая о СОЛИД, СРП, МВЦ и прочем.
Если вы придете и начнете ему затирать про принцип единой отвественности крепежного элемента с выделением в абстрацкцию его резьбы… НУ вы сами поняли.
Нет, не понял. Ни связи между "универсальной инженерной концепцией" и "философской широкой книгой", ни параллели с токарем)) Тогда можно любую книгу по теории струн, теории категорий или функциональному программированию сравнивать с библией. Относительно лаконичная теория широкого применения и многокнижие обо всём — это не одно и то же.
У токарей всё намного SOLIDней. Сама фраза "сделай мне гайку М6 со стандартной резьбой" — это DIP. В этой области уже давно провели SRP и ISP, аккуратно структурировав информацию по всяким DIN, SAE и т.п. Так что они-то, как раз, прекрасно об этом осведомлены и терминологией не нам их пугать)
Если вы придете и начнете ему затирать про принцип единой отвественности крепежного элемента с выделением в абстрацкцию его резьбы…
Вы знания вообще транспонировать не умеете? Нужно принципиально лезть в другую сферу со своей терминологией? Крепежный элемент — это уже выделение ответственности, а резьба — суть абстракция. Загляните в ГОСТ 27017 и посмотрите, как они расписали для себя SRP, DIP, ISP и какую терминологию используют. Если мы слово ответственность заменим на назначение, а абстракцию на стандарт, то мир рухнет?
Слишком много философии в весьма примитивные вещи, человек! Я об этом!))
Отличный ответ на моё удивление, что вы тащите специфичные термины в другой домен. Некорректная терминология часто встречается в брошюрках по демагогии)) Даже в нашей среде язык сильно различается и тот же ISP при работе с базами данных станет вертикальным партиционированием, а DIP станет представлениями. Но слесарь, конечно, должен пользоваться словарём из математики бинарных отношений. Вы с заказчиками и пользователями своих продуктов тоже на нашей тарабарщине общаетесь?))
Зато философии да, здесь много. Тот же слесарь говорит "гайка M7 под ключ на 12", где практически весь SOLID отражён, и чтобы это понять нужно, как минимум, четыре тома начал Аристотеля знать наизусть))
Так вот SOLID прост и важен как эта самая гайка. Возможно, он вам не сразу зашёл и оттого начались эти выдумки про его сложность. Но слушайте, скажем ФП ещё сложнее и термины ещё забористей. Может это просто не ваша сфера?)) У вас задача понять и разобраться, как я понимаю, в принципе не стоит?))
Я вам так скажу, я в детстве много читал, и грамотно писал, но никогда не знал правил русского языка. Я просто писал «ЖИЗНЬ» потому что у меня в голове не укладывалось что можно писать«ЖЫЗНЬ», хотя я и не подозревал про правило «жи-ши пиши через и».
И меня всегда забавляли попытки засунуть всю «ЖЫЗНЬ» в пять принципов, 10 постулатов, три завета, и устроить срач на тему, какой из принципов важнее. Иногда получается и круто. В данном случае не получилось, спасибо за попытку, выкиньте и забудьте.
Я просто писал «ЖИЗНЬ» потому что у меня в голове не укладывалось что можно писать«ЖЫЗНЬ», хотя я и не подозревал про правило «жи-ши пиши через и».
А какие-то люди так не могут, и им нужны правила.
Удивительным образом, с SOLID так же: кто-то интуитивно понимает, а кому-то правила нужны.
Нет, я знаю много людей, которые, сколько бы они не читали, не могут писать грамотно, поэтому им нужны правила.
Почему же, они с правилами пишут грамотнее, чем без них.
не ради срача, но есть правила грамматики которые запоминаются легко и юзаются многими. Например, «жиши» или «тся/-ться»,
а есть типа «у не отглагольных прилагатльеных в вопрсоительной форме не пишется мягкий знак, а прилагательных глаголов пишется твердый, когда мягкий в замене деепричастие не слышен, и далее два абзаца текста», что читаешь с карандашом над конкретным словом и забывашье сразу после прочтения))) Помню учил с сыном уроки))))
Во-первых, это нормальная тенденция для любой темы. Каждый второй, достигший понимания, стремится научить других. И это хорошо. Как показывает практика, дефиниции Дяди Боба не всем (и мне, в том числе) понятны.
Во-вторых, простая — это не синоним примитивной. И совершенно не значит, что её может понять любой за несколько минут. Я сам лет десять назад скорее относился к критикам и также апеллировал к созданию излишних сложностей. А потом всё поменялось, но на это ушли годы.
Пример с правилами русского языка из той же оперы. Теоретически, прочитав миллион книг, я бы смог выявить основные этимологические конструктивы. Но вместо таких бешенных инвестиций я и изучил базу. Теперь для меня не составляет большого труда понять слова вроде перипатетик или миофасциальный. Понимание конструкции приложения помогает расставлять запятые гораздо проще, чем дрессировка этого навыка.
Можно натренировать свою нейросеть огромным объемом данных чтобы научиться складывать многозначные числа, а можно ограничиться только однозначными плюс простые правила и сложение столбиком. У каждой свой выбор.
Вы мне чем-то моих детей напоминаете. Младшая ругается на арифметические операции, средний на тригонометрию. Аргументы почти те же))
Программисты — не токари в этом контексте, они гайки не делают, они определяют какой должна быть гайка, чтобы токарь услышав "М6 со стандартной резьбой" сделал именно то, что имел в виду говорящий.
А какой контекст? И кто тогда сделал первую гайку M6? Врач? То есть в начале был ANSI/ISO и только потом стали использовать гайки?
Или всё-таки были слесари, которые в начале веков соединяли детали кто во что горазд. А потом к ним снизошёл SOLID, они выделили крепежную ответственность, выделили абстракции вроде метрических систем, сделали ISP в токарей и пошло поехало.
Скажем REST — это наши гайки. Получается, что программисты REST не делают, они REST описывают? Имхо, dididididi совершенно прав, вводят специализации. ИТ часто демонстрирует, что одна и та же сущность имеет множество аспектов, или категорий говорят языком теорката. И некоторого условного программиста мы можем видеть в самых разных ипостасях. Поэтому формулировка, что программист — это только X практически никогда не будет точной в искомой мере.
Потому что даже в том определении, которое у вас процитировано на английском, указано, что принцип S означает очень тесную связанность функций объекта между собой, то есть по сути все поведение объекта крутится вокруг его предназначения. Два разных предназначения приводят к нарушению этого правила.
God Object очень легко построить на хотелках одних только бухгалтеров, поверьте. Я пробовал лет 20 назад.
Два разных предназначения приводят к нарушению этого правила.
Вопрос в том, как определить "предназначение". По группе людей — один из способов (не самый плохой).
Так god object и не обязательно нарушает single responsobility, вот инверсию зависимостей — целиком и полностью в любом исполнении.
Я не встречал лучшей интерпретации чем у Мартена, зато встречал кучу апологетов "единой ответственности" которых ставила в тупик следующая проблема: "если функция должна делать только одно действие то что насчет main которая делает все что делает программа"
ЕО не только одном действии, а для случаев, когда разработчику выгодно обозначить цепочку действий одним действием.
Пишем «удар» а на самом деле может быть:
расслабление
присед
отталкивание от опоры
запуск волны
возвратные действия
…
Таким путём, понемногу усложняя абстракции, превращая цепочки в ЕО, несколько непростых ЕО опять в цепочки… получится, что main делает одно действие.
Как в анекдоте про три желания «Недвижимость, деньги, женщины — это только раз».
Оно вывело дискуссию на зависимость объекта от среды-домена.
И ваш пример показывает опасность-сложность добавления «избыточных» степеней свободы объекту — он может начать жить не так, как хотел разработчик :-).
А тусовка нескольких «творческих» объектов превысит когнитивную способность рассчётов создателя.
Не соглашусь с тем, что SRP только про классы, функция тоже модуль, она тоже должна быть сильно связной и слабо связанной с другими.
Модули/классы они как раз и декларируют эту связность, это выделяется тем что они либо разделяют либо состояние либо детализированный интерфейс.
К примеру функции по работе с файлами fopen, fread, fclose можно выделить как модуль т.к. они разделяют состояние (файловый дескриптор) и разделяют детализированный интерфейс (файловый дескриптор — указатель на структуру, детали интерфейса закрыты для доступа снаружи, однако для этих 3х функций они доступны как бинарный АПИ, а не абстрактный интерфейс).
Одиночная функция может быть трактована как модуль если она зависит только от абстрактных интерфейсов, однако в конечном случае вы всё равно столкнётесь с тем что нужно писать функции которые зависят от детализированного интерфейса и вот это уже область деятельности SRP.
И даже этот простой пример можно изуродовать, например если у вас функция зависит от десятка разрозненных интерфейсов которые скажем так, не оптимально спроектированы, и внезапно мы получаем сильную связность через интерфейсы, но тут уже может помочь корректно определить интерфейсы LSP.
Даже если вы соберёте все хотелки от бухгалтеров в одном классе, но код будет на одном уровне абстракции этот код будет лучше, чем многое из того, что я видел.
Обратите внимание, этот принцип относится к модулю, видом которого в ООП является класс. Модули есть во многих языках и скажем прямо — в языках вроде Java не самая лучшая реализация модулей. Выходит этот принцип не ограничен ООП
Вы потеряли тут логическую цепочку. Из этого текста — не выходит. Из того, что в Java не лучшая реализация модулей, вообще мало что следует, и эта фраза только запутывает смысл вывода, который без нее выглядел бы так:
— Этот принцип относится к модулю, что бы это ни значило.
— Модули есть во многих языках (видом модуля в ООП является класс)
— Выходит этот принцип не ограничен ООП — а ограничен языками, где вообще есть модули.
Что уже немного лучше, хотя все равно не идеально.
А в целом с посылом поста я согласен. Вообще говоря, сильная связность внутри модуля, и слабая между ними — это тоже принцип универсальный, и модули тут тоже не из ООП.
Если эти принципы сбалансировано отражены в программе, то все будет хорошо независимо от деталей, типа соблюдения SOLID.
Модульность — это просто (на практике «просто» в кавычках). Нужно поделить систему на слабо связанные части с понятным поведением. Во многих случаях одной модульности достаточно.
Абстрактность — это посложнее. Здесь для себя, я представляю бесконечного размера программу, написанную для решения вообще всех возможных практически полезных задач за приемлемое время и занимающую наименьшее количество места (т.е. с близким к максимальному переиспользованием кода, где это не ограничено требованиями к скорости работы). В этой супер-программе можно выделить куски кода, которые для случайно выбранной задачи будут выполняться с большей вероятностью. Это будут самые «абстрактные» модули. Мозг каким-то образом способен отличать такие модули, когда он их видит, и способен генерировать их даже почти на пустом месте по каким-то намекам. Благодаря последнему свойству, в их работе часто (но не всегда) бывает легче разобраться (понимаем лучше то, что можем создать). И главное — у таких модулей по определению больше шансов быть вызванным без изменений в другой задаче и при другой постановке.
Дальше, нужны концепции, которые позволят сформировать границы модулей в коде программы: ООП, области видимости, женерики, чистые функции и др.
Первые две буквы SOLID как раз об абстрактности: в упомянутой супер-программе маловероятно исполнение (или даже наличие) модуля, который выполняет сразу две не связанные задачи или требует внутренней модификации для исполнения сходной задачи.
Последние 3 буквы — они на стыке поиска абстрактности и нюансов конкретного инструмента, которым мы нарезаем модули. L — абстрактнее модуль, не требующей еще одной своей версии для других входных данных, I и D — абстрактнее модуль, способный работать вне окружения (в тестах в то числе).
Правда, у всей истории есть еще одна совсем другая сторона: как трансформировать смутное понимание того, как все должно работать в работающий код. Здесь ООП и ФП как раз предлагают противоположные подходы.
Конечно существуют более общие и более абстрактные принципы как Low Coupling, High Cohesion а так же в целом абстракция. SOLID это более конкретные и более практичные советы на их базе. А уж двигаясь дальше в сторону практики и конкретики возникают паттерны.
Хотя, это базовый инстинкт программиста (и не только): если все стало слишком сложно, нужно посмотреть на вещи абстрактно.
Почему нет? Полиморфизм это про абстракцию, DI, open/closed, инкапсуляция, паттерны это вообще все абстракции.
Базовый инстинкт программиста говорит мне, что абстракция — возможность использовать что-то вместо чего-то не погружаясь в детали обоих. Самый базовый, наверное, пример абстракции во многих языках высокого уровня — переменная и/или аргумент функции.
P.S. Наверное даже не "вместо чего-то", а просто "использовать, не погружаясь в детали"
Ну вот, собственно, как 20 против что угодно. Ну или сколько изменений нужно сделать чтобы добавить 21-й класс.
— как сделать разработку более эффективной?
— используй больше абстрактных модулей;
— что это даст?
— их код легко переиспользовать и для изменения программы потребуется меньше изменений;
— ok, что имеется ввиду под «абстрактными» модулями?
— это такие модули, код которых легко переиспользовать и при использовании которых для изменения программы потребуется меньше изменений…
И второй момент: 21-й класс может иметь асинхронно работающий конструктор и допустим, раньше завершения инициализации объект нельзя передавать клиентам этого сервиса. Тогда при прямом создании объектов потребуется добавить пару строк, а при использовании IoC — переписать половину кода модуля-контейнера. Значит критерий «минимум изменений» слишком поверхностный, типа «жизнь — это способ существования белковых тел». Абстракция — нечто иное.
Абстракция нечто иное, но самые важные для программирования её свойства это именно минимизация количества изменений кода при изменении требований.
А так абстракция в программирование — это сокрытие или, скорее, игнорирование (сокрытие лишь упрощение игнорирования) деталей реализации.
Кстати, вы говорили "что угодно", а оказалось, что только с синхронными конструкторами — плохая абстракция для вашего кейса :) Может на момент создание была и хорошей, но когда появилось новое требование, оказалось недостаточно абстрактной, зависела от деталей реализации.
А так абстракция в программирование — это сокрытие или, скорее, игнорирование (сокрытие лишь упрощение игнорирования) деталей реализации.То о чем вы говорите я бы лучше просто называл модульностью: создаем некие модули, поведение которых в целом понятно, а в деталях можно разбираться или нет. Астрактность — это когда мы пишем модуль так, как будто решаем не конкретную задачу, имеющуюся здесь и сейчас и пишем библиотеку для решения широкого круга задач подобного рода. Меня смущает отсутствие теоретической базы на этот счет. Возможно она есть, но я ее не нашел.
Абстракция в общекогнитивном смысле — это как раз сокрытие неважных для "юзкейса" деталей. Теоретическая база — философия от древних греков, а то и раньше.
И философия — это не теория. Теория, это абстрактные автоматы, машина Тьюринга, Колмогоровская сложность и др.
В программировании не бывает важных и не важный деталей.
Бывает-бывает. Иначе бы вы просто не справлялись с задачами.
Скажем, когда я пишу программу на C#, мне (большую часть времени) не важно, какой IL получится в итоге, и никогда не важно, какими командами процессора это будет выполняться.
Теория, это абстрактные автоматы, машина Тьюринга
… и машина Тьюринга — это уже абстракция. Нет?
Я выше настаивал, что в программировании абстракция — это когда мы пишем нечто, что годится для решения широкого класса подобных задач. А не нечто «детали чего скрыты».
Детали скрыты в любом модуле, даже том, который жестко завязан на одну конкретную задачу конкретного заказчика и больше ни на что, но для такого модуля нет смысла говорить об «абстрактном решении задачи».
Например, компилятор позволяет вам не думать о кодовых командах процессора и это эффективно, но это работает потому, что компилятор годится для очень широкого круга задач. Если бы это был компилятор, который мог бы компилировать только одну конкретную программу с легкими модификациями, то он тоже скрывал бы детали компиляции и позволял бы отдельно думать о компиляции и о программе, но это очень мало бы что упрощало (только в той степени, в которой упрощает ситуацию обычная модульность).
Я имел ввиду «в программе не бывает важных или не важных деталей»,
Ну и это тоже неправда. Мне не важно, какой логгер подключат в мою программу через конфигурацию, мне важно, чтобы он выполнял ряд условий.
Детали скрыты в любом модуле, даже том, который жестко завязан на одну конкретную задачу конкретного заказчика и больше ни на что, но для такого модуля нет смысла говорить об «абстрактном решении задачи».
Концепция модуля — это уже абстракция. никогда не встречали простыни на десятки тысяч строк практически без всякого разделения на модули, подпрограммы и прочии абстракции?
В программировании не бывает важных и не важный деталей.
Бывает.
Изменение любого бита приводит к изменению поведения в результате.
Даже в сам общем случае не факт: в мёртвом коде можно менять что угодно — поведение не изменится. Возможно оптимизатор вообще его выкинет.
Нет деталей, которыми можно пренебречь, как в физике.
Полно. Программируя на языке высокого уровня я почти всегда могу абстрагироваться от того на процессоре какой архитектуры мой код будет исполняться, LE числа он использует или BE, например, RISC он или CISC. Не всегда, поскольку абстракции текут, но часто, очень часто. Или как выше указано — всё что от логгера мне надо — реализация им конкретного известного мне интерфейса (саботаж разработчика имплементации не учитываем). А там хоть админ пускай меняет имплементации.
Абстракция в программировании выбирает те аспекты поведения, которые будут с высокой вероятностью повторяться в других задачах подобного рода и выносит за рамки абстракции аспекты, которые меняются от задачи к задаче.
Вы говорите об абстракции для переиспользования кода. Но они приаеняются не только для этого. Например, в слое бизнес-логики я объявляю интерфейс доступа к данным (репозиторий). Я на 100% уверен, что в других задачах он повторяться не будет, но делаю я его с целью абстрагироваться от деталей поведения.
И философия — это не теория.
Философия — это одна сплошная теория. И абстракция — её основной инструмент.
Абстрагирование — отвлечение в процессе познания от несущественных сторон, свойств, связей объекта (предмета или явления) с целью выделения их существенных, закономерных признаков.
Суть в том, что мы не можем охватить всю систему одновременно, умишком не вышли. Приходится делить ее на части и рассматривать каждую часть в отдельности, называя остальные несущественными для текущего фокуса. Для этого приходится придумывать абстракции и подгонять код под них, даже именованные переменные придумали для этого, потом функции, а потом пошло-поехало...
Микросервисы хорошие тоже соблюдают солид, правда пример для dip в голову не приходит
Сервис может нарушать DI если хардкодит адрес зависимости, если api не достаточно абстрактен или если сервис полагается на особенности реализации другого.
В силу физического разделения приходится использовать api, но и в ооп интерфейс это не всегда абстракция.
Вот, да, если сервис получает адрес своей зависимости (другого сервиса, БД, очереди и т. п.) не из енв-конфига-дискавери — то это злостное нарушение DI :)
Это хорошая практика SSoT, но к DIP не имеет отношения. Во-первых, сам дискавери-сервис — это микро-сервис. Получается, что он не DIP? Во-вторых, адрес может быть абстракцией. Скажем вы заходите на habr.com и нет разницы, как он реализован, пока сохраняются основные контракты — вы можете получать и поставлять контент. Фиксированный адрес может быть абстракцией вроде rest://production/security/login и в данном случае какой-нибудь ingress-controller вместе с DNS могут выполнять роль эдакого IoC-контейнера. DIP (а также ISP+SRP) — это сам факт использования микро-сервисов, через них мы привносим эти принципы в продукты.
Я бы не сказал, что не имеет отношение. Вы же сами пишите, что ingress-controller вместе с DNS могут выполнять роль эдакого IoC-контейнера
Поясню. Есть принципиальный уровень, где правит SOLID. Он говорит, что есть абстракция DNS протокола, а будет там CloudDNS, Bind9 или Unbound — не важно. Есть абстракция Ingress-controller, а Traefik, Haproxy или Nginx — пробуй любой. Тоже самое с service discovery. Это по определению сервисный уровень. Попытка поставить в зависимость от него принципиальный уровень (фразой "если сервис получает адрес своей зависимости не из енв-конфига-дискавери — то это злостное нарушение DI") — это серьёзный фейл в дизайне. Не может принципиальный дизайн зависеть от конкретных реализаций. Это всё равно что биохимию ставить в зависимость от полок соседнего супермаркета.
Попробую пояснить на примере pure-man инфраструктуры. Абстракциями в терминах DIP делаем адреса. То, что в коде выглядело бы как некоторый интерфейс SpecificContract стало /api/specific-contract. Собираем докер-контейнеры, которые реализуют конкретные контракты, например в docker-compose или ansible playbook с соответствующими labels для Traefik. Добавляю контейнер с Traefik + docker provider, готово. В любой момент я могу подменить контейнер с реализацией, но всё будет функционировать как ожидалось, поскольку DIP. И service discovery здесь даже не пахло.
Концептуально, абстракция — это имя сервиса и грамотно выработанный convention. Service discovery — суть маппинг абстрактного в реальный, что очевидно за пределами SOLID.
Вопросы про SOLID с самого начала омрачались чрезвычайно серьезным к ним отношением, различными интерпретациями, нюансами перевода на русский и неутешительными реалиями практического применения. С ростом популярности ФП, попытки притянуть этим 5 буквам новые толкования, доводят хоть какие-то остатки смысла до абсурда.
С удовольствием бы прочитал о принципах хорошего проектирования для ФП, без попыток критики и заимствования чужих.
Ну то есть понятно, что в этом принципе есть некий здравый смысл о проектировании системы. Но почему это возводят в абсолют?
Интересно услышать мнение интервьюеров на этот счёт.
кому не лень зубрить к собеседованию разную хрень
А это уже лучше чем ничего =)
Т.е. когда ответ типа «читал я этот SOLID и смутно представляю по своей работе когда это может принести нам всем деньги и вообще как конкретно это все предлагается применять» засчитывается в минус а не в плюс.
Сам по себе — нет, не засчитывается. Просто дальше будет какая-нибудь типовая задача на один из принципов. Если человек решит ее правильно — ну ок, неудобно, что он не знает, как это называется, но можно жить. А вот дальше будет вопрос, почему, если он "читал этот SOLID" и решает задачи в соответствии с ним, не видит применимости.
Напротив, поверхностный человек может очень легко отбарабанить вам принципы одним левым полушарием, разъяснить все тонкости и обязательно учесть их в коде. Но потом выяснится, что это просто обезьянье подражание лучшим практикам без всякой реальной способности заставить эти принципы работать на пользу а не в усложнение.
Задавая академические вопросы неправильно можно дать преимущества второй категории людей по сравнению с первой. Я так полагаю, в этом заключается основное недовольство подобными вопросами.
Он привык плясать от целесообразности в архитектуре, а в тестовом задании ее нет
Можно задать уточняющие вопросы. И да, задание на архитектуру построено так, что она там есть.
Половина в реальном соблюдении SOLID — это карго-культ, не более
Если кандидат считает, что те правила, которые мы соблюдаем, карго-культ — возможно, ему правда не стоит здесь работать.
Этот человек работал в другом мире, о существовании которого вы не подозреваете, где проблемы со сложностью были совсем другие (в вашем мире он сориентируется за неделю).
А откуда мне знать, что он сориентируется в моем мире за неделю, если он не смог сориентироваться в его маленьком выделенном кусочке за время выполнения тестового задания?
до того, как он реально столкнется с их необходимостью и сделает их частью своей целостной картины мира.
Если человек до сих пор не столкнулся с необходимостью принципов, которые я считаю важными в программировании (безотносительно того, как эти принципы называются), то, возможно, его опыт мне не подходит. От позиции зависит, понятное дело.
Задавая академические вопросы неправильно можно дать преимущества второй категории людей по сравнению с первой.
Задавая любые вопросы неправильно можно дать преимущества какой-то группе людей. Задача собеседующего в том, чтобы задавать вопросы правильно.
Понимаете ли, собеседование — оно не только на некий абстрактный "технический уровень". Оно еще и на то, насколько с человеком будет удобно (или неудобно) работать. Если с ним нет общего языка, возможно, он не подходит на позицию, даже если он гений.
Если кандидат считает, что те правила, которые мы соблюдаем, карго-культ — возможно, ему правда не стоит здесь работать.
А если у него нет никакого мнения на этот счет и он просто повторяет прописные истины, которые вы хотите услышать, то это для вас более приемлемый вариант?
А откуда мне знать, что он сориентируется в моем мире за неделю, если он не смог сориентироваться в его маленьком выделенном кусочке за время выполнения тестового задания?Потому что он уже сориентировался в своем мире. Во второй раз всегда легче. А откуда вы знаете, что он способен сориентироваться вообще хоть в каком-то мире, если он просто наловчился аккуратно решать тестовые задания?
Если человек до сих пор не столкнулся с необходимостью принципов, которые я считаю важными в программировании (безотносительно того, как эти принципы называются), то, возможно, его опыт мне не подходит.А если он соглашается, что принципы классные и отражает их в тестовых примерах, то вы можете сделать вывод, что он реально сталкивался с их необходимостью?
Задавая любые вопросы неправильно можно дать преимущества какой-то группе людей. Задача собеседующего в том, чтобы задавать вопросы правильно.Поэтому лучше показать человеку местные проекты, обсудить с ним детали и решения, посмотреть как он реагирует. Попросить его показать созданные им модули, пусть расскажет что и как делал. По ходу можно оценить его уровень и ход мыслей. Можно обсудить философски насколько полезен этот SOLID, пусть выскажет свое мнение без прикрас, приведет примеры из своей работы, когда это было полезно или не очень, попытаться прийти к консенсусу с его пониманием вопроса. Ну и можно дать практическую задачу просто для оценки общего уровня, без ловли блох «правильного» и «неправильного» кода.
А если у него нет никакого мнения на этот счет и он просто повторяет прописные истины, которые вы хотите услышать, то это для вас более приемлемый вариант?
Если у него нет своего мнения на этот счет, да, это более приемлемый вариант, чем "это карго-культ".
Во второй раз всегда легче.
Это ваше допущение, с которым я не согласен.
А откуда вы знаете, что он способен сориентироваться вообще хоть в каком-то мире, если он просто наловчился аккуратно решать тестовые задания?
Потому что тестовые задания, которые я даю — это срез моего мира. Их нельзя решить, не соориентировавшись.
А если он соглашается, что принципы классные, то вы можете сделать вывод, что он с ними сталкивался?
А я не спрашиваю, классные они или нет. Я спрашиваю, что они означают и как применяются.
Поэтому лучше показать человеку местные проекты, обсудить с ним детали и решения, посмотреть как он реагирует.
Лучше сделать и то, и другое. В смысле, и на код посмотреть, и про теорию поговорить.
Ну и можно дать практическую задачу просто для оценки общего уровня
… которую кандидат завалит "по пяти причинам".
Если у него нет своего мнения на этот счет, да, это более приемлемый вариант, чем «это карго-культ».Вот здесь корень недовольства. Впечатление, что вы уверены, что владеете истиной в последней инстанции и ищете того, кто разделяет ваше мнение а не того кто будет эффективен в вашем коллективе. Эффективен будет умный человек, который видит и понимает больше а не тот, чье мнение волей судеб сложилось точно так же как наиболее обще-принятое в данный момент и в конкретной области разработки или ваше. Такая позиция не выгодна вам и не выгодна соискателю.
Потому что тестовые задания, которые я даю — это срез моего мира. Их нельзя решить, не соориентировавшись.Выглядит как какая-то слишком идеальная ситуация.
… которую кандидат завалит «по пяти причинам».Завалит, если искать там SOLID а не признаки ясного мышления.
ищете того, кто разделяет ваше мнение а не того кто будет эффективен в вашем коллективе
Я ищу того, кто будет эффективен в коллективе. Считать, что принятые в коллективе принципы это карго-культ — неэффективно.
Такая позиция не выгодна вам и не выгодна соискателю.
Я думаю, что я лучше, чем вы, знаю, что мне выгодно. А что выгодно соискателю… ну, это его дело.
Завалит, если искать там SOLID а не признаки ясного мышления.
А "признаки ясного мышления" — это что-то объективное, а не "общепринятое в данном коллективе"? То, что я считаю признаком ясного мышления — например, правильное и грамотное именование всех сущностей в коде — кто-то может считать карго-культом. А кто-то английский плохо знает, а, значит, будет в невыигрышной ситуации. А кто-то не любит тесты, поэтому дезориентирован, а поэтому не может ясно мыслить.
В проектах где я работал проблема всегда была совсем другой: найти человека, который сумеет разобраться в ТЗ и продукте и создаст что-то вменяемое понятное и работающее. Не вынесет мозг тим-лидам и тестерам бесконечными итерациями и недопониманием, не утонет в сложностях алгоритмов. Какой у него получился код в итоге никого не интересовало. Код модуля всегда можно переписать, если функция прижилась и продукт выстрелил. Плохой код и архитектура опасны в ядре системы, но его пишут гуру, а их никто не тестирует на SOLID и так далее.
Лично я написал сотни тысяч строк нормально работающего кода и даже однажды написал свой фреймворк, реализующий задачи от ORM до графики на OpenGL, и посадил на него пару продуктов (до сих пор работают). Но про SOLID тест по прежнему не пройду наверно. Не понимаю и все. Для меня это список довольно поверхностных замечаний об ООП, ничем мне не помогающих в работе. Просто каждый из них по пунктам нарушал множество раз и каждый раз это нарушение все упрощало а не усложняло.
У меня ощущение, что речь идет о довольно простых задачах, которые решаются с очень высоким вниманием к деталям.
Если вы о моих задачах, то ваше ощущение неверно. Если вы о каких-то других задачах, то мне сложно судить.
найти человека, который сумеет разобраться в ТЗ и продукте и создаст что-то вменяемое понятное и работающее.
Это оффтопик, конечно, но если в ТЗ надо разбираться, то, возможно, надо искать людей, которые будут лучше писать ТЗ. Это мое личное мнение.
Код модуля всегда можно переписать, если функция прижилась и продукт выстрелил.
… или нельзя. В моем опыте чаще было нельзя, потому что (а) не было ресурсов или, что хуже (б) модель так декомпонован, что для его переписывания нужно переписать всех потребителей.
Плохой код и архитектура опасны в ядре системы, но его пишут гуру
А, вот и разница. Я, собственно, собеседовал людей, которые будут писать код в ядре системы. В том числе и джуниоров. Поэтому мне важно, чтобы они понимали принципы, по которым этот код устроен.
А, вот и разница. Я, собственно, собеседовал людей, которые будут писать код в ядре системы. В том числе и джуниоров. Поэтому мне важно, чтобы они понимали принципы, по которым этот код устроен.Что такое тогда ядро?
Конкретно у нас это та часть системы, которая используется практически всей остальной системой, безотносительно прикладной области.
Если мне, к примеру, на собеседовании показали подобное ядро, а затем спросили про Solid и дали тестовый пример, то думаю я бы рассказал бы все красиво и написал тоже. Потому что здесь контекст понятен. Я правда, в таком не работал.
Здесь вопрос о SOLID и тест на способность формировать архитектуру под подобные требования выглядит логичным. Страшнее будет, если человек думает, что его берут какие-нибудь фитчи реализовывать в периферийных модулях, а тут ему — расскажи (покажи) как будешь использовать SOLID. А он думает «опять эти дурацкие вопросы и сейчас будут пытаться подловить меня на неправильном понимании SOLID, сами не понимая зачем он им нужен».
Теперь я знаю что отвечать, если спросят про SOLID.
Т.е. это некий код, который пишется не в один проход для одной задачи, а долго обсасывается, совершенствуется и много переиспользуется.
В идеале — да. Но не на практике.
ТЗ будет сформулировано совершенно недвусмысленно разработчиком, который это ядро отлично знает.
А вот это — точно нет.
думаю я бы рассказал бы все красиво и написал тоже.
Мне кажется, это противоречит высказываниям про карго-культ и "не понимаю я SOLID".
Страшнее будет, если человек думает, что его берут какие-нибудь фитчи реализовывать в периферийных модулях, а тут ему — расскажи (покажи) как будешь использовать SOLID.
Ну и правильно, потому чтобы периферийные модуля в системе, где все устроено в соответствии с SOLID, работали корректно, они тоже должны играть по правилам. А если человек их не понимает, то могут быть проблемы.
А вот это — точно нет.Выше вы сказали что ТЗ должно быть совершенно понятным. Как тогда выглядит ТЗ, тот кто его пишет и тот кто его выполняет — не могу представить.
Мне кажется, это противоречит высказываниям про карго-культ и «не понимаю я SOLID».Все, это уже в прошлом. Вы будете смеяться, на я только что перечитал принципы SOLID применительно к описанной вами ситуации и осознал, что они совершенно очевидны в подобных условиях и ничего премудрого там нет. Я просто ни-разу так не работал. Когда я писал фреймворк, то писал его один и в свое личное время. Поэтому вылизывать архитектуру классов у меня не было времени, абстрации я просто держал в голове, не отражая из особо в коде, а выделить лишнюю функциональность из класса или добавить интерфейсы я мог в любой момент. Потому что я один и отлично знаю этот код и могу переворачивать архитектуру буквально за день как угодно.
В других задачах (прикладных) сложными были алгоритмы, но не было необходимости в сложных объектных архитектурах — объекты были крупными и так далее.
Ну и правильно, потому чтобы периферийные модуля в системе, где все устроено в соответствии с SOLID, работали корректно, они тоже должны играть по правилам. А если человек их не понимает, то могут быть проблемы.
Опять по тем проектам что делал смутно представляю себе где они там могут так уж что-то испортить не соблюдая SOLID. Обычно это требуемое ТЗ поведение (несколько связанных алгоритмов) в god-объекте, работа которого в целом понятна. Можно конечно понаделать абстракций с интерфейсами, но неуклюжие абстракции по мне разбирать потом хуже чем их отсутствие. А чтобы делать красивые абстракции — это не те люди и не те задачи.
Выше вы сказали что ТЗ должно быть совершенно понятным.
Нет, я этого не говорил. Вы точно ни с кем меня не путаете?
Я просто ни-разу так не работал.
Ну вот видите, вот, благодаря разговору про SOLID, и выяснилось, что у вас в опыте есть, а чего — нет.
Опять по тем проектам что делал смутно представляю себе где они там могут так уж что-то испортить не соблюдая SOLID.
Ну как, достаточно нарушить принцип подстановки, чтобы сломать другие компоненты, которые потребляют интерфейс, реализуемый этим.
Нет, я этого не говорил. Вы точно ни с кем меня не путаете?Не путаю. Ну бог с ним. Я и так уже злоупотребляют вашей отзывчивостью.
Ну как, достаточно нарушить принцип подстановки, чтобы сломать другие компоненты, которые потребляют интерфейс, реализуемый этим.Как это выглядит? Программисту поручают реализовать некий сервис с интерфейсом, программист понимает, что этот интерфейс с этим сервисом плохо совместим и вместо того чтобы поднять вопрос о расширении или изменении интерфейса он использует некий «хак» вольно интерпретируя смысл интерфейса, полагая что все будет хорошо, а то что может быть плохо никогда не произойдет. Примерно так? И от подобных ошибок программиста может застраховать понимание принципа подстановки? Кто его знает. Мы множество раз делали нечто подобное, когда фитчу ждут завтра, а в следующем релизе уже все равно все будет по-другому (хотя, в 99 случаях из 100 у интерфейса только одна реализация). При этом все воспринимают это как костыль или хак. Из моего опыта, хорошим решением это может посчитать какой-нибудь заросший шерстью бывший дельфист-одиночка, чтобы не беспокоить умных коллег. Но подобные товарищи требуют внимания и воспитания, если уж их взяли работать.
Программисту поручают реализовать некий сервис с интерфейсом, программист понимает, что этот интерфейс с этим сервисом плохо совместим и вместо того чтобы поднять вопрос о расширении или изменении интерфейса он использует некий «хак» вольно интерпретируя смысл интерфейса, полагая что все будет хорошо, а то что может быть плохо никогда не произойдет. Примерно так?
Нет, не так. Он не думает о совместимости вообще. Он думает, что интерфейс — это карго-культ, поэтому делает реализацию как-нибудь, лишь бы совпало по формальным признакам.
Почему не бывает-то? Всякое бывает. Если вы чего-то не видели или не можете себе представить, то это еще ничего не значит.
Если вы чего-то не видели или не можете себе представить, то это еще ничего не значит.В том и дело, что я крайне мало видел. Поэтому и спрашивал. Хотя наверно выглядело так, как будто мне хочется поспорить.
То что вы упомянули именно принцип подстановки было неожиданно. Это уже какой-то патологический случай. Из того что я видел не в ядре, SO нарушают сплошь и рядом, I и D тоже часто не используют по факту (потому что все в одном классе), хотя при том же не забывают формально написать интерфейс для каждого класса.
Слушате, мне всегда было интересно, вот для чего вот это вот спрашивают на КАЖДОМ собеседовании?
Я вот это спрашиваю, в первую очередь, если кандидат упомянул это в резюме (ну или некоторые связанные ключевые слова).
Если не упомянуто, то могу и не спросить. Или спросить, чтобы понять уровень знакомства с теоретической областью (ключевые книжки и так далее), но обычно проще про книжки напрямую спросить.
Например мне почти всё равно, какие языки, платформы и инструменты знает разработчик. Если он не чувствует хотя бы SRP+DIP, то я с ним работать не буду (за исключением набора джунов на ковку). Правда, никогда не требую знания аббревиатур, просто нашупываю сам ген))
Как минимум, я проверяю что если на код-ревью напишу "не нарушай SRP/DIP/...", то мне не нужно будет объяснять что это такое вообще
Я вот всегда задаюсь вопросом — зачем у джунов всегда спрашивают про механизмы наследования или про боксинг? Он же пишет код, если не работает — на стековерфлоу найдет решение, зачем эту теорию зубрить? (сарказм)
Мастерство разработки складывается из двух частей — алгоритмов и структур данных (не заученных, а умения решать задачи и писать код) и архитектуры (умения собрать всякие циклы и хеш-таблицы в большой проект, который не умрет под своим весом).
Когда я спрашиваю про SOLID меня устроит ответ "не помню конкретных принципов, но вот каким должен быть проект". Я вообще уважаю людей, которые ищут причины. Почему в Java при переопределении метода можно сузить тип результата? Почему нельзя добавить исключений? Почему Spring рекомендует инъекцию в конструктор, а не в поле? Почему в проекте обычно пакеты верхнего уровня это models/controllers/services?
Почему в проекте обычно пакеты верхнего уровня это models/controllers/services?
Потому что так решил кто-то, кто думает прежде всего моделями и контроллерами, классическими многослойными архитектурами, а не, например, бизнес-функциями, ожидаемыми от приложения и луковичными архитектурами.
Кто-то может так и думал, но очень многие просто делают как все, как видели в другом проекте или как генерит билдер проекта. Не все задумываются.
А между прочим такое разделение противоречит даже классическим многослойным архитектурам, так как тут нет бизнес слоя (он обычно размазан по всем, а в пакете "models" обычно анемичные модели или вообще DTO) и подходит разве что если у вас вся бизнес-логика в базе данных.
перемещено
SOLID == ООП?