The configurable application, no need for recompilation and new deployment!
The following I will write about is something I have used in some projects to see if it gives me any value, I haven't seen any evolutionary results yet, but maybe it's because I often move along to other projects when the previous one is completed ;)
Let assume I have a User and the User has a property called
Rebate. This method can have some business logic to
calculate the rebate the use has when ordering products.
Here is an dummy example of the method:
class User { public double Rebate { get { return superUser ? 10: 5; } } }
User user = new User(....);
double rebate = user.Rebate;
By using the Interfaces and also the Factory Pattern we could solve this. Here is an example where an Interface is added to the User and a Factory is used to create the User:
public interface IUser { double Rebate { get; } } class User : IUser { public double Rebate { get { return superUser ? 10: 5; } } }
IUser user = UserFactory.Create(...);
double rebate = user.Rebate;
The UserFactory will now create an User an return an
IUser. Because the factory creates the user I don't use "new
User". I can now use late binding and load the assembly
which has the implementation of the User and return it. I
can for example use a configuration file where I specify the
type of the user I want use.
<object name="IUser" type="MyNamespace.User,
MyAssembly, Version 1.0 ...">
The UserFactory can now load the type specified in the
configuration file and create an instance of it. If I need
an new version of the User because
some changes need
to made based on business needs, I can create a new assembly
and a new IUser. I can then modify my configuration file to
make sure the UserFactory loads my new implementation. By
using this solution I don't need to compile my application
when changes to classes is needed. Instead I create a new
version of the class, put it into a new version of the
assembly and deploy it. Then I only change the configuration
file so the Factory gets my new implementation instead of
the old version.
class User : IUser { public double Rebate { get { return IsMegaUser() ? 11: 6; } } }
<object name="IUser" type="MyNamespace.User,
MyAssembly, Version 2.0 ...">
Another solution to solve this could be to use Dependency
Injection, where I inject a object with the implementation
of the business logic. I can then for example use Spring.Net
to inject the business object into my User. By using
Spring.Net I can in a configuration file specify which
business object that should be injected to the User class
when it's instantiated. This will make it possible to only
implement a new version of the business object rather then a
new version of the User. I will not use this solution
because it can be kind of ugly. But by using Spring.Net I
can hide the injection of the dependency and never see it in
my code. Let's think like an Object, would you like someone
to easy change your behavior and you can't do any thing
about it?
I sometimes uses Interfaces and in
some cases Factories, but not so often (It depends on the
project and if the Customer already have specified a design
to use). I use interfaces and factories when I want my
application to be plugable, for example make it easy to
inject Repositories into my Services etc, and also to make
it possible to use Mock object during test etc.
About using this solution for most of the classes in a
application, wouldn't it in an Agile project sort of violate
YAGNI!?
It can sort of help the people that need
to maintain the application after it's deployed, as long as
the interface of the classes can be intact. What do you
think about it? Is this something you use today in your
application and have it result into something good?