
Комментарии 18
Мне кажется, вы не поняли мысль автора. Изменение бизнес-требований должно ломать код, чтобы компилятор вам подсказал, где его надо исправить. Скажем, если добавить новое значение в enum в C#, компилятор не подскажем места, где этот enum проверяется. В отличие от F#, который покажет, где надо дописать новый вариант.
Речь именно об этом. Возможно, мой перевод хромает, но, мне кажется, я это место перевёл довольно близко к оригиналу. Свою мысль Скотт разъясняет чуть дальше по тексту.
Всё сильно зависит от проекта. У мя обычно речь идёт о десктопных/мобильных приложениях и в последнее время об играх. Тут по умолчанию нет команд, которые используют наши dll как либы в своём коде. Поэтому несмотря на приличный объём кодовой базы, мы очень легко идём на ломку типов.
Более того, я предпочитаю ломать обратную совместимость каждый раз, когда чувствую, что во всём зависимом коде надо среагировать на изменения логики. В этом случае я могу искусственно заменить .PropertyName на .PropertyName_42, после чего пойти каскадно править весь поломанный код и в ручном режиме решать, достаточно ли механической правки имени, или нужно что-то потяжелее. Это же решение будут вынуждены принять все разрабы, когда стянут изменения в свои ветки.
Сиё обсуждение происходит уже не в первый раз, и как я понял, для C#-еров такой подход выглядит экстремально, но тут просто необходимо учитывать устройство F#. Язык провоцирует нас создавать много типов с очень узкой сферой применения (<= домену в тдд). Если этому противиться, можно оказаться в ситуации, когда каждая правка будет сопровождаться философскими рассуждениями о том, каким эхом наши действия отразятся в вечности. Долго в режиме “симулятор тайп-астронавта: вид сбоку” существовать не получается, поэтому неизбежно начинается эрозия качества и прочий “реализьм”. Оба варианта мне не нравятся.
Понятно, что в случае библиотечных (ну или просто очень больших) решений у подхода ломай -> чини -> повтори будут трудности. Придётся изворачиваться, работать через type extrensions, быть может отказаться от алгебраических типов, чтобы не сталкиваться с перспективой неработающих конструкторов и т.д. Однако, во-первых, до проекта таких размеров надо ещё дожить, во-вторых, даже на больших кодовых базах большая часть кода существует в изолированных карманах, которым “библиотечный” уровень обязательств без надобности.
Поэтому рядовому разрабу достаточно чётко понимать, в каких условиях он находится и действовать соответствующим образом.
Да это не про слом обратной совместимости, это вообще про другое это другой уровень, тут обратная совместимость никак не сломается
Применительно к F# ожидания надо скорректировать. Мы действительно до поры игнорируем обратную совместимость как несущественный фактор и не испытываем по этому поводу угрызений совести, так как эта схема работает на дистанциях значительно больших, чем это можно было представить по опыту C#. Лишь когда припрёт, мы начинаем танцы с бубнами. Причём этими танцами владеет очень ограниченный набор лиц/ Большинство из них явно выходят из аудитории, с которой работает Влашин как автор блога.
// Опыта общения с ним в роли консультанта не имею, и не знаю, что он говорит при личном общении.
Всё так. Чем уже сфера ответственности, тем меньше шансов что-то сломать на широком фронте.
По хотрелоаду вполне возможно, что вы пытаетесь взять планку, которую F# не взял. У нас в REPL изменённый тип – это новый тип. С точки зрения компилятора он не эквивалентен старому, поэтому их нельзя просто так смешивать (за исключением случаев апкаста к общему предку). Часто приходится пересобирать зависимые модули и т.д. Кложуристы при столкновение с этим начинают выть, но после обретения некоторого опыта желания компилятора можно предвосхищать.
С рекордами приблизительно тоже самое происходит. Если добавить в некий тип поле B, то все конструкции вида { record with A = 42 } (новое поле не задействовано!) в зависимых dll начнут падать в рантайме, пока их не пересоберут с обновлённой либой. Код при этом останется идентичным. То есть проблему не решили by design, но существенных потерь от этого никто не понёс.
Все возможно. Только начинать надо с фундаментальных классических трудов, а не с новомодных веяний.
и вы наверно знаете что такое абсолютная инкапсуляция, например? Никаких общих слов, одна голая идея, наверно даже в не самом лучшем оформлении, в сыром виде, так сказать.
вы удивительно* четко сформулировали вопрос, на который я хотел вам ответить:
плагин изменился и перекомпилировался, но старая версия продолжает использоваться в уже загруженных сессиях. Как вызывающий код должен понять, можно Енкодеру (ваша терминология) передать среди прочих новый параметр, или нет, если старый код рухнет, увидев его, а новый — откажется работать без него?
ответ на который тоже:
банальщина из пятого класса церковно-приходской школы.
но вы, получается, этот ответ не знаете, хотя я не могу сомневаться, что классические фундаментальные труды читали! Вот этот ответ в моей интерпретации:
вызывающий код НЕ должен понять, можно Енкодеру (моя терминология) передать среди прочих новый параметр, это НЕ его задача! вызывающий код НЕ должен передавать параметров которые сломают работу со старыми параметрами! Это же очевидно, если вы добавляете параметры в конце посылки, то клиент может их просто не читать, например! Соответственно, это накладывает определенное требование И НА всех и любого клиента, и это требование уровня проектирования системы и предусмотренной возможности расширения этой системы. Если не была заложена возможность расширения системы на этапе проектирования, то сделать уже что-то потом в этом направлении действительно сложно, хотя иногда выкрутиться получается, используя другие возможности системы специальным образом.
Требование уровня проектирования системы - это то, что клиент должен уметь игнорировать неизвестные ему параметры каким-то образом (каким есть варианты, вы их должны знать!), это же элементарно согласитесь! Клиент должен работать только с тем что знает, другими словами. Поэтому старый код просто НЕ должен рухнуть увидев новый параметр, а новый код может работать так же как старый без этих новых параметров, это тоже вполне очевидно если надо поддерживать и старый и новый одновременно.
Действительно, если систему проектировали (или слепили как получилось) до вас то придется выкручиваться и как то вносить реализацию этих требований на уровне всех существующих клиентов - никуда не деться. Но это вопрос именно проектирования, если он не был решен его все равно в конце концов надо решать, либо делать-переходить на новую систему.
*удивительно - что не зря вам плюс поставил, ожидая четкой формулировки этого, интересного мне вопроса!
Может вам будет интересно, после этой статьи: проверка на предрасположенность студента к поиску... меня вообще слили здесь на Хабре когда-то, не так давно. Можете проверить - следующая статья помечена как "Из песочницы", так что у вас еще не предел здесь. Я поэтому понимаю ваши эмоции и игнорирую их, но вы и думаете интересно!
Это два перпендикулярных подхода к разработке. Раздел скорее по принципу императивный vs функциональный. Во втором случае правильная программа (о чем как раз статья) обладает свойством полноты, то есть корректно написанный код покрывает все множество корректных входных значений. В итоге всевозможные эджкейсы, для проверки которых, по мнению некоторых, и придумали ТДД, становятся не нужны.
Код программы, который компилируется и является доказательством ее корректности)
4. Проектирование с помощью типов: Исследуем новые концепции