Pure PHP architecture. How to measure and control it?

Foreword


As you already understood from the name, here I’m going to talk about the most “high” - Pure architecture. And the impetus for the development of this whole story was the book of Robert Martin “Pure architecture”. If I haven’t read it yet, I dare to recommend it! The author reveals many important topics, actively shares his rich life experience (from a professional field, of course) and the conclusions made on its basis, occasionally weaves into chapters of the story how masterfully shit-headed (and not only, of course) our fathers and grandfathers back in the 60s, 70s, 80s and even the dashing 90s, like grains of grain, everyone's favorite principles of SOLID and their analogues in the world of components were collected, and what they learned over the past half century. In the process of reading the book, the development line of the software development industry is well traced, typical problems that boys had to deal with,and methods for solving them.

Do not think, retelling the summary of the book is not the purpose of this post.
Next, we will talk about ideas that prompted me to develop one tool (I will determine the degree of its usefulness to you, and I will be waiting for feedback, suggestions and constructive criticism with great interest).

It seems to me that the article will be useful to everyone. Those who are already familiar with the book will be able to refresh some of its moments in their memory, or simply skip the first part and immediately begin to familiarize themselves with the tool. Those who have not read the book before may perhaps find something new for themselves in the first part.

For convenience, the article is divided into 2 parts.

In the first I will talk about the key ideas that generated in my head the desire to automate this whole thing, are we programmers or who in the end? Here I will quote a lot from the author, as well as actively insert extracts and illustrations from different chapters of the book.

The second part, almost entirely, will be devoted to describing the tool that has appeared, revealing its capabilities and step-by-step guidance.

If you consider yourself to be a category of people taking everything too close to your heart, I advise you to start reading from the Afterword .



Part 1


What is software architecture?


Alas, the author of the book does not give a single definition. There are a large number of different formulations, and all of them are correct in their own way.
However, we can go from the other side ..

What is the purpose of architecture?


There is only one answer:

The goal of software architecture is to reduce the human labor required to create and maintain a system.

A little introductory ..

Where do many projects start?


“We will be able to restore order later, we would only enter the market!”
As a result, order has not been restored, because the pressure of competition in the market never wanes.

“The biggest lie many developers believe is that dirty code will help them quickly enter the market, but in reality it will slow down their movement in the long run. Developers who believe in this lie show Hare’s arrogance, believing that in the future they will be able to move from creating disorder to restoring order, but they make a simple mistake. The fact is that the creation of disorder is always slower than the steady observance of cleanliness, regardless of the chosen time scale. "

Two values ​​of software products


  1. Behavior (something urgent but not always important)
  2. Architecture (something important, but not always urgent)

Many often drown in the first, and completely neglect the second.

Type: “Why waste time thoroughly thinking over architecture, the main thing is that it works correctly!” .

But they miss one important point: “If a properly working program does not allow the possibility of changing it, it will stop working correctly when the requirements change, and they will not be able to make it work correctly. That is, the program will become useless.

If the program does not work correctly, but is easily amenable to change, they will be able to make it work correctly and maintain its performance as requirements change. That is, the program will always remain useful. ”

I liked this statement:“If you think good architecture is expensive, try poor architecture.” (Brian Foote and Joseph Yoder)

It turns out that it is important to pay due attention to code cleanliness and architecture in general from the very first lines. But, if everything is relatively clear with the purity of the code (sniff out all sorts of bad smells in the code, and correct it, besides the tools are full of smart IDEs, static analyzers, and other undoubtedly important rubbish), then with architecture it’s not quite so (at least least me).

How can you control something that is so vague that it is difficult even to be defined by a single wording that it has a very versatile view and every second, damn it, shit sees it and tries to interpret it in its own way, if you are not Vanga’s grandson, didn’t win the show “Intuition ”And are not particularly sensitive fifth point? Then the author of the book throws up a couple of valuable thoughts for thought ... Let's sort it out.

Why did you come up with SOLID and why is it not enough alone?


We all probably know the principles of SOLID.

Their goal is to create mid-level software structures that:

  • tolerant of change;
  • simple and understandable;
  • form the basis for components that can be used in many software systems.

But: “Just like good bricks can make an unusable wall, so well-designed components of the average level can create an unusable system.”
Therefore, in the world of components, there are analogues of SOLID principles, as well as high-level principles for creating architectures.

I will touch on these topics very superficially, more details can be found in the book. Let's go!

Connectivity of components and its determining principles


“To which component does this or that class belong? This important decision must be made in accordance with established software development principles. Unfortunately, such decisions are of a special nature and are taken almost exclusively on the basis of context. ”

REP: Reuse / Release Equivalence Principle - The principle of equivalence of reuse and releases.

In terms of architecture and design, this principle means that the classes and modules that make up a component must belong to a connected group. A component cannot simply include a random mixture of classes and modules; There should be some theme or goal common to all modules.

Classes and modules combined into a component must be released together.

CCP: Common Closure Principle - the principle of consistent change.
This is the principle of SRP (single responsibility) rephrased for components.

Classes that change for the same reasons and at the same time should be included in one component. Different components should include classes that change at different times and for various reasons.

CRP: Common Reuse Principle - The principle of shared reuse.
This principle is similar to ISP (interface segregation).

Do not force component users to depend on what they do not need.

The principle indicates that classes that are not closely related should not be included in one component.

“Perhaps you have already noticed that the three principles of connected components come into conflict with each other. The principles of reuse equivalence (REP) and consistent change (CCP) are inclusive: both strive to make the components as large as possible. The Reuse Principle (CRP) is exceptional, striving to make components as small as possible. The task of a good architect is to resolve this contradiction. ”

image

“In the past, we looked at connectivity easier than the principles of reuse equivalence (REP), consistent change (CCP), and shared reuse (CRP) suggest. Once we thought that connectivity is just an attribute, that a module performs one and only one function. However, the three principles of component connectivity describe a much more complex variety. When choosing classes for inclusion in components, you must consider the opposing forces associated with ease of reuse and development. Finding a balance of these forces based on the needs of the application is not an easy task. In addition, the balance is almost always constantly shifted. That is, the partition considered successful today may be unsuccessful after a year. Consequently,the composition of the components will almost certainly change over time and the focus of the project will shift from ease of development to ease of reuse. ”

Component Compatibility


“The following three principles define the rules for the relationship between components. And again, we are faced with contradictions between ease of development and logical organization. The forces affecting the architecture of the component structure are technical, political, and volatile. ”

ADP: Acyclic Dependencies Principle - the principle of acyclicity of dependencies.
Loops in the component dependency graph are not allowed!

image

From whatever component displayed on the graph, you start moving along the arrows indicating the direction of the dependency, you will not be able to return to the original point. This is an acyclic oriented graph (DAG - Directed Acyclic Graph).

image

In this image, we have a dependency leading to the appearance of a cycle. The resulting cyclic dependence can always be broken.

Methods for breaking cyclic dependencies


1. By applying DIP (dependency inversion principle)

image

2. Introduction of the new component

image

“The second solution involves the dependence of the structure of the components on changing requirements. Indeed, as the application grows, the structure of component dependencies grows and changes. Therefore, it must constantly be checked for cycles. When cycles form, they need to be broken in one way or another. Sometimes for this it is necessary to create new components, which makes the structure of dependencies grow. ”

Top-down design, or rather its impracticability


“Component structure cannot be designed from top to bottom. This conclusion is not immediately reached as soon as they begin to design the system, but this inevitably happens with the growth and change of the system.

Considering a large block diagram, such as the structure of component dependencies, we believe that the components must somehow represent the functions of the system. But in reality, this is not an indispensable attribute of component dependency diagrams.

In fact, the dependency diagrams of the components weakly reflect the functions of the application. To a greater extent, they are a reflection of the convenience of assembly and maintenance of the application. This is the main reason why they are not designed at the beginning of project development. During this period, there is no software that needs to be collected and maintained, so there is no need to draw up a build and maintenance map. But with the advent of an increasing number of modules in the early stages of implementation and design, the need to manage dependencies increases ... In addition, there is a desire to limit the impact of changes as much as possible, so we begin to pay attention to the principles of single responsibility (SRP) and coordinated change (CCP) and combine the classes, which will probably change together.

One of the main tasks of such a dependency structure is isolation of variability. We do not need components that often change for the smallest reasons and affect other components that would otherwise be completely stable. For example, cosmetic changes to the GUI should not affect business rules. Adding and modifying reports should not affect high-level policies. Consequently, a component dependency graph is created and created by architects to protect stable and valuable components from the influence of volatile components.

As the application develops, we begin to worry about creating reusable items. At this stage, the principle of shared reuse (CRP) begins to influence the composition of the components. Finally, with the advent of loops, we begin to apply the principle of dependency acyclicity (ADP), as a result, the dependency graph of components begins to change and grow.

An attempt to design the dependency structure of components earlier than any classes is likely to fail. At this stage, we know almost nothing about the reconciliation of changes, we don’t imagine which elements can be used repeatedly, and we will almost certainly create components that form cyclic dependencies. Therefore, the structure of component dependencies should grow and develop along with the logical design of the system ”

Hey, are you still here? Man, this is important, you need to say hello to this at least in order to enter the meaning of the next part, there will be a raw tutorial on using tulza.

SDP: Stable Dependencies Principle - the principle of stable dependencies.
Dependencies should be directed towards stability!

“What is meant by“ sustainability ”? Imagine a coin standing on an edge. Is her position stable? Most likely you will answer “no”. However, if you protect it from vibration and wind blows, it can remain in this position for an arbitrarily long time. That is, sustainability is not directly related to the frequency of changes. The coin does not change, but hardly anyone will say that, standing on the edge, it is in a stable position.

The explanatory dictionary says that sustainability is “the ability to maintain one’s condition under external influences”. Sustainability is related to the amount of work that needs to be done to change state. On the one hand, a coin standing on an edge is in an unstable state because it takes a tiny amount of effort to knock it over. On the other hand, the table is in a very stable condition, because it requires much more substantial effort to tip it.

What does all this have to do with software? There are many factors that complicate a component’s change, such as its size, complexity, and clarity. But we will leave aside all these factors and focus on something else. There is one surefire way to make a software component difficult to change by creating many other components that depend on it. A component with many incoming dependencies is very stable, because reconciling changes with all the dependent components requires considerable effort. "

image

image

How to evaluate the stability of the component? The author suggests calculating the number of its incoming and outgoing dependencies and on their basis calculate the measure of its stability.

  • Fan-in ( ): . , .
  • Fan-out ( ): . , .
  • I: : I = Fan-out Ă· (Fan-in + Fan-out). [0, 1]. I = 0 , I = 1 – .

So, this principle says that the metric of the I component should be more than the metrics of the I components that depend on it. That is, the metrics I should decrease in the direction of dependence.

It is important to note that if all components of the system are as stable as possible, such a system will not be possible to change. Therefore, not all components must be stable.

Man, don’t fall asleep, I'm near. Just a bit left!

SAP: Stable Abstractions Principle - the principle of stability of abstractions. The stability of a component is proportional to its abstractness.

“Some parts of software systems should change very rarely. These pieces represent high-level architectural and other important decisions. No one wants such decisions to be volatile. Therefore, software encapsulating high-level rules must reside in stable components (I = 0). Volatile (I = 1) should contain only mutable code - a code that could be easily and quickly changed.

But if you place high-level rules in stable components, this will complicate the change in the source code that implements them. This can make the whole architecture inflexible. How to make a component with maximum stability (I = 0) so flexible that it remains stable during changes? The answer lies in the principle of openness / closure (OCP). This principle says that it is possible and necessary to create classes that are flexible enough so that they can be inherited (extended) without change. Which classes comply with this principle? Abstract.

SAP (the principle of the stability of abstractions) establishes a connection between stability and abstractness. On the one hand, he says that a stable component must also be abstract so that its stability does not impede expansion, and on the other hand, he says that an unstable component must be concrete, because the instability makes it easy to change its code.

That is, a stable component should consist of interfaces and abstract classes so that it can be easily extended. The resilient components available for expansion are flexible enough to not overly restrict the architecture.

The principles of stability of abstractions (SAP) and stable dependencies (SDP) together correspond to the principle of dependency inversion (DIP) for components. This is true because the SDP principle requires that dependencies be directed towards sustainability, and the SAP principle states that sustainability implies abstractness. That is, dependencies should be directed towards abstractness.

However, the DIP principle is formulated for classes, and in the case of classes there are no midtones. The class is either abstract or not. The principles of SDP and SAP apply to components and allow a situation where a component is partially abstract or partially stable. ”

How to measure the abstractness of a component? Here, too, everything is very simple.
The value of the measure of abstract component is determined by the ratio of the number of its interfaces and abstract classes to the total number of classes.

  • Nc: the number of classes in the component.
  • Na: the number of abstract classes and interfaces in the component.
  • A: abstract. A = Na Ă· Nc .

The value of the metric A varies in the range from 0 to 1. 0 means the complete absence of abstract elements in the component, and 1 means that the component contains nothing but abstract classes and interfaces.

Dependence between I and A

If you plot on the graph (Y - abstraction, X - instability) “good” components of both types: abstract stable and concrete unstable, we get this:

image

But, because the components have different degrees of abstractness and stability, far from all fall into these 2 points (0, 1) or (1, 0), and since it is impossible to require that all components be in them, we must assume that on the graph A / I there are some points that determine the optimal positions for the components.

This set can be derived by defining areas where the components should not be located — in other words, defining exclusion zones.

image

Pain Zone

Consider the components located near the point (0, 0).

They are very stable and specific. Such components are undesirable since are too tough. They cannot be expanded, because they are not abstract and it is very difficult to change because of their great stability. The more we change the component that enters the pain zone, the more pain it brings. This is due to the complexity of its change.

Correctly designed components usually should not be near the point (0, 0).
However, in reality, there are software entities that fall into this zone. For example, the database schema, it is as specific as possible and many dependencies stretch towards it. This is one of the reasons why database schema changes are usually associated with great pain.

Useless Zone

Consider the components located near the point (1, 1).

Such components are also undesirable, because they are as abstract as possible and have no input dependencies. They are simply useless. Often these are abstract classes that have never been implemented.

How to avoid getting into exclusion zones?

Place components close to or on the main sequence. Such components are not “too abstract” for their stability and not “too unstable” for their abstractness. They are not useless and do not cause much pain. Other components depend on them to the extent of their abstractness, and they themselves depend on others to the extent of specificity.
The most desirable positions for the components are the endpoints of the main sequence. However, in large systems there will always be several components that are not sufficiently abstract and not stable enough. Such components have excellent characteristics when located on or near the main sequence.

The distance to the main sequence

Since it is desirable that the component is located on or near the main sequence, it is possible to determine a metric expressing the distance of the component from the ideal.

  • D: distance. D = | A + I – 1 | . This metric takes values ​​from the range [0, 1]. A value of 0 indicates that the component is directly on the main sequence. A value of 1 indicates that the component is located at the maximum distance from the main sequence.

By adopting this metric, you can explore the entire design in proximity to the main sequence. The metric D can be calculated for any component. Any component with a metric value D far from zero requires revision and restructuring.

image

Conclusion of the author (Robert Martin)


“The dependency management metrics described in this chapter help you quantify the consistency of the dependency structure and design abstraction with what I call a“ good ”design. Experience shows that there are good dependencies, there are bad ones. This assessment reflects this experience. However, metrics are not the ultimate truth; these are just measurements based on an arbitrary standard. These metrics are imperfect - at best, but I hope you find them useful. ”

Man, I'm glad if you're still with me. That's all with the first part. Although there are still a lot of topics, and the author’s detailed thoughts remained unaffected. Still, the main purpose of my article is not to retell the book, otherwise you would definitely be more pleased to read the original. I, hike, and so already specifically went too far with the amount of content, but I will be bastard, I tried not to inflate as I could. Round!

Second day. Umm, i.e. Part 2


Introduction


What have I been rubbing about there for so long? “Ah, yes ... We are like architects, or we really want to be them, right?”

What do we have? - Some kind of miserable projection, or maybe a monstrous system, PROJECT, his mother, well, or finally there isn’t any nifig yet, but we just rub our hands, look at the calendar and figure out how well we will have to talk.

There are no us, I work alone! Or maybe we, with a sidekick, in the garage, were going to fill in a new Apple, why not? Well, either we are a army and we are all part of a hefty company, we are working hard, like the blacks of the poor at home (that is, African-Americans, of course, you understand), or maybe we’re kicking quietly so that we don’t get fired. For a fat salary with a bonus, cookies and a view from Moscow city or for bare enthusiasm, for an idea and a stake in a startup that naturally gets a hell when it takes off.

In fact, it doesn’t matter. What’s important is this: all of us, in the end, simply want our brainchild not to bend prematurely, well, at least before our departure, and there are all chances for that. Yes, yes ...

And what to do now, you ask? So, if you don’t have a big brother in the office, then bro can’t do without a third eye.

Summary of the first part


In the last part of the article, we talked a bit about metrics that enable architects to measure their numbers in figures to reflect the degree of quality of the architecture of their system.

A - abstraction of component
I - instability of component
D - distance to the main sequence on the graph A / I Erogenous zones of the pain and futility zones were

revealed . We came to the conclusion that, ideally, A should increase and decrease in proportion to a decrease and, accordingly, an increase in I

. Well-designed components should be on or at least close to the main sequence, i.e. D should be as close to zero as possible, and the dependencies between the components should be acyclic and directed towards stability.

I also hope everyone understands that some components may know about many others, while others should not know anything. Just like in the slave states before the arrival of the good uncle Abraham, only on the contrary, there Negroes (in the sense of African-Americans) were not allowed nichrome (in terms of knowledge, and not only), in our case the most important components of the system should have a minimum of knowledge, they should be self-sufficient and abstract from different details.

So what about the third eye? PHP Clean Architecture- a tool that appeared as a result of reading a book, thanks to Uncle Bob (Robert Martin) for valuable thoughts, and crazy desire to visualize the whole thing, for the convenience of analysis, and automate, for the possibility of including various checks in CI / CD (similar to PHPStan, Phan and others, only to identify precisely architectural problems).

Tool and test project. Introduction to the topic


Fuf, everything seems to be like a theory ... Now you can even get your hands dirty for details.
And so to me now do not have about abstract horses in a vacuum to rub, and you have the end of the reading was less reason to call me mudiloy, because of which you fucked spent so much time, I had prosrat spend a little of his, and to prepare a demo project, which, sobstna, we are now going to do hara-kiri. For the “super gifted” dudes who will undoubtedly be and want to hang out in comments, regarding its details, I emphasize - this is a DEMO project .
I chopped it up in about half a day, roughly speaking, on my girlfriend’s knee. After all, I can’t take and drain to the general public the details of the combat projects that I have to work with ... The guys in the wreck will not understand, they will show me, but do I need it? Well, if you are a simple lad, not one of the “particularly outstanding ones,” then I’m a lousy for such a long introduction, I just had to take the risks and reduce the potential threat of breeding in the comments of the bazaars about nothing.

So, the project itself lies here github.com/Chetkov/php-clean-architecture-example-project .

In the future, he could become a full-fledged online store. I’m certainly a fierce perfectionist, but you need to be a complete nonsensesun-eater and long-liver, besides suffering from insomnia, in order to spend so much time on the “experimental rabbit” and fashion candy from it. As you understand, this project will never be brought to its logical conclusion , however, like all the others, even combat projects.

Although it’s not so bad. At the moment it has: user, product and order , as well as scenarios: user registration, password change, adding a product and booking an order .

The project is more or less working, you can clone it yourself and run scripts from the sandbox folder, although in fact, I could not even do this, because for the analysis of architecture operability from the project is not required.

In the future, I will throw up links to specific commits in order to immediately fix the technical points described in the article.

Initial state

. I suppose that you already managed to get acquainted with the structure. So we can move on.

We include PHP Clean Architecture :
composer require v.chetkov/php-clean-architecture:0.0.3


We create and configure the configuration file

Visualization for analysis


We execute in the console (in the project root):

vendor/bin/phpca-build-reports
or
vendor/bin/phpca-build-reports /path/to/phpca-config.php

And in response we get:

Report: /path/to/reports-dir/index.html

The report consists of 3 screens:

1. General system information

image

This screen displays:

The same A / I graph showing the dispersion of the components:

image

Graph showing the remoteness of components from the main sequence:

image

And a graph showing the relationships between the components: The

image

arrows indicate the direction of the dependencies, and the numbers on them indicate the strength of the connection.

Because modern IDEs provide an easy way to refactor (they themselves find and fix all the areas where the method or class is explicitly called, for example, when renaming or transferring to another namespace), I took the number of elements of the dependency module used by the dependent module for communication strength.

For example: the elements of the services module know about 12 elements of the model module , and the infrastructure elements know about 1 element of services . Etc.

By the way, what is * undefined *? Bro, the expected question. This is a module created automatically for all elements that, during the system analysis, could not be attributed to any of the known ones (i.e. those listed in the configuration file).

If, however, you correct the config in this way:

image

Then in the process of analyzing the system, packets connected via composer will also be taken into account (they themselves will not be scanned, but the picture will become much more complete).

By the way, in vendor_path you need to specify the path to the vendor directory, and in excluded paths to the directories of packages that we want to exclude (for example, if we describe a package in the main config of modules for scanning).

After enabling vendor_based_modules the graph has changed, although we did not change the config of the modules themselves

image

2. Detailed information about the component

image

Here we also see:

  • Graph of interconnections , but not of the entire system, but only of the components involved
  • A / I chart showing only the current component
  • Key module features

    image

and
  • Outbound dependency graph showing the number and list of files in the current module, depending on the files of other modules.
  • image

  • And a graph of incoming dependencies , showing the number and list of files in other modules, depending on the current module.

    image

The last 2 graphs, in my opinion, are especially interesting, because it is easy to find unwanted dependencies on them, but more on that later.

3. Detailed information about the component element

image

Here you can see:

  • Main characteristics of the element, such as type abstraction, instability, primitive, and to which component belongs and the access modifier .

“Che, a class access modifier in PHP?” - you say, drilling a hole in the temple area with your finger, right? Take your time, I know that there are no private classes in the heat, but it would be cool if they were? In general, more about that later.

  • Dependency graph , which reflects the interaction of the element under consideration with other elements of the system

  • And tablets with outgoing and incoming dependencies

    image

With the description of the screens finished, go to the configs to pick and poke how it can be configured.

Configuration options


Limiting the maximum allowable distance to the main sequence (for all components)

First, let's try to set all the components to the maximum allowable distance to the main sequence. It would be foolish to think that they all will lie on the main diagonal, because the world is not perfect, so let's be realistic. I do 0.3

image

Restart the report generation command and immediately see the violation on the main page. The model component exceeds the allowed distance by 0.192

image

Limiting the maximum allowed distance to the main sequence (to a specific component)

It's great, but let's assume that it is the model component that can violate this restriction. Different things happen ... After all, we often already have not ideal systems that we have to work with, support them and improve. Anyone understands that no one will be able to quickly reduce this distance, even probably with a god (I hope he will forgive me).

In my opinion, the main thing is to fix the current state, work towards improvements and control the situation so as not to aggravate.

Again, go to the config, and set max_allowable_distance , only for a specific module. I fix on its current value 0.492

image

ZBS, now everything is normal again.

image

But if, with some ** ka Vasya, he smokes something again and gets worse - chop off his hands! A CI / CD that includes running the phpca-check command (we'll talk about it later) scolds him, maybe even a foul language, and of course it will highlight errors.

Component Dependency Control

What else would be nice to have in our arsenal to deal with poor architecture? Of course, dependency control. Who can know about whom, or vice versa should not know.

What do you think, can the very central part of the system, let’s say domain , so that it’s completely possible for DDDowski to know something about some smelly infrastructure?
Of course YES, for some it’s, directly, an attribute of success (well, I'm talking about those who render HTML mixed with business logic). But finally, like be, I should not ... I certainly xs, but all sorts of different clever guys in books say that this is not patsansky.

Then let's stir up like this ... Everything is in the same place, in the config of restrictions for model .

image

Hmm ... So far, all the rules, becausemodel about infrastructure really doesn’t know anything ...

Well then let's have fun ... Stupidity is certainly rare, but I didn’t come up with anything better. Krch, at the time of creating the user we will “send” SMS, and at the time of creating the order “send” email (s). And to do this through specific implementations of notifiers that lie in the infrastructure .

github.com/Chetkov/php-clean-architecture-example-project/commit/6bad365176b30999035967319a9c07fae69fabf9

Now we look into the report ... As we can see, the graphs on different pages of the report highlight this connection as illegitimate.

Home.

image

Component Report.

image

On the graphs of “outgoing dependencies” model and “inbound dependencies”infrastructure , we immediately see elements that violate the introduced rule

image

In the tables of “outgoing dependencies” of model elements and “inbound dependencies” of infrastructure elements , similarly.

PHPCAEP \ Model \ User \ User

image

PHPCAEP \ Infrastructure \ Notification \ Sms \ SmsNotifier

image

As well as on the graph of element relationships. I think in the future to get rid of it altogether, because it is not very informative (especially for actively used classes, because of the length of the name of the nodes + their huge number)

image

Similar actions can be done with the allowed_dependencies config .

image

The result will be completely opposite.

It is possible to compose a config indicating for the module and forbidden, and allowed (if there is a desire, we will discuss in more detail in the comments). It is not yet possible to specify one component both in forbidden and allowed ... There were thoughts to introduce a config to indicate priority, but so far I have not done this and am not sure what I will do. It all depends on your feedback. Maybe all this is wasted?

Public / Private Class in PHP

Okay, we learned how to narrow and control the range of knowledge of components. Already not bad. What's next?

And then another problem. The enemy does not sleep, although in most cases this enemy, we ourselves are, or our sidekicks at the office.

It happens after all, you met a girl, talked, found out something about her, maybe even courted, but damn it, it doesn't work out for you. We are friends and all that ... She can kiss you when she meets you, she can listen and support you with a kind word, but she doesn’t give you anything to kill . So what am I talking about ... Ah, here ... It's all about accessibility.

But in the code, constantly ... Connect a new package, not a day has passed, but it is already being used, but straight to all placesfrom all sides. Half of your code base is already tied to its various classes. In short, he has a very intimate connection with the rest. Maybe in some situations this is the norm, but not in all, right?

You: “Everything is good, it is shy. How to solve the problem? ”
Me: “Leave only classes allowed for interaction, and restrict access to the rest.”
You: “But in PHP there are no access modifiers for classes.”
Me: “I agree, but there is a PHP Clean Architecture .”

An example will now be again from drug addicts, but what to do.

In real projects, of course, the cases are full of cases, but they can bring a bottle for draining the information and ask them to sit down. That's why you have to compose.

Let's assume that in the model , for some reason, there are only 2 classes that others are allowed to know about ... User and Order, all the rest should be hidden.

image

What do we have now?

Count on the main.

image

You can immediately see which components need to be reviewed.

We climb to see what is wrong with infrastructure .

image

On the graph of “outgoing dependencies” we see elements that violate the rule:

image

On the element information page, similarly.

image

We will get exactly the opposite result if we specify private_elements in the config .

image

For example, we forbid everyone to know about Fio.

Now on the main

image

page : On the services component information page :

image

And on the element information page PHPCAEP \ Model \ User \ Fio :

image

Monitoring violations of the principles of ADP and SDP

Still, perhaps, we need to highlight the possibility of including checks:

  • for violations of the ADP principle, i.e. for the existence of cyclic dependencies in the graph ( check_acyclic_dependencies_principle )
  • and for violations of the SDP principle, i.e. for dependencies directed from more stable modules to less stable ( check_stable_dependencies_principle )

image

But this only works in phpca-check so far and is not displayed in the report. In the future, I think I will correct it.

Automatic control in CI / CD


All this time I talked about the first part - visualization. And the analysis that can be carried out on its basis.

The time has come to make our friends govnokodera honorable colleagues suffer.

We launch in the console (in the project root):

vendor/bin/phpca-check

or

vendor/bin/phpca-check /path/to/phpca-config.php

It is assumed that running this command will be added to the CI / CD process of your project. In this case, the error will block further assembly.

The script terminates with an error and throws something like this:

image

I give the tooth, the list will be much longer in a real project.

Debriefing

  1. Violation of the principle of acyclicity of dependencies (ADP)
  2. Similarly, but the cycle is a little shorter
  3. 2 model elements (listed) depend on infrastructure , which is not allowed by the config
  4. ADP violation again
  5. Another loop and ADP violation
  6. SDP violation because a more sustainable model depends on a less sustainable infrastructure
  7. Again cyclic dependence, be it wrong
  8. 1 services element (listed) depends on non-public Fio

Approximately this result we have thanks to our efforts and diligent govnokoding .

Now let's turn everything in the ass. Well, i.e. not quite everything, I leave the configs naturally. I rule only the code.

For starters, it makes sense to fix files that violate the rules for following dependencies. In this project, most of the cycles will probably go away by itself, but in real ones, definitely have to tinker longer (although this depends on the degree of neglect of the system and the settings of the config).

Troubleshooting

I removed a previously invented addiction.

github.com/Chetkov/php-clean-architecture-example-project/commit/f6bbbff1313bb4a22dfb6061f347ef007ba3b422f

Restart vendor / bin / phpca-check

image

Well, there’s only a config to edit, because an example was really invented by a drug addict.

image

Again vendor / bin / phpca-check

image

And the CI / CD went on!

That's all.

Afterword


Catch a fifth if you read it to the end, if not, sniff your foot on the road (anyway, you didn’t see this).

But seriously, thank you for your time, it doesn’t matter if you merged in the middle or read it, delved into each line and analyzed every screen or flipped through both parts diagonally. Thanks anyway.

I apologize again if something was wrong.

Perhaps, my manner of presentation might seem to someone too imposing or disrespectful, I just wanted to slightly dilute the article and in no way did I want to offend anyone. I think without this, it would have turned out to be too dry and difficult to read.

I’m really interested to know your opinion and if you have any thoughts, ideas, suggestions or objections, let's discuss in comments.

Clean code and flexible architecture for you!

All Articles