var blog = new ThoughtStream(me); RSS 2.0
 Sunday, April 06, 2008

Or communicate... or both.

  • If you have a problem in an application and there is more than one developer working on the project, be sure to clearly communicate who is working on the problem. Otherwise, you'll end up with two people writing the same code in the same place, duplicating the effort and wasting at least one person's time
  • If you need more than one person working on the problem, make sure that they are working together, closely, to avoid the same problem
  • If you need input from other resources, be sure that the entire team working on the problem is involved in those conversations or is at least given a summary of the conversation, so that you don't have to go back to the external resource over and over again, to get the same information
Sunday, April 06, 2008 3:20:32 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: Management

One of the primary goals of Lean Manufacturing in the elimination of waste. This may seem like an obvious goal - after all, who wants waste in their system? What's really interesting, though, is seeing where the term "waste" is actually applied and how Toyota redefined what waste really is.

Muda, the concept of the seven wastes in the Toyota Production System, is a very different concept of waste than most of us would consider. It talks about not only physical waste (trash), but also logical, time, and effort waste. These seven wastes include (from Wikipedia):

  • Defects: Quality defects prevent the customers from accepting the product produced.
  • Overproduction: Overproduction is the production or acquisition of items before they are actually required.
  • Transportation: Each time a product is moved it stands the risk of being damaged, lost, delayed, etc. as well as being a cost for no added value.
  • Waiting: Refers to both the time spent by the workers waiting for resources to arrive, the queue for their products to empty as well as the capital sunk in goods and services that are not yet delivered to the customer.
  • Inventory: Inventory; be it in the form of Raw Materials, Work-In-Progress (WIP), or Finished Goods, represents a capital outlay that has not yet produced an income either by the producer or for the consumer.
  • Motion: As compared to Transportation, Motion refers to the producer or worker or equipment.
  • Overprocessing: Using a more expensive or otherwise valuable resource than is needed for the task or adding features that are designed in but unneeded by the customer.

In "Lean Software Development: An Agile Toolkit", Tom and Mary discuss The Seven Wastes and offer a great set of parallels in software development. Rather than copy & paste what they've already said, I wanted to offer my own interpretation of these wastes - some of which are the same as Tom and Mary's.

Defects

This is exactly what it sounds like - a bug, a piece of functionality that doesn't work right, or an exception that gets thrown in the system and causes problems. How many hours, days and weeks have you spent fixing defects in software, in your career? Personally, I can't even begin to accumulate the time spent - it's far too great.

Part of the problem here, and what really makes it wasteful, is when defects are found and fixed in most software development cycles. In Code Complete 2, McConnell talks about the cost of defects in software, relative to when the defect is found and corrected (pages 472 & 473). If the cost of fixing a defect goes up over time, then the amount of waste also goes up. In other words, the higher the cost of fixing a defect, the more waste that defect has generated.

With the increasing cost of defects in mind, we will want to reduce the time to find a defect so that the amount of waste generated can be mitigated. In Lean Manufacturing, this is achieved by only creating what is needed for an actual customer order, right now. If one part is produced with a defect, that one part is scrapped and a new part is created, correcting the defect - the waste is minimal. Imagine a mass-production system where parts are created in batches of ten thousand. What happens if there is a defect caused by the process? We end up with a significant amount of waste, because we will have to scrap the defective parts in batches of ten thousand - the waste here, is significant.

The same principle holds true in software development. If we are writing code for extensive periods of time, and that code is not being tested until the end of that period, then the cost of finding a defect in that code goes up. If we have ten lines of code that rely on the defect working the way it does, it is significantly cheaper to fix than if we have ten thousand lines of code relying on the way the defect works. The easiest way of reducing the number of lines that rely on a defect is by working in small iterations. If that defect goes into test after two weeks, it will be much cheaper to fix than if it had gone in to test after two months. Additionally, if automated tests are done and can be run against the system on an even shorter schedule, then the cost of finding the defect may be even less. If the automated tests are run every twenty or thirty minutes, you may only have two or three lines of code that are affected by the defect.

Overproduction

There are several common terms for overproduction, in software development - Over-Engineering and Coding For The Future, for example. Both of these problems result in the same thing - too many features and more functionality than is actually needed right now. Additionally, overproduction can be called technical debt. The idea is that there is code in our system that will need change - when this code needs to be changed, how difficult is it to change; what is the cost of the change (how much debt are we in).

If a developer is tasked with creating Feature-X, they should focus on the core business value of that feature when writing the code. It's very easy for that developer to think about "what-if" scenarios and "we may need to" future functionality. However, this type of thinking leads directly to overproduction. If the business has not identified the "what-if" scenario, then why should the developer assume that handling the scenario would add business value? If the business has not yet identified Feature-Y or specified any additional functionality in Feature-X, then why should the developer assume that coding for the possibility of Feature-Y is valuable? Take note of the pattern in those questions - assumption. Assumption on the developer's part leads directly to the overproduction of the system being built.

So how do we prevent this overproduction? First and foremost - stop assuming you know what's coming down the line, or what will provide business value. If you believe that the specs you are currently working with are not accounting for an actual problem, then the responsible action is to discuss that issue with the customer / business analysts. Secondly, if you find yourself wanting to code for the feature that may be coming down the line - stop. Don't do it. Even if you know that this feature or functionality is coming down the line, it may not provide any business value for the current feature(s). You may be causing detriments to the business value of what is currently being built. If you truly believe that the feature you want to code is required for the feature that you are coding, then you need to go back to the customer / business analyst again, and discuss it with them. Let the customer tell you whether or not there is value in adding that feature now vs. later (vs. if at all).

Transportation

Think of transportation in the context of knowledge. No one knows everything about a particular domain or project, and possibly an individual feature. We have business analysts and customers precisely because of this. Eric Evans discusses knowledge crunching (the process of learning and gaining an understand of the domain in question, to create a model) in Domain Driven Design, in the first chapter. Tom and Mary talk about the process of learning all throughout the "Amplify Learning" chapter of Lean Software Development. There are countless other books on requirements gathering, model creation and other learning processes for software development, as well.

The problem that we face in our learning is that the transportation of knowledge, from one person to another, will always introduce change. Every person in existence has their own unique way of understanding, based on their experience, existing knowledge and methods of knowledge retention. To illustrate this, look back at your childhood. Did you ever play the "telephone" game where one person whispers in the ear of the person next to them, then they whisper the same thing into the ear of the person next to them, and so-on until the last person in line? What are the typical results of this game? More often than not, the message had some fundamental change to it throughout the transmissions. As simple as the telephone game is, it's a perfect illustration for knowledge transportation that occurs in software development projects.

How many times have your received a functional specification or requirement for a feature, and had no clue what it was trying to convey or what the functionality was supposed to be? This happens on a very regular basis. The problem may not be that the documentation is inadequate, but that the transportation of knowledge from one person's mind onto the paper and into your mind is inadequate - what makes sense to the document writer(s) may not make sense to you, because your contextual knowledge of the subject is different. This problem is exacerbated by design-up-front project methods. The knowledge is often crunched from the customer's mind into the BA's mind, and then trampled down into a linear document or subset of knowledge in a documentation set where the developer has no direct access to the customer - the source of knowledge - for clarification and discernment of the details. Even if the customer is on-site sitting next to the developer throughout the creation of the documentation, there is still a transportation problem in design up front projects. Whether or not the developer understands the information during the conversations, there is little chance that the developer will remember every detail of the information when they finally get down to coding.

The solution for the transportation of knowledge is ensure that the knowledge is transported as little as possible. Rather than focusing the effort of documentation on every last possible detail - creating tomes of documentation that no one is really willing to read - we should focus on creating higher level guidance; enough knowledge to know the direction of the development effort and the features to be created, with the understanding that the final details will come from the customer just-in-time for the development effort. In the world of lean manufacturing, this is typically done through the Kanban system. In software development, we have adopted the same process through the use of User Stories being written on index cards. The stories are not the final word in the development effort - they are merely a placeholder for a conversation between the customer and the developer.

Waiting

This is likely the most obvious of the seven wastes, when applied to software development. Whether you are waiting for a customer or business analyst to be available for questions; waiting for a requirements document to be signed off; or waiting for your next assignment of work, the simple process of waiting creates lost time which directly translates to lost opportunity. In the extreme cases, the problem is compounded by context switching. If you are waiting for a question to be answered - whether this means waiting for a phone call, a document to be written, or just walking down the hallway - you can easily lose your focus or lose you place in the code or coding process. When this happens, most people take a while to restore that focus and get back into the mind set where the new knowledge is useful. In my experience (no real data, just my experience), the average time of context switching within the same project is as little as five to ten minutes for wind down, and at least ten or fifteen minutes for spin-up. If you are context switching between multiple projects, though, expect to spend much longer on the spin-up; hours, even days, depending on the project and time between wind down and spin-up.

If we can ensure that we never wait longer than it takes for us to wind down, then we should be able to eliminate the spin-up period; thus reducing the effort required for reestablishing our focus on the feature(s) at hand. However, the solution for waiting may not be as obvious as the problem. If you are waiting for documentation, or if you are waiting for the customer to sign off on a feature or change, the way to eliminate the waiting is to eliminate the cause. Don't rely on heavy documentation or require customer sign-off on features. If we are working with the customer every hour of every day, eliminating the knowledge transportation issues, then we can also eliminate much of the waiting game by having the customer available. When the customer is available immediately, we have a much greater chance of the conversation beginning within the wind down period. When this occurs, we can stay focused on the problem at hand, and mitigate the spin-up period when we return to the code.

Inventory

Inventory in a manufacturing or supply context is typically a product or component of a product that is in storage and waiting to be used; or "a list of goods and materials held available in stock by a business" (Wikipedia). In software development, we only need to translate "good and materials" into "code and resources":

A list of code and resources held available in stock by a business.

Think of software inventory as unfinished code (as defined in Lean Software Development) or as overproduction of code. If we have unfinished code in our system, this is like having a physical component for a product - the component by itself is not useful until it is in the completed product. Similarly, the unfinished code provides no value to the software until it is finished. Even if the code is complete, if it is not being used in the software then it is dead code and is inventory for the software.

Inventory, in software development, carries a significant technical debt - the unknown factor of whether or not the code actually needs to be in the system. The longer we let inventory live in our code, the more likely we are to forget whether or not that code needs to be there. This inventory also becomes a potential mine field for developers - what happens if a developer sees this dead code and assumes that it is still functional and valid? If we are lucky, the code will work as advertised. The longer the code sits in inventory, though, the more likely it is to be outdated, invalid and eventually non-functioning.

Motion

In addition to physical movement causing waste through waiting (walking down the hall to the BA's office), motion can also be applied to the processes of producing the executable software (not the source code and other resources). How much effort does it take for your team to compile the resources, create the executables, package it into an installation and deliver it to QA, the customer, etc? The goal should be to make this as simple as possible - as little movement as possible.

Are you able to click a button and have the build, package, and delivery processes handled for you automatically? Or does it take a team of developers, build engineers and other persons with a manual process and a checklist of things to do? If your process involves people performing manual tasks - even if that task is simply the order in which multiple buttons get clicked - then you are at risk of creating waste through defects. Every manual motion in your build process is another point at which mistakes can be made, allowing defects to be built or causing the build to fail completely.

Software production (again - speaking about production of executable software, not development of resources or code) is often a difficult, tedious chore, requiring many moving parts - there is no way around this. However, it does not have to be a manual process. Continuous Integration and Continuous Deployment practices are abundant in the world of software development, specifically to address this issue. If you can automate your build process and eliminate the manual movement involved, you can eliminate a huge source of potential waste.

Overprocessing

Overprocessing, or too much process, is abundant in software development. When a customer has a request for a feature, how much process does it take for that feature to become functionality? In design-up-front project life cycles, the process of adding or changing a feature can be very time consuming, involving many steps on both the requester and implementer side:

request; acknowledgement and change management / approval; design and documentation by implementation staff (BA's, developers, etc); sign off of design and documentation by customer; implementation in software; scheduled for testing; tested; and if any issues are found, back to design or implementation for corrections, repeating several steps.

Additionally, how much work does it take for you to get your job done, as a developer? Do you spend as much time updating task / issue management tickets and managing your manager, as you do coding?  Too much process in software development is as bad, if not worse, than no process at all. Unfortunately, the failures of too much process are often seen as an indication of the need for more process, causing further delays and waste in the system.

There are often situations where you cannot do anything about the process that is in place. Life-Critical systems (x-ray machines, air plane guidance systems, etc) are abundant with process for good reason - if anything fails, people could be injured or killed. In the world of business software, though, this is not usually the case. Most business has a level of fault tolerance built into it, and some waste is expected / accepted. This is not a get out of jail free card, though. The more significant the waste, the more repercussions there are - fix the defect; pay for lost revenue; lose your job; etc. If we want to eliminate waste through the simplification of process, then we need to ensure that defects are found and fixed as early as possible, to avoid creating waste for the business using the software.

Process simplification can be done many different ways. Start with the creation of a process flow char, or value-stream chart. Find out how much time and effort is wasted in your processes and look for the waste that can be easily eliminated. Simplifying a single process by removal of waste can lead to a revolution in your process. You may find that the removal of one process negates the need for another process. You may also find that a simple change to one process does the same. If you are able to bring your customer into the work area with your team, and work in short iterations where defects are found and fixed quickly, you will likely see many of your old processes quickly become obsolete.

Conclusions

No one wants waste in their systems. Waste is money lost and revenue not earned. Waste management, though, can be a difficult proposition. Many company are willing to accept waste as the cost of doing business and are not willing to spend money eliminating waste because they do not see the waste or do not believe it can be eliminated. If we are truly going to revolutionize the business we work in, we must eliminate waste. Start where you have direct control or influence. You'll quickly find others wanting to know how you are so productive and soon the entire business will be in full waste reduction cycles.

Sunday, April 06, 2008 3:05:30 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: Agile | Behavior Driven Development | General | Lean Systems | Management | Philosophy of Software

 Saturday, April 05, 2008

I've been hearing this a lot lately, and finally started reading up on the roots of the Agile movement. It all goes back to Lean Manufacturing. Oddly enough, I've had exposure to Lean Manufacturing at a previous job. So the concepts and names are all very familiar to me. Back in those days, I had heard of the concept of Lean Software Development, but it never really made any impact on how I wrote software. These days, though, I'm diving into as much Agile as possible and the further down the road that I travel, the more and more parallels I see, to the lean manufacturing world.

If you are at all interested in the roots of agile, here's some recommend reading (mostly Wikipedia) to get you started.

Wikipedia:

Books:

I'm hoping to absorb more of this information, quickly. It seems the more I learn about lean manufacturing, the more I understand about software development. I certainly don't claim to be an expert on either subject... hopefully I can change that.

Saturday, April 05, 2008 11:58:24 AM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: Behavior Driven Development | General | Lean Systems | Management | Philosophy of Software

 Wednesday, April 02, 2008

Way back in the day (somewhere around 1994 or 1995, I think), I saw the movie, "Search for Bobby Fischer". One of the lines that has always stuck in my head is from the teacher, Vinnie:

He didn't teach you how to win, he taught you how not to lose.

At the time, I didn't like this line - I didn't understand why playing "not to lose" was different than playing to win. Over the years, I've seen variations of this statement and had a little more understanding of what it actually means. Last night, though, I was involved in various philosophy-of-software discussions with a friend and this quote popped up in my mind again, in the context of project failure and the fear of failure. I think I finally understand what this quote is saying, now - and it all comes down to the fear of failure vs. embracing failure as an opportunity to learn and find new ways to succeed.

Knowing Success Through Failure

Looking back at my life, I have two very distinct memories of catastrophic failure - the kind of failure where I was so emotionally invested in the project or goal, that the failure was truly devastating to the point where I would have a complete breakdown and be entirely lost for a while.

The first of these memories was back in College. I have an associates degree (AA) in music, from a junior college back in my hometown in Kansas. After graduating with that degree, I found another school in Denver that had a sound recording / engineering track in their music school and I signed up for it with all the passion and motivation that I now have for software development. When I moved on to campus at that school and started figuring out what classes I would be taking, etc., I found out that I had slipped through the cracks in the school of music. As it turns out, I was supposed to have interviewed for the school of music and done some performance in front of various professors, to be accepted. With that in mind, I worked with the director of the program and did my performances - and completely failed. As it turns out, I had a general skill with musical instruments and could play just about anything at a very mediocre level, but I was not terribly good at any instrument. The end is result is that I was told (in very kind, helpful terms) that I would need a few years of lessons before I could be accepted into the school of music. Needless to say, this was a very devastating experience for me. My goal and my dream, at the time, was to be a musician and work in a recording studio. Shortly after the realization that my goal was unattainable, I had various talks with various people close to me and some talks with the director of the music school. We quickly realized that I could still attain the primary goal in my dream - to work in a sound recording studio and be in the sound recording / engineering program at the school - but my specified major would not be music. I ended up in the Management Information System department, with that being my major, while still taking the sound recording / engineering classes.

The second of these memories is significantly less important in the grand scheme of my life. A few years ago, I was attempting to install a new car stereo system in my car. I had done stereo and speaker installation before, but had never done an amp and subwoofer. Over a 4 day weekend, I ended up with a car that had no working speakers, a blown amp, and a subwoofer with holes punched in it. At the time, this was another very devastating outcome for me - I had a very specific goal in mind and had spent a significant amount of time and money on the project, with no usable results. Two days later, I had my car in a professional car audio shop with professional audio installation personnel fixing the problems and installing a new amp and subwoofer. The end result was that I had a great system in my car.

Looking back at both of these experiences, I see a pattern: a project or goal, a significant personal investment, a catastrophic failure and finally, an outcome that still satisfied my criteria for success.

There's an old cliche line that I've heard many times:

You can't know true success unless you know true failure.

I believe I've been as close to true failure as I can get, without giving up on a project or goal. True failure, though, can only come from giving up.

Playing To Win vs. Playing Not To Lose

My career as a software developer has been very interesting, so far. I've had a lot of great success and a few fairly large failures. What's really interesting to me, though, is looking back at those failures and seeing the risk that I was willing take. I've jumped into some very difficult, new, demanding situations with little or no knowledge and experience in those situations. Many times, I was able to find the experience quickly and succeed, but some times I was not able to find the experience quickly enough and I failed. These successes and failures are why I believe I understand the issue of playing to win vs. playing not to lose, now. As I said before, it all comes down to the fear of failure vs. embracing failure as an opportunity to learn and find new ways to succeed. With this in mind, I have some questions that may help you understand playing to win vs. playing not to lose.

Are you willing to take risks in your project? Are you willing to put forth the effort involved in trying to create what could be a better you, or a better project, knowing that you could fail if you try? Are you willing to open yourself for failure so that you can learn, and have a greater chance of greater success?

Are you playing to win?

Or are you only willing to do the work that you are comfortable with now, and only willing to learn a little bit of something new, keeping a safety net around yourself? Are you willing to keep yourself from taking risk so that you don't have any significant chance of failure, and no significant growth? Are you afraid of change or afraid that you will fail?

Are you playing not to lose?

Good Judgement and Experience

Another tired old cliche that I've heard a thousand times:

Good judgement comes from experience. Experience comes from bad judgement.

I make a dozen bad decisions every day. I also make a dozen good decisions every day, because I am willing to honestly look at the decisions I've made and admit that they were bad decisions. By allowing myself to understand that these decisions were bad decisions, and admitting that to not only myself, but to my managers and team members as well, I set myself up for success. I'm able to look at these decisions, understand why there wrong, and correct the mistakes. And by doing this on a daily basis, if not more often, I can mitigate the failure that any one decision may cause.

Embracing Failure Without Fearing It

One of the reasons I am so in love with Test Driven Development and Behavior Driven Development is that it accelerates the failure-to-success process. I'm not unit testing to prove that I have not failed. I'm unit testing to prove that I have succeeded and created the API that I want.

I expect failure when I unit test. I expect to write horrible APIs that are unusable, ugly, stupid, and obnoxious. I WANT to realize that I am doing this, through my unit tests, because I can accelerate the process of realization and correction by using my unit tests as a design tool.

And I challenge you to do the same - to stop fearing failure and not be afraid to make mistakes. If you believe you have made a mistake, expose it for peer review. Ask for others to validate or invalidate that mistake and learn from the experience. Find the tools, techniques, coworkers and peers that will help you accelerate the realization of failure so that you can correct the failure and succeed, faster.

A Personal Rant: My Success As A Developer

I believe I am a very successful software developer and leader. I have a lot of experience under my belt and a lot of knowledge that I want to share with others.

So, why am I successful? Why was I responsible for the public face of a 300 million dollar multi-national corporation, through it's web sites, when I was 22 years old? Why was I made the lead developer in a team of 10, when I was the new guy in the office? Why am I now diving into the cutting edge of Behavior Driven Development and actively involved in the Agile community? Why am I making a name for myself not only in my office, but also in the development world outside of my office?

Because I take risk and embrace my failures. I openly admit my failures at the first possible moment, so that I can learn. I actively seek the voice of dissent and the views that I don't agree with, so that I can be proven to be wrong and learn how to be right.

Why am I successful? Because I play to win.

Wednesday, April 02, 2008 8:38:07 AM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: General | Management | Philosophy of Software

 Monday, March 31, 2008

A while back, I posted a stream of thoughts concerning programming in triples. The basic idea is that we have 2 developers doing pair programming and a third developer doing automated acceptance test development, on the same story at the same time.

Triples Programming Terms

I've been discussing this idea with various people since then, and I'm finding myself referring to this team organization with a specific term, now:

Pair+1 Programming

I don't know if this term has been used previously, or if there is already a term for this. However, I find this to be a good name for the organization that I am talking about.  It really is pair programming, as defined by many common sources, plus one acceptance test developer. The really fun part is that all three of the developers in this unit will switch roles throughout the day. The end result is that we have a very well cross-trained team - each member of each unit will be responsible for writing unit tests, writing production code, writing acceptance tests, and thinking ahead of the current code, throughout any given day.

An Agile Team includes more than just the developers - the customers, the test lead, the technical writers, the project manager, etc., are all part of the team. Pair+1 Programming is not into teams. A "team" implies that they the persons involved are fairly static - they don't move between teams, etc. In order to distinguish the Pair+1 organization from the Team as a whole, I am also going to refer to this group with another name:

Development Unit (Update: based on further discussion, renaming this)

WorkCell

Just as a developer will rotate rolls within the Unit, I believe Pair+1 programmers should move between WorkCells on a regular basis. This will further the cross-training that occurs and help to pollinate the knowledge of one WorkCell into the thoughts and goals of other WorkCells. The migration is likely to be less volatile than the role switching that happens within a WorkCell. For example, developers rotate positions every 2 or 3 hours, within the WorkCell, whereas a developer may only rotate between WorkCells once a day or once a week.

Development Systems

Within each Development Unit, there will be two development systems.

  1. The primary system of that Unit will be the pair programming system. This system should have a very large monitor - 30" is preferable - to allow the Pair to easy see everything on the screen.
  2. The secondary system will be used for Acceptance Tests and is likely to only need a 22" or 24" monitor, as it will be primarily used by a single developer.

Each of these systems, aside from monitor size, should be a mirror of each other - the same system specs with the same software development packages installed. Every machine used for development should be able to execute any of the tests - unit tests or acceptance tests - no matter the primary use of that development machine. This is required so that the Pair working on the Development machine can execute the Acceptance Tests being created on the Acceptance Test machine; thus ensuring that they are coding appropriately, and passing the expected tests. The Acceptance Test developer should also be able to execute the code being written by the Pair, to ensure that the Acceptance Tests are being written against the API correctly.

Following standard Agile practices, these machines should not be concerned with Email, IM, or other non-development tasks. They should be dedicated entirely to development work. If a person needs Email, IM, etc. then the office space should provide access via shared systems and/or a developer should have their own system (likely a laptop) that they can take with them wherever they go. The point is, though, to remove distraction from the Development Unit. Keep the non-development software off the Unit's systems, as much as possible, to ensure that the Unit can focus on development and not be distracted by 50 different flashing icons and windows on the machine.

Disclaimer

A lot of my thoughts are purely academic, at this point. I am hopefully going to have some actual experience with this environment, soon. As such, I am trying to organize my thoughts so that I can have some direction to start with. I reserve the right to be wrong and change my mind whenever I want, likely re-defining the terms and processes involved in Pair+1 Programming.

Monday, March 31, 2008 2:26:19 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: Acceptance Testing | Agile | Behavior Driven Development | Management | Pair+1 Programming | Unit Testing

In my previous post, I talked about my base repository class that I use, to abstract the NHibernate details away from the actual repository. Now that I have the Do and DoTransaction methods to further the abstraction, I thought it would be good to share my whole abstraction.

using System;
using NHibernate;
using NHibernate.Cfg;
 
namespace RepositoryBase
{
 
    public abstract class Repository : IDisposable
    {
 
        #region Vars
 
        private static readonly Configuration _config;
 
        private static readonly ISessionFactory _factory;
 
        #endregion
 
        #region Constructor / Destructor
 
        static BaseDAL()
        {
            _config = new Configuration();
            _config.Configure(typeof(BaseDAL).Assembly, "RepositoryBase.hibernate.cfg.xml");
            _factory = _config.BuildSessionFactory();
        }
 
        ~BaseDAL()
        {
            Dispose();
        }
 
        #endregion
 
        #region Properties
 
        public ISession Session { get; private set; }
 
        public ITransaction Transaction { get; private set; }
 
        #endregion
 
        #region Methods
 
        protected void Do(Action unitOfWork)
        {
            try
            {
                OpenSession();
                unitOfWork();
            }
            finally
            {
                CloseSession();
            }
        }
 
        protected void DoTransaction(Action unitOfWork)
        {
            try
            {
                OpenSession();
                BeginTransaction();
                
                if (unitOfWork != null)
                    unitOfWork();
                
                CommitTransaction();
            }
            catch
            {
                RollbackTransaction();
                throw;
            }
            finally
            {
                CloseSession();
            }
        }
 
        #endregion
 
        #region Helper Methods
 
        private void OpenSession()
        {
            if (Session != null) return;
 
            Session = _factory.OpenSession();
            Session.FlushMode = FlushMode.Auto;
        }
 
        private void CloseSession()
        {
            if (Session == null) return;
 
            if (Session.IsOpen)
            {
                Session.Close();
            }
            Session.Dispose();
            Session = null;
        }
 
        private void BeginTransaction()
        {
            ValidateSession();
 
            Transaction = Session.BeginTransaction();
        }
 
        private void CommitTransaction()
        {
            ValidateSession();
 
            if (Transaction != null)
                Transaction.Commit();
 
            CloseTransaction();
        }
 
        private void RollbackTransaction()
        {
            if (Transaction != null)
                Transaction.Rollback();
 
            CloseTransaction();
        }
 
        private void ValidateSession()
        {
            if (Session == null)
                throw new ApplicationException("NHibernate Session Not Open.");
        }
 
        private void CloseTransaction()
        {
            if (Transaction == null) return;
 
            Transaction.Dispose();
            Transaction = null;
        }
 
        #endregion
 
        #region IDisposable Members
 
        public void Dispose()
        {
            CloseTransaction();
            CloseSession();
        }
 
        #endregion
 
    }
}

Note that I am using an embedded resource as my "hibernate.cfg.xml" location. Just change this line to use a file system resource, or whatever you want for your hibernate configuration.

I'm still wanting to re-abstract this into a set of objects that let's me be concerned with transactions and queries at a business level. One step at a time, though. The syntax that I would like to see, at the moment, would be something like this:

public void SomeBusinessValue()
{
    Something something = DoSomething.BusinessRelated();
    SomethingElse somethingElse = SomethingElse();
    Repository.DoTransaction(() =>