I’ve written a lot of specification tests like this in the last three years, from a UI / Workflow perspective, with Model-View-Presenter as my core UI architecture: [TestFixture]
public class When_starting_some_process()
{
IMyView view;
MyPresenter presenter;
[Setup]
public void Setup()
{
//...setup code and execute stuff for the test here
view = MockRepository.GenerateMock<IMyView>();
presenter = new MyPresenter(view);
presenter.StartSomeProcess();
}
[Test]
public void Should_attach_the_view_to_the_presenter()
{
presenter.View.ShouldNotBeNull();
}
[Test]
public void Should_show_something()
{
view.AssertWasCalled(v => v.ShowSomething(something));
}
}
The Devil In These Details
I had one of those ‘aha!’ moments yesterday where several of my nagging suspicions and annoyances at writing specification tests like this example finally gelled into a coherent understanding. That understanding is easily stated by saying that the test, “Should_attach_the_view_to_the_presenter” is invalid and should never be written. There are a number of reasons for this.
- In practicing BDD, the technical jargon that is leaking into the test is irrelevant to the real value that is intended with this specification
- In practicing any form of TDD, the implementation detail of attaching a view to a presenter creates a brittle test – I care about the API and how the system really works, not a very technical, implementation detail like this.
- Exposing the “View” property of the Presenter object is a violation of encapsulation and an ‘over-intimate’ smell. My test has far too much fine detail, granular knowledge of what’s going on behind the scenes, to really be of any practical value
- Finally – and possibly outweighing all other reasons combined – it’s simply not necessary.
Look at the second test: “Should_show_something”. It’s actually using the view. Presumably, the “StartSomeProcess” method on the presenter is going to call a method on the view – that’s why we are asserting that the method on the view was called. If this is true, then it can be safely assumed that not having a view attached to the presenter would throw a null reference exception when trying to call that method on the view.
If not having the view attached to the presenter results in a null reference exception for the other test, then we have a valid reason for that test to fail. We certainly can’t say that the view’s method was called when the view is null. Therefore, testing to ensure that we have a view attached to the presenter is a duplication of effort. We’re only proving what we have already proved transitively, via another test.
Beauty And Meaning In Simplicity
Assuming that this is all true, we can remove that test entirely. Our specification now looks like this:
[TestFixture]
public class When_starting_some_process()
{
IMyView view;
MyPresenter presenter;
[Setup]
public void Setup()
{
//...setup code and execute stuff for the test here
view = MockRepository.GenerateMock<IMyView>();
presenter = new MyPresenter(view);
presenter.StartSomeProcess();
}
[Test]
public void Should_show_something()
{
view.AssertWasCalled(v => v.ShowSomething(something));
}
}
It’s one less test to deal with, yet is as expressive and meaningful. In fact, I would say it is more meaningful because we have avoided all of the problems I listed. I’m reminded of a quote by Alan Cooper:
“No matter how beautiful, no matter how cool your interface, it would be better if there were less of it.”
Although I think he was specifically addressing User interfaces in this quote, it is applicable to all interfaces – programmatic, user, etc. Simplicity and subtleness is the key. I know I’m not the first person to talk about this problem, why it’s a problem, or the solution. I’m only claiming that I finally had that ‘aha!’ moment and realized why so many others have talked about this before.
_________________________________ Cross Posted From LostTechies.com
In the manufacturing world, you would never find a company that assembles a bunch of parts into a final product before inspecting any of the individual parts, and they would not wait until the end of the assembly line to test for the quality of the product. The very notion of waiting until the product is “done”, to test it, would be appalling. How much time and money would be lost trying to figure out why something didn’t fit together properly, why it didn’t work, and why there was a quality issue with the final product? Rather, we see the manufacturing world taking an active role in preventing defects. Yes, they still do a final quality inspection, but the primary means of ensuring a quality product is delivered is not by waiting until the product is assembled to test it. They build quality in from the start and maintain that quality throughout the manufacturing process. Prying Open The Case Imagine the inner workings of the phone to the left. This is a very complex piece of technology. Do you think Cisco would wait until they have assembled this phone and then try to pry open the case so that they can insert a set of electrodes to test and see that the circuit board is connected correctly? I certainly hope they don’t. Instead, when a manufacturing company is building something – anything – they start with the idea of preventing defects, not waiting until they are identified and correcting them. Many companies have an active Zero Defects policy where defect prevention is paramount and quality inspection is almost just a verification of what they already know – that the product is defect free. When a part is stamped out, formed, molded, or otherwise created, it is done so to an exacting specification. After the part has been created, the part is then tested against the same specification to which it was originally built. If the part does not fall within the tolerance and guidance of the specification, it is scrapped and a new one is made. If a series of parts are found to be out of specification, it’s usually a sign that something in the process, tooling, or other portion of the manufacturing process is not right. When this happens, they fix the cause of the problem – whether the machines need to be calibrated, the people running the machines need better instructions or whatever the cause is. In the end, the specifications for the parts were used to create the part, identify whether or not the part was up to standards, and decide whether or not to keep that part. What’s more, the manufacturing company doesn’t wait until after they start creating parts to create the specification. Rather, they take the time to properly engineer the specifications up front. They take measurements, create prototypes with varying specifications to see what works best, record the success and failure rates of the various specifications that are tried, and use other design and engineering principles to scientifically calculate the exacting specifications that will be used to produce the parts. This occurs at all levels of the product’s design and creation. For every resistor, capacitor and microchip that builds a circuit board, each one of them has their own specifications that have been carefully engineered. If any single capacitor does not meet the specifications, it is not sent to Cisco with the hopes that it works anyways. Only when all of the specifications of each part are met will they solder the parts to the circuit board, creating a subassembly. When a subassembly is created, it also has a specification to which it was built. The subassembly then undergoes the same quality assurance process – verification that it meets the specifications and operational requirements. The process continues from here – each subassembly gets connected to a larger system which is built to a set of specifications, with rigorous testing of the larger system as it is built, ensuring it meets the specifications. When the final phone is assembled, we don’t have to worry about whether or not a specific capacitor is soldered to the correct location – we don’t have pry open the case on this phone and insert a set of electrodes to see if the electrical current is flowing correctly. Instead, we only need to plug this phone into the correct connections (an Cisco IP phone system in this case) and verify that the phone actually performs all of it’s functions, according the functional specifications of the phone. There simply is no need to verify the capacitor that was used in the very first step. We know it works because it was built in a system that actively prevents defects. The manufacturing world is obsessed with testing. They are willing to test from the lowest possible levels of the system, out to the end-product and the behavior that is expected. They do this because the consumers of manufactured products demand perfect. Why, then, are so many software development companies so willing to only test from one end of the process? To only test once, and only from the user interface, just before the product is shipped? A Specification By Any Other Name Unfortunately, the software development industry as a whole, is years behind the manufacturing industry. Our definition of quality and success are often skewed and we may consider fifty or more known bugs in a system of moderate to large size to be acceptable. It doesn’t have to be this way, though. We have the technical capabilities of following in the footsteps of the manufacturing industry, and we should. I’m sure there would be no small number of people that would say we already employ the use of specifications in software development. After all, that’s what the requirements gathering phase is for, right? So many software development companies have put so much effort, time and money into the process of producing a piece of paper that can be understood by humans, and labeled this a specification. The problem we face with paper, though, is how to effectively verify the software against what the paper says. How do we verify that series of software lines and I/O statements that are understood by a computer have actually implemented the human readable text on the paper? We are fortunate, actually. We don’t have to accept a Word document or a piece of paper as the specification to build to. We have the ability to create executable specifications! We can, and should, be creating specifications that can measure and verify our code. Most people call it test driven development (TDD). Some call it Behavior Driven Development (BDD). I like to think of it as Specification Driven Development (SDD? Not sure if that really exists. And really, do we need another xDD acronym?). We write code that exercises our code in the form of unit tests, integration tests, functional tests, acceptance tests, or whatever you want to call them. We’re Not Just Stamping Out Parts One of the major problems that I have with the manufacturing/software development analogy is the obvious statement that we don’t stamp out the same parts over and over again. In spite of my previous comments on this analogy, I now think that we are more analogous to a specific part of manufacturing than I had previously understood. A more accurate representation of software development in the manufacturing world is new product design and development. The parallels work quite well from this perspective. I am not going to expound on this in great detail at this point. It should suffice to say, for the moment, that the process of product development described in Wikipedia is a fairly accurate representation of what we go through for the average software development project. When a manufacturing company is working on a new product, they once again don’t stamp out parts without knowing what they are doing. Many different parts may need to be tested, many different designs may need to be tried, but every one of these is still built to a specification. The major difference is that the specifications used are expected to change over time, until the final specification for the final pieces are accurate enough to produce a production-ready prototype. The same notions can be applied to the software development processes in TDD, with some additional benefits. Built To Specs, Regression Tests And Change Change happens. It’s a simple fact of software development. A customer thought they wanted X, but in reality they needed X-1/B – not quite what we originally thought. When this happens, we once again have a significant benefit created by our executable specifications. We only need to identify those specifications that are now wrong, correct them, and change the affected portions of the system to match the new specifications. Our ability to change is direct evidence to one of the many benefits of TDD: regression tests. Every specification that we write becomes a regression test the moment we fulfill that specification’s requirements. With this in mind, we can work with an almost reckless abandon, free to add features, remove features, fix bugs (because let’s face it – we’re still going to find some issues somewhere in the system) and refactor the system to a higher standard, all without worry of breaking the system. We can act with this level of confidence because we have a safety net in our regression tests. If (when) we do break something in our new efforts, we will be notified the moment we re-execute our specifications – that is, run our regression tests. A specification test will fail and we will have a clear indication of what failed and why. This deep insight into the system gives us even further confidence in correcting any issues that we introduce. When a failed specification test tells you exactly which value from which class is wrong, and the context in which that class was executed is known (the exact input and expected output), pinpointing the problem becomes a rote process. Fixing the issue becomes relatively simple, and we begin to see true productivity improvements in our processes. Start With Quality, End With Quality Our industry is currently suffering from a lack of quality. We ship horrendously bad user experiences in products that are late and well over budget, yet we call this a ‘success’. It doesn’t have to be this way. If we change our perspective and start to take some cues from the manufacturing and product design and development world, we can dramatically increase our effectiveness as software developers. We can create high quality, low cost solutions like the world expects from manufacturers. Built to specification is certainly not a silver bullet. It is, however, the definition of quality in a Zero Defect environment. By employing a built to specification mindset in our software development efforts, we can start with quality and maintain that quality throughout the life of our projects. This is the same process that is undertaken when a manufacturing company is working on new product design and development. It works well, it’s a proven process, and most of all – it makes sense. Build your software to specifications. Just make sure they are executable specifications.
_________________________________ Cross Posted From LostTechies.com
Let's assume that we are doing the appropriate amount of testing during our development process. If we include TDD, test automation, test engineers and customer acceptance testing, we should find the majority of the bugs in our system before they are released. However, not every bug will be found. There will be some situation that no one thought about before. There will be some special circumstance on someone's computer that hasn't been accounted for. There will be some client data that does fit the expected variance, despite the data being valid. The point is, there will be something that breaks after we deliver the software. Worse yet - it doesn't even take delivery to find bugs. What happens when the software gets to customer acceptance and the customer says that something is wrong, broken or whatever? We simply must account for the inevitable bug fixes and emergency patches in our system. Our current kanban board, with all it's pipelines and queues, hasn't addressed the need to address problems. But before we get into any changes to the board, we have to define and create the culture of quality that we need in our team. A Culture Of Quality There are many different aspects of quality and many different ways to view and interpret quality. The individual specifics, as always, come down to your team, the project and the needs of both. Even with these variances, though, there are a few key concepts that should be found in any culture of quality, including Whole Team / Collective Ownership and Zero Defects. Collective Ownership I've talked about this concept before (see above link) and would recommend reading those prior posts. One thing I would like to add, though is that collective ownership can only success when the team takes their individual egos out of the equation. We must be able to accept criticism as a way to improve ourselves and our team. When we let go of our ego, we can be honest with ourselves and others, enabling everyone to own every part of the system. Zero Defects This is a subject that I have not talked about before, but is prevalent throughout the continuous improvement philosophies that I subscribe to. Wikipedia lists four principles of Zero Defect methodologies, all of which are paramount to our culture of quality. - Quality is conformance to requirements
- Defect prevention is preferable to quality inspection and correction
- Zero Defects is the quality standard
- Quality is measured in monetary terms – the Price of Nonconformance
Don't be confused by "requirements" in item number one, though. In the world of software development, the word "requirements" has many meanings - not simply the feature list or functional descriptions set forth by our customers. Our teams and processes have certain requirements that are imposed on top of, and into each of the business requirements for the software. These often include the use of source control systems, test driven development, principles like S.O.L.I.D., etc. Quality Checks in Kanban Collective ownership and zero defects are only the tip of the iceberg. There is so much more to a culture of quality and so many different aspects of quality to account for. However we define quality, though, our ability to create a culture of quality is necessary for our kanban system to work. Without it, we lose the continuous improvement and elimination of waste that defines Lean. With it, though, we can introduce some specific tools to our process and improve our kanban system by having it handle the errors that are found in our systems. Andon From Wikipedia: "a system to notify management, maintenance, and other workers of a quality or process problem" When an issue is found in our system, we need to notify the team immediately so that the problem can be taken care of. The idea in a manufacturing line is to allow a worker to stop the line when a problem is found. In our grocery store example, andon could be invoked by a shelf stocker noticing a loose nut or bolt on the shelf and then notifying a maintenance person. In software development, andon can take many different forms. We report our issues list during our daily standup. We create issue tickets in our issue management system. If we're lucky and work in a company that supports the idea of a team room, we may just need to look up or turn around and let the team know that we have problems. We could even place an actual red flag on the desk of our developers, testers, customer representatives, etc., and have them raise that flag when they see a problem. Any of these ideas, plus many many more, can all be our andon system. Andon itself is not intended to be an all encompassing electronic system with metrics and reports and yadda yadda yadda. It needs to be simple. It needs to be easily employed by anyone on the team. And it needs to mean something to the team. If a team member throws their andon card out on the table, the culture of that team needs to be ingrained with the knowledge that work may stop until the problem is addressed. There's so little to andon, yet so much more than what I've described. However andon is enabled, it is critical to our zero defect policy in software development. Jidoka AKA "Autonomation", AKA "Automation with a human touch", AKA "intelligent automation", AKA ... From Wikepedia: "Autonomation prevents the production of defective products, eliminates overproduction and focuses attention on understanding the problem and ensuring that it never recurs." I've talked about Jidoka in previous posts and would recommend reading them, at this point. I don't have much else to add, other than to say that Jidoka and Andon go hand in hand. Automated build servers (such as CCNet, TeamCity and many others) can often combine Andon and Jidoka for us by giving us instant visual feedback when something is broken. I've also recently set up BigVisibleCruise in my team area, giving even the casual observer the knowledge of whether our builds are broken or not. Applying Andon and Jidoka to Our Kanban Board Once we have the concepts of Andon and Jidoka in our team and culture, we can use these tools to generate issue cards and then look at a few possible changes to our kanban board to account for them. The three basic methods that I have seen used include: - Creating an Emergency Fixes pipeline
- Tacking a smaller bug notice onto an existing card
- Putting a Bug card in the backlog
I'm sure there are other alternatives, too. In my current team, we use the first and third method and are considering the second one as well. Options two and three essentially require no change to our kanban board. Implementing option two is a distinctive way of visually attaching a bug notice to one of the cards in our system. This could be done with little bug stickers, little red cards, or any other visual indicator that the team agrees on. Option three also needs something distinctive. Since we are creating an entire card for the bug, though, the entire card should be distinctive. I would recommend using a card that is colored red to signify issues. I would also recommend prioritizing the bug to the top of the backlog queue, when using option three. This will ensure that the bug gets worked as quickly as possible. Option number one can also make use of number two and/or three. When we move a card into the Emergency Fixes pipeline, we may want it to be distinguishable as an issue by tacking on our bug symbol or by using a colored card. Emergency Fixes Pipeline Depending on the complexity or severity of the bug, we may want to include Analysis and Customer Acceptance in our Emergency Fixes. With andon and jidoka in mind, we will want to ensure that we fix any emergency issue immediately. This is not always possible, however. The customer may decide to delay the fixing of an issue for whatever reason. This leads us to only needing a single pipeline for Emergency Fixes, letting us set our limit to one. We can easily add an Emergency Fixes pipeline to our kanban system, placing it directly underneath our existing WIP pipeline. This special pipeline can be designated with a name, color code, or other marks as needed. If you are supporting production releases, you may also need to include a Delivery queue specifically for emergency fixes. This would allow multiple fixes to be compiled into a single patch release. There are other configurations to this, of course. As always, you will need to find what your specific team needs and create your process to suit. Where Do We Go From Here? With an Emergency Fixes pipeline in place, our kanban system is now set up to handle just about every situation that we will encounter. However, this does not mean that our system is perfect or truly complete. No process, no matter how well defined it is, is worth anything if the people running the process do not believe in it. I've said it before and I'll continue to say it - never stop improving your process. Always be mindful of waste, friction, smells, problems or whatever you want to call it. Inspect, adapt and continuously improve your process. Perfection is a journey, not an end-goal. Stay tuned to my Adventures in Lean series, as I continue to explore the various aspects of lean software development in my own team and company culture.
_________________________________ Cross Posted From LostTechies.com
In part 2 of my Kanban in Software Development series, I talked about completing a kanban board with queues, order points and limits. We saw how to take a complete development pipeline and work with a team, its processes and its bottlenecks. In the end, we had a kanban board that could easily represent the processes of the fictional team that we outlined. One of the questions that I've often asked about a kanban board is how anyone would know when work in one column is done and ready to be pulled into the next column. For example - if a kanban card is sitting in the Analysis column, how does a developer know when that card is done so that they can pull it into Development and start coding it? I found the answer to this question when I was at the Kaizen Conference in October. Jef Newsom did a workshop on kanban and we ended up with this same question, and a solution. A Pipeline for Analysis - WIP and Done To facilitate the visualization of the difference between work in progress and work that is ready to be pulled to the next column, we can use the concept of a pipeline and split our existing queues into a WIP and Done step. For example, we want developers to pull work from the Analysis queue into the Development pipeline. We can show which cards are ready to move by splitting Analysis into sub-columns of WIP and Done. When an Analyst is ready for work, they would pull from the Backlog into the Analysis / WIP column. When the analysis work is done and the card is ready to go into development, the card would be moved into the Analysis / Done column. Since we are wanting to maintain the concept of a queue for the overall Analysis column, we have create the WIP and Done subdivisions as a pipeline (noted by the dashed line). This allows us to keep our order point (3) and limit (5) in place for Analysis, and know what work is ready to be pulled into Development. Applying Pipeline per Queue Across The Board Not every queue needs to be a pipeline. Consider the Backlog - the customer is placing the prioritized list of features in this column. The cards in this column exist so that the analysts will know what work needs to be done - not because any work needs to be done in this column, explicitly. The Delivery column may not need a pipeline, either. If the delivery process is composed of sending an installer package to the customer, then there is no real work to be done in this column aside from sending that package. However, if there is some specific integration work (say, changing a web.config file) that needs to be done, we could include a WIP and Done pipeline for delivery. For this simple example, we'll say that there is no configuration change needed. Let's assume that the installation package changes all the needed configuration files based on user input. With all of this in mind, we can apply our WIP and Done pipeline to the Analysis and Customer Acceptance columns. Alternative Visualizations There are other ways of visualizing WIP vs Done cards for a given column, of course. For example, you could forgo the pipeline idea and simply add a queue between Analysis and Development. This may require you to adjust your order points and limits between analysis and development - at least, where those order points and limits apply (Analysis vs. the queue between Analysis and Development). You could also split the column horizontally instead of vertically, creating either the top or bottom half as the WIP with the other being Done. Or you could just note the status on the kanban card itself. I'm sure there are a number of other ways to show this information, as well. The point is that the pipeline visualization that I'm showing here is not the only way. Find what works for you. Where Do We Go From Here? We have another tool in our belt, now. If need be, we can visualize the WIP vs work Done for a given queue, allowing us to see when we can pull work forward. But, like all tools in our belt, it is not *the* answer and this additional visualization may not be necessary for your team. If your team is small or has great communication, you may not need any special distinctions to show work in progress vs work ready to be pulled. You could rely on the daily standup for people to report when they are done, or do it ad-hoc - when someone finished a card, they announce it to the team immediately. In a larger team, though, it may become necessary to have some visual distinction between work in progress and work completed for a given column. Small teams might get away without it; larger teams might need it; its up to your team to decide. The key is not to apply these ideas as blanket rules that must be followed, but to allow the individual project and team to decide what is right for them. And as always, allow the process to change when it needs to. Always inspect, adapt and continuously improve.
_________________________________ Cross Posted From LostTechies.com
This post is part of the November 2008 Pablo's Topic Of The Month (PTOM) - Design Patterns and will outline a simple Command pattern, its implementation and use. One of the core principles of object oriented software development is the idea of Coupling, "the degree to which each program module relies on each one of the other modules" (Wikipedia). When we build software, we should strive to attain low coupling - keep the individual modules of the system as separated as possible. Of course, if there is zero coupling in a system, then the system won't really do much for us. After all, you can't write software that is very useful if you are not allowed to have any dependencies. Setting Up Shop Before we break down into the pattern, let's consider the context of a Point Of Sale system at a coffee shop. In this system, we have a menu where your server can punch in your order with all of the options you want and produce an order that is fulfilled somewhere else. When the server starts pressing the menu items and the system begins to compile the order, there is a connection between the menu system that they are using, the various products that have been configured in the system, and the back-end ordering system. This is a rather obvious location where coupling can quickly become high - the UI, the products, and the back-end ordering system could very quickly become a spaghetti mess of tangled dependencies and tight coupling - but we don't want that, do we? To combat the coupling problems of this situation while still allowing dependencies, we need to introduce various forms of abstraction - simple dependencies that are not specific to any implementation, allowing us to change the implementation when we need to. In the case of a menu - be it a WinForms application, a touch screen point of sale system, or whatever else - a Command pattern is often employed to enable the system's functionality without being directly coupled to the actual menu. The Command Pattern Originally outlined by the infamous "Gang of Four", the Command Pattern is described as an object that represents an action - a command that will be executed. Within the context of a command, we have several parts that need to be accounted for.  - First and foremost, there is the actual command object - the action that is executed.
- Second, we have the command invoker - the object that depends on the commands existence, and knows how to execute the command.
- And lastly, we have the target of the invocation - the part of the system that needs to take action when the command is executed.
A Simple Implementation To facilitate the decoupling of specific modules in our system, our command pattern implementations will be created with a naming convention that represents the objects as commands. For example, a very basic command implementation in C# can be represented as an interface such as this: public interface ICommand { void Execute(); }
By abstracting our command into an interface, we can provide any implementation we need at runtime. This lets us select a coffee from our point of sale system and have another part of the system actually create and handle the order. A pseudo-complete implementation of a command pattern to order a cup of coffee may look something like this:
public interface ICommand { void Execute(); } public class MenuItem { private ICommand _menuCommand; public Text { get; set; } public MenuItem(string menuText, ICommand menuCommand) { Text = menuText; _menuCommand = menuCommand; } public void Click() { _menuCommand.Execute(); } } public class RegularCoffeeCommand: ICommand { private SomeOrderingSystem _orderingSystem; public RegularCoffeeCommand(SomeOrderingSystem orderingSystem) { _orderingSystem = orderingSystem; } public void Execute() { Product regularCoffee = new Product("RegularCoffee", 2.99); _orderingSystem.PlaceOrder(regularCoffee); } } //... somewhere in the application UI MenuItem regularCoffeeMenuItem = new MenuItem("Regular Coffee", new RegularCoffeeCommand()); //... and when the menu item is clicked regularCoffeeMenuItem.Click();
The real power of this implementation is that we have completely decoupled our menu system from any specific knowledge of the product ordering system in our coffee shop. All our menu item needs to know about is the ICommand interface. At the same time, our back-end implementation also knows about the ICommand interface - but the back-end also knows about the actual product ordering system. This allows us to create an implementation of the ICommand interface that knows how to invoke our target system. The end result is that we can independently vary the menu system for ordering coffee and our back-end product ordering system.
More Complexity And More Flexibility
Great News! Our command pattern implementations don't have to be limited to such a rigid interface. In fact, my current project has no less than 4 different ICommand interface variations. By introducing the use of generics in C#, we can create some very flexible commands. As an example, consider the following additional interface definitions:
public interface ICommand<T> { T Execute(); } public interface IParameterizedCommand<V> { void Execute(V value); } public interface IParameterizedCommand<T, V> { T Execute(V value); }
These new interface definitions, in combination with the original definition above, can create a very flexible and very useful set of commands in a system. By creating a "parameterized command" interface, we can provide detail in the command execution that is not available at the time the command is instantiated. And by adding another non-parameterized command with a return value, we can create a system that is able to interact in more complex ways.
With these new command interfaces in mind, let's take another look at our RegularCoffeeCommand. Instead of hard coding the price of the coffee into the command, let's push that knowledge off to another part of the system.
public class RegularCoffeeCommand: IParameterizedCommand<Price> { private SomeOrderingSystem _orderingSystem; public RegularCoffeeCommand(SomeOrderingSystem orderingSystem) { _orderingSystem = orderingSystem; } public void Execute(Price coffeePrice) { Product regularCoffee = new Product("RegularCoffee", coffeePrice); _orderingSystem.PlaceOrder(regularCoffee); } }
By providing an interface that accepts a parameter, we can move the knowledge of the coffee's price out to another part of the system and provide it at runtime - a database call, a web services call, or anything else we want.
But Wait! There's More!
As you can see, the command pattern can be very useful in helping us decouple our coffee shop's point of sale system from the back-end product ordering system. Some very simple interface definitions can provide a lot of flexibility in how we compose our systems, as well.
What's more - we aren't actually limited to interfaces or base classes for abstracting our commands in .NET. The built in delegate system in .NET provides a great way to encapsulate commands with method pointers. I've previously talked about The Point of Delegates in .NET where I mentioned that delegates provide us with a way of delaying the execution of code. Though it's not strictly an "object" as the command pattern describes, a delegate certainly sounds like a command pattern implementation just waiting to break out of it's skin. In fact, I have created a few command pattern implementations using nothing more than the built in delegates in .NET, several times.
Whether you decide to use interfaces, delegates, abstract classes, or any other implementation method that you can come up with, I hope that you will think about including a command pattern implementation in your systems. It is an easy way of conquering the problems of high coupling between user interfaces and back-ends of the system.
_________________________________ Cross Posted From LostTechies.com
In my last post, I talked about the idea of encapsulation and using it to ensure that our business rules were enforced correctly. What I didn't talk about, though, was the second half of the conversation that my coworker and I had, concerning the patent -> consultation relationship. It turns out that we had the relationship wrong. That's not to say that patients don't have consultations, but that the logical model we were traveling with had an incorrect perspective and was causing us to create some very ugly workarounds in various parts of the system. What really stuck out in my mind, though, was not the idea that we had the model wrong, but how we came to the conclusion of the model being wrong. It has become apparent to me, upon reflection of the conversations and situation as a whole, that design smells are not always evidenced by design related activities, if ever. A Persistent Problem - Duplicate Redundancy After some initial coding of the patient -> consultation relationship, we start working on the persistence model via NHibernate. What we have is a patient with a collection of consultations - this is easy to map with NHibernate's one-to-many capabilities. We also have a CurrentConsultation property which needs to be mapped. This property is mapped to the same Consultation table, but only pull one specific consultation based on the business rules that state the current consultation is chronologically the most recent and has not ending date set. After some thought, we found that there were a few possibilities for handling the CurrentConsultation property in our current model: - Create a "CurrentConsultation" object that is mapped to the Consultation table and use a "where" class attribute in the NHibernate mapping that would limit the returned result
- Create a "CurrentConsultation" object that is mapped to a CurrentConsultation view and have the view coded to return the correct consultation object
- Add a CurrentConsultationId field to the Patient table, as a foreign key to the Consultations table, and map to the existing Consultation object
After some additional thought, though, we found that each of these solutions has a few significant problems that were going to cause a lot of trouble. Options 1 and 2 Both of these options have the problem of duplicating business rules into more than one language and location. We would either have the business rules of what constitutes the current consultation in the NHibernate mapping (the 'where' attribute) or in a database view, in addition to the already existing code. Changing the rule would mean changing a minimum of two locations where that rule is handled. This is a bad idea no matter how you look at it. Both of the options have also created a duplication of knowledge from the concept of a Consultation by creating a "CurrentConsultation" class and a separate NHibernate map for it. We would have the original Consultation class and the new CurrentConsultation class both representing the same data, making an artificial distinction in our code. Again, this is a bad idea. We don't want duplication of these logical concepts. We're also not dealing with a bounded context or any other logical separation of concerns at this point, so there is no need to separate the concept of a consultation into multiple classes. Option 3 This doesn't appear to have the duplication issue in code, but there is a potential for duplication of data. When we get down to the implementation of NHibernate, we could easily cause duplicate data in the consultation table by saving the current consultation class. We might be able to get around this by not cascading the saves of the current consultation property, but then we'd be forced to ensure the consultation collection was persisted prior to the patient so that we could update the current consultation object's id before saving the patient. Both of these problems sound like a serious pain to me. I'm betting it's possible, but I'm also betting that it would be a nightmare of trial and error to get it right and a lot more code than we should really have to write. Changing Perspectives As Joe Ocampo pointed out in the comments of my original post, we had a problem in our system that was really caused by our lack of correct perspective in the situation. Rather than forcing the idea of a patient being the root aggregate in this situation, causing us a lot of headache and frustration in trying to model our persistence layer, a simple change in how we looked at the situation helped us solve the persistence problem and greatly simplified how the application worked. Joe's comment (with some formatting added): "One thing I like to challenge developers with when I teach DDD is to flip the aggregate to determine if the model is sound. I know this is only an example but work with me here. You indicated you are dealing with a medical system. We can assume there are certain entities such as Patient, Consultations, Doctor and Practice. In your example you created a model where the patient is the aggregate root for consultations but what if the Doctor simply asked what consultations do I have today? In this paradigm the Practice is the aggregate root and Consultations are aggregate within where Patient is an aspect of the consultation. The code would look something like this. consultations = practiceService(IConsultationService).GetConsultationsFor(doctor);
This also allows the consultation service to encapsulate its own logic for creating a consultation for creating a consultation. You can’t get any closer than that 
consultationService.CreateConsultationFor(patient).with(doctor).at(date);
The point I am trying to make is be careful of aggregate roots. Once you go down that path it is really difficult to back the train up and break it apart."
Though our actual implementation was different, this was the same basic conclusion that we had come to - our perspective on the situation was simply wrong. When we stepped back from the problem and realized that the consultation was the primary focus of the situation, and that a nurse or doctor would be the primary user of that portion of the system, it became rather obvious that our aggregate was in dire need of rework.
A Reflective Perspective
What we ended up with was a Patient object that dealt with all of it's demographics information, billing information, etc, without a CurrentConsultation property or even a Consultations list. Then, on the the separated Consultation object, we added a child property of Patient. Once we realized that our Consultation object was the primary focus and made this distinction in our code, we also realized that the Patient object was carrying far too much information around the system. We found that we actually had two very distinct concepts of a patient, determined by two very distinct bounded contexts.
- In the 'Billing' context, we needed all of the address , billing, and other demographics information about the patient - who they are, where they live, what their insurance is, etc. The existing Patient class filled this need.
- In the 'Consultations' context, we did not need anything from the Billing context, except for the person's name and patient id. What we really care about in the consultations is medical information about the patient - their current prescriptions, allergies, past medical care, etc. So, we created a ' patient' class to represent these needs.
These changed allowed for a much more clearly defined model that was truly reflective of the systems needs. We could easily see the difference between a 'billing' patient and a 'medical' patient, and we were able to code each of these areas of the system without the concerns bleeding into each other. Essentially, we decoupled the system at a module level, not just at a class level.
We also found that the NHibernate mapping problems suddenly went away. Since the Consultation class had a child of Patient, it was a simple many-to-one mapping with no strange sequencing or duplicate data issues. In the screens that deal with the consultation directly, we load the consultation as the aggregate root and go from there. In the screens that need to show patient consultation history, we did a simple query and returned all of the consultations for the given patient. Again, we found a way to decouple our system - this time, at the persistence model.
Design Smells: Not Just A Design Problem
In the end, we were able to recognize a serious design smell in our system - not by the design itself, though. After all, the original code had encapsulated the needs quite well. But, as it turns out, it was a bad encapsulation at a higher level. It wasn't until we started working with the model we had created, specifically trying to persist the model, that we realized our design was not right.
This change was a huge breakthrough for us, not necessarily in the code or the system that was being built, but in how we look at our systems and our domain models. The realization that design smells are often evidenced not by the design itself, but by how the design is used in the infrastructure and other supporting roles of the system, has had a profound impact on how we look at system design. I'm now seeing areas of different systems that are encapsulated incorrectly, at a higher level than class design. Recognizing the problem is the first step - and we're now working to rearrange and invert these models to more accurately reflect reality.
Pay attention to the pain that your application, infrastructure and other supporting services are causing you. You may be staring at evidence of a design problem, without realizing it.
_________________________________ Cross Posted From LostTechies.com
Yesterday, I was involved two very separate yet very related conversations. One was via twitter with Colin Jack and Jimmy Bogard (which I was only a partial contributor to - mostly just reading their conversation) and another after work with a coworker. The short version of both conversations can be boiled down to encapsulation of logic surrounding collections that are held by entities. Rather than rehash all of the conversations, I wanted to specifically address a violation of encapsulation that I've seen many times when dealing with collections and business rules. Let's look at a small example where we have a medical system that deals with Patients that are having Consultations with doctors. There is a need to keep track of the historic consultations and also the current consultation, if any. For simplicity we'll say that the current consultation is identified as being the most recent, based on a starting date, and that any previous consultation must have an ending date. A very simplistic implementation of an object model to represent patients and consultations may look something like this: public class Patient { private IList<Consultation> _consultations = new List<Consultation>(); public IList<Consultation> Consultations { get { return _consultations; } } public Consultation CurrentConsultation { get; set; }} public class Consultation { public DateTime StartingDate { get; set; } public DateTime EndingDate { get; set; }}
Then, when the time comes to add a new consultation to the patient, making it the current one and closing a previous consultation, code may get called from somewhere in the application (like a code behind of a form, or if you're lucky, in the Presenter or Controller of an MVP/C setup), like this:
Consultation consultation = new Consultation{ StartingDate = DateTime.Now }; patient.Consultations.Add(consultation); if (patient.CurrentConsultation != null) patient.CurrentConsultation.EndingDate = DateTime.Now; patient.CurrentConsultation = consultation;
From a purely technical standpoint, there is nothing wrong with this code. It implements the business rule as defined. However, this code misses out on some great opportunities to encapsulate the rules we have into a process that can be called from anywhere that the system needs it - whether or not the code is in the specific presenter / controller that creates a new consultation or not. The very same code that comprises this implementation could easily be placed in the Patient object, abstracting the rules and process of creating a new consultation into a simple, single method call.
Before I show how I would approach that solution, though, there is one other implementation that I've seen recently that not only breaks encapsulation, but has to compensate for the lack of rules enforcement with logic in the wrong place. Instead of storing the current consultation as a set value, the CurrentConsultation property may have some logic in it to dynamically determine which consultation is the current one.
public class Patient { private IList<Consultation> _consultations = new List<Consultation>(); public IList<Consultation> Consultations { get { return _consultations; } } public Consultation CurrentConsultation { get { Consultation currentConsultation; DateTime mostRecent = DateTime.MinValue; foreach(Consultation consultation in _consultations) { if (consultation.StartingDate > mostRecent) { mostRecent = consultation.StartingDate; if (consultation.EndingDate == DateTime.MinValue) { currentConsultation = consultation; } } } } } }
This type of code is a huge encapsulation violation smell. Since our Patient object has no enforcement of the consultations that it holds, there is no way for us to really know which consultation is the current one. Because of this, the retrieval of the current consultation has to process the entire consultation collection and try to find the most recent consultation that has no ending date.
On top of the encapsulation issue, we have lost a great deal of performance. We now have to loop through the list every time we need the current consultation. If the list is small, this might not be such a bad problem, but as the list grows and as this code is used more and more, the performance problem may have a serious impact on the system.
Fortunately, the solution to the encapsulation violation, the enforcement of the business rules and the performance problem can all be wrapped up in to some very simple code. The first thing we want to do is prevent the ad-hoc addition of consultations to the patient. We still need to access the list of consultations, but we don't really have a need to modify it outside of the patient class itself. This can be done with a one-line code change to the Patient class's Consultations property:
public class Patient { private IList<Consultation> _consultations = new List<Consultation>(); public IEnumerable<Consultation> Consultations { get { return _consultations as IEnumerable; } } //ignoring other implementation details for the sake of illustrating the IEnumerable change }
Now that we have prevented the ability to do ad-hoc consultation additions, we need a way to actually add consultations. While we are doing this, we also want to enforce the business rules of the current consultation as described earlier. This is where we are going to take much of the original code that we found in the presenter / controller and place it into the patient class directly.
public class Patient { private IList<Consultation> _consultations = new List<Consultation>(); public IEnumerable<Consultation> Consultations { get { return _consultations as IEnumerable; } } public Consultation CurrentConsultation { get; private set; } public void StartConsultation() { Consultation newConsultation = new Consultation{ StartingDate = DateTime.Now }; if (CurrentConsultation != null) CurrentConsultation.EndingDate = DateTime.Now; CurrentConsultation = newConsultation; Consultations.Add(newConsultation); } }
In the end, this code shows a better encapsulation of the business rules and logic that surrounds the need to maintain a list of consultations and a current consultation. With this code in place, we could simplify the presenter / controller that we talked about initially. Rather than being forced to know all of that logic in the presenter, we can make one simple method call:
patient.StartConsultation();
With this one simple call, we have a guaranteed execution of the business rules that we need. This will allow us to recreate the ability to add a new consultation at any point in the application that we need, not just in the original presenter / controller that we were working with.
Side Note:
Part of the conversation via twitter revolved around where this type of logic should be encapsulated. From what I gathered, Colin tends to place this logic in custom collection objects, which would allow him to call patient.Consultations.Add() and still encapsulate the same business rules into that method. Like everything else in software development, there are multiple ways to solve the same problem. What does your specific situation, project, team, and business context need? Whatever your implementation needs are, though, we need to keep this type of logic and business rules enforcement well encapsulated in our systems.
Cross Posted From LostTechies.com
A coworker recently asked if we should always abstract every object into an interface in order to fulfill the Dependency Inversion Principle (DIP). The question stunned me at first, honestly. I knew in my head that this was a bad idea - abstracting into interfaces for the sake of abstraction leads down the path of needless complexity. However, I wasn't able to clearly answer his question with specific examples of when you would not want to do this, at the time. I've been thinking about this for a few days now and I think I have a good, albeit very long winded, answer. Before the question is answered, though, we need to step back and look at what DIP is all about. I've previously shown how to implement DIP and talked about why it's beneficial, so I won't be repeating that here. Rather, I want to talk about the language that describes DIP and what it really means. Robert Martin's original definition of DIP is this: A. High level modules should not depend upon low level modules. Both should depend upon abstractions. B. Abstractions should not depend upon details. Details should depend upon abstractions. The word 'abstraction' is used three times in the definition for DIP. So, in order to understand DIP, we have to first understand some of the basics of Abstraction. Some Background On Abstraction From Wikipedia (emphasis mine): "In computer science, abstraction is a mechanism and practice to reduce and factor out details so that one can focus on a few concepts at a time" I can't say it any better than this. Abstraction can very directly lead to a system that is more understandable by helping us ignore the detail and implementation specifics, allowing us to focus on something at a higher level. This reduction in cognitive load can benefit someone that is reading the code by not forcing them to know the detail immediately. Additionally, abstraction is a form of encapsulation or information hiding, which again helps us to reduce cognitive load and produce better systems. From Wikipedia's entry on Information Hiding: "In computer science, the principle of information hiding is the hiding of design decisions in a computer program that are most likely to change, thus protecting other parts of the program from change if the design decision is changed." At the heart of abstraction and information hiding, we find the ability to change the system. The ability to change is an absolute requirement in software development and produces good design that is easier to work with, modify, and put back together as needed. The inability to change is directly called "bad design" by Robert Martin, in the DIP article. Applying Abstraction And Encapsulation To DIP So how does our knowledge of abstraction and information hiding play into DIP? First and foremost, DIP never states that we should depend on explicit interfaces. Yes, in C# we have an explicit Interface as a form of abstraction. It is a separation of the implementation detail from the publicly available methods, properties, etc, of a class. Some languages, such as C++, don't have an explicit construct for interfaces, though. From Robert Martin's original DIP article, again: "In C++ however, there is no separation between interface and implementation. Rather, in C++, the separation is between the definition of the class and the definition of its member functions." A String As An Abstraction Abstraction does always mean explicit interface constructs, as evidenced in C++. Nor does it always mean an abstract base class, which we also have available in .NET. In fact, languages such as Ruby don't really need either of these constructs. The duck-type nature of Ruby allows an implementation to be replaced at any point, without any special constructs. In .NET, though, there are a number of abstraction forms that we can rely on, explicitly. We have the obvious interfaces and base classes (abstract or not) - but we also have constructs like delegates and lambda expressions, and even the simple types that are built into the base class library. Let's look at a simple string to illustrate abstraction. As I said in my SOLID presentation at ADNUG, we can invert our dependency on database connection information. Rather than putting a connection string directly into our code that calls the database, we can use the string as our dependency and our abstraction. All we need to do is follow the basic DIP principle and provide the string as a parameter to the class that calls the database. We certainly don't need (or want, for that matter) to introduce a new interface or base class at this point. Our abstraction is simple enough to use a common type found in the .NET framework. Other Forms Of Abstraction Even if we are talking about an object, who says that the interface we are depending on has to be an explicit interface construct or base class? When I write a Domain Service that uses an Entity from my Domain, I don't create an explicit interface for that Entity. Rather, I use the Entity's inherent interface - it's public methods, properties, etc. I also use delegates on a regular basis. By specifying my abstraction as a delegate, I can further decouple the depending object from the dependant code that it needs to call. I'd be willing to bet you have used delegates as abstractions as well. Have you ever created an event handler for something like a button click? There's a delegate's abstraction at work. Abstract Judgement The point is, there is not always a need to introduce an explicit interface or base class when inverting our dependencies. We still need to apply dependency inversion and provide our implementation as a constructor parameter (or setter, though I don't like setter injection). But, that dependency doesn't have to be anything more than the interface inherent to the object, or a simple type found in .NET. You do have to be careful when making the call to not use an explicit abstraction with DIP, though. You can quickly turn your system into a ball of mud if you rely on a concrete class that is not intention revealing or well encapsulated to begin with. At the same time, too many abstractions can lead to needless complexity and make it very difficult to see the big picture of a system. Too few abstractions, though, will certainly lead to a rigid, immobile design that is hard to change. All of these problems are equally vicious - and I've been bitten by all of them in recent months. It takes good judgement calls to determine when you do and do not need an explicit abstraction for a dependency. Unfortunately, good judgement comes from experience and experience comes from bad judgement. Don't be afraid to make bad decisions - make a decision, just be sure you can reverse that decision as easily as possible.
Let's say I have a small hierarchy of object: Faults and Parts. A Fault can contain many parts, and a part has no meaning without being associated to a Fault. To ensure that I have no Parts without a parent Fault, I have this basic code in place: public class Part { private Part() { } public string Description { get; set; } } public class Fault { private IList<Part> _parts = new List<Part>(); public IList<Part> Parts { get { return _parts; } } public Part CreatePart() { Part part = new Part; _parts.Add(part); return part; } }
This ensures that I never have a Part in an "invalid" state - without an owning parent.
I also have a business rule that say that I'm not allowed to have a Part without a description. My typical implementation of this business rule has been in the UI layer - my Presenter would have the logic to require a user to enter a description when creating adding a part to a fault.
public class PartCreationPresenter { Part _part; public PartCreationPresenter(Part part) { _part = part; } public DescriptionProvided(string desc) { if (string.IsNullOrEmpty(desc)) { view.ShowDescriptionRequiredMessage(); } else { _part.Description = desc; } } }
Here's the question:
Should this "require a description" logic be in the UI layer (Presenter) the way I have it, or should I put it in the Part object and have an IsValid flag of some sort on that object?
I don't like having this coded in the presenter only. It makes the business rule very easy to break - create a part from anywhere else, and you can ignore this rule. But I'm not sure I like it in the Part object, because it would make the presenter difficult to code. How would I execute the specific view.ShowDescriptionRequiredMessage() method if the rule is coded in the Part?
Any opinions, suggestions, articles, etc. are very welcome. I'm very interested in hearing how other people are handling this situation.
FYI - I'll be giving my S.O.L.I.D. Software Principles presentation at the Austin .NET User Group on Monday the 13th. This is the same presentation that I gave at Pablo's Day(s) of TDD last weekend, except I'll have the missing code in place and the slide errors fixed. Here's the abstract that was posted via the ADNUG mailing list: S.O.L.I.D. Software Development: Achieving Object Oriented Principles, One Step At A Time Almost every professional software developer understands the academic definitions of Coupling, Cohesion, and Encapsulation. However, many of us do not understand how to actually achieve Low Coupling, High Cohesion, and strong Encapsulation, as prescribed. Fortunately, there are a set of stepping stones that we can use to reach these end goals, giving us a clear cut path to software that is easier to read, easier to understand, and easier to change. This presentation will define not only the three object oriented goals, but also the five S.O.L.I.D. principle that lead us there, while walking through a sample application. At some point this week or next, I will have my slides and code posted for people to download. (I know I promised this at PDoTDD. I got busy. Sorry). And as usual, there will likely be a group of people heading to Rudy's after the meeting, for extended discussions and snappy banter.
A few months ago, I posted some thoughts and questions on the proper use of Inversion of Control (IoC) containers and the Dependency Inversion (DI) principle. Since then, I've had the opportunity to do some additional study and teaching of DI, and I've had that light bulb moment for the proper use of an IoC container. I haven't talked about it or tried to present the info to my team(s) yet, because I had not verified my thoughts were on the right track - until recently. I got to spend a few hours at the Dovetail office with Chad, Jeremy, Josh, etc, and had the pleasure of being able to pick their brains on some of the questions and thoughts that I've had around DI and IoC. In the end, Chad confirmed some of my current thoughts and helped me put into a metaphor that I find to be very useful in understanding what Dependency Inversion really is - a cloud objects that can be strung together into the necessary hierarchy, at runtime. Consider a set of classes that need to be instantiated into the correct hierarchy so that we can get the functionality needed. It's really easy to have the highest level class - the one that we really want to call method on - instantiate the class for next level down, and have that class instantiate it's next level down, and so-on, like this: This creates the necessary hierarchy, but breaks the core object oriented principle of loose coupling. We would not be able to use ThisClass without bringing ThatClass along with it, and we would not be able to use ThatClass without bringing AnotherClass along with it. By introducing a better abstraction for each class and putting Dependency Inversion into play, we can break the spaghetti mess apart and introduce the ability to use any of these individual classes without requiring the specific implementation of the dependent class. For starters, let's introduce an interface for ThisClass to depend on and an interface for ThatClass to depend on. Now that we have an interface that both of these classes can depend on, instead of the explicit implementation of the child object, we need to have the expected child object implement the interface in question. For example, we expect ThatClass to be used by ThisClass, so we will want ThatClass to implement the IDoSomething interface. By the same notion, we want AnotherClass to implement the IWhatever interface. This will allow us to provide AnotherClass as the dependency implementation for ThatClass. Our object model now looks like this: What we have now is not just a set of classes that all depend on each other, but a "cloud" of objects with dependencies and interface implementations that will let us build the hierarchy we need, when we need it. The real beauty of this is that we no longer have to care about the implementation specifics of IDoSomething from ThisClass. ThisClass can focus entirely on doing it's duty and calling into IDoSomething when it needs to. And, by passing in the dependency as an abstraction, we're able to replace the dependency implementation at any time - runtime, unit test time, etc. This also makes our system much easier to learn and understand, and most importantly - easier to change. Now that we have our cloud of implementations and abstractions in place, we will need to reconstruct the hierarchy that we want so we can call into ThisClass and have it perform it's operations. Here's where Dependency Inversion meets up with Inversion of Control. - To create ThisClass, we need an implementation of IDoSomething
- ThatClass implements IDoSomething, so we'll instantiate it before ThisClass
- ThatClass needs an instance of IWhatever
- AnotherClass implements IWhatever, so we'll instantiate it before ThatClass
- Once we have AnotherClass instantiated, we can pass it into ThatClass's constructor
- Once we have ThatClass instantiated, we can pass it into ThisClass's constructor
We end up with a hierarchy of objects that is instantiated in reverse order, like this: We have now successfully inverted our system's construction - each implementation detail is created and passed into the the object that depends on it, re-creating our hierarchy from the bottom up. In the end, we have an instance of ThisClass that we can call into, with the same basic hierarchy of classes that we started with. The real difference is that now we can change this hierarchy at any time without worrying about breaking the functionality of the system. Once we have our Dependency Inversion and Inversion of Control in place, we can start utilizing the existing IoC frameworks to automatically create our hierarchy of objects based on the advertised dependencies (an advertised dependency is a dependency that is specified as a constructor parameter of a class). Tools like StructureMap, Spring.net, Windsor, Ninject, and others, all provide automagic ways of creating each dependency of the object that is requested, all the way up/down the hierarchy. Utilizing one of these IoC containers can greatly simplify our code base and eliminate the many object instantiations that would start to liter our code. As I said in my previous post, I know all about what not to do with IoC containers. Good IoC usage, though, is another subject for another post.
I've seen this question a lot recently, and Scott Bellware asks it again in response to a post by Jimmy Bogard. "Ok, but why are "contracts" important? I can write concrete classes that interact with each other just fine without interfaces. And as Roy has already demonstrated, you don't need interfaces for test-focused SoC. To wit, any concrete class's signature is a contract with its user." -- Scott Bellware First - a small psychology lesson in Cognitive Load theory and Chunking. A human brain can only hold so much information in it's short term memory. The "magic number" of 7 (+/- 2) has often been touted as the average number of concepts that a person can hold in short term memory, and still understand what's going on. ... and we need to recognize this in our code. If a developer who is reading the code has more than 7 (+/- 2) concepts, then that developer is not likely to understand the code they are reading. If you can't understand the code, you can't maintain the code. It's as simple as that. So why are contracts important? An intention-revealing interface, as a contract, can significantly reduce the cognitive load that is required to understand the code in question. Abstraction and dependency inversion via interfaces help us achieve this understandability by letting a developer's mind chunk a process into what's really important - the "when" and "what" of the process, ignoring the "how". If you eliminated all abstractions and interfaces - even the interfaces that have only one implementation - you are telling a developer that they need to know the details of "how", not just the abstraction of "when" and "what". This puts an additional load on any persons' brain, and can quickly overload the person reading the code. These theories go so far beyond just code, in software. When was the last time you saw a web site that had more than 8 or 9 buttons in it's navigation/menu, and you thought it was an intuitive and easy to use site? I'd be willing to bet that you thought the site was poorly organized and difficult to navigate. Interaction design is usually the first place that people apply cognitive load and chunking theories. Unfortunately, it's also usually the last. We need to break this cycle of overloading ourselves and our coworkers, and create proper abstractions in our code that fit easily within our own cognitive load, but more importantly in the cognitive load of other developers who have to read/maintain the code.
I gave a presentation to my team on S.O.L.I.D. software development principles, talking about how these five principles enable us to achieve High Cohesion, Low Coupling, and proper Encapsulation in our software projects. If you're unfamiliar with the SOLID principles, they are: - SRP: Single Responsibility - One reason to exist, one reason to change
- OCP: Open Closed Principle - Open for extension, closed for modification
- LSP: Liskov Substitution Principle - An object should be semantically replaceable for it's base class/interface
- ISP: Interface Segregation Principle - Don't force a client to depend on an interface it doesn't need to know about
- DIP: Dependency Inversion Principle - Depend on abstractions, not concrete detail or implementations
You can find a lot of good info on SOLID via Robert Martin (the man who coined the acronym) and the Los Techies crew: The final slide in my presentation shows the before and after of migrating a small app that reads a file and sends an email, from being 100% coded in the Winforms code, to a SOLID code structure. During the summary / review, I related the five SOLID principles to High Cohesion, Low Coupling, and Encapsulation through these descriptions: Low Coupling: By abstracting many of our implementation needs into various interfaces and introducing the concepts on OCP and DIP, we’ve created a system that has very low coupling. Many of these individual pieces can be taken out of this system with little to no spaghetti mess trailing after it. Separating the various concerns into the various object implementations has also helped us ensure that we can change the system’s behavior as needed, with very little modification to the overall system – just update the one piece that contains the behavior in question. High Cohesion: This really is a direct result of low coupling and SRP – we have a lot of small pieces that can be stacked together like building blocks to create something larger and more complex. Any of these individual pieces may not represent much functionality or behavior, but then, an individual piece isn’t much fun to use without a bunch of other pieces. DIP has also allowed us to tie the various blocks together by depending on an abstraction and allowing that abstraction to be fulfilled with different implementations, creating a system that is much greater than the mere sum of it’s parts. Encapsulation: True encapsulation is not just making fields private and hiding data from external objects – but hiding implementation details from other objects, depending only on the abstractions and expected behaviors of those abstractions. LSP, DI, and SRP all work hand in hand to create true encapsulation in the new project structure. We’ve encapsulated our behavioral implementations in many individual objects, preventing them from leaking into each other – and we’ve ensured that the dependency on those behaviors is encapsulated behind a known interface. We’ve hidden the implementation details and allowed for any implementation to be put in place for that interface definition through DIP. At the same time, we’ve done the necessary due-diligence to ensure that we are not violating any of the individual abstraction’s semantics or purpose (LSP), ensuring that we can properly replace the implementation as needed. The end result of our effort has created a system that appears to be complex on the surface – after all, there’s now 13 blocks in our diagram compared to the original 2. However, the apparent complexity of this system is diminished by the simplicity of each individual interface and object. Many small, independent, simple pieces have been wired together to create a larger overall system behavior that can be described as complex. Yet any of these implementations can be changed and/or replaced – very easily. At some point, I'm hoping to post the entire slide deck and presentation / code, but for now I thought the summary that I sent to the team was worth sharing with the rest of the world.
A Food Network Challenge During this season's 'The Next Food Network Star', there was an episode where the contestants had to cook a dish and review it in front of a camera, describing it's visuals and taste. The twist to the challenge was that they were assigned someone else's dish to review, after everyone had already cooked. Once the assignments were made for who was going to describe who's dish, they were not allowed to see the dishes anymore. A given contestant was then put in front of a camera and had their assigned dish uncovered in front of them. From that point, they had 90 seconds to describe the dish that was in front of them - that included figuring out what it was, what it looks like, what it tasted like and what it smelled like. This was a rather tough challenge to watch, and a few of them didn't do so well. A Code Review Challenge What if we take the Next Food Network Star's challenge and apply it to code reviews? When we sit down in a code review session, rather than having the person who wrote the code doing the driving and telling us what is going on, have someone who has not seen the code do the driving - read the code, read the unit tests, etc - and describe to us what is going on. 90 seconds wouldn't be nearly enough time, though, so we'd have to change that time limit based on the size and complexity of the functionality being reviewed. Other than that, though, it seems like it would be a great way to test the team's ability to pick up an area of the system that they have not seen before and quickly learn it so that they can work in it. Standardized Work - Judging Code And Code Reviewer There are 2 real benefits to the code review challenge, as I see it: - Judging how well did the coder apply our coding and development standards
- Judging how well the reviewer can recognize and describe the standards being applied
We are now building our system from User Stories, with Context / Specification style unit testing. One of the intents of this style of unit testing is to provide an easy-to-read and easy-to-learn set of examples for developers that need to know how to do something or how something works in the system. If the unit tests are properly written and expressive of the code's intent - it should be really easy to see what's going on. If we have good standards in place, a developer should be able to find the code in well organized areas, easily, and know where to look for the various components and parts. It seems to me that the code review challenge would help to prove a number of these key factors in our projects and our teams: - Coding and architecture standards
- How well the standards are known
- How well the team follows the standards
- Expressive Code
- How easy is it to read the code
- How easy is it to understand the code's intent
- Maintainable Code
- How easily can the code be changed and extended
- How quickly the team can socialize and collectively own the system
A Challenge In Name, A Learning Experience In Practice I would avoid applying any sort of point system or other reward / incentive for the code reviews. It seems that this could easily backfire and cause junior team members (in skill or time on the team/project) to feel intimidated or feel that it's an unfair process comparing them to the senior level team members. The intention of the code review challenge is not to cause dismay in any team member, but to create a learning environment by continuously challenging every member of the team. Ultimately, the code review challenge should foster the socialization of the system and lead to a strengthened sense of collective ownership, resulting in a better system. Nothing New Under The Sun? With all that being said - I'm doubtful that I'm the first person to ever hold a code review like this. I'd be interested in knowing if there's any standard development practices (Agile or otherwise) that are heading in the same direction. Any advice or opinions of you, the reader, would also be very welcomed. If you know of a resource that describes the same basic ideas or if you have any input to help me improve the idea, please leave a comment and let me know.
Test Driven Development Is To Unit Testing As Interaction Design (IxD) Is To Accidental Design One of the major problems with writing unit tests after the code is that it is very natural to write tests that prove the code works the way it was written, instead of the way it should work. Writing code test-first (via whatever flavor of Test Driven Development) flips that scenario right side up. TDD helps to ensure that code is written to work according to specifications and not the other way around. Similarly, designing and/or implementing a UI after a behavior or process has been coded is a likely to result in a UI that fits the code model and not a model that fits the needed interaction and workflow. This situation must also be flipped right side up - interaction design should be done before, or at least in parallel, with coding. It cannot be left to accidental or incidental happenstance - interaction design must occur with proper interaction patterns and practices in mind. Overlapping IxD and TDD To overlap interaction design and test driven development, there are a few key words that need to be borrowed from interaction design. Fortunately, they easily fit within TDD development techniques and philosophies. Epistemic work is exploratory in nature, or a process of trial and error through research. TDD and interaction design sketching are both epistemic. TDD explores API possibilities and allows easy trial and error to find the simplest implementation for what you need at the time. UI design sketches also allow you to quickly explore interaction designs - whether it's a white board, pencil and paper, graphics design software, or even quick-hack forms layout in IDEs. You can quickly and easily throw away a bad API in TDD and you can quickly and easily throw away a bad UI/Interaction design when you have nothing more than pencil sketches or white board drawings. Pragmatic work is very structured and step-by-step in it's nature, implementing patterns and practices to fulfill what is needed at the moment. Implementing Code after writing unit test and implementing UI after designing around constraints are both pragmatic. TDD is pragmatic in that you only implement what is needed to properly pass the tests that have already been written. Similarly, with previously designed interactions and UI elements, implementation can be easily limited to what is needed for the UI. With epistemic and pragmatic work covering both interaction design and test driven development, it seems that they are a natural pair. An analysis of a user story and it's acceptance criteria will create the unit tests that we need. At the same time, the same analysis can be applied to interaction designs. Additionally, a strong understanding of how a UI will look can have a profound impact on the code that is written, and vice-versa. Therefore, it is natural that interaction design and test driven development are done at just-in-time intervals - before the real work is implemented in the real code and UI platform. IxD As Part of "Done" Despite interaction design being a required part of UI development, not all user stories require a UI. Interaction design may not fit into a swim lane board or be part of every story's "done" criteria. However, interaction design will always be done for any story that does have a UI - it may simply be an accidental or incidental part of the software development process for a team, though. If it's safe to assume that the work will be done, then it is the team's responsibility to ensure that it is done correctly. Don't let interaction design happen accidentally or incidentally in the development process. Set a standard of always including interaction design in the development process, the same way Model View Presenter/Controller is a part of development.
Earlier this week, I was doing a training session with my current team, building a sample Org Chart application. One of the user stories we were working with, talked about assigning managers to department and had the following acceptance criteria: - When assigning a manager to a department, ensure that they are an employee of that department, and remove them from their old department
The basic code that we came up with worked well and was encapsulated into a service object in the domain. public class AssignmentService { private IDepartmentRepository _repository; public AssignmentService(IDepartmentRepository repository) { _repository = repository; } public void AssignManagerToDepartment(Employee manager, Department assignedDepartment) { Department previouslyAssignedDepartment = _repository.GetDepartmentForEmployee(employee); if (previouslyAssignedDepartment != assignedDepartment) { previouslyAssignedDepartment.RemoveEmployee(manager); _repository.Save(previouslyAssignedDepartment); } assignedDepartment.AssignEmployee(manager); assignedDepartment.AssignManager(manager); _repository.Save(assignedDepartment); } }
Problems
At first glance, this code seems simple enough, but we quickly ran into a problem when we started coding for another story and acceptance criteria.
- When creating a department, allow a manager to be assigned
Off-hand, this seems like a very simple situation. We'll just call the AssignmentService object after we create the Department. However, there's a large potential problem with this - the AssignmentService handles the entity persistence for both of the departments that were changed, when the manager is assigned. With that in mind, the developer working on the new requirement would have to ensure that the department is created with all of it's required fields and information before calling this service object. If the developer allows the manager to be assigned before the department's info has been completely filled in, we may accidentally allow an invalid state for a department object when calling the AssignmentService. Since the AssignmentService tries to save the department being assigned, we may also have created an semantic coupling between the department creation process and the AssignmentService - the developer needs to know that the AssignmentService will save the department. If they don't know this, they may try to save the same entities more than once, may try to save an invalid state, etc, etc, etc.
Unfortunately, we didn't have time to fix the problem during the training session - we had to stop the training almost immediately after we discovered this issue. I've got a few ideas running around in my head, on how to fix this, but I'm not 100% sure that I like any of them.
Possible Solutions
First and foremost, though, it's becoming rather apparent to me that we want to avoid entity persistence calls from within the domain service objects. This essentially means that the AssignmentService object would have to return the assigned department, and the 'previously assigned department' objects, so that the coordinating presenter could save them both. That seems a little odd, if you ask me.
One of my coworkers suggested that we allow the service to save the previously assigned department, since that is an self-contained operation in the method (the method loads the department, modifies it, and saves it) and then return the assigned department so that the presenter can save it. This option seems a bit better off-hand, but I'm still worried about the possible side effects of the AssignmentService saving the previously assigned department.
Questions
What are your thoughts on this situation... How would you solve the dilemmas that I'm pointing out? Is there a better design for the model that would eliminate this problem and make the department persistence more obvious, without having to 'know' when it is persisted?
Is the idea of not allowing entity persistence from a domain service object valid? Should we go with allowing the self-contained operations to persist the entity in that operation?
Or ???
During a TDD/BDD training session with my team, today, we wrote the following code: public void SaveRequested() { Employee employee = Department.CreateEmployee(firstName, lastName, email); if (employee == null) repository.Save(Department); }
I ignored this when we first wrote it, as it was "technically correct", but later returned to this code as a point of refactoring for greater insight and expressiveness. When we came back to it, though, I started off by asking a series of questions:
- Why would that method return a null?
- Why would it not return a null?
- Why is it important to not call repository.Save if the employee is null?
The code is essentially a mystery to anyone that hasn't memorized the details of the Department.CreateEmployee method. Worse yet, I can make a lot of assumptions about this code - but every one of them is going to be wrong until I can prove that they are right by reading the code in Department.CreateEmployee.
So how do we refactor this code for better insight and more expressiveness? How do we change this code so that the assumptions a reader creates in their own mind are more likely to be correct - or better yet, are irrelevant because you don't need to even care about the details of the Department.CreateEmployee method? First and foremost, you need to understand what this code is supposed to be expressing - what it's supposed to be doing and why. If you don't know, you need to ask the person that wrote it. If they don't know (or aren't around), you need to find someone that can help you determine the intended behavior. Ultimately, you may need to dig into the Department.CreateEmployee method to figure it out for yourself.
In this situation, we were trying to express some business rules from a set of acceptance criteria on a user story:
- When creating an employee, the employee must belong to a department
- When creating an employee, require a first name, last name, and email address
This code is a factory method on the Department object that is used to ensure these rules are satisfied. In this case, if CreateEmployee returns a null, one of these rules was violated and we should not attempt to save the Department (with the associated employee, or lack there-of). If CreateEmployee returned an employee, we satisfied the rules and we can save the Department and it's associated employees.
The code that we have in place doesn't express any of that intent, though. What we really want is code that tells us that the employee creation failed - and probably why it failed. Fortunately, the changes can be extraordinarily simple.
public void SaveRequested() { EmploymentResult employmentResult = Department.Employ(firstName, lastName, email); if (employmentResult.Success) { repository.Save(Department); } else { view.DisplayError(employmentResult.FailureReason); } }
UPDATE: Thanks to Martin Linkhorst for the comments, and making this code even more expressive (changing from Department.CreateEmployee to Department.Employ)
By creating an AddEmployeeResult object and supplying a few additional bits of information in it, our code became much more expressive of it's intent. We can now read the SaveRequested method and have a much better chance of knowing what it is really doing - try to create an employee and if it successfully created, then save it. Otherwise, display the failure reason.
What assumptions does your code create in the minds of the readers? Are these assumptions correct, incorrect, or unintelligible? And finally, what can you do to make your code assumption-free and/or assumption-irrelevant?
Over the weekend, I spent some time refactoring some business rules in my current project, to use the ISpecification<t> framework that I previously created. One of my coworkers had asked about logical groupings - making sure that we can handle complex logic such as, "(this and this) or this". Since my project actually made use of logical groupings I wanted to share with the world and show how easy it is. In this example, I have a Date Range that is being selected – a From date and a To date. The rules are as follows for validating the range: - If a From date and a To date are provided, the From date must be equal to, or before, the To date
- Or, you can specify a From date without To date
- Or, you can specify a To date without From date
The following is the actual code that I’m using to define these business rules, via the ISpecification<t> framework. PredicateSpec<ExtractSearchCriteria> fromDateProvided = new PredicateSpec<ExtractSearchCriteria>(crit => crit.FromDate > DateTime.MinValue); PredicateSpec<ExtractSearchCriteria> toDateProvided = new PredicateSpec<ExtractSearchCriteria>(crit => crit.ToDate > DateTime.MinValue); PredicateSpec<ExtractSearchCriteria> fromDateBeforeToDate = new PredicateSpec<ExtractSearchCriteria>(crit => crit.FromDate <= crit.ToDate); ISpecification<ExtractSearchCriteria> validDateRangeSpec = ( (fromDateProvided.And(toDateProvided)) .And(fromDateBeforeToDate) ) .Or( fromDateProvided.Not(toDateProvided) ) .Or( toDateProvided.Not(fromDateProvided) );
Here, I am defining the core of the business rules – to check if the From date was provided, to check if the To date was provided, and to check if the From date is before or equal to the To date. From these core specifications, I can build the aggregate spec that handles all of the stated rules for validating the date range.
There are three logical groupings using parenthesis to represent each of the business rules that can comprise a valid date range. The first logical grouping checks to see if both a From and To date are provided, and checks if the From date is before or equal to the To date, if both are provided.
( (fromDateProvided.And(toDateProvided)) .And(fromDateBeforeToDate) )
The second group is specified with an Or, and checks to see if we provided a From date but not a To date.
.Or( fromDateProvided.Not(toDateProvided) )
And the third group also uses an Or, and checks to see if we provided a To date but not a From date.
.Or( toDateProvided.Not(fromDateProvided) )
The end result is that we have one of three possible ways for this date range to be valid – all logically grouped and relatively easy to read (compared to a bunch of if-then statements, at least). Even better – we re-used two out of three simple ISpecification<t> objects to create all of the rules for this validation check. This helps to create a validation that is not only easier to read, but easier to maintain and enhance in the future.
My Previous Post talked about a sample Specification pattern implementation. Today, during a discussion with some team members, I had the revelation of how fluent interfaces are really built and how they operate under Closure of Operations. So I decided to expand my previous sample code with a more operators on the spec class, and I came up with a very powerful fluent interface for creating specifications. Here is the example I coded into my spike, to illustrate a fluent interface. Note that I changed nothing in my implementation of the ISpecification<t> or base Specification<t> from yesterday - other than to add the "Or" and "Not" specifications. The fluent interface was already there and available! //show the real power of Closure Of Operations, in creating a fluent interface! ISpecification<Foo> chainedSpec = equalSpec .And(passingSpec.And(trueSpec)) .Or(passingNotSpec) .Not(failingSpec.Or(falseSpec)) .And ( passingSpec.Or ( failingSpec.Not(falseSpec) ) );
I'll leave it to you, the reader, to implement the "Or" and "Not" specification classes. It should be pretty simple, based on the code I posted yesterday.
I can see how we could easily use an a "Closed" interface like this, to create a more fluent implementation of business rules and logic. I've often implemented multiple if-then statements in order to evaluate equality and equivalence, via multiple methods and a lot of ugly code. This specification implementation may be the answer to that ugliness.
And suddenly, Ayende's UnitOfWork and NHibernate's ICriteria make a lot more sense to me... I love those "AHA!" moments. 
Inspired by my recent readings in Domain Driven Design - specifically Chapter 10, "Supple Design" - and recent posts by David Laribee and Nigel Sampson, in combination with the recent pains I've been putting myself through, trying to test query generation code in a search screen, I decided to spike out a quick example of a reusable Specification implementation. Rather than repeat what's already been said, I'm just going to get straight to the code. using System; namespace Spec_Spike { class Program { static void Main() { Foo foo1 = new Foo(); foo1.Bar = "Test"; ISpecification<Foo> equalSpec = new Specification<Foo>(foo => foo.Bar == "Test"); ISpecification<Foo> notEqualSpec = new Specification<Foo>(foo => foo.Bar != "Not Equal To This Text"); ISpecification<Foo> falseSpec = new Specification<Foo>(foo => false); ISpecification<Foo> passingSpec = equalSpec.And(notEqualSpec); ISpecification<Foo> failingSpec = passingSpec.And(falseSpec); Console.WriteLine(equalSpec.IsSatisfiedBy(foo1)); Console.WriteLine(notEqualSpec.IsSatisfiedBy(foo1)); Console.WriteLine(passingSpec.IsSatisfiedBy(foo1)); Console.WriteLine(failingSpec.IsSatisfiedBy(foo1)); } } public class Foo { public string Bar; } public interface ISpecification<t> { bool IsSatisfiedBy(t obj); ISpecification<t> And(ISpecification<t> lhs); } public class Specification<t>: ISpecification<t> { private readonly Predicate<t> _pred; public Specification(Predicate<t> pred) { _pred = pred; } protected Specification(){} public virtual bool IsSatisfiedBy(t obj) { return _pred(obj); } public ISpecification<t> And(ISpecification<t> andSpec) { return new AndSpecification<t>(this, andSpec); } } public class AndSpecification<t>: Specification<t> { private readonly ISpecification<t> _spec1; private readonly ISpecification<t> _spec; public AndSpecification(ISpecification<t> spec1, ISpecification<t> spec) { _spec1 = spec1; _spec = spec; } public override bool IsSatisfiedBy(t obj) { return (_spec.IsSatisfiedBy(obj) && _spec1.IsSatisfiedBy(obj)); } } }
Drop this code into a console app in C# 3.5 and watch the magic happen. Here's the output:
These are the results that I expected - the first 2 individual specs passed, the first combined spec passed, and the last combined spec failed.
Overall, I'm fairly excited about the possibilities here. I'm thinking that I may actually be able to properly unit test the query generating code in my search screen with this basic technique. I'm still not 100% sure on that, but I plan on trying, anyway.
For more information on the Specification pattern, I highly recommend you read the previously linked posts by David Laribee and Nigel Sampson, in addition to reading all of the Domain Driven Design Book. This is one of those books that should fundamentally change the way you think about software development.
I'm currently working on a search screen for a shipment tracking system. At the bottom of this screen, there are 4 checkboxes that will determine whether or not we are supposed to display Imports, Exports, Air shipments, or Ocean shipments - in whatever combination the user wants: Down in the depths of the search process, I am creating a "finder" object, as Ayende talked about quite a while back. In this object, I have to account for the checkbox values here - whether or not the user wants to display whatever types of shipment (import or export) and/or the method of shipment (air or ocean). What gets really interesting is that when a box is un-checked, I should not show that particular type or method. A quick analysis of these 4 checkboxes will come up with the following variants that must be accounted for when building the query. - Show Imports Only
- Ocean and Air
- Ocean only
- Air Only
- Show Exports Only
- Ocean and Air
- Ocean only
- Air only
- Show Imports and Export
- Ocean and Air
- Ocean only
- Air only
- Show no imports or exports (returns no results)
- Show no ocean or air (returns no results)
All totaled up, that's 11 different query variants that have to be accounted for. The end result of my query build methods is the following: private void AddShipmentMethodCriteria(DetachedCriteria criteria) { ICriterion air = Restrictions.Eq("ShipmentMethod", "Air"); ICriterion ocean = Restrictions.Eq("ShipmentMethod", "Ocean"); if (searchCriteria.ViewAirShipments && searchCriteria.ViewOceanShipments) criteria.Add(Restrictions.Or(air, ocean)); else { if (searchCriteria.ViewAirShipments) criteria.Add(air); else criteria.Add(Restrictions.Not(air)); if (searchCriteria.ViewOceanShipments) criteria.Add(ocean); else criteria.Add(Restrictions.Not(ocean)); } } private void AddShipmentTypeCriteria(DetachedCriteria criteria) { ICriterion import = Restrictions.Eq("ShipmentType", "Import"); ICriterion export = Restrictions.Eq("ShipmentType", "Export"); if (searchCriteria.ViewImports && searchCriteria.ViewExports) criteria.Add(Restrictions.Or(import, export)); else { if (searchCriteria.ViewImports) criteria.Add(import); else criteria.Add(Restrictions.Not(import)); if (searchCriteria.ViewExports) criteria.Add(export); else criteria.Add(Restrictions.Not(export)); } }
By having the first If statement check for both 'Import' and 'Export' being requested, we can properly create our query to show both of them via the Restrictions.Or() criteria. Additionally, we have to account for either or both of them not being checked and explicitly call them out to say that we do not want to show whichever one is not selected. The same is true for the 'Air' and 'Ocean' shipment methods.
The end result is that the user can select or un-select whichever shipment methods and shipment types they want, resulting in the correct data being displayed.
...
On a side note, there's probably some abstraction that I could create where I pass in the ICriterions and the boolean flags to help reduce code redundancy but that's not the point of this post. I'm really trying to illustrate the complex logic used in creating the correct NHibernate ICriteria/DetachedCriteria, and the analysis that you need to undertake for what looks like the most simple of situations. After all, how hard could it be to create a query based on 4 check boxes? ... more difficult than you might imagine, at first. Take the time to analyze even simple scenarios like this.
|