Wednesday, July 30, 2008 |
|
|
The marker interface is an interface that is empty. It does not implement any properties nor methods. It is used to mark the capability of a class as implementing a specific interface at run-time. In languages that do not provide support for associating metadata to a class, this approach can be useful. In C#, metadata attributes are available to apply to a class, and according to the .NET Framework 3.5 Design Guidelines for Developing Class Libraries, marker interfaces should be avoided. When I first noticed these marker interfaces in project I immediately thought it was a code smell. It just did not seem "right." Why provide an interface that defines nothing? Why provide a marker interface that implements a non-marker interface? Obviously there must be a reason for this? Two sources encourage me to avoid using marker interfaces and to use attributes in C#. Interface Design and .NET Type Design Guidelines - Interface Design. There advice is to avoid this... public interface IFooAssignable {} public class FooAssignableAttribute : IFooAssignable { // ... }
And to embrace this approach...
[FooAssignable] public class Foo { // ... } public class FooAssignableAttribute : Attribute { // ... }
There appears to be more work involved in writing "good" code.
If I am using "marker" interfaces, I can do this...
if(foo is IFooAssignable) { // ... }
If I am using attributes, I can do something like this...
object[] attributes = foo.GetType().GetCustomAttributes(false); foreach (string attribute in attributes) { if(attribute == "FooAssignable") { // ... } }
Or, thanks to Jarod Ferguson's suggestions on using extension methods and LINQ, I could have this...
public static class AttributeExtensions { public static bool IsAttributedAs<T>(this object obj) { if(obj.GetType().GetCustomAttributes(false).Where(x => x is T).ToList().Count == 1) return true; return false; } } // Then wherever I want to check for the attribute marker... if (foo.IsAttributedAs<FooAssignableAttribute>()) { // ... }
At this point, while "marker" interfaces are a code smell to me, I am still on the fence when it comes to using them versus custom attributes. I will more than likely tend to favor the attribute approach, unless I can prove that the cost of reflection is too expensive for my situation. I admit, I will do what I can to omit marker interfaces, perhaps by using some other interface where possible.
What are you doing in situations like this? Can you offer me a more elegant solution? |
|
|
|
|
Tuesday, April 08, 2008 |
|
|
Duplicate code to me is wrong. Writing duplicate code to me is like using poor grammar. If I am unaware of it, I am none the wiser. However, if I knowingly use poor grammar or duplicate code, I feel bad.
After seeing too many duplications across methods in one or more classes, I decided to investigate a way to remove these. I am always looking to remove duplicate code, even code that shares similarities, I look to refator. Removing duplications is important to adapt more easily to change. When a code change is required, we should only have to make it in one place. The following article will show two relatively simple means to address this code smell, delegates and an Aspect-Oriented approach.
The example I am using in this article is seen below. It is a unit test class, StackFixture class, and it is extremely trivial. This is a typical unit test taken from Test-Driven Development in Microsoft .NET. I have added the logging functionality as an easy means to show how these types of DRY violations can occur. While the duplications in this example deal with logging, they could pertain to other, more complex, functionality as well. The approaches to removing duplications across methods in this article can work with these simple scenarios, as well as more complex ones.
Take for example this sample test case. Each test method logs a message before and after executing the test logic. This violates DRY. We want to keep our test logic in our method, but factor out the duplicate logging. Again, if we were not logging, but doing some repetitive logic, we could factor that out as well.
1: [TestFixture] 2: public class StackFixture : AbstractBaseFixture 3: { 4: private Stack stack; 5: 6: [SetUp] 7: public void SetUp() 8: { 9: stack = new Stack(); 10: } 11: 12: [Test] 13: public void Empty() 14: { 15: Log.Info("Starting Empty test"); 16: 17: Assert.IsTrue(stack.IsEmpty); 18: 19: Log.Info("Ending Empty test"); 20: } 21: 22: [Test] 23: public void PushOne() 24: { 25: Log.Info("Starting PushOne test"); 26: 27: stack.Push("first element"); 28: Assert.IsFalse(stack.IsEmpty, "After Push, IsEmpty should be false."); 29: 30: Log.Info("Ending PushOne test"); 31: } 32: 33: [Test] 34: public void Pop() 35: { 36: Log.Info("Starting Pop test"); 37: 38: stack.Push("first element"); 39: stack.Pop(); 40: Assert.IsTrue(stack.IsEmpty, "After Push - Pop, IsEmpty should be true."); 41: 42: Log.Info("Ending Pop test"); 43: } 44: 45: [Test] 46: [ExpectedException(typeof(InvalidOperationException))] 47: public void PopEmptyStack() 48: { 49: Log.Info("Starting PopEmptyStack test"); 50: 51: stack.Pop(); 52: 53: Log.Info("Ending PopEmptyStack test"); 54: } 55: }
Remove Duplications with Delegates
Quite simply, we can remove our method duplications using a delegate, in this case, the System.Action delegate. Thanks to Ayende for helping me understand this option. We create a method, TestMethod (as shown below), and add it to our StackFixture class. The method takes two strings (string beforeMessage and string afterMessage) and the Action delegate, representing the test method logic. We will call this method within our test cases.
1: public void TestMethod(string beforeMessage, string afterMessage, Action action) 2: { 3: // before 4: Log.Info(beforeMessage); 5: 6: // invoke our method 7: action(); 8: 9: // after 10: Log.Info(afterMessage); 11: }
Then, in our tests, we replace the following test method...
1: [Test] 2: public void Pop() 3: { 4: Log.Info("Starting Pop test"); 5: 6: stack.Push("first element"); 7: stack.Pop(); 8: Assert.IsTrue(stack.IsEmpty, "After Push - Pop, IsEmpty should be true."); 9: 10: Log.Info("Ending Pop test"); 11: }
With the same method using our delegate approach.
1: [Test] 2: public void Pop() 3: { 4: TestMethod("Starting Pop test", "Ending Pop test", 5: delegate 6: { 7: stack.Push("first element"); 8: stack.Pop(); 9: Assert.IsTrue(stack.IsEmpty, "After Push - Pop, IsEmpty should be true."); 10: }); 11: }
We can replace each of our test methods with the same TestMethod using the System.Action delegate. It will then easy to omit our before and after strings replacing them with "action.Method.Name," or some other intelligent logic to determine what to log.
This approach works well, but delegates are often difficult to understand. If this solution suits your needs, make sure the implementation is easily maintainable. What is nice about this approach is how simple it is. There is no need to reference any assemblies outside of the .Net framework, i.e. no third party dependencies.
The Aspect-Oriented Approach
Aspect-Oriented Programming (AOP) is an entirely different animal. It certainly deserves more than just a blog post. Please read more about it online. This article will not explain the details of AOP.
If you are reading this, welcome back. I will assume you are now familiar with AOP. There are several options for AOP frameworks. Some frameworks I have used are Spring.net, Castle Project, and PostSharp. The former two provide IoC capabilities as well. I suggest using a well-supported framework, one with community support and frequent updates. Investigate for yourself, there are several nice options available.
AOP with Castle DynamicProxy
Hamilton Verissimo put together a good sample using Castle's DynamicProxy. It is a nice, clean implementation.This worked fine for me and would work well in other situations. However, in my scenario, if I were to use this approach, I needed to have each of my test classes extend from MarshalByRef. In addition, I would need to modify the underlying NUnit framework to create my proxies in order to provide advice. Since I could not do the latter, or did not want to investigate, I searched for other AOP options.
The DynamicProxy aproach to solving your AOP needs is a great option. It just did not work in my situation, only because NUnit executes each of my methods. I would need to somehow intercept the creation of my test class, create a proxy of it, and execute the test methods on it.
AOP with PostSharp
Gael Fraiteur's PostSharp is a great option for AOP needs. It is extremely clean and easy to use. It is the simplest AOP framework I have used. I suggest watching Gael's video tutorial.
The first thing I needed to do, besides downloading and installing PostSharp, is to add two references to my project, PostSharp.Laos and PostSharp.Public. After that, I create a simple class extending OnMethodInvocationAspect, called LoggingMethodInvocationAspect.
1: [Serializable] 2: public sealed class LoggingMethodInvocationAspect : OnMethodInvocationAspect 3: { 4: private ILogger log; 5: 6: public LoggingMethodInvocationAspect(ILogger logger) 7: { 8: log = logger; 9: { 10: 11: public override void OnInvocation(MethodInvocationEventArgs eventArgs) 12: { 13: // before 14: log.Info("OnInvocation Before proceed"); 15: 16: // invoke 17: eventArgs.Proceed(); 18: 19: // after 20: log.Info("OnInvocation After proceed"); 21: } 22: }
At this point, all we need to do is apply our aspect on target methods. The "AttributeTargetMembers" attribute can use wildcards. This tells the AOP framework to only intercept those methods in the "MathService" class that start with "Test." Below is the sample where I specify the target assembly, target type (class or classes to intercept), and target methods to intercept. There are many features beyond what I am showing so do further investigation.
1: [assembly: ClassLibrary.SampleInterfaces.LoggingMethodInvocationAspect( 2: AttributeTargetAssemblies = "ClassLibrary.UnitTesting.Sandbox", 3: AttributeTargetTypes = "ClassLibrary.UnitTesting.Sandbox.MathService", 4: AttributeTargetMembers = "Test*")]
Finally, my StackFixture class now looks something like this. Notice that the duplicate logging logic is now removed and each test method is prefixed with "Test" in the method name. This is so that PostSharp can filter what methods to intercept.
1: [assembly: ClassLibrary.SampleInterfaces.LoggingMethodInvocationAspect( 2: AttributeTargetAssemblies = "ClassLibrary.UnitTesting.Sandbox", 3: AttributeTargetTypes = "ClassLibrary.UnitTesting.Sandbox.MathService", 4: AttributeTargetMembers = "Test*")] 5: 6: [TestFixture] 7: public class StackFixture 8: { 9: private Stack stack; 10: 11: [SetUp] 12: public void SetUp() 13: { 14: stack = new Stack(); 15: } 16: 17: [TearDown] 18: public void TearDown(){} 19: 20: [Test] 21: public void TestEmpty() 22: { 23: Assert.IsTrue(stack.IsEmpty); 24: } 25: 26: [Test] 27: public void TestPushOne() 28: { 29: stack.Push("first element"); 30: Assert.IsFalse(stack.IsEmpty, "After Push, IsEmpty should be false."); 31: } 32: 33: [Test] 34: public void TestPop() 35: { 36: stack.Push("first element"); 37: stack.Pop(); 38: Assert.IsTrue(stack.IsEmpty, "After Push - Pop, IsEmpty should be true."); 39: } 40: 41: [Test] 42: [ExpectedException(typeof(InvalidOperationException))] 43: public void TestPopEmptyStack() 44: { 45: stack.Pop(); 46: } 47: }
The end result, a StackFixture test class with duplicate logging logic removed. The PostSharp AOP framework post-processes the compiled assembly and inserts itself, easily providing points of interception.
The PostSharp approach does involve a third-party dependency, but I feel like it is cleaner than the delegate approach. Gael informed me future versions of PostSharp will provide a more configurable solution than adding the [assembly ...] reference for the aspects, perhaps an XML configuration option. This can be done today, but involves some work.
Whether you use delegates, AOP, or some other approach, remove duplicate code wherever possible. I am happy to use either approach in my projects. There are tradeoffs to either solution, so investigate for yourself. |
|
|
|
|
Tuesday, April 01, 2008 |
|
|
Craig Neuwirt recently started a blog focused on NHibernate, as mentioned by Ayende. NHibernate is an ORM tool I have used on current and past projects and it is something I feel I would like I want to study further. So far, Craig is walking us through NHibernate from the ground-up, with the latest and greatest. I anticipate this being an informative blog to follow.
The NHibernate FAQ Craig Neuwirt Hibernating Rhinos |
|
|
|
|
Friday, March 14, 2008 |
|
|
This is a nice example using the new ASP.NET MVC framework. It is a clone of the Digg site, so it shows some more practical functionality, well beyond "Hello World." Not that there are not other practical examples out there, but the site goes into good detail on the MVC framework. |
|
|
|
|
Sunday, March 09, 2008 |
|
|
Boise Code Camp 2008 was awesome. Thank you to David Starr and his wife, Eleanor, for taking ownership of this event and dedicating many months of their time to make this a reality. Thank you to the presenters for having the passion and desire to present technologies and practices, both new and not-as-new. Thank you to the many volunteers who put in countless hours to help coordinate the weekend's events. Thank you to the campers for attending and making this year's code camp a success. I am sure everyone will be blogging about all the great sessions they attended at code camp. I enjoyed all of the presentations I attended, and I am excited to explore some new material. I want to share a few thoughts on my presentation dealing with Model-View-Presenter in ASP.NET after listening to Scott Hanselman's session on the ASP.NET MVC Project. I may have the percentage incorrect, but Scott mentioned something like it is predicted that only 10% of the ASP.NET community currently using Web Forms will adopt and use the MVC framework. The MVC framework is an addition to ASP.NET, it is not a replacement. What this means is that Model-View-Presenter will still be a viable pattern to implement with your ASP.NET applications, and it is not going away. ASP.NET Web Forms will not be going away either. Use MVP to get your third party controls under test. Use MVP to provide that separation of concerns in your legacy applications. Use it entirely or in conjunction with the MVC framework. It is all about testability. Glenn Block presented on the Web Client Software Factory, and what pattern does this implement? Model-View-Presenter. I am providing my presentation and source code (3.67 MB) from my talk on MVP. It will be available via the Boise Code Camp site as well. Again, thank the many individuals and their families who sacrificed their time to bring to the local community this years code camp. Around the office's water cooler on Monday, I will be able to say, "and this one time, at code camp..." |
|
|
|
|
Saturday, January 05, 2008 |
|
|
Recently I was developing some unit tests that had a dependency on a third party library and I found the adapter pattern applicable. I have decided to share what motivated me to apply this pattern since it is common dilemma. In addition, I am providing some general information on the adapter pattern that I hope will be useful. My initial need for the pattern occurred when I was using SubSonic, an open-source data access layer that uses the active record pattern. SubSonic's implementation of the active record pattern relies heavily on static methods to access data, which is not always necessary. In addition, I use RhinoMocks, an open-source unit testing framework, to help with my testing. With RhinoMocks, static methods cannot be mocked. The adapter pattern paid for itself by providing me a common interface with a third party library and encapsulating active record's static methods. SubSonic is a powerful option for data access and I recommend trying it out. In my situation, SubSonic and RhinoMocks fail to play nicely together due to static "Fetch" methods. In my application, I can retrieve all of my products, or a single product, using SubSonic like the following code below. 1: IDataReader dataReader = Product.FetchAll();
2: Product product = Product.FetchByID(1);
In my service layer, I call the static method "FetchAll," using something similar to what is shown above. If I want to write a unit test for this class, I need to write more code to get this static dependency resolved. I could use TypeMock to mock this static method, but I choose to use RhinoMocks, and since RhinoMocks cannot mock static methods, I need to consider refactoring. I am using a third party library, and while I do have the source code for it, implementing the adapter pattern is easier than rewriting SubSonic for what I need.
Adapter pattern to the rescue
The adapter pattern converts the interface of a class into an interface that clients expect (dofactory.com). The client expects what is defined by the target interface. The adapter implements the target interface and is composed with the adaptee. The adaptee receives receives all the requests from the adapter. Below is a UML diagram depicting the relationship among the objects.

The adapter pattern is useful in situations where:
- Two or more classes are doing similar things but have different interfaces
- You are using a third party API or framework that many clients already use
- You are using a third party API or framework and you do not have access to modify its source code
- You are using static methods that need to be mocked for unit testing using RhinoMocks
In my situation, SubSonic provides data access functionality that I need to encapsulate behind an interface that my clients expect. This will in turn make it easier for me to allow other data providers to participate in the future. Before refactoring, my service class's GetAllProducts() method calls the static method Product.FetchAll(). After refactoring, I move the Product.FetchAll functionality into its own class, ProductDAO. I now pass a reference to ProductDAO into my service layer class. This I can easily mock with RhinoMocks.
1: public class ProductService
2: {
3: private IDomainDAO dataAccess = null;
4:
5: public ProductService(IDomainDAO dataAccess)
6: {
7: this.dataAccess = dataAccess;
8: }
9:
10: public IList<ProductDTO> GetAllProducts()
11: {
12: IDataReader dataReader = dataAccess.FetchAllByName();
13: IList<ProductDTO> productList = new List<ProductDTO>();
14:
15: while (dataReader.Read())
16: {
17: int id = int.Parse(dataReader["ProductID"].ToString());
18: string name = dataReader["ProductName"].ToString();
19: productList.Add(new ProductDTO(id, name));
20: }
21:
22: return productList;
23: }
24: }
My service class, ProductService, now only references an interface called IDomainDAO, which is my "Target." My "Adapter," ProductDAO, implements that interface. ProductDAO has a reference to the "Adaptee," SubSonicProductDAO. My ProductDAO delegates its requests to the adaptee.
1: public interface IDomainDAO
2: {
3: IDataReader FetchAllByName();
4: }
5:
6: public class ProductDAO : IDomainDAO
7: {
8: SubSonicProductDAO adaptee = new SubSonicProductDAO();
9:
10: public IDataReader FetchAllByName()
11: {
12: adaptee.FetchAll();
13: }
14: }
15:
16: public class SubSonicProductDAO
17: {
18: public IDataReader FetchAll()
19: {
20: return Product.FetchAll();
21: }
22: }
In the example above, I implemented the adapter pattern as outlined in the UML diagram. I did not actually need to create the adaptee since I am using static methods. I could have just had my adaptor's FetchAllByName() function call Product.FetchAll(). I wanted to stick to the pattern.
The unit test exercising my ProductService's GetAllProducts() method looks like the following. With RhinoMocks, I can mock my target, IDomainDAO. At some point, a unit test will be needed that will test that static method. It cannot avoid being tested forever. I would feel comfortable testing this in a separate integration test project so as not to violate the rules of unit testing.
1: [Test]
2: public void GetAllProducts_ShouldReturn_ListOfProductDTOs()
3: {
4: using (mocks.Record())
5: {
6: IDomainDAO dataAccess = mocks.DynamicMock<IDomainDAO>();
7: dataReader = mocks.DynamicMock<IDataReader>();
8:
9: Expect.Call(dataAccess.FetchAllByName()).Return(dataReader);
10: Expect.Call(dataReader.Read()).Return(true);
11:
12: Expect.Call(dataReader["ProductID"]).Return(1);
13: Expect.Call(dataReader["ProductName"]).Return("My Product");
14:
15: Expect.Call(dataReader.Read()).Return(false);
16: }
17:
18: using (mocks.Playback())
19: {
20: IList<ProductDTO> productList = new List<ProductDTO>();
21:
22: Assert.AreEqual(0, productList.Count);
23:
24: productList = service.GetAllProducts();
25:
26: Assert.AreEqual(1, productList.Count);
27: }
28: }
Code Smells Indicative of the Adapter Pattern (thanks to Industrial Logic)
Alternative Classes with Different Interfaces
Occurs when the interfaces of two classes are different and yet the classes are quite similar. If you can find the similarities between
the two classes, you can often refactor the classes to make them share a common interface.
Duplicated Code Smell
Duplicated code is the most pervasive and pungent smell in software. It tends to be either explicit or subtle. Explicit duplication exists in identical code, while subtle duplication exists in structures or processing steps that are outwardly different, yet essentially the same.
Oddball Solution Smell
When a problem is solved one way throughout a system and the same problem is solved another way in the same system, one of the solutions is the oddball or inconsistent solution. The presence of this smell usually indicates subtly duplicated code.
The adapter pattern often works in conjunction with the facade pattern. While the adapter adapts objects, the facade is used to adapt systems. I will not go into more detail for the facade pattern. Perhaps it will become a separate post.
In my situation described above, I really needed the adapter pattern to help me bypass the issue with RhinoMocks not allowing me to mock static functions. If you have static functions in your code and they are proving difficult to test, determine if they are necessary and/or refactor them. |
|
|
|
|
Wednesday, November 07, 2007 |
|
|
Implementing MVP in ASP.NET |
|
|
|
|
Sunday, October 07, 2007 |
|
|
MVC framework for ASP.NET |
|
|
|
|
Sunday, August 26, 2007 |
|
|
Event-driven MVP in ASP.NET |
|
|
|
|
Sunday, April 29, 2007 |
|
|
Applying the Observer Pattern in ASP.NET |
|
|
|
|
Monday, February 05, 2007 |
|
|
Integrating Monorail into an ASP.NET WebForms application |
|
|
|
|
Sunday, January 07, 2007 |
|
|
|
Sunday, January 07, 2007 10:22:07 PM (Mountain Standard Time, UTC-07:00) | | Frameworks/Patterns
|
|
|
|
Friday, December 29, 2006 |
|
|
Installing a BAT file as a windows service |
Friday, December 29, 2006 1:36:50 PM (Mountain Standard Time, UTC-07:00) | | Frameworks/Patterns
|
|
|
|
Saturday, September 16, 2006 |
|
|
ASP.NET 1.1 and 2.0 Misconfigurations |
Saturday, September 16, 2006 7:03:55 AM (Mountain Standard Time, UTC-07:00) | | Frameworks/Patterns
|
|
|
|
Sunday, April 02, 2006 |
|
|
Why would I need Inversion of Control? |
|
|
|
|
Friday, January 13, 2006 |
|
|
An MVC Framework Update, and some thoughts on MonoRail up to this point. |
Friday, January 13, 2006 2:23:36 PM (Mountain Standard Time, UTC-07:00) | | Frameworks/Patterns
|
|
|
|
|
|
|
| Archive |
| June, 2009 (1) |
| May, 2009 (1) |
| April, 2009 (1) |
| March, 2009 (1) |
| February, 2009 (2) |
| January, 2009 (1) |
| December, 2008 (2) |
| November, 2008 (1) |
| October, 2008 (1) |
| September, 2008 (1) |
| August, 2008 (1) |
| July, 2008 (2) |
| June, 2008 (1) |
| May, 2008 (1) |
| April, 2008 (8) |
| March, 2008 (8) |
| February, 2008 (2) |
| January, 2008 (1) |
| December, 2007 (2) |
| November, 2007 (2) |
| October, 2007 (4) |
| September, 2007 (3) |
| August, 2007 (1) |
| July, 2007 (2) |
| June, 2007 (1) |
| May, 2007 (2) |
| April, 2007 (2) |
| March, 2007 (1) |
| February, 2007 (1) |
| January, 2007 (3) |
| December, 2006 (1) |
| November, 2006 (1) |
| October, 2006 (2) |
| September, 2006 (1) |
| August, 2006 (1) |
| July, 2006 (2) |
| June, 2006 (3) |
| May, 2006 (9) |
| April, 2006 (1) |
| March, 2006 (4) |
| February, 2006 (2) |
| January, 2006 (3) |
| December, 2005 (4) |
| November, 2005 (4) |
| October, 2005 (3) |
| September, 2005 (5) |
| August, 2005 (7) |
| July, 2005 (5) |
| June, 2005 (5) |
| May, 2005 (7) |
| April, 2005 (3) |
| March, 2005 (6) |
| February, 2005 (7) |
| January, 2005 (9) |
| December, 2004 (4) |
|
|
|
|
| About |
Powered by:
Disclaimer
The opinions expressed herein are my own personal opinions and do not represent
my employer's view in any way.
© Copyright 2010 MuellerDesigns.net
Sign In
|
|
|
|