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;

 
The business rule for calculating the Rebate is something that can be changed in the future based in new business needs. Can we do the changes without  a new recompilation and deployment of the application?

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?

7 Comments

  • what about performance and runtime errors that normaly is handled by the compiler?


  • Donald:
    Good question. I don’t think the performance will be any problem here, when creating an instance by using a Factory we can for example make sure it returns a singleton, Spring.Net will help us with this also if we use it as the infrastructure service for the Factory.
    Compilation and runtime errors. When you create a new version of the IUser for example, you still need to write code. But you don’t need to open the whole project and deploy the whole application, only the new assemblies. You need of course to update your test project and test the new implementation. I don’t say that this solution should be used, but I like the idea and have tried it on some projects with success (or at least I think so ;)).
    I hope someone maybe have used this also or tried it out and have notice some BIG problems with it.

  • "I haven't find the value yet, but maybe because I often move along to other projects when the previous one is completed"

    If the project is complete and you haven't seen the value yet, I would question the value.


  • &gt;If the project is complete and you haven't seen the value yet, I would question the value.
    Wow, that one was good Andrew!
    I think I need to change the sentence:
    "I haven't find the value yet, but maybe because I often move along to other projects when the previous one is completed"
    To
    "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"
    I think that one is a more correct for what I’m trying to say, sorry for my English.

  • Could you explain a bit more why you think using depency injection would break the open-closed model? I rather think that's caused by poor coding, rather then by depency injection itself.


  • JV:
    I wanted to be cool and use a cool name, but I failed ;)
    If we only look at a short summary of the “The Open-Close Principal”
    “Classes should be open for extension, but closed for modification.”
    I think the Rebate logic belongs to the method and the User class. If someone could be able to pass in (do a DI) an object that can “modify” the Rebate. The logic is somehow modified and the whole thing is bad coding as you say. So instead it’s better to create a new implementation of the class. But I can agree, using the Open-Close here was bad and not really right.. &nbsp;Thanks for the great comment. I will update the content to be more accurate.

  • I wasn't commenting on your English; changing the words doesn't change what you are saying.

    You start an experiment but you are not there to experience the results of your experiment. The big challenge of design is to see if people actualy use your stuff in the way you intended.

Comments have been disabled for this content.