📜 ⬆️ ⬇️

PostSharp. Aspect-oriented programming vs Dependency Injection

In my conversation with Andres Hejlsberg about fears, insecurity, and doubts about Aspect-Oriented Programming, I mentioned general confusion and misunderstanding that AOP and DI are competing concepts. In this article I will try to explain to you about all the differences and similarities in these two approaches. Recently, I had a great time reading Dino Esposito’s article “ Aspect-oriented programming, interception and unity 2.0, ” in the December issue of MSDN Magazine. This is a great article and I strongly advise any developer involved in .NET development to read it completely. Like many DI frameworks, and some basic frameworks (WCF, ASP.NET MVC), Unity offers a similar feature to AOP: interceptors.



What is Dependency Injection?


Dependency Injection is an architectural template that is designed to reduce dependencies between components. One of the benefits of reducing dependencies (moving from a closely-connected architecture to a weakly-connected architecture) is reducing the awareness of the components about each other. Thereby, a better separation of tasks is achieved using the design principle “a program based on an interface, and not on classes” (orig .: “program to an interface, not to an implementation”). A common misinterpretation of this design pattern among C # and Java developers consists that clients usually work with interfaces (what you declare as the interface keyword), and not with classes. I prefer to interpret it like this: “program-for-contract, not program-for-implementation” (orig .: “program to a contract, not to an implementation”). The contract for the use of a class in this case consists of public (public) members of the class, supplied with documentation (plus their pre-, postconditions, if applicable). To be even more precise: “a program based on documentation, not on classes”. Thus, if your goal is just to divide concepts, you really do not need interfaces so much. All you need are the keywords public, Internal, protected and private. It is important to note that in object-oriented design, interfaces are not dogma at all. Not all framework developers adhere to this philosophy: “The Java class library is based on interfaces more than .NET, simply because .NET developers have a negative experience using COM interfaces”

Programming based on interfaces (not classes) is useful when your component needs to work with many interface implementations. There are countless cases in which this will be very useful (after all, we all want our architecture to be extensible), but let's face it: in many cases where our component must interact with another component, we know it perfectly subsequent implementation, and we know perfectly well that no other implementation is foreseen. So why then use it here? There are two options when you may want to use the concept of a program based on interfaces:

In these situations (which actually happen only when it comes to testing) it is actually very good that the components are not related in the source code, even if we know how they will depend on each other during the final installation. So how do we tie these components together? This is where Dependency Injection comes into play. With the Dependency Injection design pattern, you instruct the “container” as objects must be linked to each other, and you force this “container” to link objects to each other. In fact, you do not create class objects using constructors; you do this using “container” methods. The container decides which implementation you need, creates an object and returns it to you.


Aspect-oriented programming


Dependency Injection solves the problem of associating weakly related components with each other. Aspect-oriented programming solves a variety of problems. Indeed, in reality, where various functions and capabilities (such as auditing, logging, transaction processing) affect almost all business requirements, AOP expresses this complex reality as a compact solution, with minimal code duplication. When we want to conduct a code review, audit our code, our natural desire will be to see only one file. However, when we do a revision of the code that relates to some management of customer requirements, we do not want to see this code. As you understand, this is not possible to achieve using only object-oriented programming, and this was the reason for the emergence and development of Aspect-Oriented programming.

Similarities and differences between AOP and DI

There are some similarities between DI and AOP:

However, DI and AOP differ significantly in situations where they prove to be helpful:


Dynamic proxies


So after all, how did Dependency Injection become associated with Aspect-Oriented Programming? Yes, a simple DI design pattern makes it easy to add new behaviors to components. Here's how to do it: when you request a dependency on a container, you expect to get an interface implementation. You can only guess what kind of implementation you will get, but often you play a game with it. If you ask the container to add some behavior (for example, call tracing) to the component, you will not get the object itself. Instead, you will get a dynamic proxy object. The proxy object will be between you and the requested component, and will implement the behavior you requested. And since DI frameworks have the ability to embed behavior between a client and a component implementation, DI is understood by many as one of the technologies that can enable you to develop in AOP.

Proxy-based AOP: what's good?

What I love about the proxy-based approach is how AOP fits into the concept of DI. DI helps you customize the container, how it will build components, using dependencies between objects, setting their properties and invoking initialization methods. You can configure aspects simply as some dependencies in the XML file or using C # code, so the construction and assembly of components will be unified.
The ability to add aspects, just changing configuration files, can be a very useful feature. Suppose there is some problem somewhere. And you want to track all calls to a component. You can do this without recompiling the entire application. This can be a decisive advantage in a runtime environment where there are no appropriate debugging tools. Where in order to find a problem and solve it, it may take several months.

Proxy-based AOP: What's Bad?

Proxy-based AOP, which is implemented using DI frameworks has a large number of restrictions:
They
Proxy-based AOP: What is Ugly?

When a developer begins to practice something all the time, without being distracted by competing technologies, it becomes a risk, because a person who practices something constantly feels safe. And practice becomes dogma. This happens in TDD, which imposes people to write tests at a meaningless level of detail. And the same with Dependency Injection, where people are forced to isolate all classes from each other. Remember, DI was originally designed to isolate components, not classes. Components are parts of an application, its blocks, not objects. I’m concerned that we are forced (under the pressure of society) to write much more complex applications just to meet the testing requirements, which in fact do not lead to an improvement in the quality of the final product. Remember that unit testing is a tool, not a goal. The ultimate goal is the quality of your application throughout its life.

Conclusion


Aspect-oriented programming and Dependency Injection are very different concepts, but there are a limited number of cases when they are well suited to each other. In these situations, the use of AOP within DI makes sense. For other options, you have only two choices: deactivate the dynamic proxy (and this is not the solution), or use a specialized tool for AOP development. And this dilemma is not just for me, PostSharp, or .NET. The same dilemma hangs over Java programmers who think what to choose: Spring AOP or AspectJ. AOP and DI are not competing technologies. You can use them together in one project. However, it is important to know and understand what each technology was made for and focus on the quality of your code.
')

References:

Source: https://habr.com/ru/post/123186/


All Articles