Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

How do you deal with extreme personalization?

Options
  • 29-06-2009 1:12pm
    #1
    Registered Users Posts: 4,475 ✭✭✭


    I have a webapp that's being used by a few companies and most of them are very happy with it. I update it sparingly and give the companies a lot of notice, etc. However, recently I signed on a fairly large company (comparatively speaking) and they've been "bullying" me ever since. They've requested a bunch of changes to be made to the app. None of them are particularly difficult and it is part of the contract I signed, but very few of them are useful to the other companies, which means I end up putting in crap code like
    if (company_id == 3) {
    // this is BigCompany, do something specific
    }
    
    which is obviously not ideal. At last count, I had something like 20 of these little code switches and more are on the way.

    I need a better way to do this. I was thinking of putting all affected functions into a separate include file and having one version for BigCompany and one for everybody else, but this strikes me as even dafter than the above solution.

    There must be an elegant way to do this, something that's not going to be a nightmare to maintain, and will also be pretty foolproof (ie avoid accidentally releasing the BigCompany code to the other companies, or worse, vice versa). I'd like to avoid having double maintenace on the common parts of the webapp, if possible, so 2 different projects is not a solution either.


Comments

  • Registered Users Posts: 66 ✭✭bala


    corblimey wrote: »
    I have a webapp that's being used by a few companies and most of them are very happy with it. I update it sparingly and give the companies a lot of notice, etc. However, recently I signed on a fairly large company (comparatively speaking) and they've been "bullying" me ever since. They've requested a bunch of changes to be made to the app. None of them are particularly difficult and it is part of the contract I signed, but very few of them are useful to the other companies, which means I end up putting in crap code like
    if (company_id == 3) {
    // this is BigCompany, do something specific
    }
    
    which is obviously not ideal. At last count, I had something like 20 of these little code switches and more are on the way.

    I need a better way to do this. I was thinking of putting all affected functions into a separate include file and having one version for BigCompany and one for everybody else, but this strikes me as even dafter than the above solution.

    There must be an elegant way to do this, something that's not going to be a nightmare to maintain, and will also be pretty foolproof (ie avoid accidentally releasing the BigCompany code to the other companies, or worse, vice versa). I'd like to avoid having double maintenace on the common parts of the webapp, if possible, so 2 different projects is not a solution either.

    I do not know what personalizations you are doing . Is it change in logic or change in UI elements like Labels, page headings, date format etc

    If it is the latter then all personalizations can be externalized into a config file (I lean towards xml config files). The code could be then modified to read the config file and get the data from it. Each customer can then create their own config file to personalize


  • Registered Users Posts: 11,980 ✭✭✭✭Giblet


    You should have a core layer which is general and that only changes for the benefit of all the clients. Anything specifc should be in a class that extends the core class, overrides anything that needs to change.


  • Registered Users Posts: 4,475 ✭✭✭corblimey


    You should have a core layer which is general and that only changes for the benefit of all the clients. Anything specifc should be in a class that extends the core class, overrides anything that needs to change.

    I'm not sure I understand what you mean. If you have a core class called Print() and you need to do something different for BigCompany, ok, you can have a extender on that BC_Print(), but you still need to call BC_Print() for BigCompany, you're still going to have to check the company_id? Or am I missing a basic piece of the puzzle?


  • Registered Users Posts: 5,618 ✭✭✭Civilian_Target


    Sounds to me like a Strategy Pattern would go a long way.

    How it works is like this.... make an interface that contains the application configuration as the return objects of some methods. For example, if you're making a pattern matching engine, you'd make your interface with a method called match() and return true or false.

    Now you have one implementation for each of your big clients, and you initialise your core with the implementation for a given client, and it behaves differently.

    This is incredibly versatile, although it can be quite heavy. Read up and take a look at some examples, see if it's what you need.

    http://www.exciton.cs.rice.edu/JavaResources/DesignPatterns/StrategyPattern.htm
    http://www.berniecode.com/writing/inheritance/


  • Registered Users Posts: 3,945 ✭✭✭Anima


    The first image on that first link makes my eyes explode.


  • Advertisement
  • Registered Users Posts: 4,475 ✭✭✭corblimey


    Me too! :)

    Also, I'm again not seeing the benefit of this. Taking the example in the second link of the fading bouncing ball. That's all very well, but in my case, I want most of my clients to get a bouncing ball and BigCompany to get a fading bouncing ball. I'm back to my original problem of instantiating the class differently for BC:
    var d = new StrategyBall(); 
    if (company_id == BC) {
      d.yMotionStrategy = new AbsSineStrategy(80, 200); 
      d.alphaStrategy = new AbsSineStrategy(0, 1); 
    } else {
      d.yMotionStrategy = new AbsSineStrategy(80, 200); 
      d.alphaStrategy = new AbsSineStrategy(1, 1); // or whatever
    }
    


  • Registered Users Posts: 15,443 ✭✭✭✭bonkey


      var d = new StrategyBall();
      d.yMotionStrategy = new AbsSineStrategy(80, 200);
      d.alphaStrategy = new AbsSineStrategy(0, 1);
      int i = ConfigLoader.getSomeParameter(company_id);
      d.alphaStrategy = new AbsSineStrategy(i, 1); 
    

    Build some sort of configuration manager.

    If the source is being given to the companies, then each company can be given their own, seperate config file, and you don't need to worry about company_id at all.

    If you're hosting the app, then you're somehow determining the company_id...by URL, or login-name, or something. So you define multiple configurations and determine which to read bsed on the company_id. (Ideally, you shouldn't even be handing the company_id to the ConfigManager like I'm doing...but rather instantiate it for a company_id and then just use it.)

    In all cases, abstract away from the choice being for a company, and rather being a choice from available options...and then you have a configuration for a company which selects those options. This way, if the code was compeltely different for companies (as opposed to
    just being different parameters to some method as above), then you'd implement something like this:
      var d = new StrategyBall();
      int motionStrategy = ConfigLoader.getMotionStrategyId(company_id);
      if (1 == motionStrategy) {
        // do stuff
      }
      else if (2 == motionStrategy) {
        // do other stuff
      }
      else {
        // error or default? no config found
      }
    

    With this type of approach, then when a new company comes on board, who don't want new features, but rather a configuration of existing ones, you don't have to change a single line of code....just the configuration.


  • Registered Users Posts: 11,980 ✭✭✭✭Giblet


    Just a brief example. What language are you using? You could use virtual methods that can be overridden. Our extended class can use the core methods and the specific methods for the client, using the same names.
    class CoreCompanies
    {
        public void CommonMethod1()
        {}
        public virtual void BouncingBall()
        {}
    }
    
    
    Now our specific company.
    
    class CompanyClass : CoreCompanies
    {
         public override void BouncingBall()
         {
              //do company stuff.
          }
    }
    

    You should probably have a core library, and a project file for each company. The presentation layer stuff for each company is contained in their own project file while the core is a seperate library. Any custom code can be implemented in the project file of the company, unless it can benefit all your clients. You'll basically end up with a seperate implementation of certain features per company, with one single core class that should never be changed unless it doesn't break everything.


  • Registered Users Posts: 515 ✭✭✭NeverSayDie


    You could also look into reflection and late-binding, if you're using .NET or Java at least. This will let you (amongst many other things) have your company-specific config store the details of the DLLs/classes that implement particular interfaces, and have your core code load and call them at runtime. There can be some performance impact, but you can gain some serious flexibility. That way, you can customise particular bits of behaviour (that Print() call for instance), with what are effectively "plugins", without having to add "if company X" type checks around your main codebase.

    Really depends on your specific requirements though - other scenarios might better suit the behaviour configs or class hierarchy described by Bonkey and The Hitcher.

    Bear in mind it's all a case of balancing costs - if it comes to it, it may be cheaper (time and effort wise) to maintain largely separate codebases for each of your clients (allowing for shared libraries of low-level stuff). Compromises as suggested by The Hitcher, where you have a custom presentation tier but they all share the back tiers' implementation, are also worth considering. The most likely customisations they'll want are probably in the presentation tier anyway, so if you can maintain the same model behind that, well and good.


  • Registered Users Posts: 4,475 ✭✭✭corblimey


    Thanks, all
    NeverSayDie, I think I'm leaning towards that idea a little (although on a much simpler scale, this is PHP after all). I'm actually probably going to go with a 'mode' of some description so that it's not specific to companies. Then I'll have a config file that controls aspects that are unique to that certain mode. Now I just have to decide whether to do it now or wait until it's imperative that I do something about it :)


  • Advertisement
  • Registered Users Posts: 27,163 ✭✭✭✭GreeBo


    I would say that you need to try to abstract anything that is configurable so that rather than being hardcoded (or a crap load of IF's) its read from a configuration file.

    Then you just point each company at the appropriate config file.

    Without knowing with it is thats going to be different its very hard to comment on what the config file should look like or how to implement it...


Advertisement