Mike Hogan, and some other bloggers are talking about maintainability patterns. Mike has been working with the same 50,000 lines of code for the last 2 years, and has run across issues. He sees maintainability in: test suites, IDEs, OO, interfaces, small code, reuse, and dependancies.
He then goes into rules on maintaining dependencies:
- Law of demeter: your objects should deal with its properties and what is passed to it
- Interfaces: Well placed interfaces enable you to slice your object model into independent sections, thereby enabling you to maintain parts of the model independently
- Sub-projects: Deliver the system with multiple jars. Use Maven to state your dependencies and use the Reactor to decide on build order.
- Do not allow package dependency cycles: Use JDepend as a JUnit test to guard against this
- Reuse when you can
- Use a framework that enables dependency inversion
- Analyze and refactor your dependencies
- Don't live with broken windows: maintenance requires fierce vigilance. You must always be on top of things, fighting against entropy, by fixing every broken thing you see, big or small, as soon as you see it.
Read: Mike Hogan on Maintainability Patterns
What other tips have you come across to help you maintain your apps?
-
Maintainability Patterns: Manage Dependencies and more (13 messages)
- Posted by: Dion Almaer
- Posted on: July 15 2003 01:28 EDT
Threaded Messages (13)
- Maintainability Patterns: Manage Dependencies and more by Erik Bengtson on July 15 2003 07:00 EDT
- There is a great book. by Yuval Goldstein on July 15 2003 09:37 EDT
-
Right on the money by Leif Ashley on July 15 2003 11:33 EDT
-
Right on the money by Mike Spille on July 15 2003 01:01 EDT
-
Right on the money by Gabriel Kastenbaum on July 16 2003 07:57 EDT
-
Right on the money by martin farrell on July 16 2003 08:27 EDT
- Right on the money by Lofi Dewanto on July 16 2003 01:37 EDT
-
Right on the money by martin farrell on July 16 2003 08:27 EDT
- Maintainance-Oriented Design by Jerome Duprez on July 22 2003 04:49 EDT
-
Right on the money by Gabriel Kastenbaum on July 16 2003 07:57 EDT
-
Right on the money by Mike Hogan on July 15 2003 01:17 EDT
- Maintainability pattern by Bharath Kasimani on March 06 2005 12:13 EST
-
Right on the money by Mike Spille on July 15 2003 01:01 EDT
-
Right on the money by Leif Ashley on July 15 2003 11:33 EDT
- There is a great book. by Yuval Goldstein on July 15 2003 09:37 EDT
- Coplien Organization Patterns by Dario Louzado on July 15 2003 12:27 EDT
- Maintainability Patterns: Manage Dependencies and more by Lofi Dewanto on July 16 2003 01:40 EDT
- Carlos has some good comments too... by Dion Almaer on July 16 2003 14:14 EDT
-
Maintainability Patterns: Manage Dependencies and more[ Go to top ]
- Posted by: Erik Bengtson
- Posted on: July 15 2003 07:00 EDT
- in response to Dion Almaer
- Create the architect team to define interfaces of components
- Separate teams to work along independent packages/components and implement interface defined by the architect team
- Create a baseline architecture, implement 1 or more use cases to be a proof of concept
- In code, make use of interfaces ratter than implementations eg.
List obj = new ArrayList();
- encapsule as much as possible
The list is big and should be book. I hope someone can suggest one. -
There is a great book.[ Go to top ]
- Posted by: Yuval Goldstein
- Posted on: July 15 2003 09:37 EDT
- in response to Erik Bengtson
"Refactoring: Improving the Design of Existing Code by Martin Fowler" is one of the best professional books i have ever read.
It presents you with an easy-to-follow methodology for changing existing code and provides a list of 'smells' - hints to were should you refactor your code and how.
I strongly recommend!
Yuval. -
Right on the money[ Go to top ]
- Posted by: Leif Ashley
- Posted on: July 15 2003 11:33 EDT
- in response to Yuval Goldstein
I really like what Mike Hogan had to say, and I agree with a good portion of it even if I didnt get a chance yet to read it all. I think its pretty amusing and cool to see that he contradicts some of his past articles, like putting business logic in the struts action. I learned this lesson with tools in the past too.
Ive grown fond of the same concepts he has about separating code using interfaces and also what some refer to implementation fault-lines, which are in effect an API to a service like business logic or DBServices.
Interdependencies can be hell on wheels at times, and I found the same was true in my experience with existing projects. Unlike him though, almost none of my projects are greenfield, so I have to start refactoring and reducing dependencies immediately.
The only caveat to the article though is that this is not a pattern. It is a standard development procedure list or best practices guideline. However it could be broken up into patterns, and to be honest, I think it would have tremendous value if it were. -
Right on the money[ Go to top ]
- Posted by: Mike Spille
- Posted on: July 15 2003 13:01 EDT
- in response to Leif Ashley
What he says about new development vs. maintaining a living code base is very, very true. I know a surprising number of consultants and "perms" who have never done any significant maintenance development, only one new project after another, and they just don't understand the full life-cycle implications of many design and coding decisions. And you really can't understand such things in your belly until you've lived it for awhile.
I also agree with what he says about dependency analysis, reducing coupling, and using independent code sections (which I generally call application sub-systems). When I'm designing, I start with a sub-system approach at all levels, even the business logic levels, and make it explicit that there's a wall around each one that should limit coupling. And you also make it explicit what the sub-system dependencies. Beyond making coding easier, this kind of approach scales very well and helps tremendously in programming-in-the-large - for many design tasks you can design at the sub-system level, instead of the class level, which is often too fine grained, and such fine granularity makes it easy to miss the critical aspects of each sub-system.
It's also important to make sure the sub-systems are shown in the architecture, that they're clear to developers, and that either tools or responsible people check the code to make sure that coupling rules aren't being violated frivolously. Tools to check coupling can be a problem here, because sometimes coupling two or more systems together just makes sense, and you need a person to decide on it and note it and move on.
What he doesn't mention in great detail (though he mentions it briefly), is that you also have to avoid the dangers of over-isolation. Some developers can get a little crazy and start overusing factories and interfaces in the name of low-coupling, and end up obscuring the code more than helping it. I believe you should go for low-coupling (low, not none!) initially without too much abstract infrastructure on top of it, and then grow it over time and add in more abstract infrastructure/isolation when and where it becomes clear you need it. This is IMHO the biggest danger to this approach - over abstracting and letting an ideal (low coupling) get in the way of deliverying an application.
-Mike -
Right on the money[ Go to top ]
- Posted by: Gabriel Kastenbaum
- Posted on: July 16 2003 07:57 EDT
- in response to Mike Spille
I could not agree more about the idea that the object is often a too fine grained view.
Maintaining learns you how lives a system and how it is used.
By the way, one of the best programming lesson I ever read is in "How To Write Unmaintainable Code". And one of the funniest - and most realistic! -
Right on the money[ Go to top ]
- Posted by: martin farrell
- Posted on: July 16 2003 08:27 EDT
- in response to Gabriel Kastenbaum
I could not agree more about the idea that the object is often a too fine grained view.
> Maintaining learns you how lives a system and how it is used.
> By the way, one of the best programming lesson I ever read is in "How To Write Unmaintainable Code". And one of the funniest - and most realistic!
i think the people who wrote my system misread 'unmaintainable' for 'maintainable'
one of the best things you can do to write maintainable code is to use people who know what they are doing, and stop developers following fads and every new toy the moment it arrives. -
Right on the money[ Go to top ]
- Posted by: Lofi Dewanto
- Posted on: July 16 2003 13:37 EDT
- in response to martin farrell
<quote>
one of the best things you can do to write maintainable code is to use people who know what they are doing, and stop developers following fads and every new toy the moment it arrives.
</quote>
Software development is a "process" not a "project". We never stop to learn ;-) People who know what they're doing today, may be doing something wrong tommorow ;-)
Lofi. -
Maintainance-Oriented Design[ Go to top ]
- Posted by: Jerome Duprez
- Posted on: July 22 2003 04:49 EDT
- in response to Mike Spille
<Mike Spille>
What he says about new development vs. maintaining a living code base is very, very true. I know a surprising number of consultants and "perms" who have never done any significant maintenance development, only one new project after another, and they just don't understand the full life-cycle implications of many design and coding decisions. And you really can't understand such things in your belly until you've lived it for awhile.
</Mike Spille>
I couldn't agree more, and indeed I find it pretty much applies to myself!
Could you and other TSS addicts elaborate on long-term life-cycle implications of design and coding decisions, including low-level design?
Admittedly, many Design Patterns (e.g. those described by the GoF or Floyd Marinescu's EJB-centered book) focus on maintainability, highlighting the points of extension. But do they scale when the modifications over the years count in the dozens, if not hundreds, per "component"?
Here are a couple of examples, taken from my current project, which involves the maintainance of a big long-lived (well, hopefully) J2EE app which existed long before me (I mean, before I came to work on it... I'm not a 4-years old consultant!).
My point is not to advocate for or against them, they are both controversial, so please don't strive to comment them. I just want to reinforce that pro and cons of design decisions show up only in the long run.
Therefore I'd like people with strong maintainace experience to provide their insights as to well-known or not-so-well-known architectural and design practices and patterns, and even coding idioms:
- that are valuable for start-from-fresh projects and lose their value over maintainance time
- or on the contrary that are considered harmful and are avoided in early stages of development but prove (or would have proven) beneficial in the long run
Examples:
---------
This application makes heavy use of the HashMap DTO "pattern". As a fervent strong-typing let-compiler-work supporter, I'm not at all a fan of this pattern, but acknowledge it has its advantages at least in early stages of development:
- It eases to make quick changes without editing existing code
- It provides an all-purposes bag of data that may pass from component to component, each one putting/taking what it needs in/from the bag.
- It hides dependencies which may simplify compilation order
The corrolaries are:
- It makes quick changes prone to break existing code in a way that only shows at runtime (because of loose typing)
- The all-purposes bag is hard to understand and maintain
- It hides dependencies which complexify the understanding of the application architecture. Plus, it does not get rid of dependencies, it just hides them : it replaces interfaces for a dictionary of keys that must itself be maintained and documented
As the application lives and is maintained (that is, continually modified), the drawbacks overshadows the merits, and in the long run I find this pattern considerably decreases productivity.
Another aspect of this application is that although it is separated in functional modules, with their own unit and susbsytem tests, all developers get the whole app source from the version control system, and build the whole application. Although I initially found that very disturbing (anyone may break the head-version build for all application developers, not only his module-teammates), I found out that:
- it eases debugging : it's easier to follow the flow with step-by-step or breakpoint-style debugging
- and speeds maintainance as well : if two modules need to exchange a new parameter, the same developper may modify both modules in the same session without too much release/redeploy hassle; this is important when experimenting changes that would otherwise go back and forth between separated modules and require a specific integration task (or team).
I guess these advantages show up only in the long run (in start-from-scratch projects, I found having separately-built modules with versions and milestones were easier to integrate).
Still, I wouldn't recommend this approach on a big application, because it requires much self-discipline and procedures (such as, don't get the source in bulk from the VCS, instead get each module separately, and don't get the latest version but only module-labelled versions, except for the ones you're modifying of course), procedures which are quasi-automatically enforced when modules are built separately and each team only gets the other teams' precompiled modules.
As mentioned above, these are only examples, please share your experience on your own Starter/Maintainance paradoxes. -
Right on the money[ Go to top ]
- Posted by: Mike Hogan
- Posted on: July 15 2003 13:17 EDT
- in response to Leif Ashley
I think its pretty amusing and cool to see that he contradicts some of his past articles, like putting business logic in the struts action. I learned this lesson with tools in the past too.
Leif, I don't think I contradicted anything I said from past articles. My message about putting business logic in actions is consistent: don't do it. I did mention that I _used_ to do it but, hey, thats just part of growing up :-) -
Maintainability pattern[ Go to top ]
- Posted by: Bharath Kasimani
- Posted on: March 06 2005 12:13 EST
- in response to Mike Hogan
Can somebody please point to the original article about the Maintainability pattern or post it in TSS? The website hosting the original article seems to have gone out of service for a while. -
Coplien Organization Patterns[ Go to top ]
- Posted by: Dario Louzado
- Posted on: July 15 2003 12:27 EDT
- in response to Dion Almaer
Good stuff.
It´s also interesting to consider also the "Coplien Organization Patterns" pattern language.
There is not an absolute good design or architecture.
See "ArchitectureFollowsOrganization".
http://www.bell-labs.com/cgi-user/OrgPatterns/OrgPatterns?ConwaysLaw
http://www.bell-labs.com/cgi-user/OrgPatterns/OrgPatterns?CoplienOrganizationPatterns
[ ]´s
Dario -
Maintainability Patterns: Manage Dependencies and more[ Go to top ]
- Posted by: Lofi Dewanto
- Posted on: July 16 2003 01:40 EDT
- in response to Dion Almaer
A good summary! This is also what component-based software engineering all about.
- Design your component (you also call this sub project or sub system) totally independent (no dependencies) from others. In this case you can test, run, debug the component completely independent from others. You can reuse the component easily in this way.
- Build your "glue component" to attach/to add the dependencies between one with other components. By doing this you can avoid circular reference.
- That's why following architecture helps a lot:
-> Service Components (Infrastructure)
-> Core/Foundation/Base Components (basically the core functionalities)
-> Extension Components (to add functionalities)
- Each component should be "logically" seperated, minimally into "specification", "business implementation", "data" and "presentation" (MVC, multi-tier). Again logically, so you don't have to use EJB for your business (phisically seperated) but you can if you want to. The "specification" is the most important one: all interfaces are putting here. This is actually the API for the component. The "business" is just the implementation of the specification (you can implement the specification in more than one techniques). The "data" is just the data. The "presentation" should only use the specification and never touch the business implementation. This idea is actually quite old. If you see all the Java APIs, they use this technique.
-> Specification: component API provider
-> Business: component implementor
-> Data: component data
-> Presentation: component API user
- Choose good package namings, which differ the package of the specification and business implementation.
Everything is still based on good old computer science principles: MVC (Model View Controller), layered architecture, seperate implementation from specification and information hidding ;-)
I've done this in OpenUSS (based on EJOSA) and this helps a lot to build an easy to extend application.
Regards,
Lofi.
http://ejosa.sourceforge.net
http://openuss.sourceforge.net -
Carlos has some good comments too...[ Go to top ]
- Posted by: Dion Almaer
- Posted on: July 16 2003 14:14 EDT
- in response to Dion Almaer
Carlos Perez comments on Mike's blog. He looked at an old text that discusses building large software in C++ and picks out the relevant info:
- Escalation. Moving mutually dependent functionality higher in the physical hierarchy.
- Demotion. Moving common functionality lower in the physical hierarchy.
- Dumb Data. Using data that indicates a dependency on a peer object, but only in the context of a separate higher level object.
- Redundancy. Deliberately avoiding reuse by repeating small amounts of code or data to avoid coupling.
- Callbacks. Using client supplied functions that enable lower-leve subsystems to perform specific tasks in a more global context.
- Manager Class. Establishing a class that owns and coordinates lower-level objects.
- Factoring. Moving independently testable subbehaviour out of the implementation of complex components involved in excessive physical coupling.
- Escalating Encapsulation. Moving the point at which implementation details are hidden from clients to a higher level in the physical hierarchy.
He also talks about a good AOP paper: Aspect-Oriented Dependency Inversion which demonstrates how guided by the OO principles that code can become more manageable using Aspects.
Dion