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.
I had a lot of fun giving my SOLID Principles presentation at the Austin .NET User Group last night. It was a pleasure and an honor to be able to give back to the community that has supported me for so many years. I'd like to thank everyone that came out to see the presentation, for being such a great audience. There were a lot of great questions and comments and good discussion. I sincerely hope that I've inspired at least a few people to continue digging into the SOLID principles. As promised, I've posted my slides and the example code for download. Additional resources for SOLID: For the questions on legacy code from last night: If anyone has any questions about the SOLID principles, would like more information, etc, please feel free to contact me via the contact link on my blog(s) or via my email address listed at the end of the slides.
A coworker just asked me this question - what's the point of delegates in .NET? My answer was very short and one that he had not found online: to delay execution of a method. Consider this: if you pass a Method2 as a parameter to Method1, Method2 is evaluated immediately and the result is passed into Method1. public class SomeObject { public void Method1(int someValue) { //... code here } } ... someObject.Method1(anotherObject.Method2());
Additionally, Method2 must have a return value (not void) so that the value returned from Method2 can be passed as the parameter of Method1.
With a delegate, though, we get method pointers that can be used to delay the execution of the method in question until it's needed (if at all). We can also get rid of the requirement for a return value and we can pass values that were created by the host method, into the delegate method.
public class SomeObject { public void Method1(Action<int> someAction) { //.. do some stuff here int aValue = GetTheValueFromSomeWhere(); someAction(aValue); //... do some more here } } public class AnotherObject { public void Method2(int aValue) { //do something that is dependent on aValue, here. int i = aValue + 1; // or anything else that needs aValue. } }
FYI - Action (void return; with many parameterized variations) is a delegate that is build into .NET 3.5, along with Func<T> (return value of type T; with many parameterized variations). These are the two most common delegates that I use in my code.
Most .NET developers have used delegates without realizing it, too. The event system in .NET is nothing more than a multi-cast delegate - a delegate that points to more than one method - with a special signature and syntax (depending on the language being used).
There's a lot of good use for delegates. And like any other tools, there's a lot of bad uses. Take the time to learn what they are, how they work, and where they can be beneficial.
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.
It's official - I'm now a member of Los Techies. I will continue to post here, at DerickBailey.com, and will be cross-posting over at Los Techies once I figure out how to do that.  Thanks to Joe, Chad, and everyone else in the Los Techies crew, for the vote of confidence in adding me!
At some point, you will need to put a timer into your C# code. Hopefully you're doing Test Driven Development, or at least unit testing, to cover your need for a timer with a unit test. If you are - I'm betting you ran into some really ugly problems like tests that would not pass without having 'Thread.Sleep(1000)' calls in them. Worse yet - last week, I put a 3 second timer into a class that was being unit tested. This one mistake cause my CruiseControl build to go from 2 minutes, to timing out at 90 minutes because NUnit was keeping the app domain alive while the timer was alive, so it never closed the test run. Oops. To fix this problem, we decided we needed to eliminate the use of an actual timer and use an abstraction that could be mocked/controlled in our unit tests. Unfortunately, the .NET Framework does not have an actual abstraction for a timer. So, if you need to use a timer in your code - and at some point in time, you will - you'll want to create a very simple ITimer interface that would let you control when the timer elapses and fires its registered action. Here's the core of the abstraction that we came up with, initially. public interface ITimer { void Start(Action timerAction); }
With such a simple interface in place, we can now mock it out in our unit tests (I like Rhino Mocks) and set up an expectation on the Start method to capture the timerAction parameter, then simulate the timer elapsing by calling the timer action from our unit test. Here's an example test and 'system under test' to illustrate how we use this interface.
[Test] public void DemonstratingHowToUnitTestATimerElapsing() { Action timerElaspedAction; ITimer timer = MockRepository.GenerateMock<ITimer>(); timer.Expect(t => t.Start(null)).IgnoreArguments().Callback( delegate(Action timerAction) { timerElapsedAction = timerAction; return true; }); MySystemUnderTest sut = new MySystemUnderTest(); sut.StartMonitoringStuff(timer); //here's where we simulate the timer elapsing timerElapsedAction(); Assert.IsTrue(sut.TheTimerActionWasCalled); } public class MySystemUnderTest() { public bool TheTimerActionWasCalled { get; set; } public MySystemUnderTest() { TheTimerActionWasCalled = false; } public StartMonitoringStuff(ITimer timer) { timer.Start(() => TheTimerActionWasCalled = true); } }
There is a bit more detail to the actual ITimer interface, and the implementation, though. We ran into issues where we needed to stop the timer, prevent it from firing after we close the SUT, etc. So, all said and done, here's the full ITimer interface and MyTimer implementation that we ended up with.
public interface ITimer { void Start(Action action); void Stop(); } public class MyTimer : ITimer, IDisposable { private TimeSpan _timerInterval; private Timer _timer; private Action _timerAction; private bool IsRunning { get; set; } public MyTimer(TimeSpan timerInterval) { _timerInterval = timerInterval; } public void Dispose() { StopTimer(); } public void Start(Action action) { _timerAction = action; IsRunning = true; StartTimer(); } public void Stop() { IsRunning = false; StopTimer(); } private void StartTimer() { _timer = new Timer(o => Timer_Execute(), null, 0, Convert.ToInt32(_timerInterval.TotalMilliseconds)); } private void StopTimer() { if (_timer != null) { _timer.Change(Timeout.Infinite, Timeout.Infinite); _timer.Dispose(); _timer = null; } } private void Timer_Execute() { try { StopTimer(); _timerAction(); } finally { if (IsRunning) StartTimer(); } } }
This has worked out very well for us, so far. It lets us put a timer in place when we need one, but not worry about thread racing issues, long running tests, etc.
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.
After some additional Twitter discussion with Jimmy last night, I realized that my previous response had neglected to distinguish between two very important contexts - new code and legacy code. Considering a legacy system (as defined by Michael Feathers), I'm 100% on board with everything Jimmy is talking about and all of the techniques, troubles, and diminishing returns that he identifies. I still maintain that 100% coverage should be the default result of true TDD when writing new code - and I apply this philosophy when writing new code inside of a legacy system. Write a test to prove you need the new code that you are writing... unfortunately, the distinction between new and legacy code does get blurry and can be difficult to navigate when working in a legacy system. For more info on legacy code, in this context, and how to deal with it:
|