Статьи

Забавная вещь, случившаяся на пути к заводу

Структура и почему мы заботимся.

Структура может быть определена как набор элементов и их отношений.

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

Другими словами: волновой эффект .

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

Сама Java структурируется (как минимум) на трех уровнях: уровне метода, уровне класса и уровне пакета. По различным интересным причинам, хотя аналогичные принципы действуют на всех уровнях, некоторые уровни учитывают определенный организационный аппарат, недоступный для других. Несмотря на то, что структура пакета в значительной степени является производной от структуры метода, например, механика обработки пакетов в Java, тем не менее, ограничивает структуру, созданную на всех более низких уровнях. Этот пост касается только этого уровня, уровня пакета и реализации, на которую наткнулся во время обычного рефакторинга.

Радиальная инкапсуляция: молниеносная реприза.

Oracle дает нам официальные термины «Пакет верхнего уровня» и «Подпакет», когда пишет : «Если имя пакета состоит из одного идентификатора, то этот идентификатор обозначает пакет верхнего уровня, названный этим идентификатором», а затем , «Структура имен для пакетов является иерархической. Членами пакета являются классы и типы интерфейсов … и подпакеты.»

Средство организации структур пакета, радиальная инкапсуляция в Java, затем находит тривиальное выражение: разрешить зависимости пакета только в направлении пакета верхнего уровня. Зависимость может падать на любой пакет между зависимым пакетом и пакетом верхнего уровня, но ни на какой другой. Поэтому , учитывая полный пакет com.codetrumpet.base.app.model того приложения пакет может зависеть только от пакетов ком , codetrumpet и базы , но она не должна зависеть от модели . Также запрещено зависеть, скажем, от com.codetrumpet.scrape, потому что он видит только com , codetrumpet иbase, когда он смотрит в направлении ком- пакета верхнего уровня : он не видит царапины , которая объявлена ​​«в сторону».

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

Радиальный рефакторинг.

На рисунке 1 показана иерархическая структура пакета Spoiklin Soice (точнее, иерархическая структура именования, но мы будем применять этот термин свободно к самой структуре пакета). Страдая изменением ориентации, пакет верхнего уровня, com , появляется внизу с подпакетами, расположенными выше.

Иерархическое изображение

Рисунок 1: Иерархия пакетов Spoiklin Soice.

Большинство деталей неважно, но на рисунке 2 показан крупный план гордого вида и вывод его подпакетов.

Иерархическое изображение

Рисунок 2: Крупный план пакета представления.

На рисунке 2 вид пакета имеет шесть подпакетов:

com.edmundkirwan.base.spoiklin.link.view.sequence
com.edmundkirwan.base.spoiklin.link.view.window
com.edmundkirwan.base.spoiklin.link.view.option
com.edmundkirwan.base.spoiklin.link.view.draw
com.edmundkirwan.base.spoiklin.link.view.prep
com.edmundkirwan.base.spoiklin.link.view.overview

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

Spoiklin Soice image

Рисунок 3: Фактические зависимости пакета.

Рисунок 4 изолирует вид упаковки показана только его зависимость, как и из других пакетов. Диаграмма показывает, что семь пакетов зависят от представления (шесть являются подпакетами на рисунке 2, плюс стартовый пакет, особый случай), а представление зависит от трех других.

Spoiklin Soice image

Рисунок 4: Как представление пакета зависит от других.

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

Иерархическое изображение

Рисунок 6: Новый общий подпакет пакета представления.

Извлечение, однако, оказало любопытное влияние на прорисовку зависимостей между пакетами, см. Рисунок 7.

Spoiklin Soice image

Рисунок 7: Вся система с извлеченным общим пакетом.

По сравнению с рисунком 3 На рисунке 7 показано , что вид пакет, с его 15 интерфейсов, в настоящее время не имеет Выездной зависимости: это зависит от того, нет другого пакета. Сам по себе это представляет никаких проблем , а только основные моменты смотреть «s эксклюзивную услугу для остальной части его подпакетов; как радиальные диктата инкапсулирования , что вид «s подпакеты не могут видеть друг друга, то подпакеты публиковать интерфейсы в — и потреблять интерфейсы из — зрения для того , чтобы успешно взаимодействуют, тем самым проявляя хорошо изношенного фасад шаблон дизайна. Тем не менее, вид упаковки выглядит странно anchorless, его затруднительное постановка вопроса: это мнениепакет теперь можно свободно перемещать в другое место в иерархии пакетов? Действительно, какие силы, если таковые имеются, ограничивают иерархию пакетов?

Радиальное ограничение.

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

Потенциальная связь метода — это просто число методов, к которым у него есть доступ, таким образом, оно подсчитывает максимальное количество методов, от которых можно зависеть. Он измеряет не связь, а потенциалсвязь. Метод (обычно) может видеть все методы в своем классе, все не приватные методы в классах / интерфейсах своего пакета и все открытые методы в открытых классах / интерфейсах других пакетов. Учитывая, что метод не может установить прямую зависимость от той, к которой он не имеет доступа, минимизация потенциальных попыток связывания сводит к минимуму количество целей, от которых может формироваться зависимость, и, таким образом, объединяет волновой эффект в бою в статистическом измерении. Это объясняет безжалостное сведение программистов к минимуму в Java-программах. Радиальная инкапсуляция пытается еще больше сократить эту область, позволяя методу видеть только те методы в своем собственном пакете и в тех пакетах, которые лежат в направлении пакета верхнего уровня.Радиальная инкапсуляция добавляет экстралингвистическое ограничение, чтобы сделать недоступными даже общедоступные методы вне этой линии видимости.

Concerning the view considered here, the question becomes not, «Whither can this view travel?» but, «Where will this view minimize the system’s potential coupling?» It turns out that, despite the package’s having no dependencies on any other, this requirement to minimize potential coupling shackles the package to its hierarchical location without hope of escape.

To begin with, view cannot rise any higher up the graphic (deeper into the hierarchy) as it would then elevate to the level of the six packages it serves, packages that would then not be able to see it. So its position below these six packages marks the upper limit of possible locations it might attain. Nor can it wander into a new branch of the hierarchy, say as a peer of link, because its subpackages depend on link so it must remain in their line-of-sight. Finally, it cannot fall any further below its current location because if it did, if it fell for example from com.edmundkirwan.base.spoiklin.link.view to reposition itself a package below link as in com.edmundkirwan.base.spoiklin.view.link, then it would become visible to every subpackage of link, a broadened exposure that would increase the system’s potential coupling and violate the overarching principle. Thus radial encapsulation fixes view‘s hierarchical position brutally, despite its lack of out-going dependencies.

Indeed, all packages find themselves similarly immobile. Though this sounds restrictive (and it is), a powerful engineering benefit follows: programmers need not waste their energies carving package hierarchies from semantic containment schemes unproven in the war on costs. Once a programmer decides the services supplied and needed, and the consequent dependencies required, the package hierarchy comes for free.

(As it happens, this analysis lead to the discovery of a structural flaw in the source code inspected, a flaw clearly visible in figure 2: can you spot it?)

Summary.

It is ripple effect management that validates or discredits syntactical structure and ripple effect flows from dependency.

In a normal Java program no rigid relationship exists — by design (see the Java Language Specification link above) — between package hierarchy and package dependencies, no correlation exists between package hierarchy and change propagation probability. The package hierarchy of a normal Java program serves no syntactic analytical purpose. Radial encapsulation, by contrast, fuses inseparably package hierarchy and package dependencies, rendering the former a unique derivation of the latter, re-tasking the package hierarchy as an aid to change-cost prediction.

The principle of potential coupling, which underwrites radial encapsulation, is not alone, however. Many principles attempt to imbue package structure with value beyond that afforded by the Java Language Specification. Programmers bloodied in vicious complexity battles do not limit their arsenal to JLS howitzers but fight dirty, weaponizing the tools others discard. The fields of software development lie weed-choked and fallow, all plowshares long-since re-forged.