Почему нам нужно так много классов в шаблонах дизайна?

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

Я читаю управление доменами (DDD) и не могу понять, почему нам нужно создать так много классов. Если мы будем следовать этому методу проектирования программного обеспечения, мы получим 20-30 классов, которые могут быть заменены не более чем двумя файлами и 3-4 функциями. Да, это может быть беспорядочно, но это намного удобнее и удобочитаемо.

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

Простая математика:

  • 60 строк фиктивного кода и 10 классов X 10 (скажем, у нас совершенно разные такие логики) = 600 строк беспорядочного кода против 100 классов + еще несколько для их переноса и управления; не забудьте добавить инъекцию зависимостей.
  • Чтение 600 строк беспорядочного кода = один день
  • 100 классов = одна неделя, все еще забывайте, что делать, когда

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

Скажем, если вы пишете 50K LOC messy code за один месяц, для DDD требуется множество обзоров и изменений (я не против тестов в обоих случаях). Одно простое дополнение может занять неделю, если не больше.

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

Пожалуйста, объясните. Зачем нам нужен этот стиль DDD и множество шаблонов?

UPD 1 . Я получил так много замечательных ответов. Можете ли вы, ребята, добавить комментарий где-нибудь или отредактировать свой ответ со ссылкой на список чтения (не уверен, с чего начать, DDD, Design Patterns, UML, Code Complete, Refactoring, Pragmatic, ... так много хороших книг), конечно, с последовательностью, так что я также могу начать понимать и становиться старшим, как это делают некоторые из вас.

198 голосов | спросил user1318496 10 PMpTue, 10 Apr 2018 19:10:46 +030010Tuesday 2018, 19:10:46

10 ответов


323

Это проблема оптимизации

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

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

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

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

Сложность исходит из отношений, а не элементов

В вашем анализе я замечаю, что вы смотрите на количество - количество кода, количество классов и т. д. Хотя это довольно интересно, реальное воздействие происходит от отношений между элементами, которые взрываются комбинаторно. Например, если у вас есть 10 функций и нет идеи, которая зависит от того, у вас есть 90 возможных отношений (зависимостей), о которых вам нужно беспокоиться - каждая из десяти функций может зависеть от любой из девяти других функций и 9 x 10 = 90. Возможно, вы не знаете, какие функции изменяют переменные или как передаются данные, поэтому у кодеров есть масса вещей, о которых нужно беспокоиться при решении какой-либо конкретной проблемы. Напротив, если у вас есть 30 классов, но они расположены умно, у них может быть всего 29 отношений, например. если они слоистые или расположены в стеке.

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

ответил John Wu 10 PMpTue, 10 Apr 2018 21:51:18 +030051Tuesday 2018, 21:51:18
64

Хорошо, в первую очередь, читаемость и постоянство часто находятся в поле зрения наблюдателя.

То, что читаемо для вас, может быть не для вашего соседа.

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

DDD

Один из способов, которым DDD помогает командам разработчиков, - предложить определенный (но все же субъективный) способ организации ваших концепций кода и поведения. Это соглашение облегчает поиск вещей и, следовательно, упрощает поддержку приложения.

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

Это не просто объективно . Тем не менее, измеримо легче поддерживать, когда все понимают, что они работают в контексте DDD.

Классы

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

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

Я знаю, что это звучит очень абстрактно, но вы можете думать об этом так:

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

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

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

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

Это кажется довольно управляемым.

Резюме

По существу, то, что вы видите у старших разработчиков, это:

Они разбивают приложение на легко рассуждать о классах .

Затем они организуют их в легко рассуждать о уровнях.

Они делают это, потому что знают, что по мере того, как приложение растет, становится все труднее рассуждать об этом в целом. Преодоление его в Слоях и Классах означает, что им никогда не приходится рассуждать о целом приложении. Им нужно когда-либо рассуждать о небольшом подмножестве.

ответил MetaFight 10 PMpTue, 10 Apr 2018 19:35:45 +030035Tuesday 2018, 19:35:45
29
  

Пожалуйста, объясните мне, зачем нам нужен этот стиль DDD, много шаблонов?

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

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

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

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

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

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

Справедливость: некоторые из них также объектно-ориентированные повреждения мозга. Шаблоны, первоначально описанные Evans, основаны на проектах Java, в которых он участвовал более 15 лет назад; состояние и поведение тесно связаны в этом стиле, что приводит к осложнениям, которые вы, возможно, предпочтете избежать; см. Восприятие и действие Стюарта Хэллоуэй, или код вложения от Джона Кармака.

  

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

ответил VoiceOfUnreason 10 PMpTue, 10 Apr 2018 19:38:35 +030038Tuesday 2018, 19:38:35
26

В других ответах есть много хороших моментов, но я думаю, что они пропускают или не подчеркивают важную концептуальную ошибку, которую вы делаете:

Вы сравниваете усилия, чтобы понять всю программу.

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

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

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

Я работал в обоих типах систем. Разница может быть легко на два порядка по производительности для сопоставимых задач и сопоставимого размера системы.

Эффект, который это оказывает на другие действия:

  • тестирование становится намного проще с меньшими единицами
  • меньше конфликтов слияния, потому что шансы для двух разработчиков работать с одним и тем же фрагментом кода меньше.
  • меньше дублирования, потому что легче повторно использовать фрагменты (и, в первую очередь, найти фрагменты).
ответил Jens Schauder 11 AMpWed, 11 Apr 2018 09:05:05 +030005Wednesday 2018, 09:05:05
19

Поскольку тестовый код сложнее, чем писать код

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

Тем не менее, есть еще один аспект: тестирование может быть только мелким, как ваш исходный код.

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

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

Решение: многие более мелкие тесты, которые определяют один конкретный потенциальный отказ каждый.

Эти небольшие тесты (например, Unit Tests) имеют преимущество в проверке определенной области кодовой базы и помогают находить ошибки в ограниченной области. Это не только ускоряет отладку, когда тест терпит неудачу, но также означает, что если все ваши малые тесты терпят неудачу - вы можете легко найти отказ в своих более крупных тестах (т. Е. Если он не находится в определенной проверенной функции, он должен находиться во взаимодействии между ними). ​​

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

Так же, как примечание: это не значит, что люди не будут воспринимать вещи «слишком далеко». Но есть законная причина для разделения кодовых баз на более мелкие /менее связанные части - если сделано разумно.

ответил Bilkokuya 11 PMpWed, 11 Apr 2018 16:09:01 +030009Wednesday 2018, 16:09:01
17
  

Пожалуйста, объясните мне, зачем нам нужен этот стиль DDD, много шаблонов?

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

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

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

Может появиться время, когда вы обнаружите, что можете использовать часть того, что вы читали, но сначала не получили «получить», а может и нет.

ответил Vector 11 AMpWed, 11 Apr 2018 01:53:42 +030053Wednesday 2018, 01:53:42
8

По мере того, как ваш вопрос охватывает множество вопросов, с множеством предположений, я выделил тему вашего вопроса:

  

Зачем нам так много классов в шаблонах дизайна

Мы этого не делаем. Нет общепринятого правила, в котором говорится, что должно быть много классов в шаблонах проектирования.

Существует два основных руководства для определения места размещения кода и как сократить ваши задачи на разные единицы кода:

  • Cohesion: любая единица кода (будь то пакет, файл, класс или метод) должна принадлежать вместе . I., любой конкретный метод должен иметь задачу one и делать это хорошо. Любой класс должен отвечать за one более крупную тему (независимо от того, что может быть). Мы хотим высокой сплоченности.
  • Сцепление: любые две единицы кода должны зависеть как можно меньше друг от друга - в особенности не должно быть круговых зависимостей. Нам нужна низкая связь.

Почему эти два важны?

  • Cohesion: метод, который делает много вещей (например, старомодный CGI-скрипт, который делает GUI, логику, доступ к БД и т. д. все в одном длинном беспорядке кода) становится громоздким. На момент написания книги, соблазн просто положить ваш ход мысли в длинный метод. Это работает, его легко представить и тому подобное, и с ним можно справиться. Проблемы возникают позже: через несколько месяцев вы можете забыть, что вы сделали. Строка кода сверху может быть несколько экранов от линии внизу; легко забыть все подробности. Любое изменение в любом месте метода может нарушить любое количество поведения сложной вещи. Для рефакторинга или повторного использования частей метода будет довольно громоздко. И так далее.
  • Связь: в любое время, когда вы меняете единицу кода, вы можете разбить все остальные единицы, которые зависят от него. В строгих языках, таких как Java, вы можете получать подсказки во время компиляции (т. Е. О параметрах, объявленных исключениях и т. Д.). Но многие изменения не вызывают таких (например, поведенческих изменений), а другие, более динамичные языки, не имеют таких возможностей. Чем выше сцепление, тем сложнее он может что-то изменить, и вы можете остановиться, когда полная редизайна необходима для достижения определенной цели.

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

Очевидно, что эти два понятия ничего не говорят о том, что на самом деле do . Некоторые люди ошибаются на стороне слишком много, другие на стороне слишком мало. Некоторые языки (глядя на вас здесь, Java), как правило, предпочитают многие классы из-за чрезвычайно статической и педантичной природы самого языка (это не утверждение стоимости, а то, что оно есть). Это особенно заметно, когда вы сравниваете его с динамическими и более выразительными языками, например Ruby.

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

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

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

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

ответил AnoE 11 PMpWed, 11 Apr 2018 20:22:33 +030022Wednesday 2018, 20:22:33
7

Опытные кодировщики узнали:

  • Потому что эти небольшие программы и классы начинают расти, особенно успешные. Эти простые шаблоны, которые работали на простом уровне, не масштабируются.
  • Потому что может показаться обременительным добавить /изменить несколько артефактов для каждого добавления /изменения, но вы знаете, что добавить, и это легко сделать. 3 минуты ввода превосходят 3 часа умного кодирования.
  • Множество небольших классов не является «беспорядочным» только потому, что вы не понимаете, почему накладные расходы на самом деле являются хорошей идеей.
  • Без добавленных знаний домена код «очевидный для меня» часто таинственен моим товарищам по команде ... плюс будущее меня.
  • Племенные знания могут сделать проекты невероятно сложными, чтобы добавить членов команды к легко и тяжело для них, чтобы они были продуктивными быстро.
  • Именование - одна из двух трудных задач в вычислении, по-прежнему верна, и многие классы и методы часто являются интенсивным упражнением в именовании, которое многие считают очень полезным.
ответил Michael Durrant 11 AMpWed, 11 Apr 2018 05:06:49 +030006Wednesday 2018, 05:06:49
2

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

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

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

ответил Josh Rumbut 13 AMpFri, 13 Apr 2018 09:22:20 +030022Friday 2018, 09:22:20
-4

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

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

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

ответил Sanjeev Chauhan 13 PMpFri, 13 Apr 2018 18:16:44 +030016Friday 2018, 18:16:44

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132