Какие изменения слишком велики, чтобы их было легко сделать с помощью правильного дизайна?

11

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

Как правило, когда вы узнаете об объектно-ориентированном программировании, абстракции, факторинге и т. Д., Святой Грааль дизайна - и причина, по которой они всегда утверждают, что вы используете рассматриваемые методы разработки - заключается в том, что это сделает вашу программу «легкой для изменения» «ремонтопригодный», «гибкий» или любой из синонимов, используемых для выражения такой продуктивно звучащей концепции. Помечая ivars как частный, разбивая код на множество небольших, автономных методов, сохраняя общие интерфейсы, вы предположительно получаете возможность изменять свою программу с полной легкостью и изяществом.

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

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

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

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

В частности, проблема, с которой я столкнулся, которая привела меня к форумам, заключается в следующем: я работал над реализацией интерпретируемого языка программирования (реализованного в D, но это не актуально), и я решил, что аргументы моих замыканий должны быть на основе ключевых слов, а не позиционные, как они в настоящее время. Это требует изменения всего существующего кода, который вызывает анонимные функции, что, к счастью, довольно мало, потому что я нахожусь на ранней стадии разработки моего языка (<2000 строк), но было бы огромным, если бы я принял это решение на более позднем этапе. Есть ли в такой ситуации какой-нибудь способ, который, если бы я был достаточно предусмотрительным в дизайне, мог бы упростить эту модификацию, или определенные (большинство) изменения имеют далеко идущие последствия? Мне любопытно, является ли это каким-то образом неудачей моих собственных дизайнерских навыков - если да, то я

Чтобы быть ясным, я никоим образом не скептически отношусь к ООП или любым другим шаблонам, обычно используемым. Для меня, однако, их достоинства заключаются в оригинальном написании, а не в поддержании основ кода. Наследование позволяет хорошо абстрагировать повторяющиеся шаблоны, полиморфизм позволяет разделять код по понятной человеку функции (какой класс), а не по машинному эффекту (какая ветвь switchоператора), а небольшие автономные функции позволяют вам писать в очень приятном стиле "снизу вверх". Однако я скептически отношусь к их заявлениям о гибкости.

существует, FORALL
источник
Я не вижу, как изменение вашего языка затрагивает что-либо, кроме парсера. Не могли бы вы уточнить это?
шарфридж
В языке, похожем на болтовню, это правда, что вам нужно всего лишь изменить синтаксический анализатор, потому что это было бы простым вопросом foo metarg1: bar metarg2: bazкак foo.metarg1_metarg2_(bar, baz). Тем не менее, мой язык вносит более существенные изменения, а именно: списочные параметры в словарные параметры, что влияет на время выполнения, но не на синтаксический анализатор, на самом деле, из-за специфических свойств моего языка, я не буду сейчас вдаваться в подробности. Поскольку нет четкого сопоставления между неупорядоченным ключевым словом и позиционными аргументами, время выполнения является основной проблемой.
существует

Ответы:

13

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

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

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

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

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

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

Карл Билефельдт
источник
+1 за поддержку нового дела и старого дела, чтобы вы могли постепенно отказаться от него.
Эрик Реппен
9

Я бы порекомендовал вам прочитать эссе « Большой шар грязи» .

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

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

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

Кстати, вы должны скептически относиться к объектно-ориентированному программированию. Это отличный инструмент во многих контекстах, но вы должны знать о его пределах. Особенно неправильное использование наследования может привести к невероятно запутанному коду. Конечно, вы должны одинаково скептически относиться к любой другой технике дизайна. У каждого есть свое применение, и у каждого есть свои слабые стороны. Там нет серебряной пули.

Ян Худек
источник
1
+1: новаторский дизайн редко бывает успешным. Успешные проекты - это либо повторение проверенных проектов, либо итеративное уточнение.
Кевин Клайн
1
+1 Вы должны скептически относиться ко всем концепциям программирования, только посредством объективной критики мы применяем наши аналитические навыки, чтобы найти правильное решение, а не просто решение .
Джимми Хоффа
4

В общих чертах, есть «кусочки кода» (функции, методы, объекты, что угодно) и «интерфейсы между кусками кода» (API, объявления функций, что угодно; в том числе поведение).

Если часть кода можно изменить без изменения интерфейса, от которого зависят другие части кода, то изменение будет легче (и не имеет значения, используете ли вы ООП или нет).

Если часть кода не может быть изменена без изменения интерфейса, от которого зависят другие части кода, то изменение будет сложнее (и не имеет значения, используете ли вы ООП или нет).

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

Brendan
источник
Другое преимущество ООП состоит в том, что инкапсуляция данных с помощью логики, которая на них работает, приводит к меньшим общедоступным интерфейсам (если все сделано хорошо).
Майкл Боргвардт
2

Не существует методологии проектирования, которая могла бы спасти вас от неприятностей, связанных с большими изменениями требований / масштабов. Просто невозможно представить и учесть все возможные изменения, о которых можно подумать позднее.

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

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

Барт ван Инген Шенау
источник
1

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

Во всяком случае, все наоборот. Некоторые изменения слишком малы, чтобы беспокоиться о каком-либо «дизайне» или причудливом мышлении. Простые исправления ошибок, например.

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

Вся работа в программном обеспечении, естественно, порождает ошибки. Футболисты получают травмы. Музыканты получают мозоли или спазмы губ в зависимости от своего инструмента. (Если у вас возникают спазмы губ во время игры на гитаре, вы делаете это неправильно.) Разработчики программного обеспечения получают ошибки. Мы любим находить способы снизить скорость их появления, но она никогда не будет нулевой.

DarenW
источник
3
Начальная позиция также может быть отрицательной. Не
стоит
Разработка проекта с нуля является легкой частью. Но даже если вы начнете новый проект с нуля, что само по себе редко, вы только в первые несколько дней будете наслаждаться строительством из ничего. То, что первое первоначальное проектное решение оказалось неверным, и оттуда дела только начнут падать. Дизайн с нуля абсолютно не имеет значения на практике.
Ян Худек
1

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

В вашем примере правильный дизайн уже упростил вашу работу: нужно вносить изменения в 2000 строк кода, а не в 20000 или 200000 строк кода.

Правильный дизайн уменьшает широкие изменения, но не устраняет их.

Быстрые изменения довольно легко автоматизируются, если есть надлежащая поддержка инструментов анализа языка. Общее изменение рефакторинга можно применить ко всей кодовой базе в стиле поиска и замены (при должном соблюдении правил языка). Программисту нужно только принять решение да / нет для каждого поискового хита.

rwong
источник
+1 за предложение по автоматизации. Я думаю, что на самом деле я буду использовать это для многих моих библиотечных функций, которые вызывают замыкания - это просто вопрос определения, какие функции принимают блоки, и изменения их, чтобы иметь дополнительный символьный параметр для имени аргумента, чтобы передать значение как.
существует