NDepend

Improve your .NET code quality with NDepend

Business Complexity vs. Implementation Complexity

It is good software design practice to make sure that methods can be entirely viewed in the code editor that typically shows 30 to 45 lines at a time. The root of this principle is easy to grasp: scrolling up and down over a too large method impedes code readability.

Refactoring a too large method or a too large class implies to create several code elements smaller in terms of number of textual lines. But ultimately the code behavior didn’t change. In other words the business complexity remained the same but the refactor session reduced the implementation complexity (at least we hope so).

Software complexity is a subjective measure relative to the human cognition capabilities. Something is complex when it requires effort to be understood by a human. Software complexity is a 2 dimensional measure. To understand a piece of code one must understand both:

  • What this piece of code is doing at runtime, the behavior of the code, this is the business complexity.
  • How the actual implementation solves the business needs at runtime, this is the implementation complexity.

The whole point of software design, SOLID principles, code maintainability, patterns… is to avoid adding implementation complexity to the business complexity. But from where implementation complexity comes from? There are 5 main sources of implementation complexity:

Too Large Code

We already mentioned this one. It is easy to limit implementation complexity by abiding by simple code rules that check thresholds on code metrics like methods number of lines of code and method complexity, or classes with too many methods. The Single Responsibility Principle (SRP) also contribute to smaller implementations: less responsibilities for a class necessarily means less code.

Lack of Abstractions

An abstraction such as an abstract method, an interface or even a delegate, is the minimum required knowledged to invoke an implementation at runtime without knowing it at design time. In other words an abstraction hides implementation detail. Abstraction represents a great weapon to reduce the implementation complexity because polymorphism can replace quantity of if/else/switch/case. Concretely code like that:

Can be replaced with code like that:

Abstraction also reduces implementation complexity because it frees the developer mind of implementation details.

The S in SOLID is the SRP (mentioned above) and is not related to abstraction. But the OLID principles are all about using abstractions wisely:

How do we check for good usage of abstractions? There is no magic stick like thresholds to limit too large code elements. However the Abstractness vs. Instability graph and metrics and the Level metric are a good start to identify code areas that need more abstractions. They are both described in this post about Dependency Inversion Principle.

State Mutability at Runtime

A common source of implementation complexity is mutable states. The human brain is not properly wired to anticipate what is really happening at runtime in a program. While reviewing a class, it is hard to imagine how many instances will simultaneously exists at runtime and how the states of each these instances will evolve over time. This is actually THE major source of problems when dealing with a multi-threaded program.

If a class is immutable (if the states of all its instances objects don’t change at runtime once the constructor is called) its runtime behavior immediately becomes much easier to grasp and as a bonus, one doesn’t need to synchronize access to immutable objects. See here a post explaining in-depth immutable class.

A method is a pure function if it produces outputs from its inputs without modifying any state. Like immutable classes, pure functions are also a good mean to reduce implementation complexity.

Some code rules exists to enforce state mutability like Structure should be Immutable or Fields should be marked as ReadOnly when possible. Being immutable for a class or pure for a method is such an essential property that dedicated C# keywords for that would be welcome, like readonly for fields. Here is a proposal for C# support of the immutable keyword. By now some ImmutableAttribute or PureAttribute can be used to tag such elements and some code rule can check for Types tagged with ImmutableAttribute must be immutable or Methods tagged with PureAttribute must be pure

Over Coupling

When trying to re-engineer/understand/refactor a large piece of code (I mean something made of dozens of classes like a big namespaces or an assembly), the difficulty is directly proportional to the amount of coupling between considered code elements. Both dependency graphs below shows dependencies between 36 classes: but the left contains 64 edges and the right one contains 133 edges: which one would you prefer to deal with?

One key strategy to control coupling is to layer components and make sure that there is no dependency cycles. This can be checked on namespaces for example with the code rule Avoid namespaces dependency cycles. Using abstractions is also a good way to limit over coupling. If an interface has N implementations then relying only on one interface is virtually like depending on the N underlying classes.

Lack of Unit Tests

Software testing is a large topic I won’t cover here. But one key benefit of writing tests (apart enforcing business rules and detecting regressions early) is to ensure that the code is testable. Being testable for code means less coupling, more abstractions and overall simple code. Ultimately if the code is easily testable we can safely assume that its implementation complexity is kept low. Here also many code rules like Code should be tested can help enforce high testability.

One Measure for All

There are more sources of implementation complexity but those 5 ones are certainly the bigger culprits. To reduce this unnecessary complexity one must be able to measure it. But how to unify too large code, bad design, poorly tested code and more in a single metric?

As we saw most of these aspects can be enforced with code rules. A code rule produces issues and for each issue the code rule can estimate the cost to fix an issue and the annual cost to let an issue unfixed. A famous analogy with the financial field says that:

  • The estimated cost to fix code smells is the Technical-Debt: a measure of the implementation complexity.
  • The estimated annual cost to let code smells unfixed is the Annual Interest of the Debt: a measure of the business operation cost induced by poorly written and poorly tested code.

These estimations can be expressed in developer-time and ultimately in money cost which can be used by management to take the right decisions.

Static Analysis and Dependency Injection

For quite some years now, we (the NDepend team) got some demand about resolving Dependency Injection, see this page on our User Voices. Lately we’ve been considering such support carefully but came to the conclusion that it’d be awkward. On the other hand we have alway been prioritizing features development based on user feedback and need. So our conclusions are not definitive yet. I write this post to not only expose our point of view, but eventually trigger more productive discussions.

Static Analysis

First let’s underline that NDepend is a static analyzer. It gathers 100% of its data from the code itself, and also parses more data like code coverage. Static analysis is in opposition with dynamic analysis that gathers data from runtime execution.

  • Static analysis deals with classes, methods and design measures like lines of code or complexity. It is design-time analysis.
  • Dynamic analysis deals with objects and runtime measures like performance or memory consumption. It is run-time analysis

Dependency Injection (DI)

Recently I explained the basis of Dependency Injection (DI) and how it relates to DIP in the post SOLID Design: The Dependency Inversion Principle (DIP). DI is all about depending on interfaces instead of depending on classes. Here is simple DI sample code, ClientCode() depends on IDbConnection and not on SqlConnection. The power of DI is that now ClientCode() can run on other RDMS than SQL Server, like Oracle or SQLLite. ClientCode() can now also be unit-tested seamlessly by mocking the interface IDbConnection.

Stable Dependency Principle (SDP)

DI is an application of the Stable Dependency Principle (SDP), which is not part of the SOLID principles, but is much related with the Dependency Inversion Principle (DIP).

SDP states: The dependency should be in the direction of the stability. Stability is a measure of the likeliness of change. The more likely it will change, the less it is stable.

The Liskov Substitution Principle (LSP) and the Interface Segregation Principle (ISP) articles explain how interfaces must be carefully thought out. As a result an interface is a stable code element, that is less likely to change than the the classes that implement it. Following the SDP, it is better design to rely on interfaces than to rely on concrete classes.

The Users need: supporting DI through Static Analysis

In this context, users want NDepend to be able to parse DI code like that.

Concretely users want NDepend to bind all calls to an IDbConnection member with a call to the corresponding SqlConnection member . For example a dependency toward SqlConnection.Open() should be created for any method calling IDbConnection.Open().

But why would this be useful? Here is a user feedback:

We have layered architecture: Foundation, Feature, Project. Following current NDepend report, everything follows right dependencies. Project depends on Feature and Foundation. Feature depends on Foundation. However due to some of DI registrations, we have complex dependencies (…) there is dependency from Foundation to Project in reality. Interface is declared in Foundation, but implementation is in Project and registered via DI. It means that Foundation projects, that are core and stable part of solution, depend on Project level, which is not so stable and reliable.

In reality is highlighted in bold, because the user really meant at run-time. At run-time Foundation depends on Project, the same way that at run-time ClientCode() depends on SqlConnection. But at design-time Foundation doesn’t depend on Project, the same way that at design-time ClientCode() doesn’t depends on SqlConnection. At design-time ClientCode() only knows about IDbConnection.

From this, one implies that not only at design time, but also at runtime dependencies should go from Project towards Foundation. In other words, one feels that implementing an adapter into Project and injecting it into a Foundation component “is not so stable and reliable”, but that’s not how those principles are meant and described.

As a matter of fact, being able to inject Project adapters into Foundation components (where the Project adapter implements one of Foundation’s interfaces) is the core of the Dependency Inversion Principle (DIP). Without it, it is impossible to create flexible systems. This can be unreliable, but only if one doesn’t follow the Liskov Substitution Principle (LSP), when Foundation interfaces are not well thought-out, like for example when ICollection<T> forces the Array class to implement ICollection<T>.Add() which obviously cannot be supported.

Conclusion

Hence it looks like this feature need results from a confusion between design-time dependencies and run-time dependencies. The purpose of design is to reduce the cost of change, anything else is not design. Managing design-time dependencies is at the heart of design. All SOLID principles and all principles surrounding SOLID like the Stable Dependency Principle (SDP) are about design-time dependencies.

Moreover adding DI support would be a never-ending story—and I guess it cannot be done right without information collected at run-time. DI Containers are very complex beasts internally, their behavior often changes from one major version to the next, and there are dozens of DI Containers in .NET (Autofac, UnityContainer, NInject, StructureMap, MEF, SimpleInjector, Castle.Windsor, LightInject, Prism, Spring.net … just to name a few).

Again all our developments are driven by users-need, but on this particular need we’re not sure it’d make sense. We let the discussion open on this post and on the User Voices page. Whether you agree or disagree with our positions, feel free to comment.

 

 

SOLID Design: The Open-Close Principle (OCP)

The Open-Close principle (OCP) is the O in the well known SOLID acronym.

Bertrand Meyer is generally credited for having originated the term open/closed principle, which appeared in his 1988 book Object Oriented Software Construction. Its original definition is

  • A module will be said to be open if it is still available for extension. For example, it should be possible to add fields to the data structures it contains, or new elements to the set of functions it performs.
  • A module will be said to be closed if it is available for use by other modules. This assumes that the module has been given a well-defined, stable description (the interface in the sense of information hiding)

Upon these definitions the principle is usually expressed and summarized this way:

Modules should be open for extension and closed for modification.

There have been (and still are) a lot of debates about the meaning of this simple definition and its implication on the usage of Object-Oriented Programming (OOP) in the real-world.

In this post I’ll try to be as concrete and concise as possible.

The classical code example to explain OCP

The classical code example to explain OCP can be translated in C# this way:

I find this example a bit gross. I believe one must have no idea of what OOP is to write such code. It can obviously be refactored to something like this:

Let’s look at the implication of this refactoring:

  • We introduced a new abstraction IShape to represent a concept that we already had in mind. Indeed, in the first code sample the method DrawShapes() already accepted a sequence of shapes. With the new IShape abstraction our design is now open to accept more shapes like Triangle or Pentagone.
  • The method DrawShapes() will draw any new shape without any need for modification. In other words the DrawShapes() method implementation is closed.

Here is how the OCP is usually presented. It is all about anticipating the future changes in the system in a way that:

  • When a change occurs existing code is left untouched. Existing code here is DrawShapes() concrete method body, IShape interface and Circle and Square classes.
  • When a change occurs new code to implement changes is written in new classes that implement existing abstraction. New classes here could be Triangle and Pentagone.

The Point of Variation principle

Another way to see the OCP is the Point of Variation (PV) principle that states:

Identify points of predicted variation and create a stable interface around them.

I find PV more understandable than OCP because it is actionable. First identify potential variations, second build the proper abstractions around these variations.

The real challenge: Anticipation

But the real challenge is anticipation, anticipating is hard. If anticipation was easy we’d be all billionaire in bitcoins. In real world, when you anticipate the risk is high that:

  1. We do anticipate variations that won’t vary. This is what the YAGNI principle says (You aren’t gonna need it): Always implement things when you actually need them, never when you just foresee that you need them. Developing and maintaining an abstraction has a cost and if we won’t need it this cost is negative.
  2. The risk is also high that we don’t anticipate the variation that will really be needed. But once the need for variation becomes real this is your developer responsibility to refactor and create the right abstractions and the right stable code that will act upon these abstractions. This is the fool me once, don’t fool me twice idea: I am not supposed to foresee what I’ll need but I am supposed to identify and then write the right abstraction when I need it.

OCP in the real world

Here is a pragmatic approach to OCP:

  • In any case the KISS principle applies (Keep It Simple Stupid): don’t underestimate the difficulty of anticipating and don’t waste your resources creating abstractions you won’t need.
  • Write automatic tests: one of the greatest benefit of writing tests is that for a while, you must look at your code from the client perspective. If your code contains some area difficult to cover by tests, it certainly means that your code should be refactored to be easily 100% testable. Experience shows that when refactoring from poorly testable code to fully testable code, the need for right abstractions naturally pops up.
  • Some static analyzers can help you pinpoint typical OCP violations:
    • when downcasting reference (i.e casting from a base class or interface to a subclass or leaf class.),
    • when using the is or as operators (as in the first example above).
    • NDepend has the rule Base class should not use derivatives: matches of this rules are obvious violation of the OCP.
  • Keep in mind the fool me once, don’t fool me twice idea. You must refactor code as soon as the need to abstract some concepts is identified. Of course sometime it is not possible if tons of client code depend upon your API: in this situation you cannot easily refactor and often you’ll have to live with wrong design. This is why public API design is such a sensitive topic: you have no other choice than doing your best to anticipate and to accept to live with your past design mistake.

Be open to more than one variation with the Visitor pattern

Finally let’s underline that in the real world, data objects (like the shapes here) don’t implement themselves algorithm such as drawing. Experience tells that this is a clear violation of OCP because when a new algorithm is needed on data objects, like persistence in addition of drawing for example, all shape classes must be modified again. This is also a violation of the Single Responsibility Principle (SRP, the S in SOLID) because a shape class has now two responsibilities: 1) holding the shape data 2) drawing the shape.

Hence we now have two variations: we  need a way to abstract both the shapes and the algorithms applied on the shapes, in order to to write something like algorithm.ApplyOn(shape). This sort of call on two abstractions is named a double dispatching call: the implementation really invoked depends both on the IShape object’s type and the IAlgorithm object’s type. If you have N shapes and M algorithms you need [N x M] implementations.

Fortunately the visitor pattern helps implementing double dispatching. The code with the new persistence algorithm would then look like:

 

 

 

Service Oriented Architecture, A Dead Simple Explanation

Service Oriented Architecture: A Dead Simple Explanation

Service-oriented architecture (SOA) has been with us for a long time. The term first appeared in 1998, and since then it’s grown in popularity. It’s also branched into several variants, including microservice architecture. While microservices dominate the landscape, reports of SOA’s death have been greatly exaggerated. So, let’s go over what SOA is. We’ll cover why it’s an architectural pattern that isn’t going anywhere. Then we’ll see how you can apply its design concepts to your work. Continue reading Service Oriented Architecture: A Dead Simple Explanation

REST_vs_RESTful_The_Different_and_Why_the_Difference_Doesn_t_Matter

REST vs. RESTful: The Difference and Why the Difference Doesn’t Matter

What’s the difference between a REST API and a RESTful one? Is there a difference? This sounds like the kind of academic question that belongs on Reddit. But then you find yourself in a design session, and the person across the table is raising their voice.

The short answer is that REST stands for Representational State Transfer. It’s an architectural pattern for creating web services. A RESTful service is one that implements that pattern.

The long answer starts with “sort of” and “it depends” and continues with more complete definitions.

Continue reading REST vs. RESTful: The Difference and Why the Difference Doesn’t Matter

Should Architects Write Code

Should Architects Write Code? You Bet They Should!

There’s a common misconception that’s permeated our profession: Architects don’t need to write code to do their jobs.

Now, this may seem like a harmless approach. After all, writing code is what developers do. And architects should be busy with more important tasks.

However, keeping architects from writing code can limit the potential of your development teams. It can also result in an architectural mess when requirements and business needs change.

So today let’s look at why giving your software architect time to write code is a good thing. But first, we’ll start off by looking at what life is like as an architect.

Continue reading Should Architects Write Code? You Bet They Should!

Hexagonal_Architecture_What_Is_It_and_How_Does_It_Work

Hexagonal Architecture: What Is It and How Does It Work?

Hexagonal architecture is a model or pattern for designing software applications.

The idea behind it is to put inputs and outputs at the edges of your design. In doing so, you isolate the central logic (the core) of your application from outside concerns. Having inputs and outputs at the edge means you can swap out their handlers without changing the core code.

In this post, we’re going to take a look, in detail, at just how hexagonal architecture works.  But first, let’s talk about why this is desirable.

One major appeal of using hexagonal architecture is that it makes your code easier to test. You can swap in fakes for testing, which makes the tests more stable.

Hexagonal architecture was a departure from layered architecture. It’s possible to use dependency injection and other techniques in layered architecture to enable testing. But there’s a key difference in the hexagonal model: The UI can be swapped out, too.

Interested in seeing what your codebase’s architecture looks like and whether it exists in the Zone of Pain?

Download the NDepend trial for free and see if your actual architecture matches your design documents.

And this was the primary motivation for the creation of hexagonal architecture in the first place. There’s a bit of interesting trivia about its origins. The story goes a little like this….

Continue reading Hexagonal Architecture: What Is It and How Does It Work?

layered_architecture_solid_aproach_ndepend

Layered Architecture: Still a Solid Approach

Layered architecture gets a lot of flack.

Even though it’s still the most prevalent architecture, we view it as an anti-pattern. It’s old, not scaleable, and anti-SOLID. It encourages (shudder) monoliths!

Yes, I know. Hexagonal architecture is the way to go. Or maybe I’m feeling a taste for onions. But only if it’s clean!

The point is that even though it may not be an object-oriented nirvana, layered architecture is still a useful pattern. And if done right, it paves the way towards more advanced designs and architecture.

So let’s talk about layers.

Continue reading Layered Architecture: Still a Solid Approach