Frameworks and layers
I’ve recently started on a new project where we are rewriting a legacy app basically from scratch. This means that the first coding task is to set up all of the architecture, frameworks, and layers that we will use for the rest of the project.
I think that this is the most crucial time in the life of the project. The work that is done now will affect many things, including:
- How long it will take to develop the rest of the application
- How long it will take for other developers to understand the architecture (learning curve) so that they can be productive
- How easy it will be to add new features and make changes several years later (after many of the original developers are no longer on the project)
- Whether or not the project ultimately succeeds
Those are some important issues! So we better get it right!
Many of the problems I have seen have come from having too many unnecessary layers to deal with in the project. Let’s look at some common rationalizations for layers and tiers in project architecture.
“By separating the business entities and logic from the database code, we can insulate the business code so that it can work with any database.”
I would hope that almost every application does this one. I was on a project that used NHibernate and we were able to rip out Oracle and replace it with SQL Server in a day or so. This separation is fairly easy to implement, especially if you use an O/R mapper. It also lets you write unit tests against the business layer so that you can make sure that database changes don’t break your application.
“We’ll have a separate UI layer and business layer and keep the validation code out of the UI.”
This is good on many fronts — you are able to write a new UI and use the existing business layer (e.g. put a web front end on top of a business layer that was used in a Winforms app, or maybe you’re really brave and you move from Winforms to WPF!). Also, in most cases you will need certain pieces of validation and logic code that can’t just live in one screen on the UI, and putting validation logic in the UI makes it impossible to unit test.
“Let’s write our data layer so that we could plug in any database with any schema so that it will work without our business layer knowing that anything changed.”
I really have to question this one. Let’s say that there is a possibility that we could have another database schema that we might have to plug in. But let’s think about this some more.
- Honestly, what are the chances that this will ever happen? If we’re going to invest a significant amount of time in order to have this flexibility, we better be pretty sure that we’re going to have to plug in another database someday.
- Even if we did someday have to plug in a different database schema, would we even be able to get it working? Can you really switch to a drastically different database schema and have the app be fast enough? What if the new database has different constraints and foreign keys?
- Would it be easier to write some kind of integration that would bring the data from the new database into our database? No one likes to write integration code, but it gets the job done and it won’t affect the performance of the application.
- Having a bulkier architecture to deal with will affect how fast you can develop pretty much any feature that you want to add to the application. Also, when a new developer joins your team, it will affect how fast they can get up to speed (and they might be bitter at you for making their life more painful).
We need to always remember why we are writing code in the first place — to provide business value. Sure, writing applications can be fun, but they’re not paying us just to have fun!
Frameworks and layers are meant to serve us… if you feel like you’re a slave to your framework, maybe you need to rethink how your project is structured.
I like to keep things simple. Use existing code libraries whenever possible (such as Enterprise Library, an O/R mapper, etc.). Don’t create some extra layer just because of what we might have to do in the future, when we don’t even know if we’re going to have to do it. Design your application to be flexible so that you can adapt to change, but don’t burden yourself with something that is just going to make everything more difficult in the process.
Another thing that I have seen developers doing, is prematurely trying to optimize their code. It would be more efficient to try to get the piece of functionality working FIRST. Then, when you get metrics and real stats, then re-factor and try to optimize.
And yet another — don’t forget the mindset of least privledges when you consider security and/or access.