Я младший разработчик среди пожилых людей и много борюсь с пониманием их мышления, рассуждений.
Я читаю доменно-управляемый дизайн (DDD) и не могу понять, почему нам нужно создавать так много классов. Если мы будем следовать этому методу проектирования программного обеспечения, мы получим 20-30 классов, которые можно заменить максимум двумя файлами и 3-4 функциями. Да, это может быть грязно, но гораздо удобнее и понятнее.
В любое время, когда я хочу увидеть, что EntityTransformationServiceImpl
делает какой-то вид , мне нужно следить за множеством классов, интерфейсов, их вызовов функций, конструкторов, их созданием и так далее.
Простая математика:
- 60 строк фиктивного кода против 10 классов X 10 (скажем, у нас такие разные логики) = 600 строк беспорядочного кода против 100 классов + еще несколько для их обертывания и управления ими; не забудьте добавить инъекцию зависимостей.
- Чтение 600 строк беспорядочного кода = один день
- 100 уроков = одна неделя, все равно забудь, кто что делает, когда
Все говорят, что это легко поддерживать, но для чего? Каждый раз, когда вы добавляете новые функции, вы добавляете еще пять классов с фабриками, объектами, службами и значениями. Я чувствую, что этот код движется намного медленнее, чем грязный код.
Скажем, если вы пишете грязный код 50K LOC за один месяц, DDD требует много проверок и изменений (я не против тестов в обоих случаях). Одно простое дополнение может занять неделю, если не больше.
За один год вы пишете много грязного кода и даже можете переписывать его несколько раз, но в стиле DDD у вас все еще не хватает функций, чтобы конкурировать с грязным кодом.
Пожалуйста, объясни. Зачем нам нужен этот стиль DDD и множество шаблонов?
UPD 1 : Я получил так много отличных ответов. Не могли бы вы, ребята, добавить комментарий где-нибудь или отредактировать свой ответ со ссылкой для списка чтения (не уверен, с чего начать, DDD, Шаблоны проектирования, UML, Выполнение кода, Рефакторинг, Прагматика, .. так много хороших книг), конечно, с последовательностью, так что я также могу начать понимать и становиться старше, как некоторые из вас.
источник
Ответы:
Это проблема оптимизации
Хороший инженер понимает, что проблема оптимизации без цели бессмысленна. Вы не можете просто оптимизировать, вы должны оптимизировать для чего - то. Например, параметры вашего компилятора включают оптимизацию по скорости и оптимизацию по размеру кода; это иногда противоположные цели.
Я хотел бы сказать моей жене, что мой стол оптимизирован для добавления. Это просто куча, и это очень легко добавлять вещи. Моя жена предпочла бы это, если бы я оптимизировал поиск, то есть немного организовал свои вещи, чтобы я мог найти вещи. Это, конечно, усложняет добавление.
Программное обеспечение так же. Вы, безусловно, можете оптимизировать создание продукта - сгенерируйте тонну монолитного кода как можно быстрее, не беспокоясь об его организации. Как вы уже заметили, это может быть очень, очень быстро. Альтернативой является оптимизация технического обслуживания - сделать создание прикосновения более сложным, но сделать модификации более легкими или менее рискованными. Это цель структурированного кода.
Я бы предположил, что успешный программный продукт будет создаваться только один раз, но изменяться много, много раз. Опытные инженеры видели, как неструктурированные кодовые базы начинают жить самостоятельно и становятся продуктами, растущими в размерах и сложности, пока даже небольшие изменения не станут очень трудными для выполнения без значительного риска. Если код был структурирован, риск может быть ограничен. Вот почему мы идем ко всем этим неприятностям.
Сложность проистекает из отношений, а не элементов
Я заметил, что в вашем анализе вы смотрите на количество - количество кода, количество классов и т. Д. Хотя это и интересно, реальное влияние оказывают отношения между элементами, которые взрываются комбинаторно. Например, если у вас есть 10 функций, и вы не знаете, от чего зависит, у вас есть 90 возможных отношений (зависимостей), о которых вам нужно беспокоиться - каждая из десяти функций может зависеть от любой из девяти других функций, и 9 x 10 = 90. Вы можете не знать, какие функции изменяют какие переменные или как данные передаются, поэтому у кодеров есть масса вещей, о которых нужно беспокоиться при решении какой-либо конкретной проблемы. Напротив, если у вас есть 30 классов, но они организованы умно, они могут иметь всего 29 отношений, например, если они наслоены или расположены в стеке.
Как это влияет на пропускную способность вашей команды? Ну, есть меньше зависимостей, проблема гораздо более разрешима; кодеры не должны жонглировать миллионами вещей в своей голове, когда они вносят изменения. Таким образом, минимизация зависимостей может значительно повысить вашу способность грамотно рассуждать о проблеме. Вот почему мы делим вещи на классы или модули, и ограничиваем переменные области видимости, насколько это возможно, и используем принципы SOLID .
источник
EntityTransformationServiceImpl
, вы вынуждены учиться , как все это работает , прежде чем вы можете это исправить - но если , например , что - то не так с форматом иFormatter
класс обрабатывает , что вам нужно только , чтобы узнать , как та часть работы Plus. чтение собственного кода через ~ 3 месяца похоже на чтение кода незнакомца.) Мне кажется, что большинство из нас подсознательно думают об этом, но это может быть из-за опыта. Не уверен на 100% в этом.Ну, во-первых, читаемость и удобство обслуживания часто находятся в поле зрения зрителя.
То, что читается для вас, может не быть вашим соседом.
Сопровождаемость часто сводится к обнаруживаемости (насколько легко поведение или концепция обнаруживается в кодовой базе), а обнаруживаемость - еще одна субъективная вещь.
DDD
Один из способов, которым DDD помогает командам разработчиков, - это предложить конкретный (но все же субъективный) способ организации концепций и поведения вашего кода. Это соглашение облегчает обнаружение вещей и, следовательно, облегчает поддержку приложения.
Такое расположение объективно проще поддерживать. Тем не менее, его значительно легче поддерживать, когда все понимают, что работают в контексте DDD.
Классы
Классы помощь ремонтопригодности, читаемость, понятность и т.д ... потому , что они хорошо известны конвенции .
В объектно-ориентированных настройках классы обычно используются для группировки тесно связанного поведения и для инкапсуляции состояния, которое необходимо тщательно контролировать.
Я знаю, это звучит очень абстрактно, но вы можете думать об этом так:
С классами вам не обязательно знать, как работает код в них. Вам просто нужно знать, за что отвечает класс.
Классы позволяют вам рассуждать о вашем приложении с точки зрения взаимодействия между четко определенными компонентами .
Это уменьшает когнитивную нагрузку при рассуждении о том, как работает ваше приложение. Вместо того, чтобы помнить, что выполняет 600 строк кода , вы можете подумать о том, как взаимодействуют 30 компонентов .
И, учитывая, что эти 30 компонентов, вероятно, охватывают 3 уровня вашего приложения, вы, вероятно, только каждый должен рассуждать о примерно 10 компонентах одновременно.
Это кажется довольно управляемым.
Резюме
По сути, то, что вы видите, делают старшие разработчики:
Они разбивают приложение на легкие рассуждения о классах.
Затем они организуют их в простые рассуждения о слоях.
Они делают это, потому что знают, что с ростом приложения становится все труднее рассуждать об этом в целом. Разбиение его на слои и классы означает, что им никогда не придется рассуждать обо всем приложении. Они только должны рассуждать о небольшом подмножестве этого.
источник
AddressServiceRepositoryProxyInjectorResolver
когда можно решить проблему более элегантно? Шаблоны дизайна ради шаблонов дизайна просто приводят к ненужной сложности и многословности.Во-первых, обратите внимание: важной частью DDD являются не шаблоны , а согласованность усилий разработчиков с бизнесом. Грег Янг отметил, что главы в синей книге расположены в неправильном порядке .
Но на ваш конкретный вопрос: классов, как правило, гораздо больше, чем вы ожидаете, (а) потому, что предпринимаются усилия, чтобы отличить поведение домена от сантехники, и (б) потому, что прилагаются дополнительные усилия для обеспечения того, чтобы концепции в доменной модели выражены явно.
Если говорить прямо, если у вас есть две разные концепции в домене, то они должны быть различны в модели, даже если они совпадают в представлении памяти .
По сути, вы создаете язык, специфичный для предметной области, который описывает вашу модель на языке бизнеса, так что специалист по предметной области должен уметь анализировать его и выявлять ошибки.
Кроме того, вы видите немного больше внимания, уделяемого разделению интересов; и понятие изоляции потребителей некоторых возможностей от деталей реализации. Смотри DL Parnas . Четкие границы позволяют вам изменять или расширять реализацию, не затрагивая эффекты во всем решении.
Мотивация здесь: для приложения, которое является частью основной компетенции бизнеса (имеется в виду место, где оно получает конкурентное преимущество), вы захотите иметь возможность легко и дешево заменить поведение домена лучшим вариантом. По сути, у вас есть части программы, которые вы хотите быстро развить (как состояние изменяется со временем), и другие части, которые вы хотите изменить медленно (как состояние сохраняется); дополнительные уровни абстракции помогают избежать случайного соединения одного с другим.
Справедливости ради: некоторые из них также являются объектно-ориентированным повреждением мозга. Шаблоны, первоначально описанные Эвансом, основаны на проектах Java, в которых он участвовал более 15 лет назад; состояние и поведение тесно связаны в этом стиле, что приводит к сложностям, которые вы, возможно, предпочтете избегать; см. « Восприятие и действие » Стюарта Хэллоуэя или « Встроенный код » Джона Кармака.
источник
В других ответах есть много хороших моментов, но я думаю, что они упускают или не подчеркивают важную концептуальную ошибку, которую вы совершаете:
Вы сравниваете усилия, чтобы понять всю программу.
Это нереальная задача с большинством программ. Даже простые программы состоят из такого большого количества кода, что просто невозможно управлять всем этим в голове в любой момент времени. Ваш единственный шанс - найти ту часть программы, которая соответствует поставленной задаче (исправление ошибки, реализация новой функции) и работа с ней.
Если ваша программа состоит из огромных функций / методов / классов, это практически невозможно. Вам нужно разобраться с сотнями строк кода, чтобы решить, соответствует ли этот кусок кода вашей проблеме. С оценками, которые вы дали, становится легко потратить неделю, просто чтобы найти кусок кода, над которым нужно поработать.
Сравните это с базой кода с небольшими функциями / методами / классами, названными и организованными в пакеты / пространства имен, которые делают очевидным, где найти / поместить данный фрагмент логики. Во многих случаях, когда все сделано правильно, вы можете прыгнуть прямо в правильное место, чтобы решить вашу проблему, или, по крайней мере, туда, где запуск вашего отладчика приведет вас в нужное место за пару прыжков.
Я работал в обоих видах систем. Разница может легко составить два порядка в производительности для сопоставимых задач и сопоставимого размера системы.
Влияние это оказывает на другие виды деятельности:
источник
Потому что тестировать код сложнее, чем писать код
Многие ответы дали веские аргументы с точки зрения разработчика - такое обслуживание может быть сокращено за счет того, что код, в первую очередь, будет более трудоемким для написания.
Однако есть еще один аспект - тестирование может быть только детализированным, как ваш исходный код.
Если вы пишете все в монолите, единственный эффективный тест, который вы можете написать, - «учитывая эти входные данные, правильный ли вывод?». Это означает, что любые найденные ошибки находятся в «где-то в этой огромной куче кода».
Конечно, вы можете попросить разработчика сидеть с отладчиком и точно определить, где возникла проблема, и поработать над ее исправлением. Это требует много ресурсов и является плохим использованием времени разработчика. Представьте себе, что когда-либо незначительная ошибка, которая у вас есть, приводит к тому, что разработчику необходимо снова отлаживать всю программу.
Решение: множество небольших тестов, каждый из которых указывает на один конкретный потенциальный сбой.
Эти небольшие тесты (например, модульные тесты) имеют преимущество проверки конкретной области кодовой базы и помогают находить ошибки в ограниченном объеме. Это не только ускоряет отладку при сбое теста, но также означает, что если все ваши маленькие тесты не пройдут - вы сможете легче найти сбой в ваших больших тестах (т. Е. Если это не определенная проверенная функция, она должна быть во взаимодействии). между ними).
Как должно быть ясно, создание меньших тестов означает, что ваша кодовая база должна быть разбита на более мелкие тестируемые порции. Способ сделать это на большой коммерческой базе кода часто приводит к тому, что код выглядит так, как вы работаете.
Просто как примечание: это не значит, что люди не зайдут «слишком далеко». Но есть законная причина для разделения кодовых баз на меньшие / меньшие связанные части - если сделано разумно.
источник
Многие (большинство ...) из нас действительно не нуждаются в них. Теоретики и очень продвинутые, опытные программисты пишут книги о теориях и методологиях в результате большого количества исследований и их глубокого опыта - это не означает, что все, что они пишут, применимо к каждому программисту в их повседневной практике.
Будучи начинающим разработчиком, полезно читать такие книги, как та, о которой вы упомянули, чтобы расширить ваши перспективы и дать вам знать о некоторых проблемах. Это также избавит вас от смущения и замешательства, когда ваши старшие коллеги используют терминологию, с которой вы не знакомы. Если вы находите что-то очень сложное и, кажется, не имеете смысла или кажетесь полезным, не убивайте себя из-за этого - просто запишите это в голову, что есть такая концепция или подход.
В вашем повседневном развитии, если вы не академик, ваша задача - находить работоспособные, поддерживаемые решения. Если идеи, которые вы найдете в книге, не помогут вам достичь этой цели, не беспокойтесь об этом прямо сейчас, если ваша работа считается удовлетворительной.
Может наступить время, когда вы обнаружите, что можете использовать кое-что из того, о чем читали, но сначала не совсем «получили», а может и нет.
источник
AccountServiceFacadeInjectResolver
(реальный пример, который я только что нашел в системе на работе) - ответ, скорее всего, нет.Поскольку ваш вопрос охватывает много вопросов и предположений, я выделю тему вашего вопроса:
Мы - нет. Не существует общепринятого правила, согласно которому в шаблонах проектирования должно быть много классов.
Есть два ключевых руководства для того, чтобы решить, куда поместить код и как разбить ваши задачи на разные блоки кода:
Почему эти два должны быть важными?
Эти два аспекта являются базовыми «драйверами» для любого выбора «куда поместить» на любом языке программирования и любой парадигме (не только ОО). Не все точно знают о них, и требуется время, часто годы, чтобы по-настоящему понять, как они влияют на программное обеспечение.
Очевидно, что эти две концепции ничего не говорят вам о том, что на самом деле делать . Некоторые люди ошибаются на стороне слишком много, другие на стороне слишком мало. Некоторые языки (глядя на вас здесь, Java) имеют тенденцию отдавать предпочтение многим классам из-за чрезвычайно статичной и педантичной природы самого языка (это не утверждение о значении, а то, чем оно является). Это становится особенно заметно, когда вы сравниваете его с динамическими и более выразительными языками, например Ruby.
Другой аспект заключается в том, что некоторые люди поддерживают гибкий подход, заключающийся в написании кода, который необходим прямо сейчас , и в значительной степени при необходимости, в последующем. В этом стиле разработки вы не создали бы,
interface
когда у вас есть только один реализующий класс. Вы бы просто реализовали конкретный класс. Если позже вам понадобится второй класс, вы будете проводить рефакторинг.Некоторые люди просто так не работают. Они создают интерфейсы (или, в более общем случае, абстрактные базовые классы) для всего, что когда-либо могло бы использоваться более широко; это приводит к взрыву класса быстро.
Опять же, есть аргументы за и против, и не важно, какой я или вы предпочитаете. В своей жизни в качестве разработчика программного обеспечения вы столкнетесь со всеми крайностями, начиная от длинных методов спагетти, заканчивая просвещенными, достаточно большими проектами классов, до невероятно взорванных схем классов, которые сильно перегружены. По мере того, как вы становитесь более опытным, вы будете все больше превращаться в «архитектурных» ролей и сможете начать влиять на это в том направлении, в котором хотите. Вы найдете золотую середину для себя, и вы все равно обнаружите, что многие люди не согласятся с вами, что бы вы ни делали.
Следовательно, сохранение открытости является самым важным моментом, и это был бы мой основной совет для вас, поскольку вы, кажется, испытываете большую боль по этому вопросу, судя по остальной части вашего вопроса ...
источник
Опытные программисты узнали:
источник
Ответы до сих пор, все они хорошие, начав с разумного предположения, что спрашивающий упускает что-то, что он также признает. Также возможно, что спрашивающий в основном прав, и стоит обсудить, как эта ситуация может возникнуть.
Опыт и практика очень важны, и если пожилые люди приобрели свой опыт в больших и сложных проектах, где единственный способ держать вещи под контролем - с помощью множества элементов
EntityTransformationServiceImpl
, то они быстро и комфортно воспринимают шаблоны проектирования и строго придерживаются DDD. Они были бы намного менее эффективными при использовании облегченного подхода даже для небольших программ. Как ни странно, вы должны адаптироваться, и это будет отличным опытом обучения.Хотя, адаптируясь, вы должны воспринимать это как урок в балансе между глубоким изучением единого подхода и тем, что вы можете заставить его работать где угодно, вместо того, чтобы оставаться универсальным и знать, какие инструменты доступны, не обязательно будучи экспертом в любом из них. Есть преимущества для обоих, и оба необходимы в мире.
источник
Создание большего класса и функциональности в соответствии с использованием будет отличным подходом для решения проблем особым образом, который поможет в будущем решить любые проблемы.
Несколько классов помогают идентифицировать их как основную работу, и любой класс может быть вызван в любое время.
Однако, если у вас много классов и функций с их именами, их легко вызывать и управлять ими. Это называется чистым кодом.
источник