Maintainability Patterns: Manage Dependencies and more

Discussions

News: Maintainability Patterns: Manage Dependencies and more

  1. 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?

    Threaded Messages (13)

  2. - 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.
  3. There is a great book.[ Go to top ]

    "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.
  4. Right on the money[ Go to top ]

    I really like what Mike Hogan had to say, and I agree with a good portion of it even if I didn’t get a chance yet to read it all. I think it’s 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.

    I’ve 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.
  5. Right on the money[ Go to top ]

    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
  6. Right on the money[ Go to top ]

    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!
  7. Right on the money[ Go to top ]

    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.
  8. Right on the money[ Go to top ]

    <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.
  9. Maintainance-Oriented Design[ Go to top ]

    <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.
  10. Right on the money[ Go to top ]

    I think it’s 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 :-)
  11. Maintainability pattern[ Go to top ]

    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.
  12. Coplien Organization Patterns[ Go to top ]

    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
  13. 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
  14. 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