Maintainability, Learnability, Component, Layering

Normal

0

21

false

false

false

FR

X-NONE

X-NONE

Share/Bookmark

The last
ayende’s post
contradicts everything I know about software. Ayende goes against the idea
that maintainability can be measured by how easy it is for someone
unfamiliar with the code to pick it up and easily understand and make
changes to it. (as David mentioned in the comment, we must assume that someone has appropriate skills to do the job).

 

I am about
to expose my point of view. I organize my thoughts as a mathematical
demonstration. If you disagree with something and wish to comment, please refer
to the exact step you disagree with.

Maintainability

I always
learnt to forget about all code I wrote, about all code I’ve been familiar
with. One cannot claim to be familiar with a sufficiently large code base (I
would estimate something with more than 100 K LoC). This is an axiom, if there
is no upper threshold from which one cannot be familiar with a code base, one can be
virtually familiar with every lines of code written on earth.

 

A code base
is maintainable if any developers can quickly and efficiently work on any part.
We never know where in the code the next bug will pop-up.

 

From the
axiom above, to be able to work on any part of an application, one must be able
to discover easily the code to work on (because we cannot assert that one is familiar with the whole code base). This is possible only if the code is
learnable.

Learnability

Thus Maintainability and Learnability of a code base represent the same thing. To be
maintainable, code must be learnable. But what makes code learnable?

 

Code is
learnable when implementation details can be quickly mastered. Details are mainly algorithm in
method bodies, classes interaction and state evolution at run-time.

 

The human
brain can only focus on a small amount of details at a time. Thus code must be
partionned in such way that when discovering details, this doesn’t lead to an
escalation of detail discovery.

Component

To prevent
such escalation, the code base must be partionned and elements of the partition
must be abstracted from each other. Elements of the partition are named
component.
Concretely, components are group of types strongly interacting together (this
is refered to high cohesion inside a component). If one use one type of a component, one uses all of them.
If one changes one type of a component, one changes all of them.

 

Components
are abstracted from each other if when learning details of component A, one
doesn’t need to learn details of component B. Thus implementation details in
different component doesn’t relate to each other. This is known as low-coupling
between component.

 

Unfortunately
a certain amount of coupling between component is needed to make them working
together. At the very least, to communicate, components must agree on
interfaces (or even better and more restrictive, components must agree on interfaces +
contracts).

 

Thus
component statically depend on each others. Having abstract components
boundaries solve well the problem of escalation of details to discover. But another problem
is luring: the complexity of the graph of dependencies between component.

Layering

If the graph of dependencies between components is complex, developers cannot get the big picture of the code base. This big picture is needed to determine which component will be touched to achieve a particular maintenance/evolution task. This big picture is also needed to anticipate future major evolutions.

 

The best
way to make the graph of dependencies between components easy to understand is
to avoid cyclic dependencies in it. If a cycle exist between some components, they
cannot be developed, refactored, tested in isolation. This is what Robert C.
Martin is calling the ‘morning after syndroma’ in its fantastic paper on
componentization
.

 

Basically
the ‘morning after syndroma’ says that when breaking a component, the
escalation of problem becomes dramatic if the component broken is involved
in cycle with other components. When breaking a component you are breaking components that depends on it. Without cycles, this set of components can be clearly identified. With cycles,
this set of components represents virtually the whole code base.

 

Having no
cycles between components means that components are living in a DAG (Directed
Acyclic Graph). In other word, it means that components are layered.

Share/Bookmark

This entry was posted in Ayende, Component, Layering, Learnability, Maintainability. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://codebetter.com/members/Patrick-Smacchia/default.aspx Patrick Smacchia

    Marcel, this debate is also around what science means in software development. Every sciences abide by the divide and conquer principle. Scientists know for 400 years that this is the best way to handle complex things with the human brain.

    Divide and conquer in software means making well isolated piece of codes interacting each others, or in a word, it means component.

    Why the heck software development is the only science where people still believe it is relevant to discuss the divide and conquer principle? because it is still a young science?

  • http://mdpopescu.blogspot.com Marcel Popescu

    My comment here – http://mdpopescu.blogspot.com/2009/08/maintainability.html

    In short: I’d go with not just one average programmer’s opinion, but with “what would most programmers think”?

  • http://codebetter.com/members/Patrick-Smacchia/default.aspx Patrick Smacchia

    David, you are right, I modified the post.

  • http://david.safitech.com David

    “A code base is maintainable if any developers can quickly and efficiently work on any part….
    “From the axiom above, to be able to work on any part of an application, one must be able to discover easily the code to work on…”

    I think you need a stronger axiom to argue your point:
    “A code base is maintainable *only” if any developers can quickly and efficiently work on any part.”

    I also think you’re making implicit assumptions about the quality and background of developers you’re working with.

    For example, if you worked in a team of developers whose background was in procedural programming and who struggled with OOP concepts like the SOLID principles, which would you then consider more maintainable:
    - an object-oriented codebase where changes can be made in one place, but where some of the developers will struggle to work out which place.
    - a codebase with methods lasting over 1,000 lines and where changes have to be made in multiple places, but where it’s obvious where each change(s) go?

    Personally I’d be thinking of modifying the axiom to something like:
    “A code base is maintainable only if any competent developer can quickly and efficiently work on any part without reducing future maintainability.”

    where “competent” is defined as having skills (etc) appropriate to the role.

  • http://codebetter.com/members/Patrick-Smacchia/default.aspx Patrick Smacchia

    >Yes, chances are that the application snowballs into a big mess, but there are certainly examples where this is not the case.

    The whole problem in our industry is that most of the projects are failing, so if there is principles to avoid big mess then let’s avoid it.

     

    >Yours is the view of the consultant and Ayende’s is the view of the in-house/maintanence programmer.

    There is a high risk that in-house/maintanence programmer end up turning-over. So better stick with some ideas that make maintainability something verifiable by tier, and independent from the programmers knowledge. Not only it makes development safer in the long term, but also doing so will scale better once the code base will become very large.

  • http://georgemauer.net/blog George Mauer

    Counterpoints:
    Maintainability – It’s cheating to limit discussion to only very large applications. Many business-critical applications are under 100K lines. For these applications maintainability is still an incredibly important concern. This is especially true as langauages evolve allowing you to be more expressive in less lines of code. I have an application that is probably in the 8K LoC which is constantly getting feature requests, what is most important is that I can incorportate them easily without deviating from the architectural philosphy. Perhaps you want to give this a different term – maelability perhaps – but it certainly falls under the maintanance banner.

    I do not think it is necessary for “any” developer to quickly and efficiently work on any part of the application. Consider an application created by a good and thoughtful developer who simply as never read GoF, DDD, and who makes up his own structures and nomenclature. Yes, chances are that the application snowballs into a big mess, but there are certainly examples where this is not the case. As long as their terminology and strucutres are consistent and effective I don’t think you can consider their code unmaintainable, yet it could be a significant ramp-up for the “any” developer.

    Learnability – I agree that this is achieved when implementation is quickly mastered but it is not necessary that the mastery comes from the code itself. It is preferable of course; but if there is an excellent design document or even a senior designer that can get you caught up quickly then why is the code not learnable?

    Components & Layering – I’d add in that components and layers must be logical and of a managable size. I maintain an AJAX heavy ASP.NET application. Each page’s functionality is stovepiped into a component and barely ever touches other code. The application is a horror. Each “component” contains thousands of lines of Javascript, C#, and PL/SQL with business logic spread throughout. Is it easy to pick up and understand what’s going on? Well, it’s not too hard, the programmer was a beginner and there is nothing fancy going on at any point. But making changes is another story whatsoever. If you need to change how a name displays you need to search through client, server, and database code because the formatting can be coming from either. And business logic changes? Forget about it – they are nearly impossible with no domain model and the logic spread between components, layers, and languages.

    I think we are talking of 2 different views of maintainability. Yours is the view of the consultant and Ayende’s is the view of the in-house/maintanence programmer. Being the latter, I tend to agree with him.

  • Jeremy

    I would modify your definition of maintainability slightly:

    A code base is maintainable if any developers can quickly and efficiently work on any part *without taking on significant code debt*.

    Code debt is a great analogy. You could rephrase the above another way:

    A code base is maintainable if any developers can quickly and efficiently work on any part without making the overall codebase worse.

    You could argue to fold this into your definition of ‘efficient’ but I think that you should keep a clear distinction.