Иерархия принципов проектирования, или самые важные слова для инженеров

В этой короткой заметке я хотел бы систематизировать (а именно, расположить в иерархию) многие популярные принципы проектирования программных приложений (test-driven development, ООП, SOLID и т. д.), а также рассмотреть следствия из этой иерархии.

В частности, такая иерархия (я надеюсь) позволит лучше расставлять приоритеты в разработке и профессиональном росте, лучше понимать старые технологии и быстрее изучать новые. При появлении новой парадигмы разработки (a la test-driven development) вы сможете быстро включить ее в эту иерархию и, следовательно, быстрее понять, из каких принципов исходили создатели парадигмы и как правильно ее использовать. Новичкам в программировании статья может быть полезна как обзор существующих принципов.

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

Эта короткая статья будет состоять из нескольких разделов:

Базовое правило для расположения принципов проектирования в иерархию будет следующим: если вы можете следовать принципу А, но отказаться или не знать о приеме B, то A является более базовым принципом проектирования. Например, вы можете разобраться с ООП, но пока не прочитать о шаблонах проектирования Gang of Four—это не помешает вам писать программы с использованием ООП; поэтому ООП является более базовым принципом. Или, например, вы можете отказаться от ООП (или от каких-то его атрибутов—например, наследования и полиморфизма), но, тем не менее, продолжать писать модульные программы на С с четкими интерфейсами модулей и уровнями абстракции. Поэтому модульность и абстракция являются более базовыми принципами, чем ООП.

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

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

Читайте также:  LG Electronics представляет на российском рынке технологии для здорового образа жизни

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

Что такое управление сложностью / минимизация технической сложности (с сохранением необходимого функционала, разумеется) и почему ее можно считать базовым принципом проектирования, можно узнать в прекрасной книжке Стива МакКоннела « Совершенный код » («Code Complete»), глава 5. Обсуждение начинается именно с термина «управление сложностью», но лично мне он кажется менее информативным.

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

Модульность и абстракция, или самые важные слова для инженеров

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

Поэтому хотелось бы подробнее остановится на модульности и абстракции—понятиях, рассматриваемых в отличной книге « Structure and Interpretation of Computer Programs » («Структура и интерпретация компьютерных программ», SICP; первое издание в свободном доступе, второе —нет)—и процитировать введение к этой книге, которое, на мой взгляд, содержит в себе самые важные слова для инженеров.

«We control complexity by building abstractions that hide details when appropriate. We control complexity by establishing conventional interfaces that enable us to construct systems by combining standard, well-understood pieces in a “mix and match way”. We control complexity by establishing new languages for describing a design, each of which emphasizes particular aspects of the design and deemphasizes others».

Читайте также:  Планы по расширению семейства Discovery

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

Если вы хотите глубже проникнутся этими принципами, горячо рекомендую вам SICP и, как водится, МакКоннела. [Ремарки: конечно, многим эти книги будут известны, а цитата из SICP покажется банальной, но среди, по крайней мере, моих знакомых, профессиональных и высококвалифицированных программистов, очень многие не слышали о SICP—кто-то прогулял лекции, а кто-то учился на физика. И если вы знаете аналогичную книжку, но посовременне—добро пожаловать в комментарии].

Конечно, test-driven development и domain-driven design сложно представить без использования ООП, и, следовательно, изучать их необходимо после ООП, поэтому их можно было бы расположить на одном уровне с шаблонами проектирования.

С другой стороны, test-driven development вполне можно применять для программ на С, в которых не используется ни полиморфизм, ни наследование, но при написании которых можно проектировать архитектуру c расчетом на тестирование отдельных процедур и писать такие тесты. То же относится и к domain-driven design: программа может быть написана на C, но совершенно в духе DDD. Именно поэтому они помещены на один уровень с ООП.

Читайте также:  Сцену Харьковского государственного академического кукольного театра им. В.А. Афанасьева отремонтируют

Если архитектура программы изобилует шаблонами проектирования и модными штуками типа Dependency Injection/Inversion of Control, это еще не значит, что программу будет легко понимать и сопровождать. Причина кроется в том, что есть более базовые принципы проектирования—модульность и абстракция, и архитектор может легко упустить их из виду в погоне за шаблонами. Помня об этой иерархии, вы как архитектор больше не допустите подобную ошибку, а как разработчик всегда сможете легко вербализовать для архитектора, почему именно он не прав, совершая такую ошибку.

Правильные приоритеты в профессиональном росте и обучении (младших сотрудников или студентов)

Иерархия принципов проектирования, я надеюсь, сделает очевидным несколько фактов:

Например, что ООП—это не единственное средство создания уровней абстракций, и что процедурное программирование предназначено для тех же целей.

Всем спасибо за внимание!

P.S.

Вообще, раз уж я рекламировал SICP, называемую также Книгой Мага, в этой заметке, то надо для полноты картины порекомедовать Книгу Золушки и Книгу Дракона, являющиеся не менее фундаментальными. Итак, список сказочных книжек:

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

Источник: http://habrahabr.ru