Как два программиста хлеб пекли



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

    Итак, представим себе, что есть два программиста. Один из них умный, прочёл кучу статей на Хабре, знает каталог GoF наизусть, а Фаулера — в лицо. Другой же делает всё просто. Первого будут звать, например, Борис Н., а второго — Маркус П. Само собой, имена вымышленные, и все совпадения с реальными людьми и программистами случайны.

    Итак, к ним обоим приходит проектный менеджер (если в вашей вселенной PM не ходит сам к программистам, назовите его как-то иначе, например BA или lead, сути это не изменит) и говорит:
    — Ребята, нам нужно, чтобы делался хлеб.

    Именно так, «делался», без уточнения способа производства.

    Как же поступят наши программисты?



    Борис создаёт свою первую абстракцию — класс Product, от него он наследует класс Bread, а инстанциирует экземпляры этого класса фабричный метод класса ProductFactory — createProduct().

    Маркус делает примерно то же. Он создаёт класс Bread и класс Manager с фабричным методом createBread().

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

    А сразу нельзя было сказать, что хлеб печётся не в вакууме, а в печке? Ну ладно, что же делают программисты?



    Борис переименовывает класс ProductFactory в Oven, и выделяет абстракцию — AbstractOven. Чтобы было совсем красиво, он метод createProduct() переименовывает в bakeProduct(). Тем самым Борис в первый раз выполнил рефакторинг, применив «выделение абстракции», а так же реализовал шаблон «абстрактная фабрика» точь-в-точь как он описан в литературе. Молодец, Борис.

    А вот Маркус ничего не делает. С его точки зрения всё и так хорошо. Ну может быть, стоит слегка поменяет реализацию createBread().

    Фаза луны меняется, и менеджер в третий раз приходит к программистам. Он говорит:
    — Нам нужно, чтобы печки были разных видов.

    Что ж, справедливо.



    Борис, радостно потирая руки, создаёт три наследника AbstractOven — ElectricOven, MicrowaveOven и GasOven. А класс Oven он удаляет за ненужностью.

    Маркус тоже вносит изменения в программу. Он добавляет в метод createBread целочисленный параметр ovenType.

    В четвёртый раз приходит к программистам менеджер. Он только что прочёл одну из книг серии «Я познаю мир». Интерференция новой информации и PMBoK дала неожиданный результат. Менеджер говорит:
    — Нам нужно, чтобы газовая печь не могла печь без газа.



    Борис абсолютно безосновательно считает, что источник газа может быть только один. А для таких случаев всегда есть наш любимый шаблон. Он создаёт одиночку GasSourceSingleton, а для уменьшения связности внедряет его через интерфейс GasSource в GasOven. Ура, он применил внедрение зависимости через сеттер!

    Скромный от природы Маркус создаёт вещественное приватное поле gasLevel в классе Manager. Естественно, придётся чуть поменять логику метода createBread, но что поделаешь!

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

    Программисты тоже хотят есть, поэтому берутся за работу.



    Борис уже начинает что-то такое чувствовать, но остановиться уже не может. Как печка узнает, что именно ей нужно готовить? Очевидно же — ей нужен повар. И Борис, не долго (а может и долго) думая, создаёт класс Cook. У него будет метод для приготовления, принимающий на вход абстрактную печь — cook(owen: AbstractOwen): Product. Ведь это логично — повар берёт печь, и с её помощью готовит. Потом Борис создаёт ещё несколько наследников класса Product — Cake и Pasty, а от Pasty наследует MeatPasty и CabbagePasty. А затем для каждого типа продукта создаёт отдельного повара — BreadCook, PastyCook и CakeCook.

    Вроде ещё нормально, но времени на это ушло намного больше, чем у Маркуса, который просто добавил ещё один целочисленный параметр к методу createBread — breadType.

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



    «Хм», — произносит Борис и вспоминает про шаблон «строитель» (вместе со «свободным интерфейсом», конечно же). Он создаёт класс Recipe, а к нему — строитель RecipeBuilder. Рецепт он внедряет (ВНЕЗАПНО!) в печку с помощью сеттера setRecipe(recipe:Recipe).

    А Маркус (вы не поверите) добавляет ещё один целочисленный параметр в createBread — recipe.

    Самое интересное, как всегда, происходит вдали от компьютеров. А именно: менеджер впервые после начала разработки встречается с заказчиком и наконец-то понимает, зачем тому нужна была печка. Он (менеджер) в седьмой раз приходит к программистам и говорит:
    — Нам нужно, чтобы в печи можно было обжигать кирпичи.



    Для Бориса это последняя встреча с менеджером, но всё же он из последних сил вносит изменения в архитектуру. Он выделяет абстрактный класс AbstractHeatingSmth — абстрактное нагревающее нечто. Для него он создаёт фабрику HeatingFactory. От AbstractHeatingSmth он наследует ProductOven и Furance. У последнего есть фабричный метод makeBrick, создающий экземпляр объекта Brick. Но ничего не работает. Читателю предлагается самостоятельно найти ошибку в архитектуре.

    У Маркуса тоже не всё так гладко. Ему приходится создать уже третий (!) по счёту класс. Он называет его Brick, и добавляет в свой Manager метод makeBrick.

    Конечно, можно возразить, что у Маркуса внутри метода createBread творится Адъ и Израиль, и это на самом деле так. Но с помощью шаблона «шаблонный метод» беспорядок вполне можно структурировать. А в обилии фабрик и абстракций разобраться, ну, чуть сложнее.

    Выводы, которые я хочу сделать, наверное, немного предсказуемы.

    Подход Бориса хорош тем, что практически каждую часть системы можно изолировать и покрыть тестами. Но времени на создание такого количества классов уйдёт неприлично много, и каждое изменение требований обернётся каскадным изменением кода. Попытка же сделать архитектуру гибкой, предугадав пожелания заказчика, обычно проваливается — архитектура гнётся совсем не в том месте. Ведь, как известно «мир не просто удивительнее, чем мы себе представляем, —
    он удивительнее, чем мы можем себе представить». И, получив очередной change request, программист убеждается в этом как никто другой.

    Подход Маркуса, конечно, не позволяет использовать модульное тестирование, но зато он даёт результат намного быстрее, и изменения даются меньшей кровью. Этот подход — тот самый быстрый старт, которого так хотят стартаперы всех мастей. И, как ни странно, в таком коде действительно легче разобраться, потому что он проще.

    А переписать всё заново, если что, — это всегда успеется.

    Картинку взял отсюда

    UPD. Очень приятно, что статья получила столько откликов. Вот, например, решение этой задачи на Haskell, а вот на List.

    UPD.2 А вот и версия на C#. Кто ещё?

    UPD.3 Хлеб Маркуса и YAGNI
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 319
    • +17
      Всегда успеется переписать? Сомнительно.
      А менеджер вообще знает, что он хлеб печет? Судя по его заказам — не знает.
      • +42
        часто так получается, что даже заказчики не знают, чего они хотят. чего уж говорить о менеджерах
        • +6
          Если нет 500 страничной документации на проект, то переписать какие-то части придется, потому что все постоянно меняется и ничего до конца не ясно, ни заказчику, ни тем более менеджеру.
          Часто во многих местах пишется говнокод. А потом, переправленный на сто раз и весь в заплатках говнокод, переписывается, когда заказчик доволен всем и это оказывается именно то что он хотел.
          • +7
            Если она есть, то будет все еще хуже. Вы ведь ей доверитесь, а зря.
            • +1
              Если она подписана, то программисты и менеджеры в принципе, имеют полное положить на клиентское «а я хочу чтоб оно ещё и самолёты делало!» большой и толстый… мм… синглтон :)
              • 0
                Как вы его назвали… а ведь да, прямо по Фрейду…
                • +7
                  Положить то конечно можно, но если в итоге клиент получит систему полностью соответствующую документации и всем спецификациям, но не способную функционировать должным образом, то виноват в любом случае окажется разработчик. Конечно, формально в этом случае контракт будет выполнен и никаких легальных претензий со стороны клиента быть не может, но репутация разрабочика все равно пострадает. Разочарованный клиен, как правило, никогда не признает своих ошибок и в неформальных бесдах будет негативно отзываться об исполнителе работы.
                  • +1
                    А вы уверены что исполнитель сможет реально выяснить, нет ли противоречий в ТЗ на 500 страниц перед тем как его подпишет?
                    • +2
                      Эт пока в свое резюме такие программисты не впишут очередной эпик фейл.

                      К слову, за 20 лет работы я ни разу не видел 100% выполнения первоначального ТЗ. Просто потому, что этот гроссбух устаревает еще до того, как на нем чернила просохнут.

                      И всегда эта игра в бумажки заканчивается «мы можем из этого провала вытянуть нечто сферическое в вакууме, но нам надо еще 1 год и пять лямов» (Ц), и еще очень хорошо, если количество итераций ограничивается тремя — пятью, а то ведь цифры бывают и двузначными.
                      • 0
                        Иметь-то они имеют, но это только если разработчикам пофигу, будет ли кто-нибудь использовать результат их труда, и что при этом думать. Потому как раз отсутствие 500-страничной документации — база для последующих компромиссов =)
                        • 0
                          Это называется «итальянская забастовка»
                      • 0
                        Рефакторинг в помощь…
                        • +45
                          image
                          • НЛО прилетело и опубликовало эту надпись здесь
                            • 0
                              отличная гифка) я впервые её увидел в твиттре у того самого Маркуса П.
                          • 0
                            Скорее всего в ней будет описано всё, кроме того что действительно важно. Как-то раз наблюдал подобную ситуацию.
                          • +36
                            Когда сравниваем две картинки кажется что слева всего много и все сложно.
                            Когда заглянем в солюшен эксплорер засомневаемся, а когда заглянем в исходный код — картинки поменяются местами.

                            Много лет назад был тренд переусложнения функционала, до появления гибких подходов к разработке.
                            Сегодня все чаще начинаешь встречать злоупотребление принципом KISS.
                            Когда такой продукт достаточно развитый его уже невозможно переписать, а стоимость внесения изменений начинает стремится к бесконечности.

                            Хотите быстого старта — используйте готовые фреймворки.

                            Архитектурное планирование необходимо. Надо придерживаться разумного балланса.
                            • –9
                              Хотите быстого старта — используйте готовые фреймворки.
                              ХЗ. Если эта фрамуга — не Гуава, то есть почти 146% шанс, что придётся допиливать или дообвязывать.
                              • +4
                                Чесно говоря я не знаю, что такое фрамуга и гуава, но подозреваю что если речь о быстром старте — то предполагается, что когда бизнес поднимется, данный продукт заменит новое решение. Если работа с фреймворком ведется как с блек боксом — то чем меньше будет расширений для него — тем лучше на этом этапе.
                            • +6
                              Есть один классный «паттерн», помогающий не только в программировании: «Золотая середина».

                              Проблема Бориса — бездумное воспроизведение всего, что он увидел в умной книжке. То есть он не мыслит самостоятельно, гроше цена такому разработчику до того момента, пока он не начнёт задумываться над тем что делает.

                              Проблема Маркуса — отсталость и не имение представления о том, какие вообще паттерны и средства существуют на данный момент. Он не видит перспективы и общей архитектуры проекта, а реализуют чётко поставленную задачу. Короче этот товарищ скорее малоопытен, недостаточно любознателен или просто ленив.

                              В любом случае, отчасти это вина проект-менеджера. Именно в его обязанности входит грамотная поставновка полной задачи, взаимодействие с заказчиком и проработка архитектуры будущего приложения совместно с разработчиком. Так что подтверждаю Ваши слова, «Архитектурное планирование необходимо». А иначе — это просто игра в песочнице, а не серьёзная работа.
                              • +1
                                Сторонники коротких итераций поглядывают на вас как-то грустно и одновременно неодобряюще.
                                • –2
                                  Не путайте архитектуру и итерацию.
                                  • +1
                                    Короткие итерации вынуждают делать архитектуру простой, но в то же время высокоэффективной.
                                    • +1
                                      Я согласен, но проектировать даже простую архитектуру всё равно ведь необходимо. Независимо от того, разбиваются задачи на большие или мелкие итерации.
                                      • 0
                                        При таком подходе на первый план выходят не архитектурные изыски, а создание конструкторов, с помощью которых потом строится весь остальной код. Например, если стандартизировать передачу данных между модулями, зафиксировать формат и методику обработки, то это послужит той ниточкой, на которую будет нанизано «ожерелье» исполнительных блоков. Это простое как двери архитектурное решение, которое можно все так же итерационно эволюционировать, но оно не требует вдумчивого планирования всего и вся.
                                        • 0
                                          Хм, а стандартизацию формата передачи, протоколов обмена и интерфейсов исполнительных блоков вы не считаете проектированием? Замечу, что это более высокоуровневое проектирование (=создание архитектуры), чем паттерны.
                                          • +1
                                            Проектированием можно называть что угодно, даже написание метода. Мой акцент был немного на другом. Проектирование API передачи данных не требует сложных телодвижений, которые тянут за собой обязательное документирование, создание тестов, сложных схем. Тщательность проектирования этого интерфейса заведомо убыточна, потому что вы все равно не предусмотрите всего. Ну так зачем тянуть кота за хвост, если можно арихитектуру эволюционным путем развивать?

                                            Приведу пример из своей жизни. Мы перемещали бизнес-логику несколько раз, в разные места. Реализовывали ее несколькими способами. Рефакторили только потому, что нужно было обеспечить ряд требований, которые возникли в процессе использования систем. Некоторые архитектурные решения умерли в процессе прототипирования, потому что мы напоролись на деградацию сервиса. Это предусмотреть было просто нереально. Некоторые решения были отброшены как неоправданное усложнение. От кода, который был пять лет назад, остались только жалкие наметки, это касается общей организации файлов и методики обработки запросов.

                                            И если меня спросят, как бы я делал аналогичный проект сейчас, я бы снова внес ряд улучшений к тому, что работало годами. :) Стал бы я много времени тратить на продумывание архитектуры? Скорее всего нет. Не потому что я хочу напороться на проблемы в будущем, а потому что я знаю, что я напорюсь на них, но не знаю, на какие именно. У меня есть ряд обалденных заготовок, которые отточены временем. Они достаточно универсальны для проектов любой сложности.
                              • 0
                                Самая здравая мысль в этом топике.

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

                                Лично мне картинка Бориса нравится больше и в ней нет ничего сложного на самом деле. Я уверен и код внутри всей структуры не такой уж сложный.

                                Версия Маркуса может быть актуальна только в случае быстрого стартапа, но это будет протототип и его придется выкинуть.
                            • +3
                              А как же программирование по модели?

                              Хотя второй подход, бесспорно, лучше, если изначально сущностей немного. Тут же Печь, Пирожок и Кирпич, остальное — объекты-значения. А расплодили в первом подходе выше крыши
                              • +4
                                Вопрос в том, а нужна ли их ПМ-у модель? ПМ явно пляшет от «хотелок», а не от модели. Вот Маркус и рулит, тем что делает, что от него хотят. У Эванса же написана, что модель — это артефакт нужный и заказчику и программисту. Модель нужная только программисту будет только мешать, так как у заказчика полет фантазии будет сильно дальше.
                                • +3
                                  модель — это артефакт нужный и заказчику и программисту.

                                  вот это очень правильно
                            • +15
                              Полностью согласен. Это ещё напоминает классификацию программистов. Когда в итоге самый опытный начинает писать код также как студент первого курса. Просто, потому что не нужно усложнять. Я это по полной на себе прочувствовал, когда взялся за проект с хорошими людьми, но вообще ничего не понимающими в программировании, зато отлично понимающими в своей сложной предметной области. А далее было очень много косяков, из-за того, что для них какие-то вещи очевидны, а я вообще не понимал, что это. И целая уйма «универсального» кода была выброшена, потому что он был вообще не в ту тему.
                              В итоге я перешёл к буквальной реализации требований минимальными силами. Писал код 2-3 дня, демонстрация, поправки, ещё 2-3 код, ещё демонстрация и т.п. Таким образом мы очень быстро пришли к согласию.
                              • +8
                                Когда в итоге самый опытный начинает писать код также как студент первого курса.

                                Тут важное, на мой взгляд, слово «начинает». А вот продолжает опытный программист уже исходя из своего багажа знаний да и шестое чувство достаточно развито. «Перваш» же может наделать кучу ошибок по неопытности.
                                • +8
                                  В итоге я перешёл к буквальной реализации требований минимальными силами. Писал код 2-3 дня, демонстрация, поправки, ещё 2-3 код, ещё демонстрация и т.п. Таким образом мы очень быстро пришли к согласию.


                                  [sarcasm]Это тот самый agile, который дает результат без скрамов, митингов, досок и прочих странных вещей с непонятными названиями. К сожалению, если использовать его именно так, то менеджеры окажутся не нужны и их уволят, поэтому большинство программистов все еще остается командой с гибкими и прогрессивными методиками разработки и нерабочим продуктом.[/sarcasm]
                                  • +2
                                    Когда в итоге самый опытный начинает писать код также как студент первого курса.


                                    Потому, что знает, что отрефакторить газонокосилку в пулемёт Калашникова всегда успеет, ибо хорошо знает как это делать.
                                    • 0
                                      Я бы добавил, что они пишет так, как вроде может написать студент первого курса, но чисто случайно. Грубо говоря, есть с десяток возможностей написать нужную функциональность и все они примерно одинаковы по известным студенту (читай — очевидным) метрикам, но по неизвестной студенту метрике «простая возможность рефакторинга». Студент выберет случайно одну из десяти, а опытный сознательно ту самую, которую будет проще рефакторить.
                                      • 0
                                        сознательно ту самую, которую будет проще рефакторить.
                                        Вот оно — дао и дзен настоящего предварительного проектирования. Это не какие-то там «дизайн-паттерны»…
                                  • +38
                                    Большинство проектов начинают писать вот такие Борисы, с множеством фабрик на все случаи жизни, используя все 24 паттерна. А заканчивают едакие Маркусы, после чего архитектуру не прочитает ни один вменяемый программист. И вроде как все покрыто тестами, но они уже 7 итераций как не запускались, там чтото(!) падает…

                                    Спасибо за статью :) Качественно написано
                                    • +3
                                      Ошибка в том, что HeatingFactory на выходе выдает что-то такое абстрактно нагревающее (AbstractHeatingSmth), что непонятно как включать? Т.е. без известных методов?

                                      Да, и я в этой истории на стороне Бориса, как ни странно, в его ахритектуре больше информации. Да, немного с избытком. Чтобы навести порядок в его коде — достаточно будет 30 минут вдумчивого чтения, и да — любую часть покрыть тестами, выборочно.

                                      Чтобы проверить код Маркуса для начала необходим будет сам Маркус, причем достаточно свежий. Который сможет по номерам сказать какой тип булочки под номером 4, и какой тип печи под номером 3, потому что это не очевидно. Отрефакторить такое сложнее чем кажется. И как показывает практика — переписывать никогда не успевается. Стартапы так и гибнут, когда старый код начинает пахнуть, а ПМ хочет новых безумных фишек.
                                      • +32
                                        Который сможет по номерам сказать какой тип булочки под номером 4, и какой тип печи под номером 3, потому что это не очевидно.

                                        #define BREAD_TYPE_WHITE 1
                                        #define BREAD_TYPE_BLACK 2
                                        #define BREAD_TYPE_SAMSA 3
                                        #define BREAD_TYPE_KULEBYAKA 4
                                        
                                        #define OVEN_TYPE_MICROWAVE 1
                                        #define OVEN_TYPE_GAS 2
                                        #define OVEN_TYPE_RUSSIAN 3
                                        

                                        • –2
                                          // Комментарии тоже никто не отменял
                                          • +18
                                            комментарии быстро устаревают, поэтому лучше константы с нормальными именами
                                            • +3
                                              Терпеть не могу когда пишут магическую лабуду и комментарий, вместо того чтобы просто назвать лабуду по-человечески и не надо уже никаких комментов
                                            • +31
                                              Только хардкор, только #define!

                                              struct BreadType {
                                              
                                                enum Type { White = 1, Black = 2, Samsa = 3, Kulebyaka = 4 };
                                              };
                                              
                                              struct OvenType {
                                              
                                                enum Type { Microwave = 1, Gas = 2, Russian = 3 };
                                              };
                                              
                                              • +9
                                                define, const, enum… способов избежать «магических чисел» много ;)
                                                • +3
                                                  И в большинстве языков с недостаточно строгой типизацией (типа C), ни один из них не запретит писать бредовые и совершенно нечитаемые конструкции в духе manager.createBread(17, 42). Или, и того хуже — передать в аргумент «тип печки» значение из «вида рецепта».

                                                  И это не последняя причина для чуть большего размышления об архитектуре.

                                                  Ибо у настоящего спагетти-код-дел-мастера Маркуса makeBrick мог бы и не оказаться отдельным методом, а всего лишь отдельным типом хлеба. И в его коде createBread можно вызвать с кодами, соответствующими «в мартеновской печи изготовить бородинский кирпич».

                                                  Всё, что нас не убивает, делает нас сильнее, угу.
                                                  • +2
                                                    Да, тип «кирпич» вводить было не нужно. Это действительно отдельный тип хлеба, и ветвление в коде пойдет довольно глубоко, если пойдет вообще — хорошо написанный метод разберется с ситуацией, ориентируясь только на физикохимические параметры сырья (неважно, теста или глины) и желаемого результата. А смотреть на то, хлеб нужен, или кирпич, без необходимости — зачем? Keep it simple!
                                                    • +1
                                                      и пусть себе желают шамотную булочку, надо — испечём…
                                                      • +1
                                                        Боевой гномий хлеб
                                                • 0
                                                  Поясните, пожалуйста, для маркусов, чем ваша конструкция лучше чем
                                                  enum BreadType { Foo=1, Bar=2 }
                                                  ?
                                                  • +2
                                                    потому что у вас будет
                                                    BreadType bt = Foo;
                                                    а у valashko
                                                    BreadType::Type bt = BreadType::Foo;

                                                    а на самом деле нужно использовать C++11:
                                                    enum class BreadType { Foo=1, Bar=2 }
                                                    и дальше
                                                    BreadType bt = BreadType::Foo;
                                                    • 0
                                                      а на самом деле нужно использовать C++11: enum class

                                                      Полностью поддерживаю.
                                                    • 0
                                                      Неймспейс не засоряется. Иначе Foo и Bar будут видны без префикса BreadType. Разумеется, в данном случае речь только про C/C++.
                                                      • +1
                                                        Напомните, а как в C (который у вас первый в паре C/C++) создать неймспейс и, по возможности, засорить его?
                                                        • –2
                                                          Например, так:

                                                          // SimpleMath.h
                                                          namespace BasicConstants { const float pi = 3.14f; }
                                                          
                                                          // AdvancedMath.h
                                                          namespace BasicConstants { const double pi = 3.14159265; } // error C2371: 'BasicConstants::pi' : redefinition; different basic types
                                                          
                                                          • +1
                                                            К сожалению, это не C.
                                                          • 0
                                                            Это очень просто. Достаточно представить на секунду, что подразумевается не буквальный «неймспейс», как объявленный юзером scope-контейнер. После чего, обратиться за подтверждением своей теории к ISO.IEC-9899.1999.pdf:

                                                            6.2.3 Name spaces of identifiers
                                                            If more than one declaration of a particular identifier is visible at any point in a translation unit, the syntactic context disambiguates uses that refer to different entities.
                                                            Thus, there are separatename spacesfor various categories of identifiers, as follows:
                                                            — label names(disambiguated by the syntax of the label declaration and use);
                                                            — thetags of structures, unions, and enumerations (disambiguated by following any of the keywords struct, union, or enum);
                                                            — themembersof structures or unions; each structure or union has a separate name
                                                            space for its members (disambiguated by the type of the expression used to access the
                                                            member via the.or->operator);
                                                            — all other identifiers, calledordinary identifiers(declared in ordinary declarators or as
                                                            enumeration constants).
                                                            • –1
                                                              Пожалуйста, уточните, какую именно теорию в данный момент вы подтверждаете этой цитатой? Неймспейсы, как пространства имен, а не как области видимости, перечисленные в этой цитате, не могут быть созданы по воле программиста, ибо являются частью самого языка.
                                                              • +1
                                                                Где в моём исходном комментарии я говорил про создание _своего_ пространства имён, в C, или C++?

                                                                > Неймспейсы, как пространства имен, а не как области видимости
                                                                Ага, т.е. «неймспейс» можно прочитать и так и так. Я подразумевал «область видимости», другие прочитали «кастомное пространство имён». Энд оф стори?
                                                                • 0
                                                                  Области видимости создать можно и в C, и в С++, не прилагая для этого никаких усилий (разве что фигурные скобки напечатать). Тогда как простраства имен в C создать нельзя, нет для этого соответствующих механизмов.

                                                                  Мой изначальный комментарий ставил перед собой целью предупредить дальнейшее использование названия языка «С» в качестве синонима для «С++», ибо эти два языка ничего общего, кроме буквы в названии и маникального стремления общественности писать их через слеш, не имеют.

                                                                  Энд оф стори.
                                                                  • –1
                                                                    Энд оф стори, да.

                                                                    Но вот это интересно:
                                                                    > Мой изначальный комментарий ставил перед собой целью предупредить дальнейшее использование названия языка «С» в качестве синонима для «С++»
                                                                    Меня? Других? Во-первых, я прекрасно знаю разницу. Во-вторых, написал я их вместе (через слэш) _намеренно_, потому что сабжевая проблема встречается в обоих языках. Ошибка на ошибке: о том что в C якобы можно создавать неймспейсы и что некто по ту сторону не знает разницы между C и C++.

                                                                    Окей, хотелось как лучше. Но всем известно куда вымощена дорога с такими благими намерениями. Возможно виновата подача, но у меня на протяжении всей ветки обсуждения перед глазами стоял очередной воин, вызывая раздражающие, болевые позывы в одном месте.
                                                        • 0
                                                          Таким образом сокращается область видимости перечисления.

                                                          enum First { Foo = 1, Bar = 2 };
                                                          enum Second { Baz = 1, Ban = 2, Bar = 3 }; // error C2365: 'Bar' : redefinition; previous definition was 'enumerator'
                                                          

                                                          Также есть вариант положить определение в namespace. Более детально тут.
                                                          • 0
                                                            тогда вопрос в догонку:
                                                            почему namespace сделан через struct, а не через namespace?
                                                            • 0
                                                              Наследие С… Но чаще пишут так
                                                              class Bread
                                                              {
                                                              public:
                                                                  enum Type { ... };
                                                              
                                                                  ...
                                                              };
                                                              
                                                              • 0
                                                                Это вопрос предпочтений. Детальнее на stackoverflow.
                                                          • 0
                                                            Можно еще так:

                                                            namespace BreadType {
                                                                enum {
                                                                    White = 1,
                                                                    Black // etc
                                                                };
                                                            }
                                                            
                                                        • –1
                                                          Подход Маркуса не исключает комментариев в коде с указанием номеров булочек и печей.
                                                          • 0
                                                            А если это отдельная библиотека?
                                                            • +3
                                                              А как вы собираетесь с ней работать если к ней нет описания API?
                                                          • +6
                                                            стартапы гибнут по другому. Переписать код, зная как работает старый и перенести данные со старого движка в новый — не так сложно — в старом уже все учтено и можно написать четкое ТЗ ко второй итерации (а первому программисту никто ТЗ не давал- так и бегали «добавь кирпичей» и «концепция изменилась — заказчик хочет пылесос»). При этом второй раз можно уже и по Борисовому написать и на другом языке(времена меняются). Маркус стартует стартап, стартапу выделяются деньги на которые десяток Борисов пишут чистый новый код. А писать на начальном этапе Борисов код, когда не понятно еще ни ТЗ ни выстреливаемость стартапа — не целесообразно. Писать поддерживаемый код нужно тогда, когда есть понимание что его нужно будет поддерживать, а 90% стартапов дохнет. Так какой смысл?
                                                            • 0
                                                              Часто успешный проект доходит до стадии взрывного роста новый хотелок при скромном росте дохода с него. Тогда просто нет денег чтобы сесть и переписать всё.
                                                              • +1
                                                                В общем-то, хотелки, не подтверждённые деньгами, — это не хотелки, а так себе…
                                                                • 0
                                                                  Вы сейчас только про заказные проекты говорите.
                                                              • 0
                                                                >а 90% стартапов дохнет.

                                                                Так, может, это вносит свою лепту в 90%?
                                                                • +1
                                                                  99% биологических видов вымерло… тут то же, но менее затратно.
                                                                • 0
                                                                  Переписать код, зная как работает старый и перенести данные со старого движка в новый — не так сложно — в старом уже все учтено и можно написать четкое ТЗ ко второй итерации

                                                                  Ключевое слово «зная». А в ситуации когда программист первой итерации уволился, а у менеджера остались максимум записи того, что он говорил на первой стадии, а то и этого нет, а есть продукт у которого есть исходники и который вроде текущим требованиям удовлетворяет, я бы предпочёл чтобы мне в наследство достался код Бориса, а не Маркуса.
                                                                • –1
                                                                  Обычно такие вещи (соответствие типов с названиями и описанием) просто хранят во внешнем справочнике (в маленькой базульке mysql например, там можно и редактирование прикрутить и интерфейс простенький для менеджера. Ну или в xml или на худой конец csv)

                                                                  Использовать цифровые типа без описаний конечно не дальновидно
                                                                  • +1
                                                                    Имхо, БД — это ещё хуже для поддержки. Если хардкодить, то хотя бы соответствие номера и названия будет где-то в коде, если же хранить его в БД, то при изучении кода надо будет лезть в БД, чтобы узнать соответствие. Как правило, это более долгая операция, чем открытие файла в редакторе, не говоря о функциях IDE типа Find usages. Ну и хардкод позволит избежать рассинхронизации продакшен и дев окружения. Менеджер прибежит с криком «Булочка обжигается, а должна печься» и разработчику придётся лезть на продакшен базу, чтобы понять что там нынче менеджеры булочками обозвали. Ещё хуже, если он начнёт исходить из того, что у булочки ид 1, а на самом деле менеджер имел в виду запись с ид 101.

                                                                    Имхо, если и выносить подобные вещи в базу, то использовать не суррогатные числовые ид, а текстовые. что бы вместо кода типа if (bread.type == 1) был код типа if (bread.type == 'black'), а суррогатные использовать только для связи между таблицами.
                                                                    • 0
                                                                      Я тут писал длинный коммент, который в итоге стер потому что его можно просто написать одной строкой — всё зависит от конкретной ситуации.
                                                                • +25
                                                                  Ага, а вы видели код этого Manager? Который знает все о рецептах, типах печей, управлении газом.
                                                                  • –2
                                                                    да. он чудовищен. но имхо его можно отрефакторить
                                                                    • +14
                                                                      Нет, отрефакторить его нельзя, потому что для этого нужно покрытие тестами, о чем Маркус явно не в курсе.

                                                                      Весь код надо будет переписывать, как у Бориса (хотя тут видно что Борис — тоже не супер спец, так много сущностей плодить не обязательно было сразу).
                                                                      • +4
                                                                        К коду Маркуса гораздо легче написать функциональные тесты. А дальше можно спокойно рефакторить.
                                                                        • 0
                                                                          Не напишите вы функциональные тесты на каждый костыль, который вставлен там внутри.
                                                                          • +15
                                                                            А и незачем. Если хлеб и пирожки пекутся — то что еще нужно от этого кода?
                                                                            • +1
                                                                              Да, но путём тестов можно узнать, что получившаяся система ещё может и сталь выплавлять!
                                                                            • +1
                                                                              Вырефакторивать в отдельный метод каждый костыль.
                                                                              • +1
                                                                                Мы вырефакторивали-вырефакторировали, да не доревыфакторировали.
                                                                                • 0
                                                                                  Почему недовырефакторивали? Человеко-часов не дали больше?
                                                                            • 0
                                                                              не соглашусь. там у объектов есть состояния, из-за этого тесты крайне сложно писать
                                                                            • +3
                                                                              Я рефакторю без тестов, доверяю IDE.
                                                                              • +3
                                                                                Рефакторинг — это не только переименование, %username%
                                                                                • +3
                                                                                  IDE может не только переименовывать, но и, например, выделять метод или функцию, %username%
                                                                                  • 0
                                                                                    IDE еще умеет разделять классы, выделять интерфейсы. А еще оно НЕ умеет кучу других вещей которые нужны при рефакторинге.
                                                                                    • 0
                                                                                      Вопрос времени, имхо, если говорить о рефакторинге в узком смысле слова. Вообще, конечно, совсем без тестов сложно, но, с другой стороны, если есть старый код, который разрабатывался без учёта возможности тестирования, то нормальная IDE хотя бы с тем же выделением методов/функций очень может помочь в деле покрытия тестами для рефакторинга в широком смысле слова.

                                                                                      Вот представьте, есть у вас «плоский» скрипт на PHP на тысячу-другую строк, который вызывается веб-сервером, или программа на Си из одной функции main(), или программа на Java из одного класса с одним методом main. Для покрытия его тестами без рефакторинга придётся, как минимум, эмулировать веб-сервер, а с помощью IDE мы можем безопасно (ну, считая, что разработчики IDE не допустили ошибок) разорвать зависимости логики от получения параметров программы из окружения, чтобы иметь возможность эмулировать окружение в среде тестирования и тестировать логику, а не создавать виртуальное окружение и тестировать всю программу целиком.

                                                                                      Если всё равно не понятно о чём я, могу привести чуть позже примеры на PHP.
                                                                                • 0
                                                                                  Смотря какой рефакторинг. Мне недавно пришлось переколбасить ядро своего фреймворка, чтобы ввести поддержку новых требований. Диаграмма сервисных классов изменилась до неузнаваемости, при полном сохранении контрактов существующих интерфейсов. Без тестов все бы рухнуло.
                                                                                  • 0
                                                                                    Реально падали тесты и вы потом исправляли?
                                                                                    • +1
                                                                                      Да, рефакторинг выходил за пределы возможностей IDE. Например была одна структура, которая умела себя строить по определенному образцу. Мне нужно было сделать ее более пассивной — только для хранения данных, а построение доверить классу сборщику. Тесты у меня довольно высокоуровневые — тестируют в основном контракты высокоуровневых интрефейсов, которые не менялись, переписывать их почти не пришлось, но пара тестов свалилась из за ошибок при переносе.
                                                                                      Плюс еще в одном месте пришлось переписать MergeSort на QuickSort — вроде рефакторинг, с сохранением внешного контракта, а IDE ничем помочь не может. Тут тоже тест помог отловить баги.
                                                                                • 0
                                                                                  Покрытие тестами — это хорошо, но всегда ли необходимо?
                                                                                  Поясню. Если вы делаете что-то мелкое, то вряд ли вы будете использовать методы Бориса. Оно мелкое, его результаты легко проверить на практике, а отладку делать при помощи нескольких брякпоинтов.
                                                                                  Как вариант — написание чего-то сильно критичного к скорости работы. Надеюсь, вы не будете отрицать, что при прочих равных вариант Маркуса будет работать быстрее варианта Бориса?
                                                                                  Ну а нагромождение классов и тесты стоит использовать там, где нужна надежность и стабильность работы.
                                                                                  Я к чему все это… Не стоит забивать микроскопом гвозди, а на бактерии смотреть сквозь лупу.
                                                                                  • +1
                                                                                    Если вы на 100% уверены, что делаете что-то мелкое и, самое главное, оно таковым и останется, то конечно используйте метод Маркуса.

                                                                                    На моей практике такого ни разу не было. Всегда ПМ приходил со все новыми дополнениями а ля «а еще печка должна сталь выплавлять, причем уже вчера».
                                                                                    По неопытности пытался делать по-Маркусовски, потом этот проект затянулся на 2 месяца багфиксов, которые вылезали в непонятных местах после каждого такого дополнения.

                                                                                    А вот покрытие тестами мне жизнь хуже еще ни разу не сделало.
                                                                                • +1
                                                                                  Методом всасывания и упразднение посредников можно отрефакторить и Борисовы художества. Другое дело, что выделить суперкласс раз в 10 легче, чем упразднить…
                                                                                  • 0
                                                                                    И тогда получится то, что на картинке слева.
                                                                                  • +2
                                                                                    Я видела.
                                                                                    Есть у нас продукт, а точнее два файла один на 40к строк кода, второй на 60к строк и это только .aspx.cs, сама вёрстка в два раза больше. Дак вот, это и есть тот случай. Понять, что там происходит — просто не реально.
                                                                                      • +1
                                                                                        Спасибо, это надо сохранить.
                                                                                    • +11
                                                                                      Мне кажется метод Маркус очень похож на создания прототипа, что в данном конкретном случае конечно лучше чем подход Бориса. Потом главное этот прототип отрефакторить знаю уже большенство требований заказчика, которые были скрыты в начале разработки.

                                                                                      Чтобы проверить код Маркуса для начала необходим будет сам Маркус, причем достаточно свежий. Который сможет по номерам сказать какой тип булочки под номером 4, и какой тип печи под номером

                                                                                      Я не думаю, что у Маркуса все так запущено, даже студент догадается сделать тут enum.
                                                                                      • +4
                                                                                        Если делаешь прототип, не забудь его выбросить.
                                                                                        • Полностью согласен про прототипы и очень удивлён, что об этом практически ничего не написали в комментариях. Вся эта история высосана из пальца и предоставляет 2 крайности совершенно не опытных программистов, которые могут легко исправить положения одним тим лидом, если их проект-менеджер занят книжками «я познаю мир» :)
                                                                                          Вообще в большинстве случаев при разработке любого проекта, аналогов которого нет, то есть реально новый функционал, которые необходим заказчику, а тот в свою очередь если не программист никак не может продумать всей архитектуры, а особенно объяснить все детали проект-менеджеру. В таких случаях всегда разрабатывается прототип и подгоняется его работа под требования без всяких свистелок и прочей мешуры, должно просто выполнять основные задачи для работы данного проекта. И только потом на основе этого прототипа создаётся архитектура и всё это обвешивается классами и рефакторится 10 раз. Все выводы из собственного опыта автоматизации разного рода бизнеса, когда понять задачу было просто очень сложно понять изначально всех мелочей каждого бизнес-процесса, всё это только в процессе предварительного тестирования и запуска прототипа возможно выявить.
                                                                                        • +7
                                                                                          «Не плоди сущности сверх необходимого» Окама.
                                                                                          Основная проблема Бориса в том, что он сразу стал генерализировать и обобщать сущности, порождая при этом новые сверх необходимости. В этом его основная ошибка. Кроме этого, сущности должны отличатся поведением.
                                                                                          Ну а у Марка конечно, будет спагетти внутри, что конечно же скажется на сопровождении.
                                                                                          В общем, это две крайности, которых следует избегать.
                                                                                          • +2
                                                                                            До меня долетел другой посыл: четко определись что именно нужно делать, прежде чем делать.
                                                                                            >> А переписать всё заново, если что, — это всегда успеется.
                                                                                            Вот с переписать всегда проблемы. Если проект на 1к строк, то конечно, можно и переписать, а когда там уже 1кк… такое уже не переписывается, а добавлется очередной адъ внутрь реализаций. А еще есть такая штука, как обратная совместимость, которая не позволит просто так взять и добавить еще один параметр в метод функции. Вот что тогда будет делать Маркус?
                                                                                            • 0
                                                                                              упс… не в ту ветку запостилось :'(
                                                                                            • +7
                                                                                              Согласен — две крайности. Они тут полезны в том что мы хотим понять. Я считаю что оба программиста молодцы, а вот косячник — менеджер.
                                                                                              Программисты вообще всегда молодцы, живут в своем мирке и как знают мирок свой так и пишут.
                                                                                              А вот менеджеры, блин, ну неужели они не могу объяснить какой будет проект:
                                                                                              1) прототип для показа — который выкинут и надо код писать быстрее пусть с утечками памяти немасштабируемый и т.д. (Маркус тут даже перестарался, все можно было написать в main()),
                                                                                              2) серезный проект с ТЗ, которого действительно утверждено — надо показать это ТЗ, диаграмки состояний нарисовать, объяснить как в дальнейшем может развиться система. Какие перспективы сопровождения (Борис не виноват что ему не предоставили полной информации, однако он правильно начал с минимумом абстракций, а потом их наращивал, основной бедой его был повар, который является инициатором выпечки — он фабрика, а не плита, плита — инструмент, который на ровне с рецептом должен использоваться поваром и просто поддерживать температуру определенную, из-за неправильного повора рецепт вперся в плиту зачем-то и пошло поехало, Борис действительно не мог остановиться и развернуть архитектуру вовремя из-за косноязычности менеджера, кирпичи выпекать стало не кому выходит, кстати хороший паттерн чтобы не плодить под пирожки своих поворов — мост / Bridge)
                                                                                              3) стартап, в котором надо делать быстро и с возможность масштабирования. Тут любой подход хорош, единтсвенное надо реализовывать его качественно. Если разобратся в подходах данных программистов, то Борис пишит объектно-ориентированный код, а Маркус — процедурно-ориентированный, ну и кто сказал что последний сложно тестировать? Можно и нужно поколоть его основные методы на составляющие и их так же легко тестировать как объекты. Разница их подходов лишь в том, что у Бориса есть модель объектов, она более наглядна, чем математическая модель Маркуса. А код один и тот же, просто дайте процедурнику объектно ориентированный код, он его поймет, но напишит все посвоему и криво. А если наоборот, то объектник начнет все рефакторить излишни пытаясь структурировать. Так что лучше не мешать программистам, а грамотно менеджерам ставить задачки))

                                                                                              Вывод из статьи: менеджеры виноваты во всем
                                                                                              • 0
                                                                                                Менеджеры виноваты — тут я не спорю — но часто, как упоминалось выше, заказчик сам не знает, или хитро не говорит, будет это прототип или мегапрога.

                                                                                                Бывало разное — раз заказчик сказал, что будет прототип, а потом перепишем. Написали, а его жаба заела переписывать — итак работает, мы конечно договаривались, но запилите пока на том что есть ещё пару мелких фишечек. Потом ещё фишечек. Так прошло 2 года, на проекте 2 раза сменилась команда, ну в общем вы поняли…

                                                                                                А что нам, команде, было делать? Тут всё зависит от Product Owner-а. Но это я про мелкий и средний конвеерный аутсорсинг, конечно в продукте всё по-другому.
                                                                                              • +40
                                                                                                image
                                                                                              • +14
                                                                                                Знаете, у меня тут полно кода Маркуса. Его действительно круто фиксить итд, но чьорт побери! Листинги функции на 5 экранов и отсутствие тестов при портировании на другую архитектуру… ААААААА!!!!111
                                                                                                • +1
                                                                                                  Написано красиво, не без смысла, но наблюдая оба подхода, поддерживая и развивая проекты, доставшиеся по наследству, мне кажется, что главное, это не делать все слишкмо гибко или слишком просто, а делать это понятным. Если у Маркуса понятный код и прозрачная, однообразная логика — все круто, если это не так — его «простую» конструкцию рано или поздно выкинут и напишут заново, потому что никто не будет понимать, как оно вообще работает.
                                                                                                  • +6
                                                                                                    У Бориса получился ад, т.к. очень сложно проследить взаимодействие между всеми этими классами. И это обусловленно тем, что он всегда пытается сделать через чур универсальное решение. Зато его код легко покрывается юнит тестами и соотвественно не ломается непредсказуемо сразу в 10 местах. И потенциально это дает возжность третить меньше времени на разработку — программинг, отладку, тестирование.

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

                                                                                                    KISS здравый принцип, но в данном примере им никто не воспользовался.
                                                                                                    • +3
                                                                                                      кажется, главный месседж статьи в том, что Борис свой адъ не осилил.
                                                                                                      • +6
                                                                                                        Вы так про тесты говорите, как будто это самоцель.
                                                                                                        • 0
                                                                                                          Юнит-тестами там можно покрыть все, да. Только тестироваться будет присвоение переменных в конструкторах, т.к. при таком накале ООП там тестировать больше бывает и нечего. И то, что тесты выполняются, ничего абсолютно не гарантирует: это всё просто поломается не в классах, а по швам между классами.
                                                                                                        • +4
                                                                                                          Хорошее дополнение к статьям: "Жизнь без объектов" и "Перестаньте писать классы" про злоупотребление ООП.
                                                                                                          • 0
                                                                                                            да, я этими статьями вдохновлялся) ещё кстати в дополнение к этому у меня юмореска есть
                                                                                                          • +37
                                                                                                            Ваш Маркус создал God Object — это тоже плохо
                                                                                                            принцип KISS — «сохрани это простым», а не «сохрани это тупым»,
                                                                                                            т.е. не стоит плодить сущностей более чем необходимо, но и менее чем необходимо тоже не стоит.
                                                                                                            • +4
                                                                                                              > Но с помощью шаблона «шаблонный метод» беспорядок вполне можно структурировать.

                                                                                                              Ага, и в итоге все это сведется к схеме похожей на первую :) Плюс вы бы подрисовывали квадратики «переписанного почти с нуля кода». А то складывается впечатление, что во втором подходе раз — и сразу все написано.

                                                                                                              А схемы Бориса надо было рисовать в «проекции 5D на 2D» чтобы вообще все запутано выглядело (намек на то, что несколько выровняв их можно даже якобы кашу классов сделать понятнее).

                                                                                                              Хотя одно верное наблюдение есть:

                                                                                                              > Борис уже начинает что-то такое чувствовать, но остановиться уже не может.

                                                                                                              Надо знать где остановиться с абстракцией. :) А то можно сочинять и дальше — ведь повар тоже не из вакуума взялся… мама, папа, учителя… :)
                                                                                                              • +4
                                                                                                                Ну тут либо Борис еще начинающий программист с блеском в глазах и полон романтики программирование, либо Маркус — уже умудренный опытом человек, который точно знает, что как ты не корячься, всё равно прийдётся переписывать, потому что менеджер к тебе прибегает без какого либо ТЗ, без понятия о продукте и так далее.
                                                                                                                Ну или Маркус еще будлокодер, а Борис — еще слишком умный чувак.
                                                                                                                • 0
                                                                                                                  Хороший небольшой учебник по шаблонам можно написать по левой модели.
                                                                                                                  • +2
                                                                                                                    А в чём суть статьи то? Ну описали вы два подхода, которые применяются к одному заданию, но ведь важна цель задания!
                                                                                                                    Нам нужен Proof of Concept и менеджер идёт к Маркусу. Быстро, эффективно. Концеция прошла демо презентацию и то же задание получит Борис. Вот теперь у компании есть продукт.

                                                                                                                    Дело в том, что многое зависит от компании и специализации. Компания со своим продуктом уделяет большее внимание проблемам поддержки/правки кода и масштабируемости. Пример из реальной жизни — через год приходит менеджер и говорит: «Помнишь хлебо-печку? Одна большая компания хочет построить хлебзавод и мы уже продали им наш модуль!». А потом менеджер будет приходить ещё много раз с новыми требованиями для API к уже завершённому проекту… И тут вот вам захочется сломать что-нибудь очередному Маркусу. Причём что то жизнено-важное.
                                                                                                                    • +2
                                                                                                                      Любую проблему можно решить добавлением еще одного уровня абстракции. Кроме проблемы слишком большого числа уровней абстракции. =)
                                                                                                                      • +4
                                                                                                                        Принцип KISS гласит: делай настолько просто, чтобы проще было некуда.
                                                                                                                        Вопрос в том, что такое «проще». Вместо классов использовать дополнительные поля и ветвить логику? Или, наоборот, использовать полиморфизм? Однозначного ответа тут нет.
                                                                                                                        Зато есть хороший принцип третьего дублирования: если что-то хочешь продублировать в третий раз — пора с условий перейти на полиморфизм.
                                                                                                                        А заранее создавать абстрактные фабрики, отвязывание по интерфейсам и инъекции — это, естественно, усложнение, а не упрощение. А главная причина создания ООП как раз была в упрощении.
                                                                                                                        Так что, люди, используем исконные принципы ООП, а паттерны, архитектуры и т.д. — только если они упрощают жизнь.

                                                                                                                        P.S. IMHO, оба приведенных в статье примера сложны. Первый — чрезмерной абстрактностью и гибкостью, второй — слишком большим количеством условий и логики на нетипизированных данных, собранным в одном месте. Истина где-то между.
                                                                                                                        • +4
                                                                                                                          Как всегда — истина где-то посередине между двумя крайностями
                                                                                                                          • –1
                                                                                                                            Борис — ты не прав!
                                                                                                                            • +60
                                                                                                                              А!!! Это моя любимая ситуация! Когда мы видим, что выдуманным примером, можно доказать какие угодно положения.
                                                                                                                              • 0
                                                                                                                                А если принять за факт, что 2+2=5, то можно доказать, что я — английская королева.
                                                                                                                                • 0
                                                                                                                                  Доказательство — в студию! :-) мне всегда было интересно на это посмотреть )
                                                                                                                                  • +2
                                                                                                                                    Ну, например, так:
                                                                                                                                    Доказывать будем от противного. Предположим, что я — не английская королева. Пусть n — число английских королев, которыми я являюсь. В нашем предположении n=0. Тогда:
                                                                                                                                    n+(2+2)=0+5 (сложили два равенства)
                                                                                                                                    (n+2)+2=5
                                                                                                                                    n+2=5-2=3
                                                                                                                                    n=3-2=1.
                                                                                                                                    Откуда (по определению n) следует, что есть хотя бы одна английская королева, которой я являюсь. А значит, я и есть эта самая королева. Впрочем, все остальные королевы — тоже я.
                                                                                                                                    P.S. Короны не жмут.
                                                                                                                                    • –1
                                                                                                                                      если мы предполагаем, что n=0, то тогда самое первое равенство записано не верно. n+(2+2)=0+5
                                                                                                                                      Т.е. мы изначально соглашаемся с тем, что 2+2=5, что позволяет мне переписать последнее равенство в n=3-2=0
                                                                                                                                    • +1
                                                                                                                                      или так:
                                                                                                                                      Примем, что 2+2=5.
                                                                                                                                      Отнимаем от обеих частей 2: 2 = 3
                                                                                                                                      Отнимаем от обеих частей 1: 1 = 2

                                                                                                                                      Допустим единица слева — это я, а двойка справа — это я и английская королева. Получается, что «я» — это тоже самое что «я и английская королева». А значит я являюсь и тем и другим.
                                                                                                                                • +4
                                                                                                                                  Оба случая — крайности, сущностей должно быть чуть больше, чем в примере справа, но они не должны быть настолько абстрактными, как в примере слева.
                                                                                                                                  • +3
                                                                                                                                    Неожиданный результат, начиная читать статью, я думал что вот вот ближе к концу менеджер поставит такое задание, которое легко впишется в логическую структуру Бориса, а Маркус начнет строить костыли, и уже потирал ручки в предвкушении этого, а нет, Маркус выкрутился.
                                                                                                                                    • +5
                                                                                                                                      Астрологи объявили октябрь месяцем стартапов. Популяция топиков про быстрый старт возросла втрое.
                                                                                                                                      • +17
                                                                                                                                        Борис умеет готовить лазанью, а Маркус спагетти…
                                                                                                                                        • +9
                                                                                                                                          Явно не хватает какого-нибудь Василия с золотой серединой.
                                                                                                                                          • +2
                                                                                                                                            И на функциональщине :)
                                                                                                                                            • +1
                                                                                                                                              А умный Василий пойдёт печь хлеб, пока эти лоботрясы будут зарабатывать гастрит.
                                                                                                                                            • +14
                                                                                                                                              Можно посмотреть с другой стороны.

                                                                                                                                              Вот так выглядит создание хлеба с использованием кода Бориса:

                                                                                                                                              Cook* cookchief = CookFactory.GetNeededCook(BossSay);
                                                                                                                                              
                                                                                                                                              OvenParams ovenParams = CreateOvenParams(GasIsAvailable(), MicrowaveOvenAvailable());
                                                                                                                                              
                                                                                                                                              AbstractOven* oven = OvenFactory.CreateOvenFromParams(ovenParams);
                                                                                                                                              
                                                                                                                                              Product* p = cookchief->cook(oven);
                                                                                                                                              
                                                                                                                                              return p;
                                                                                                                                              


                                                                                                                                              А вот так — с использованием кода Маркуса:

                                                                                                                                              if (BossSay("We need to cook bread!"))
                                                                                                                                              {
                                                                                                                                              	if (GasIsAvailable())
                                                                                                                                              	{
                                                                                                                                              		
                                                                                                                                              		Manager.gasLevel = GetGasLevel();
                                                                                                                                              		Bread* bread = Manager.createBread(OT_GAS_OVEN, GetNeededBread(), STANDARD_RECEIPT);
                                                                                                                                              		return bread;
                                                                                                                                              	}
                                                                                                                                              	else
                                                                                                                                              	{
                                                                                                                                              		Manager.gasLevel = 0;
                                                                                                                                              		if (MicrowaveOvenAvailable())
                                                                                                                                              		{
                                                                                                                                              			Bread* bread = Manager.createBread(OT_MICROWAVE_OVEN, GetNeededBread(), FAST_RECEIPT);
                                                                                                                                              			return bread;
                                                                                                                                              		}
                                                                                                                                              		else
                                                                                                                                              		{
                                                                                                                                              			int neededBread = GetNeededBread();
                                                                                                                                              			if (VasyaWantsBreadToo())
                                                                                                                                              			{
                                                                                                                                              				neededBread = neededBread + 1;
                                                                                                                                              			}
                                                                                                                                              			
                                                                                                                                              			Bread* bread = Manager.createBread(OT_HEAT_OVEN, neededBread, STANDARD_RECEIPT);
                                                                                                                                              			return bread;
                                                                                                                                              		}
                                                                                                                                              	}
                                                                                                                                              }
                                                                                                                                              else if (BossSay("We need to cook bricks!"))
                                                                                                                                              {
                                                                                                                                              ....
                                                                                                                                              }
                                                                                                                                              
                                                                                                                                              • +18
                                                                                                                                                Совсем не обязательно, у Маркуса может быть так:
                                                                                                                                                if (BossSay("We need to cook bread!"))
                                                                                                                                                {
                                                                                                                                                    int ovenType = GetAvailableOvenType();
                                                                                                                                                    Manager.gasLevel = GasIsAvailable() ? GetGasLevel() : 0;
                                                                                                                                                    Bread* bread = Manager.createBread(ovenType, GetNeededBread(), ovenType  == OT_MICROWAVE_OVEN ? FAST_RECEIPT : STANDARD_RECEIPT);
                                                                                                                                                    return bread;
                                                                                                                                                }
                                                                                                                                                else if (BossSay("We need to cook bricks!"))
                                                                                                                                                {
                                                                                                                                                ....
                                                                                                                                                }
                                                                                                                                                
                                                                                                                                                • +1
                                                                                                                                                  Не поверите, но второй листинг читабельнее и его легко чуть подрефакторить, чтобы убрать громоздкость в ветвлениях. Например, вынести код в ветвлениях в отдельные приватные методы и будет вообще зашибись )
                                                                                                                                                  • 0
                                                                                                                                                    Да, С++ — это ещё дополнительный уровень хардкора…
                                                                                                                                                    • 0
                                                                                                                                                      С++ открывает ящик Пандоры.
                                                                                                                                                      Но никто не заставляет Вас в него заглядывать, верно?
                                                                                                                                                      • 0
                                                                                                                                                        Заглядывают в такие места обычно по любопытству и по незнанию. Заставлять не требуется.
                                                                                                                                                  • +1
                                                                                                                                                    Хм, вот интересено было бы увидеть правильный вариант слева, так как там перегиб, хотелось бы увидеть золотую середину.
                                                                                                                                                    • +3
                                                                                                                                                      Похоже на жизнь, но есть некоторый перекос. По сути проблема Бориса не в том, что он использует ООП, а в том, что не придерживается YAGNI. Если бы он не фантазировал, то его более типизированный и структурированный пример мог бы получиться даже проще, чем у его коллеги.
                                                                                                                                                      • 0
                                                                                                                                                        Не хватает ещё одного пункта: теперь менеджер просит 5 членов команды добавить по 2 печи и по 4 рецепта.
                                                                                                                                                        Слева картинка разрастается, справа нет, но тут какой-то подвох.
                                                                                                                                                        • +1
                                                                                                                                                          Самое интересное, как всегда, происходит вдали от компьютеров. А именно: менеджер впервые после начала разработки встречается с заказчиком и наконец-то понимает, зачем тому нужна была печка. Он (менеджер) в седьмой раз приходит к программистам и говорит:
                                                                                                                                                          — Нам нужно, чтобы в печи можно было обжигать кирпичи.
                                                                                                                                                          После этого надо было начать проект с нуля и сделать просто печку для кирпичей.

                                                                                                                                                          Ну а если проанализировать работу Бориса, то на мой взгляд он сделал две серьезные ошибки:
                                                                                                                                                          1. Неоправданно ввел набор сущностей Cook. Можно было сделать просто шаблонный метод в печке. Либо допилить печку до Фабрики Продуктов. Впрочем тут есть масса вариантов.
                                                                                                                                                          2. Перемудрил с печкой для кирпичей — тут варианта два, либо сделать кирпич таким же продуктом как и хлеб, либо вообще отдельную несвязанную печку для кирпичей сделать и отдельный кирпич не связанный с хлебом, т.к. предметная область очевидно иная и с развитием проекта расхождение требований будет только усугубляться.

                                                                                                                                                          • 0
                                                                                                                                                            простите что-то напутал с цитатами
                                                                                                                                                            • +2
                                                                                                                                                              Очевидно, забыли слеш для закрывающего тега: <blockquote>…</blockquote>. Хабр автоматически закрывает незакрытые теги.
                                                                                                                                                          • +41
                                                                                                                                                            «Что я хотел этим сказать? Мораль сей басни такова, что с помощью надуманного примера можно доказать всё, что угодно.» (с) Joel Spolsky
                                                                                                                                                            • 0
                                                                                                                                                              А в каком контексте он это использовал? Можете дать ссылку?