Pull to refresh

Comments 105

Интересно, как будет выглядеть велосипедная рама, если проектировщик ожидает (и по опыту уверен) что любая самая неожиданная деталь этой рамы может измениться во время проектировки или, что бывает гораздо чаще, непосредственного производства. И без учёта времени на доработку и бюджета.
Программисты очень часто занимаются производством велосипедов, которые, возможно, полетят в космос, а, возможно, отправятся исследовать дно океана.
Только потому, что заказчик, как правило, не знает, чего хочет.
Вот тут-то и нужен хороший менеджер.
По аналогии с велосипедами — «я бы хотел, провести исследование и для 10% покупателей поставить еще один руль вместо сиденья. А в чём проблема? У вас же уже есть руль? Ну так используйте его повторно!»
UFO just landed and posted this here
Нет, потому что сам боится потом «все переделать с нуля». Поэтому с самого начала старается заложить абстрактность мега-уровня.
На моей памяти еще ни один велосипед не побывал в космосе и ни один не отправился в глубины океана. А если в какой-то момент стало необходимо поменять размер колес — быстрее и дешевле поменять и раму.

Отличный коэн на тему слабой связности — thecodelesscode.com/case/119?lang=ru
На лицо попытка доказательства по аналогии с объектом реального мира. По умолчанию все такие аналогии надо считать лживыми.

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

Мысли правильные, аргументация — неочень.
Все аналогии лживы, ибо апеллируют к эмоциям, а не к разуму.
Обобщения используются, вообще говоря, не только для реюза общей части, а для последующей более легкой поддержки ОДНОГО общего фрагмента вместо 15 копий. Поэтому у обобщения есть разумные пределы, которые можно увидеть двумя способами: либо знать развитие проекта наперед, либо иметь опыт непредсказуемого развития и его обычных последствий.
UFO just landed and posted this here
Актуальная статья. Иногда кажется, что некоторые программисты пишут код ради самого кода.
Всегда умиляла любовь людей из мира CS/IT к аналогиям и метафорам. Если забыл умные слова или не можешь привести конкретный пример, сделай мудрое лицо и расскажи про яблочки велосипеды.
Есть обратная сторона медали.
Если ты четко понимаешь принцип работы некоторой системы или явления, то должен быть способен объяснить «на пальцах» как это работает.

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

PS: я понимаю, что в данном треде шло обсуждение попытки внушить правдивость одного утверждения путем прикрытия другим, более простым и, возможно, не связанным напрямую с первым.
Квантовую физику можно объяснить с помощью бытовых аналогий?
Ну, это всё научпоп, попробуйте, например, объяснить волновую функцию с помощью бытовых аналогий. Да и вообще всё в квантовой физике математические абстракции, у которых бытовых аналогий то и нет
Ну понятно, что специфичные детали трудно объяснить на пальцах. Я же о принципах работы, об основах процессов и явлений говорил.
Метафоры здесь, я думаю, лишь для более выразительного изложения, а суть выражена в последнем предложении.
А по-моему вполне наглядно, потому что есть рама, есть виртуальные узлы(руль, колёса) и есть абстрактные в (например багажник). Другое дело, что кто-то умудрится из рамы велосипеда в итоге сложить кузов машины попутно заткнув каретку картоном, а дырку рулевого стакана заклеив скотчем. Но это уже вопрос к клиенту — если нравится, пусть (велосипед же в итоге был куплен), но все претензии по итоговому качеству — самому себе же. Ну а кто-то возьёт напильник и приделает искуственную ногу к одной педали, потому что у конкретного человека только одна нога — и в итоге получит то что нужно.
Один мой знакомый считает, что когда программист начинает тратить много времени на архитектуру — это такая форма прокрастинации. Вроде бы и делом занят, даже полезным и интересным, но при этом конечный продукт стоит на мертвой точке.
UFO just landed and posted this here
Понимаю ваш сарказм. Оппа-говносайт-стайл — тоже не выход. Поэтому я и не сказал, что однозначно разделяю его точку зрения.

Ну да, а потом другие ребята приходят и рефакторят то, что первые накодили. Всем кушать надо, все при деле. Межпрограммерский заговор налицо!
Зачем программировать вообще? Есть же давным давно написанный ИИ, который может сам программы писать. Главное, никому не показывать. Межпрограммерский заговор ведь :)
Это так. Но с другой стороны, два месяца программирования могут съэкономить один час проектирования архитектуры.
Ну тогда может за час все спроектировать и потратить два месяца без этого часа на что-то более полезное?
И этот знакомый в чем-то, но не во всем, прав: если задаться вопросом, а кому эта архитектура нужна — то оказывается, что заказчика она в общем не интересует — ему нужно сейчас и побыстрее; а вот самому программисту через месяц/два/год будет очень сложно объяснить заказчику, почему задача, очень похожая на ту, что в прошлый раз сделали за день, теперь стОит хорошо если неделю. И из рассказа про плохую архитектуру заказчик поймет только «этот программист плохо напрограммировал», а не «я так давил по срокам в начале, что теперь это аукнулось».

То есть хорошая архитектура очень нужна, но нужна именно программисту.

Нужна-то она заказчику, чтобы программист быстро делал задачи. А вот если он не смог это донести в самом начале, то и будет «этот программист плохо напрограммировал»

По существу вопроса. Насчет Java. Я лично программирую в основном на Scala и JavaScript. Мне нравится и Java, но мне кажется, проблема модели «сильное сцепление и слабая связанность» в том, что на Java она стоит слишком уж дорого по сегодняшним меркам. Очень много кода приходится писать, чтобы ее поддерживать. Опять же система зависимостей Maven/Ant(кстати, и SBT тоже) довольно громоздкая, и там довольно тяжело поддерживать большое количество микромодулей. Много обслуживать приходится. Скажем, если сравнивать с тем же NPM для Node.JS, то учитывая все плюсы и минусы Ноды, нельзя не признать, что на практике низкий порог для публикации модулей сыграл важную роль в развитии системы модулей. Системы из микромодулей со слабой связанностью на Node/NPM собирать гораздо легче, чем на том же Java.
Как то вы слишком категоричны. Меня например не устраивает когда заднее колесо знает о руле. Мне нравится хороший дизайн. Дробить раму по сантиметру это конечно бред, объект должен быть целостным, функционально значимым.
> Меня например не устраивает когда заднее колесо знает о руле.

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


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

1) рама — несущий элемент, ответсвенный, а значит дробление его на мелкие части повышает вероятность отказа или поломки.
2) рамы бывают разные, форма у них похожа, однако рамы не взаимозаменяемы (интерфейсы каретки, рулевой колонки, подседельной трубы разные)
3) если пользователю нужно получить наиболее надежный и целесосбразный вариант — реализация рамы делается под конкретного пользователя (карбон, титан и т.п.)
4) именно рама задает практически все свойства велосипеда.

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

Я хочу сказать о том, что для каждого изменения в сторону развязывния кода нужны предпосылки. Считаю, что главной задачей разработчика в этой части является создание такого кода, который при необходимости несложно рефакторить и развязать. Хотя это конечно ИМХО.

Модуляризовать ради того, чтобы просто получить кучу модулей — раньше времени увеличить сложность продукта. Создать кучу интерфейсов, применить кучу паттернов просто так? Сложность (а соответственно и стоимость разработки) должна возрастать с ростом полезности, ведь так?
У Java-прлограммистов всегда есть ответ на вопрос: нафига это выделено в отдельную функцию на три строки. Для тестирования! Понять, что код тестов и код продукта несопоставимы по важности им почему-то не дано. И вообще иногда складывается впечатление, что главная цель программирования — «покрыть» всё тестами. Почему, зачем, какова цель этого сакрального действия — неясно.

Нет, я не против тестирования. И понимаю что иногда код таков, что написать тесты к нему не сложно и очень сложно. Но блин, когда в код добавляется сток 100 для того, чтобы тесты стали на 50 строк короче — это уже перебор.

Тесты — это вспомогательный элемент. Как леса в строительстве или временные подпорки. В идеале — они вообще не должны влиять на архитектуру или, уж по крайней мере, влиять минимально. А не являться оправданием для того, что у вас всё работает через… я даже не знаю что.
Скажем так, тестирование конечно важно. Даже и необходимо. Но все жа главная цель программирования — написать программу, а не тесты. И эта программа должна правильно делать то, что она должна делать.

Но тут возникает проблема — что считать правильным? Я для себя определил так: делать правильно — это делать сообразно требованиям осозанным мной и заказчиком в данный момент времени. Требования могут немного измениться в процессе разработки и надо закладывать такую гибкость, которая позволит недорого изменить функционал всвязи с этим. Ну а потом — рефакторинг. Вот тут будут незаменимы тесты как раз.
Тесты улучшают архитектуру. Если для программного кода очень сложно написать тест, то проблема, очевидно, в плохом программном коде и этот код нуждается в рефакторинге (с дроблением на кусочки и определением более понятных связей между ними).
Всё так же как и с велосипедом. Если нужно сделать велосипед и ездить на нем 50 метров до магазина — можно и монолитным сделать, а вот проф велосипеды должны быть хорошо протестированы с разными колёсами, каретками, шатунами и так далее по списку. Всё зависит от целей :) Если разрабатывается велосипед для поездки в магазин, нет смысла тратить x2-x3 времени на хорошую архитектуру и тесты. Имхо.
Фаулер писал, что наличие тестов — это необходимое условие для проведения рефакторинга. А рефакторинг, это единственный способ улучшения архитектуры уже написанного приложения в случае, если в этом появится необходимость.

Даже если у нас не супер хорошо спроектированный код, который покрыт тестами, то, при возникновении необходимости, мы сможем его отрефакторить. А вот если тестов нет — не сможем, какой хороший код бы ни был.

Отсюда простое следствие, если без изменений в архитектуре нельзя покрыть код тестами, значит это изменение в архитектуре сделать нужно, потому что если не покрыть код тестами… см. первый абзац…
Когда фаулер это писал, то еще не было автоматического рефакоринга. Сейчас есть инструменты, которые могут проводить рефакторинги, гарантируя корректность кода.
В завасимости от языка и конкретной среды разработки, набор гарантираванно безопасных рефакторингов разнится, и для таких языков как Java или C# далеко не полон, и не достаточен для серьезного рефакторинга. Это вызвано тем, что инструменты рефакторинга опраются на статически выводимую на основании анализа кода информацию, а есть ещё рантайм…

Например, в сишарпе «безопасным» рефакторингом «Introduce factory method» можно легко сломать всю систему, т.к. инструмент рефакторинга не знает, что класс может инстанциироваться через DI фреймворк, которому нужен открытый конструктор (а рефакторинг делает его приватным).

Поэтому, безопасные автоматические рефакторинги не отменяют необходимости в тестах, так как их «безопасность» во многих случаях — условна.
Я понимаю что всегда можно написать «слабосвязный код», работающий на соглашениях, который может развалиться при, казалось бы, простых рефакторингах. Некоторые системы, легко поломать даже переименованиями.

Но обычно эти соглашения хорошо известны и при первом же чтении кода ошибки обнаруживаются. Тесты на солашения редко пишут. Дорого это, а выхлоп маленький. Проще запилить расширение для тулов, которое будет соглашения проверять в любом проекте.
Любая программа — это одно большое соглашение…

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

Пример решения вышеупомянутой проблемы:
Вводится соглашение, что каждый класс, который допускает создание через контейнер — помечается аттрибутом. Пишется тест, который проверяет, что все классы, помеченные аттрибутом имеют публичный конструктор. Дополнительный бонус — разработчик знает, что если класс помечен аттрибутом, то выполнять рефакторинг «Introduce factory method» — возможно не стоит.
Тогда можно и в инструменты встроиться, которые скажу что не надо рефакторить классы с атрибутом. И снова тесты не нужны.

Тесты нужны только тогда, когда другого способа гарантировать корректность нету. Современные языки многие гарантии дают на уровне типов и проверок компилятора. Только этих проверок достаточно, чтобы тулы делали многие рефакторинги. Там где встроенных возможностей тулов не хватает, то включаются расширения.

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

В итоге тесты всё равно нужны, только не на саму программу, а на «встраивание в инструменты рефакторинга» и это замкнутый круг, разорвать который можно лобо тестированием, либо автоматическим доказательством корректности кода, что ещё более трудоемко…
Ну что за бред? В простых случаях статический анализ на порядок проще, чем тесты. Ибо тесты это динамика, эмуляция входных данных и зависимостей, а статический анализ работает не более чем с AST. Особенно проверки соглашений сделать в C#\Java совсем несложно. Для этого и тесты не нужны ибо код будет очень простой.

В итоге тесты всё равно нужны...

А еще тесты нужны для тестов или как вы гарантируете что тесты правильные?

Тестирование на самом деле помогает очень мало.
Для тестов тоже нужны тесты ;-) Ибо наличие тестов не гарантирует корректности…

Если предположить, что в каждой строчке кода содержится ошибка с вероятностью 0,001, то в 100 строках кода хотябы одна ошибка будет с вероятностью 0,0952

Предположим, что мы написали 100 строк юнит тестов. Юнит тест содержит ошибку с той же вероятностью. Вероятность ложно-положительного юнит-теста (читай, что ошибка попадет в продакшен) в этом случае будет 0,00906304 (в 10 раз меньше).

Итого:
100 строк кода — 0,0952 вероятность ошибки в продакшене
100 строк кода + 100 строк тестов = 0,00906304 вероятность ошибки в продакшене
100 строк кода + 100 строк кода = 0,181 вероятность ошибки в продакшене

Не бейте тапками, ибо я предположил, что ошибки не всязаны между собой.
Кстати… очень интересно посмотреть зависимость этих чисел от длины кусочков кода. Становится понятно подсознательное желание побить код на как можно более мелкие независимо тестируемые кусочки…
Юнит тест содержит ошибку с той же вероятностью.

С хорошо тестируемой архитектурой вероятность будет меньше. Тупо не в чем ошибаться :)

Но в подсчетах вы, кажется, не учли, что ошибка попадет в продакшен, если совпадут ошибки и в коде, и в тесте. Грубо говоря, будут в одной строке. Только в этом случае тесты ложно-положительно сработают
Но в подсчетах вы, кажется, не учли, что ошибка попадет в продакшен, если совпадут ошибки и в коде, и в тесте.

Я учел. Это было сказано про ошибку в юнит тесте без учета его результата:
Юнит тест содержит ошибку с той же вероятностью.


С учетом результата у меня получилось вот это:
100 строк кода + 100 строк тестов = 0,00906304 вероятность ошибки в продакшене


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

Очень грубое предположение по-моему.
Очень грубое предположение по-моему.

Согласен, грубое. Но для приведенной грубой модели — вполне допустимое :-)
тесты нужны для проверки логики, чтобы компоненты/система вели себя по-прежнему, как и раньше (если требования не сменились), а не для корректности кода. О нарушении последнего вам расскажет компилятор. Ну и плюс полностью согласен с комментом habrahabr.ru/post/206684/#comment_7125298, прям в точку
Еще раз: современные инструменты позволяют много рефакторинги проводить не изменяя наблюдаемого поведения. То есть сохраняя корректность.
окей, а как вы достигнете необходимого поведения изначально?
Отвечу вопросом на вопрос. Вы считаете что это невозможно?

Я вот умудрялся писать программы, которые делают то что надо, без тестов, я даже не знал о них. Иногда даже не запуская (тяжелые были времена, компьютер бы доступен раз в неделю). И это я еще в школе учился.
я хотел узнать, каким образом вы достигали требуемого поведения системы? что было критерием достижения цели?
Код соответствовал алгоритму, приводящему к решению задачи.
это по вашему мнению ответ на вопрос «каким образом»? ладно, пойдет, если не будете отвечать
Еще раз: есть алгоритм, на бумаге или в голове. Код соответствует алгоритму. Это же можно утверждать просто посмотрев на код.
ладно, бог с ним с этим. Вы первый человек из тех, кого я встретил, который сразу пишет корректный код без ошибок, самодокументируемый, по которому сразу понятен весь алгоритм, и при этом временнЫе затраты максимально снижены
сделал выводы, что вы одним только взглядом сразу видите правилен код или нет, значит можете в уме его откомпилировать на предмет корректности поведения
предлагаю остаться при своих мнениях, и в будущем, быть может, кто-то из нас двоих, а может быть и оба, скажут себе «а тот чувак с хабра был прав» :)
Обычно это ручной прогон нескольких сценариев.
да, но это совсем другой вид тестов. Быть может я отхожу от общепринятой терминологии, но у меня подобные тесты закрепились под название функциональные. И порой прогнать целый такой тест утомительно и отнимает уйму времени. Особенно если речь идет о приложениях с графическим интерфейсом
Во многих случаях целиком их не прогоняют, а проверяют лишь только что написанный код.
разумеется. Но даже в таком случае это достаточно утомительное занятие и по идее вообще работа не разработчиков, а тестеров. Просто в описанном вами случае ответственность смазывается, а разработчик так вообще занят не своим делом, впридачу код пишется маленькими итерациями, каждый шаг необходимо проверять. А проверять запуском — откровенное расточительство временем.

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

По поводу как проверять код — разумеется каждый склонен выбирать сам, нет какого-то уголовного кодекса по нарушению каких-то правил. Есть устоявшиеся, хорошие практики, подтвержденные и проверенные неоднократно и не вчера. Им можно следовать. Но никто не запрещает от них отходить. Только если такие отклонения идут вразрез с практиками, грешить на них точно не следует. Советую вам найти посты на хабре, посвященные тому же TDD. Там тема нашего с вами холивара развёрнута гораздо шире, глубже и большим кол-вом участников. Есть, кстати, даже целые притчи. Там уже определитесь, на чьей стороне вы, с кем согласны и с кем нет. Я свою позицию выбрал.
И нет тут единого мнения, которое устраивало бы всех.
Про TDD я и сам могу посты писать, но частая проблема что автотесты запрещают использовать, в лучшем случае разрешают их писать в личное неоплаченное время.
так я не столько о постах говорил, сколько о комментариях к ним, к этому и употребил «большим кол-вом участников» и «холивар».
Тесты как правило пишутся вперёд, поэтому о каком неоплачиваемом времени идёт речь — не совсем понимаю. В голове представляется картина, как разработчики прежде чем писать код, в нерабочее время проектируют систему и пишут по кейсам тесты. А в остальное время занимаются простым кодингом, с которым и обычный индус справится.
Что касается упорства начальства, так тут проблема возможно даже и не в использовании методологии, а неумении «продать» её применение начальству. Во всяком случае никто не мешает заложить это время в общую разработку (собственно, это и есть часть разработки). И если уж сроки всегда и строго, даже с точностью до итерации, устанавливает начальство, то это уже рабство какое-то
В комментариях я тоже отмечался :)

Ну, вечером дали задание на завтра, пришёл домой и тесты написал. Заодно поправил те, что за день сломались.

Продавать я никогда не умел :( А со сроками сложно — чем за монитором занимаюсь никто не следит, но вот дифф за день виден же.
Даже если у нас не супер хорошо спроектированный код, который покрыт тестами, то, при возникновении необходимости, мы сможем его отрефакторить. А вот если тестов нет — не сможем, какой хороший код бы ни был.
Чушь это. Даже скажу больше: профанация. Для рефакторинга не нужны unittest'ы. Совсем. Нужны функциональное тесты проверяющие всю систему — и всё. Если они достаточно хороши, но что-то не покрывают, то у вас появляется готовый способ что-то отрефакторить: выкинуть этот кусок.

Unitest'ы же — целиком и полностью вспомогательный инструмент. Их наличие или отсутствие вообще никак не влияет на возможность рефакторинга. Они могут его облегчить или затруднить, но и только. Никого не волнует что происходит внутри вашего компонента пока ваш компонент работает.

Когда вспомогательный инструмент начинает вдруг определять архитектуру всей системы — получается бред. Это всё равно как если бы здания строили не исходя из того, что нужно получить, а исключительно исходя из того, чтобы к любой его части был бы идеальный подход с лесов, которые бы никогда не убирались. Хотели бы вы жить в таком здании?
Вы вступили на скользкий путь холивара на тему «что лучше, юнит тесты или функциональные тесты».
Для себя я сам не решил, что лучше, и использую и то, и то, в зависимости от ситуации, но в своем комментарии я не говорил про какие-то конкретные виды тестов. Я говорил про необходимость тестов вообще. Потому не понимаю, почему вы, называя мое утверждение чушью, сами — фактически утверждаете то же самое.
То, о чём вы пишите мне знакомо, и соглашусь, что ломать архитектуру ради тестов как-то странно. И здесь мне кажется лишь проявляется ошибка в использовании TDD, то есть когда тесты пишутся на существующий код.
По сравнению создания программных продуктов с проектами в реальном мире есть хорошая метафора:
«Почему постройка домов никогда не затягивается по срокам так, как создание программного обеспечения? Потому что после построения дома заказчик не может сказать: „А теперь я хочу, что бы лифт ездил не только между этажами, а еще и внутри этажа, развозя корреспонденцию по отделам“»
В этом и основная проблема — в IT требования к продукту постоянно меняются, и хорошая архитектура должна давать возможность реализовывать эти требования без необходимости разбирать дом до кирпичика и строить всё заново.
А не задумывались почему так? Не раз встречался с фразами от потребителя: «Ну вы же специалист — ну что вам стоит?» Хотя в общем случае это правильно, что заказчих хочет чтобы лифт ездил и так и сяк. Хочет — надо сделать. Ведь софт (soft) — это мягкий, податливый. В отличие от харда (hardware) — который просто так и не изменить. И софт должен оставаться мягким вне зависимости от его сложности, его должно быть можно изменить так, как хочет заказчик. Это тоже одна из задач разработчика. Прослойка firmware — другое дело, кстати, она не сможет делать больше, чем заложено в железе.

Если заказчик просит изменить что-то, надо просто назвать ему соответствующую цену. И все вопросы сразу отпадут ;)
Вы сильно упрощаете, такой механизм может работать только при заказной разработке.
Если вы разрабатываете продукт, который продается разным заказчикам, то либо продукт сможет обслуживать требования 100 разных заказчиков и будет успешен, либо вы продадите первому заказчику, а остальных потеряете.
Не совсем понял к чему вы это написали? Я как раз говорил о том, что продукт должен быть достаточно гибким, чтобы у разработчиков была возможность подстроиться под требования рынка, но при этом достаточно жестким, чтобы не развалиться по пути к решению задачи.
Аналогия велосипеда и программного совершенно не корректна. Да железная рама должна быть прочной из единого куска алюминия. Но программный код не должен быть монолитным чтобы быть надежным
Ответил ниже. Но в данном опусе мне кажется не столь принципиально, на чем показывать аналогию, вся суть, на мой взгляд, выражена в последнем предложении. Но если бы я написал только его, это было бы очевидно.
Термин «велосипед» явно выбран неудачно, лучше бы машина или чтото похожее.
Возможно, так как в у нас «велосипед» имеет ещё одно значение, но я решил оставить переводом, а не статью «по-мотивам».
UFO just landed and posted this here
По моему мнению, обилие интерфейсов со всего лишь одной реализацией немного затрудняет поддержку кода. В одном из проектов, в котором я участвую, практически все сервисные интерфейсы имеют только одну реализацию. В итоге чтобы добавить метод, нужно сначала добавить его в интерфейс, потом в реализацию. Хотя всем уже итак понятно, что в обозримом будущем других реализаций для этого интерфейса не предвидится. Но «магический фреймворк» требует интерфейсов. Т.е. по сути здравого смысла понятно, что мне тут нужен один файл, но поддерживать приходится два. А вообще ад — это когда один такой сервис через цепочку таких же сервисов взаимодействует с другим сервисом. Приходится протаскивать нужный метод путем редактирования интерфейса и реализации для каждого элемента цепи. Отсутствие здравости в том, что практически всегда это редактирование сводится к одной строчке вызова метода из другого сервиса.
по-разному бывает. бывает, что разработчики в состоянии аффекта действительно забыли про какую-то важную штуку, например, про третье колесо для детского велосипеда — тогда да, надо половину рамы перекраивать. а иногда пытаются фонарик к рулю приделать методом всепроникающей диффузии, вместо того, чтобы заимплементить сей девайс с интерфейсом стандартного хомута. еще говорят, что сервисы это не ооп, поэтому понятие интерфейса к ним применимо лишь чисто условно.
Ну, так-то да я бы сказал, что объектно-ориентированная парадигма как бы перпендикулярна сервисно-ориентированной. Но, например, параллельна классической структурной парадигме (в стиле языка C). Т.е. мы можем следовать сервисно-ориентированной парадигме как на базе ООП, так и на базе структурной парадигмы.
В том, что у вас все модели исходят из интерфейсов — это не есть плохо.

Во-первых, очень удобно документировать: все что торчит наружу — торчит из интерфейса. И тестировать API тоже удобно.

Во-вторых, вы еще сотню раз подумаете, а нужен ли наружу тот метод, который вы хотите протащить. Должен ли он быть в этом месте, является ли он методом этого интерфейса? А может это уже совсем другой интерфейс?

В -третьих, совершенно не факт, что у вас не появится в будущем другой реализации. Однако наличие абстракций в разумных пределах не сильно повышает сложность кода. Это цена, которую необходимо и можно заплатить за гибкость.
не понимаю, что все к этому «loose coupling» так мм… прицепились ;). вот если бы автор еще и «high cohesion» так же красочно расписал, то половины интриги могло не получиться — как раз этот принцип не дает совершать всякие глупости. как то крошить код без надобности, или пилить рамы лисапедов на кусочки длиной 1см. в теории конечно: принципы-принципами, — они не мешают делать на практике весьма причудливые вещи.
UFO just landed and posted this here
Да, сперва не поймешь, где выполнение вообще начинается. А потом с грустью в глазах ищешь в траве интерфейсов где хоть какой-то реальный код и что вообще он вызывает…
Хорощий код — это тот код, который решает задачи проекта при наименьшей стоимости реализации и поддержки.
Простите, опечатка. Хороший.
Согласен с положениями в статье, но не согласен с примером. Пример специально подведен к космическому построению архитектуры.
Например: требуется велосипед. К велосипеду есть определенный набор требований, и мы их реализуем. Именно по факту требований. Нужно что-то больше? Появляются новые требования. Из-за них могут появиться первые или новые уровни абстракции, опять же в угоду требованиям, но мы не пишем всё заново.

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

Ещё один момент: фреймворки. Они для того и нужны, что позволяют построить каркас. Но они ни разу не завязаны на требованиях к конкретной области, поэтому и стараются максимально декомпозироваться на модули. А вы уже выбираете: вам один позвонок или всё-таки позвоночник.

А что касается дженериков в их привычном понимании — это сугубо техническая фича, направленная на решение именно технических задач, но никак не бизнесовых. В бизнесовых собственно можно наплодить абстракций уйму.
В статье под дженериками (generic) подразумеваются не те дженерики, которые параметризованые типы, а обобщенные абстракции.
В остальном, как выше уже писали необходим баланс, эта статья, на мой взгляд, как раз об отсутствии баланса — о забивании гвоздей микроскопом.
согласен, что в примере кинулись в крайность, отсюда получилась аж целая развёртка размышлений на эту тему
А по-моему, хороший код — это тот код, который легко может поддерживать сторонний разработчик.

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

Sign up to leave a comment.

Articles