views:

236

answers:

8

I've been tasked with re-writing a fairly large web application for a company. This application provides certain financial/risk analysis to 3 clients that we currently have.

The huge issue around this app is each client is different and has slightly different data. They all log into the same website but after that their experience can differ slightly. Their database schemas aren't the same, occasionally their views have to differ to represent different data and their user management is a complexity nightmare. When a user logs into our site we need to pull data from the right database (each client has their own).

Say our clients are 3 hardware companies:

  • HackmansHardware
  • LowesHardware
  • FranksHardware

Hackman's Hardware might have slightly different analysis needs or request certains special columns in our reports. Similarly, Lowes Hardware might want to have slightly different security access to its pages then a different company based on its users.

Functionally, the web application is the same for them. It has the same tabs and the same goals at what information it is trying to present. But there are subtle differences between them that I'm having trouble encapsulating and it is making the code a mess.

Question: What is the best practice for handling a base application that needs modification for each new client that we get? What architecture/design pattern can we use to make adding new clients relatively painless despite their need for customization while still re-using as much as possible? How can we keep our codebase clean without the need for per-client hacks?

We are using ASP.NET MVC for this rewrite but I'm not sure how relevant that is to the question.

+2  A: 

How many potential clients do you expect? If the answer is 2 new ones annually, your solution will be different than if you say 200 new clients annually.

As a start, it sounds like a master configuration database (or file) is needed. Your application could use this configuration information to determine everything that is customizable. After that, building a UI to add a client is fairly easy.

If I was doing it (with the little knowledge I have on your project)... I would start by creating a "base" client model. All new client models would be derived from this base, which would contain all my standard logic. For existing clients, it may be painful to fit them in but through a series of wrapper functions and configuration classes, it can be done.

Cody C
+1  A: 

You need a "Web Portal."

There is good information available on how to build web portals in ASP.NET that might give you some ideas on how to do it with MVC. In particular there is the DropThings portal, and its companion book, Building a Web 2.0 Portal with ASP.NET 3.5. You might be able to adapt most, or all, of its ideas to ASP.NET MVC.

Robert Harvey
A: 

Ultimately you need a way to describe the schema in metadata that the application can understand. There are quite a number of different ways this can be done, you'll have to choose for yourself, but as an example (not necessarily the best choice -- or a good choice):

Use XML to describe the schema for each store. Create a tool that generates DB schema based on the XML. Code your reports to look at the XML to determine what columns to display. Continue ad nauseum.

Another option is to keep the core of your application the same but create different implementations of key parts where they differ. Use a IoC container library to load the appropriate implementations for each store.

Talljoe
+4  A: 

Create a master page that contains all of the information that is the same for every client. Then, add views and/or controllers that are unique to each client.

Have a look at the following link. It explains how to create an "Application Controller," an abstract class that can be inherited by your other controllers, so that you only have to write the code once that pushes your needed master page data into the view.

Passing Data to View Master Pages:
http://www.asp.net/learn/MVC/tutorial-13-cs.aspx

Also, have a look at the following link, which explains how to implement Partial Views and Subcontrollers in ASP.NET MVC:

Partial Requests in ASP.NET MVC
http://blog.codeville.net/2008/10/14/partial-requests-in-aspnet-mvc/

Robert Harvey
A: 

Customization at the data level is always challenging. Start with a thurough analysis of exactly what is different from one client to the next. Then look for ways to create a single data design that encapsulates the variations. This can be tricky but us isually well worth the effort. If you can try to think of how you could create the design to be flexible enough for the needs of future clients (yes, this may involve a crystal ball).

From an architectural perspective, consider using an anstract factory pattern at the data access layer. Without knowing the details of the requirements or the degree of variation from one customer to another I'm not sure how applicable this is, but I've been successful in the past using this pattern to account for rather wide variations in format and structure of data sources that needed to be delivered to a common processing/presentation layer. This would allow you to create data layer components that plug directly into the front end of the system.

Customizing the presentation layer gets a little more straight forward and can be readily handled through the user of MVC, Master pages, and themes. I think some of the other comments/answers posted here address those aspects of the customization process.

James Conigliaro
A: 

It might be a good idea to use a mixture of hard boiled C# code and some scripting language like IronPython to solve your problem. It is fairly hard to create a configuration file comprehensive enough to describe the subtle differences that occur between clients and you can't use any kind of logic in configuration files (unless you're up for developing yet another half baked programming language yourself).

I'd try to write everything that is similar for all installations in C# and everything that is different between installations in Python. I would further use your source control tool to manage the combination of the C# framework and the Python configuration. This should give you a well defined boundary between reusable code and specific business logic requirements for each client. In addition, since scripting languages aren't compiled, you'll be able to tweak the configuration on-site. It's widely considered bad practice to do that, but when you think of the Python code as glorified configuration for your application it might not be so bad. As customizations are hacked in Python for specific clients mature into reusable concepts, I would rework them into C#, add them to the framework and remove the customizations.

Note that I'm using C# and IronPython as examples here - you can use any combination of two languages. I do think however that there should be a significant different in syntax between the two to keep the boundaries clear.

gooli
+1  A: 

Have a look for "multi tenant" application. Here multi tenant on so

Or here Bart blog

Malcolm Frexner
+1  A: 

I'm going to have to disagree with some of the approaches that describe deriving from a common base controller, etc. because subclassing alone is not going to work out well. You'll be adding derived classes for each client and it will become a maintenance nightmare if you have more than just a handful of clients. Also, while a MasterPage is going to be used in some capacity, if your clients want input into the look and feel of their site, a lot of the things like colors, styles, etc. are going to need to be data driven.

The portal idea is pretty good, but if you have a lot of custom domain logic that will differ from client to client, it will also start becoming an issue quickly. If it is just a matter of hiding some pages for some clients, then a portal idea is not a bad suggestion. Keep in mind that if you are using pre-production environments that portal sites like DotNetNuke can be difficult to deploy from one environment to another unless you become intimately familiar with their schema. Plus, sites like DotNetNuke are not written in MVC so applying any test driven development practices will be much more challenging than beginning from scratch.

I would first start reading up on design patterns if you don't have a good background in them already, specifically the Strategy and Abstract Factory patterns. This will allow you to look at the design of the project with an eye towards favoring dependency over inheritance. Try to develop a few domain classes that will expose properties which are the templates for what you will expose to your clients. Those properties' types will use the classes that encapsulate what can vary from client to client. Once you build a couple of classes and test them, you can then produce the database schema necessary to support it. I suspect you will end up with a clients' table, tables that will contain the possible values for your entities and their related value types, and tables for each that associate the clients with these entities.

Hope this helps.

Lance Harper