Статьи

Абстрактность против нестабильности: пример Neo4j

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

Вот из статьи, что он сказал о взаимозависимости между модулями:

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

И для борьбы с жесткостью он ввел такие метрики, как Афферентная связь, Эфферентная связь, Абстрактность и Неустойчивость.

Давайте узнаем все эти метрики и как они могут быть очень полезны для улучшения дизайна приложений. Для этого давайте проанализируем Neo4j от JArchitect .

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

И вот график зависимости между всеми банками Neo4j

neo4j1

Neo4j содержит много jar-файлов, и все они зависят от neo4j-kernel, и, чтобы получить более подробную информацию о весе использования каждого jar-файла, DSM (Dependency Structure Matrix) — это компактный способ представления и навигации по зависимостям между компонентами.

neo4j6

Как показывает матрица, ядро ​​neo4j активно используется другими jar-файлами.

Afferent Coupling:
количество типов вне этого проекта, которые зависят от типов в этом проекте.

Давайте выполним следующий запрос CQLinq, чтобы получить афферентную связь jar-файлов Neo4j:

    from p in Projects where !p.IsThirdParty select new { p,p.NbTypesUsingMe }

neo4j2

Как выяснилось ранее, ядро ​​является более востребованным другими банками.

Efferent Coupling
Количество типов вне этого проекта, используемых типами этого проекта.

    from p in Projects where !p.IsThirdParty select new { p,p.NbTypesUsed }

neo4j3

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

отвлеченность

Отношение количества внутренних абстрактных типов (т.е. абстрактных классов и интерфейсов) к количеству внутренних типов. Диапазон для этой метрики составляет от 0 до 1, где A = 0 указывает на полностью конкретный проект, а A = 1 указывает на полностью абстрактный проект.

    A = Na / Nc

    Where:

    A = abstractness of a module
    Zero is a completely concrete module. One is a completely abstract module.
    Na = number of abstract classes in the module.
    Nc = number of concrete classes in the module.

Давайте возьмем в качестве примера jar neo4j-kernel-1.8.2 и ищем все абстрактные типы.

from t in Types where t.IsAbstract || t.IsInterface
select new { t, t.NbLinesOfCode }

neo4j4

neo4j-kernel-1.8.2 имеет 1071 тип, поэтому абстрактность равна 233/1071 = 0,21755

Чтобы увеличить абстрактность проекта, мы должны добавить больше абстрактных классов или интерфейсов.

Нестабильность
Отношение эфферентной связи (Се) к полной связи. I = Се / (Се + Са). Этот показатель является показателем устойчивости проекта к изменениям. Диапазон для этой метрики составляет от 0 до 1, где I = 0 указывает на полностью стабильный проект, а I = 1 указывает на полностью нестабильный проект.

I = Ce/(Ce + Ca)
I represent the degree of instability associated with a project.
Ca represents the afferent coupling, or incoming dependencies, and
Ce represents the efferent coupling, or outgoing dependencies

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

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

— Это зависит от многих других классов. В него стало труднее вносить изменения. И если бы мы изменили его, нам бы пришлось изменить все другие классы, которые зависели от него. Таким образом, существует огромная сила, которая мешает нам изменить эти классы и повышает их стабильность.

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

Давайте найдем более ответственные типы, выполнив следующий запрос CQLinq

(from t in Types
orderby t.NbTypesUsingMe descending, t.NbTypesUsed descending, t.NbBCInstructions descending
select new { t, t.NbTypesUsingMe,t.NbTypesUsed})

neo4j5

Класс Expression является самым популярным.

Абстрактность против нестабильности График и зона боли

Чтобы получить более подробную информацию об этом графике, вы можете обратиться к статье Роберта К. Мартина .

Вот график для Neo4j Framework

AbstractnessVSInstability

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

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

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

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