CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

May 2008 - Posts

  • The Open/Closed Principle on MSDN

    My latest article entitled The Open Closed Principle is available in the June 2008 edition of MSDN Magazine.  I tried to present both the motivation for following the OCP and some design strategies (besides the obvious Plugin example) and related principles to bring your design closer to being "Open for Extension, but Closed for Modification." 

    If you've never heard of the Open/Closed Principle, think of doing an addition to an existing house.  What sounds easier, laying all new bricks for an all new room, or changing the layout of existing rooms with a reciprocating saw?  An Open/Closed design allows us to extend the system with new code instead of having to potentially screw up existing code that works today. 

    Lastly, if you've read about the OCP before and think the OCP == "Plugin Pattern," go give the article a read, because that's not the entire story.

    This is the first in a bi-monthly series of articles called Patterns in Practice on software design fundamentals.  The next article (Object Role Stereotypes/Responsibility Driven Design) is already completed, but I'd be perfectly happy to take requests.  I think the next two leading candidates are "design vectors" (i.e. better designed code by moving in the direction of this, that, or the other) and treating Inversion of Control as a design pattern independently of IoC tools.

    Related Posts to the Article:

     

  • We're talking past each other on the Entity Framework

    Yeah, I know everyone is tired of the Entity Framework argument, but maybe we can start a real discussion.  I've seen two very different conversations about the Entity Framework from the data centric folks (pro) and the DDD/TDD/OOP folks (con).  It's not even a real argument, because we're concerned about very different things that aren't even in real opposition.  I'm completely agnostic about the Entity Data Model and the farther reaching, universal data access goals of the EF.  I'm strictly concerned with the EF's poor applicability for evolutionary design, Domain Driven Design, testability, and separation of concerns.  The EF seems to have all the major bases all covered in terms of functionality, it's just the *way* that it implements this behavior that concerns me.

    The problem with the blogging from last week is that it's two different conversations!  The "pro-EF" folks seem to be giddy about the functionality and features of the EF.  I'm steamed about what I feel to be the poor usability of the EF.  I do fully understand that the EF is about so much more than O/R mapping, I just don't think that their vision for data access adds more value than the harm that EF will do to my architecture by being intrusive.  The cool thing is that the EF team *can* actually make both camps happy.  There is absolutely no technical reason that the EF cannot deliver all of this utopian EDM goodness AND make the necessary structural changes to allow for real Persistence Ignorance to address my concerns about its usability. 

    The only real argument is their priority queue.  I obviously think the EF team needs to get a full Persistence Ignorant story in place before adding any other new functionality.

    For the record, I'm somewhat dubious about the actual usefulness of the Entity Data Model, but I will very seriously consider using the Entity Framework the minute that the EF team ships a real Persistence Ignorant option (which HAS to include transparent lazy loading) and a streamlined mapping configuration story (i.e. I want the conceptual model completely hidden away).  Until then, all that impressive sounding EDM stuff does not justify what I feel are severe compromises in my application architecture that do not occur with other persistence solutions. 


  • What Dan Simmons forgot to tell you about the Entity Framework

    Dan Simmons from the Entity Framework team at Microsoft made a nice post comparing the Entity Framework to other existing tools.  I wanted to pick a little bone with his comparison to NHibernate.  I don't think he said anything inaccurate, and he was very fair minded, but he left out the crucial fact in any consideration of using NHibernate versus the Entity Framework.  The Entity Framework is very intrusive into your application, but NHibernate is not.  NHibernate lets me use POCO's to model the business process in a database agnostic way.  The Entity Framework wants me to bake EF infrastructure directly into my business objects.

    The major problem I have with the Entity Framework is very apparent in Dan Simmon's post.  The EF team, and its advocates in the blogosphere, are strictly focused on data.  The last I checked, an application, system, or service usually consists of more than just getting data in and out of a database.  Some of that other stuff is quite challenging as well.  I'd prefer to be able to make that other stuff work in peace without data access infrastructure concerns bleeding into my business classes. 

    I would really like to challenge the EF team and the EF cheerleaders to be more cognizant of the entire application architecture instead of focusing strictly on the grubby details of data access. 

  • The little things do matter

    I, I mean, my friend, just wrapped up an article on object stereotypes.  At the last minute I decided to use an example from a system I worked on several years ago and many employers ago.  I think it was a great illustration of a particular design concept, but it's a better example of why small design decisions can have dramatic consequences for a company.  Let's hope that everybody involved with this system has moved on onto a happier place, and is wiser for the experience.  Just to start up the old argument about the relevance of architects on a project, I think the decision I'm criticizing here would be below the purview of many architects, but yet it had some sweeping consequences.

    Here we go, a little bug goes kachewww!

    •  A very complicated business process is kicked off when a physical scanning device sends a socket message
    • Listening to the socket and the business processing is effectively the same piece of code.  IP addresses are hard-coded into the VB6 code.
    • The very complicated business process can NOT be simulated except in a testing lab that is set up with physical scanners.
    • Developers cannot adequately unit test the code, so more bugs make it into testing
    • The code does not exhibit separation of concerns, so it is very easy for a developer to cause regression bugs, which aren't easy to catch because...
    • Developers cannot efficiently unit test the code!
    • Testing is very laborious, making all projects in this codebase more expensive because of the increased time to adequately test the system.
    • Testing is very laborious, so the testers cannot adequately run enough test scenarios to completely test the system in the allotted time, which means...
    • An alarming number of bugs occur in production...
    • Leading to lost productivity in the factories...
    • Leading to lost revenue and decreased profitability...
    • Leading to angriness, bad feelings, and bad morale all the way around...
    • Leading to many good people leaving the division or the company...
    • Leading to a general loss of ability in the I/T division
    • Possibly contributing to the company trying very hard to move all software development overseas? -- that might not be justified, but I wonder if the offshoring plans would really be there if the I/T organization was achieving better result.


    Oh yeah, at the time I was involved, there were not automated unit tests or deployment automation that could have made regression testing cheaper and test migrations easier and quicker.  Given better project automation, maybe the design wouldn't have been so bad.

    Morale of the story?  You need to apply real design skill at the point of attack, regardless of whatever that person(s) happens to be called.  Pay attention to the little design decisions too. 

  • Why do we Refactor?

    I've been refactoring the StructureMap codebase in preparation for wrapping up the 2.5 release.  I've been doing this work with a couple goals in mind.

    1. Experimentation.  I'm purposely revisiting some code just to see if I can come up with a better solution and structure.
    2. Improving the structural quality of the code in order to make the code more approachable to others.
    3. Some of the code is flat out embarrassing.
    4. Changing the structure to allow for easier extensions.  There's a couple specific new pieces of functionality that I thought would be easier to implement if I did some refactoring first.
    5. To more closely align the architecture with its functionality and usage.  StructureMap was originally envisioned as a generic mechanism to build an object graph from some sort of Xml representation.  Today, we do vastly more things with an IoC tool than I had in mind back in the summer of 2003.

     

    As the effort proceeds, I've been thinking about the reasons that we do refactoring, or more importantly, the reasons that justify refactoring.  When the topic of refactoring as a described practice was first being broached earlier in this decade, I read a lot of people upset over the idea of refactoring.  Refactoring was variously described as:

    • A result of insufficient upfront design (which I still think is silly because refactoring is often a result of doing upfront design too early and/or getting that upfront design wrong)
    • Undisciplined hacking
    • A dangerous activity that needlessly risked destabilizing working code (a very real fear that can nevertheless be mitigated by good automated test coverage with well written code and well written tests)
    • A waste of resources.  Useless goldplating, or as my buddy Chad Myers would say, "polishing the nosecone."

    That being said, what are the responsible reasons that lead us to refactor our code?  I can think of two major reasons.

    1. To remedy a deficiency in code, design, or architectural quality.
      1. We shouldn't declare a coding task complete until it reaches the quality demanded by the team.  These refactoring's are generally small, cheap items like renaming methods and extracting methods that can be performed safely and quickly with an automated tool.
      2. I'm doing a lot of work on StructureMap as a result of static analysis results from NDepend.  NDepend helpfully pointed out some flaws in the class structure that I've since remedied.  In specific, I've been working on reducing the complexity of any class with a high Cyclomatic Complexity (all the classes are now under 30 with a few exceptions that I'm ignoring because the methods are all simple).  I would also worry about efferent and afferent coupling plus the size of the classes and methods in your system. 
    2. To make a forthcoming change to the code easier. 
      1. If I'm changing a big method or complex class I'll often start by refactoring towards a Composed Method by extracting methods or even smaller, more focused classes.  On a project last year I did some quick renaming of variables from "m0, m1, m3" to more descriptive names.  My goal in these cases is to simply make the existing code easier to understand *before* I start to make modifications.
      2. For a new feature, I might need part of the functionality of an existing method or a class, but not the rest of it.  Rather than duplicate that functionality by copying and pasting, I'll extract the functionality to be shared into a new class or method so that it can be easily reused by the code for the new feature.
      3. In several cases, I've wanted to change one aspect of the behavior of an existing class while leaving the rest of the class's behavior intact.  In that case, I think the class is violating the Single Responsibility Principle, and I've split the class up along responsibility lines to isolate the changes to a smaller surface area. 
      4. Before making a change, you may need to decrease or even eliminate coupling on an existing code structure.  In StructureMap, I've frequently found myself wanting to change the internal structure of a class for various reasons, but first being blocked because other classes are coupled to internal details of the existing code structure.  In many cases, the culprit has been a Law of Demeter violation. 
      5. Introducing new abstractions often gives us a new seam in the class structure that we can exploit to add new behavior with minimal change to existing classes
      6. If we have to change any functionality that has duplicated representations in the code, it's often worth the while to first refactor the code to eliminate that duplication before making the change.

     

    Either way, you're main goal with refactoring is to make the code easier to work with in the future.  In some cases (the second category), that desired change is immediate.  In the first category, you're simply keeping the code cleaner to handle any type of extension and make the system easier to understand.  In regards to Lean thinking, you only refactor on a project when the proposed refactoring will lead to better throughput of the development work.  If a structural problem in the code isn't causing any immediate harm or friction, you probably leave it alone for now.

     

    Any thoughts?  What did I miss?

  • Going back to work

    I've been enjoying being an unemployed goof for the past month, but all good things must come to an end.  I'm starting a new position next month with the gang over at Dovetail Software. I've always enjoyed being around the Dovetail developers at Austin events, so I'm looking forward to working with them.

    I'll be, gasp, doing large scale web development on a regular basis for the first time since the glory days of 2002.  I'm not sure what the exact technology set will be (or should be), but I can promise you that no WebForms will be produced anywhere in my immediate line of sight.  

    I flirted hard with going solo, but my personal situation is probably best served by a permanent position in a stable company.

  • I finally get Git

    Last week I listened to Scott "blogs are obsolete" Bellware expound on the virtues of Git and distributed source control.  I nodded politely and thought to myself that good ol' centralized Subversion doesn't cause me the slightest bit of pain and very little friction.  Until this week that is. 

    I'm on a 2-3 week vacation before starting my new job next month.  I did about 2-3 days of significant architectural cleanup and refactoring to the StructureMap codebase while at my grandparents' farm in Missouri.  Needless to say, I couldn't commit the changes into the SVN repository on Sourceforge after each successful refactoring because I wasn't even in the vicinity of anything resembling internet connectivity. I finally had to drive into the big town just to find a wireless connection to get the changes checked in before I did something catastrophic to the codebase.

    I think I'll consider moving StructureMap into Git for local versioning pretty soon just for this scenario. 

     

     

  • My friend needs some help on an article

    I would never do this, but a "friend" of mine has procrastinated entirely too long and let a deadline for an article sneak up on him.  Here's a couple ideas that my friend has for his next article.  The article has to be on design fundamentals from a relatively ideology agnostic standpoint (not overtly pro-Agile or TDD in other words).  His first article in the series on the Open/Closed Principle will appear next month.  Please think about which topics would benefit your team members too, Mr. "I know the basics cold" Alpha Geek.

    • "Design Vectors" / "It's the Little Things" / "A title that doesn't stink" -- Why do you care about Encapsulation, Coupling, and Cohesion.   Then follow up with some heuristics to push your design towards these qualities.  Tell, Don't Ask, Law of Demeter, Don't Repeat Yourself, and a bit on some Code Smells.  My friend wants to sneak in an example of using a lambda expression to remove duplication.  Yes, Mr. Alpha Geek, you've read the Pragmatic Programmer front ways, backwards, and sideways, but this is for a more general audience.
    • Creational Patterns -- Builder, Factory, Abstract Factory.  Then talk about using an IoC tool as a generic way to implement these patterns.  The importance of separating functionality from the grunge work of assembling object graphs.  My friend isn't that excited about this one.
    • Object Stereotypes -- An introduction to the idea of object stereotypes from Responsibility Driven Design.  Apply these stereotypes to some bigger patterns like MVC/MVP.  It's an under appreciated topic.
    • Inversion of Control as a Pattern -- Forget the IoC/DI tooling.  Let's talk about how, why, and when this pattern is useful.
    • Patterns for Persistence and Data Access -- Lots of stuff from Fowler's PEAA book.  Unit of Work, Database Mapper, Active Record, Row & Table Gateway.
    Anything sound good to you?  My "friend" would appreciate some opinions here.
  • Would you do it differently today?

    A year and a half ago I wrote a post called My Gameplan for Starting a New Project from Scratch that just detailed my thoughts on starting up a new project.  I was asked via email last week if I had any changes to that post.  Yes, absolutely:

    Follow it Through!

    Don't jump into the work too early without a good story backlog definition, an understanding of the goals of the system, and some inkling of the expectations of the client (which are undoubtedly going to turn out to be ridiculously unrealistic).

    All processes, even XP and Scrum, have some sort of fuzzy project conception phase.  The activities that you perform in that phase are crucial to the success of the project by preparing the field, but easy to neglect because there isn't much pressure upfront and the feedback loop that says "you're wrong!" hasn't started yet.  On the other hand, I think you need to work with a sense of purpose early in the project to get through that initial phase and get started.  In My Gameplan post I talked about the importance of getting momentum early on in the project.  That's largely based on my experiences in a large organization that let the early phases drag on way too long.  After doing three projects and starting a fourth since that post, I'd still err a little bit on the side of starting the coding in earnest too early rather than too late. 

    I did have some issues with coding outrunning the build, test, and deployment infrastructure.  Take care of that stuff as early as possible.  Especially early on the project, if you see chances to add some automation to reduce friction, do it right then.  Investments early on pay off more in the lifecycle of a project. 
     

     

More Posts

Our Sponsors

Proudly Partnered With


This Blog

Syndication

News

All opinions expressed here constitute my (Jeremy D. Miller's) personal opinion, and do not necessarily represent the opinion of any other organization or person, including (but not limited to) my fellow employees, my employer, its clients or their agents.

About Me

"Best Of" Compendium

StructureMap (Dependency Injection for .Net)

StoryTeller (Supercharged Fit)

Build your own Cab

TestDriven

MVP