views:

418

answers:

9

I've read a lot of books on software design, and more and more I'm wondering if what I learned about separation of concern between business object and serialization makes me more productive.

I'm influenced by Domain Driven Design, so when I design my business classes I don't think about persistance. The only objects who are coupled to my database/web service technology/caching technology are encapsuled behind a repository with a nice domain interface.

To illustrate, for a traditionnal application database<->web service<->RIA, I design my business classes Account and Employee. Then if I want to get accounts from a data source I create a IAccountRepository, and implement methods to query, or add accounts to my data source.

To add caching capability to my application, it's only a matter of creating a proxy class which implements IAccountRepository and wraps the real repository, then inject it in my IOC container.

To implement a database repository, I use an ORM which create classes from my database schema, then I use create a translator to transform database classes to/from business classes, this way my business classes are decoupled from my database schema.

I also create dedicated data contract classes for my web services, then the web service use translators to transform an aggregation of business objects to its data representation from the web service perspective.

When I create my RIA application, again I design its own domain model, but this time the repository implementation use a webservice instead of the database (and again translators).

For WPF developers, I create then my ViewModel and my View.

I used to program like this.

BUT, when my boss comes and says : can you add a field to this form to... blah blah blah I must :

  1. Update my database
  2. Update my database translator
  3. Update my business object
  4. Update my web service translator (server)
  5. Update my web service translator (client)
  6. Update my business object (client)
  7. Update my view
  8. For WPF adepts, update my ViewModel

I'm more and more thinking to couple my business object with database access technology and web service technology or serialization technology.

This way I don't need to maintain my translators anymore. For example why not using attributes/annotations of these technologies on the business objects ? Yes it brings some contrains, yes I will need a get/set on my fields, even if I want my property to be readonly, yes my business module will have external dependencies. But I think it will result to less code, and a more maintenable system.

The implementation of my repositories will be trivial, and won't rely on translators.

Although I see advantages to code this way, I always feel guilty to code like this. I feel really guilty about adding a 5 attributes/annotations coupled with my data access technology/web service technology/Serialization technology on my business objects and I feel it's not right.

why my separation of concerns Database/Business objects/Web service, makes me write more code ?

Do you have some alternatives ?

+4  A: 

Your personal productivity is not the point.

The point of separation of concerns is to increase the value of the software you produce by making it usable, maintainable and adaptable.

I'm sorry if this makes you write more code, but your time is typically a tiny fraction of the life-time cost of using, maintaining and adapting what you're writing.

Separation of concerns is essentially for keeping the life-long total cost of ownership down. It has little to do with your personal productivity.

If your boss is asking you for a pervasive change... well... it's pervasive. I'm sorry it's pervasive.


Edit 1

The value of your software is the value that is produced by people using it.

"Is it the purity/beauty of the code? To me, value is in simplicity and readability." It's neither. It's the value created applying the code to real-world problems.

If the code is hard to maintain, adapt or use, that devalues it. If the code is easy to maintain, adapt or use, then there are fewer barriers to getting full value from the code.

Your time developing the code is a tiny, tiny cost compared to the value of using it. Also, your time developing is a smaller cost than maintaining or adapting.

Edit 2

Pervasive change is an unavoidable consequence of building software. Nothing -- no practice -- can prevent your boss from making a change that breaks your architecture.

If you have one layer, almost any change breaks that layer.

if you have 3 tiers, 7 layers or n+1 layers, it's always possible for your boss to ask for a change that breaks more than one layer.

The idea is that MOST changes are isolated. Nothing can assure that ALL changes are isolated.

S.Lott
Interesting, if a little condescending. I would think that a programmer's personal productivity would correlate well with application value. Otherwise, why would we continue to create new and better programming languages and tools? Why didn't we just stick with Cobol? One boss's requested change is fine, but if a lot of changes are requested on a regular basis, perhaps a more agile, decoupled design is in order.
Robert Harvey
We don't stick with COBOL is because the maintenance, adaptation and operating costs are so high. New development tools usually produce code of higher "quality" where quality means maintainable, adaptable and usable. Development costs are a tiny fraction of life-cycle cost.
S.Lott
Is a code base maintainable if it requires you to 1.Update my database2.Update my database translator3.Update my business object4.Update my web service translator (server)5.Update my web service translator (client)6.Update my business object (client)7.Update my view8.For WPF adepts, update my ViewModel
Robert Harvey
S.Lott, I agree with you but the problem is, like Robert understood, that following "best practices" my code doesn't seem maintainable.
Nicolas Dorier
Just what is this *value*?? Is it the purity/beauty of the code? To me, value is in simplicity and readability. See "your most controversial opinion" thread: best practice should be "Use your brain".
hasen j
It reads to me like they've implemented every abstraction layer they've read about as "common practice". Perhaps for good reason, if this application is as complex, highly distributed and active as would require it. But then the answer would be self-evident - the scope of conflating the layers would be daunting. Best practices differ by, among other things, application scale. Hopefully someone is around who can relate the history (and reasons) it accreted all these levels.
le dorfier
@hasen, my code is simple and readable, but some changes like the one my boss said ripple through all my layers and it becomes a maintenance nightmare.
Nicolas Dorier
There is a tradeoff between 8 simple changes in a highly-readable code base, and one difficult change in a complex, obtuse, difficult to read codebase. It sounds to me like you're in the former position and not the latter. It also sounds like these changes can be made in a half-hour (including unit testing to make sure you didn't break anything). Is that true?
Robert Harvey
@Robert, it's not just the time (half an hour to add a form field is still too much), but the amount of context switching that goes in your brain. If you have to update 8 layers for every form field, it's not fun at all. From my experience it's too much stress (and I've only had 3 layers).
hasen j
+3  A: 

A maintainable application is one which has a low cost of maintenance. If common changes take a long time, then that is not a maintainable application.

The key question to ask is how common feature requests are, versus technology changes.

If you change your preferred technology set every 3 months or so, then you will never have time to implement new features, so your architecture is optimal...

soru
+2  A: 

I also have the same experience, alot of the stuff I learned in school about abstraction and separation of "stuff" makes my code actually more and more complicated.

I'm come to realize that, when you have high cohesion (your classes are very small and very to the point), you will have high coupling. By simplifying each individual class further and further, each component will be more and more useless by itself; to get simple functionality you'll need to manage complex interactions between these simple "cohesive" objects.

Then, simple tasks will be complicated!! Think about reading a file in Java, I don't remember how to do it (I've had to do it many times), and I don't ever want to do it again.

In Python it's dead simple:

for line in open("filename"):
    # do something with line

I'm not saying separation of concerns and abstractions are bad, just do them sanely.

IMO, it's always better with something that "just works" even if it's spaghetti, given that you do refactor.

hasen j
+2  A: 

You are definitely writing too much code. Adding a single field shouldn't be a 8 step process.

  1. Why not use NHibernate? You cans till have your true domain model and the "database translator" is (now) a simple exercise with FluentNHibernate.

  2. There are some very robust frameworks out there for combining steps 4-6 in a relatively transparent way. WCF (the horror!) for one.

Jim
oh I didn't know FluentNHiberante, it doesn't seem to pollute my BO and the mapping seems very easy to do ! I'll take a look :D
Nicolas Dorier
+1 for "writing too much code", -1 for "use NHibernate". So it kinda evens out.
Ian Boyd
I don't know why you would -1 for use NHibernate. It's the best ORM for creating building an application with DDD. Perhaps you just don't have enough ability to build an application this way.
Jim
+1  A: 

It is about the upfront investment. The time it takes to build something correctly will always be greater than the time it takes to build something that just works. One important takeaway from DDD is that you can abstract out a lot of the plumbing and put it towards a development framework that can be reused, so that you don't have as high of an initial investment on other projects. You can abstract the bases for your repository, unit of work, domain object, etc. Additionally, you can take the actual database functionality and implement them as a provider, so that you write once and chose the correct one for the job next time, or if you need to change the backing store for your domain object.

A solution that has properly addressed its seperations of concern has some very productive features - such as it being highly testable, more apt to be scalable, more reusable, easier to debug, easier to modify, and easier to extend. Being able to see how the domain flows through the code is a total rush, and being able to describe a concept to a stakeholder, or walk them through the concept that a code artifact is executing is worth its weight in gold.

With my developers, I had a very hard time selling the concepts of SOC, and DDD for that matter, at first. Apart from the testability, ease of debugging, and a unified language between technical resources and stakeholders, a lot of the benifits either come after the initial deployment, or not at all. For example, you might not need to scale out (for example, wrapping a facade around your services and putting them on another server to host a REST-ful API through web services), but knowing that you can is a really, really great feeling.

I understand your fear of the ripple effect. To be honest, there is always going to be a ripple of some sort. With a properly designed repository, you can isolate the size of the ripple to be just a few places, though. Since it appears that you are using .NET (based on the WPF comment), you might want to take a look at .NET Domain-Driven Design with C#: Problem - Design - Solution. While I do not agree with 100% of the implementation in the sample, it really does illustrate how well this approach can really work.

joseph.ferris
+4  A: 

When designing an application, the levels of abstraction should provide value. They should not be there just because it is a 'best practice'. Some applications have a rich domain model and benefit from the layers of abstraction. However, an application that is very data centric without much logic may not have a need for as many layers.

I have seen some applications that define multiple layers corresponding to each object with the names dutifully matching the layer EmployeeDL, EmployeeBL, EmployeeUL. None of the objects added any value and simply passed values between layers from the user interface to the database. It was pointless.

I find when working with applications with a richer domain model, changes may affect multiple layers, but seldom are as simple as passing a value from the UI through several layers to the database. There is business logic in the middle that would be much more difficult to implement without the levels of abstraction.

At the end of the day, it is most important to choose an architecture that matches the needs of your application in terms of its complexity and maintainability.

g .
A: 

What tools are you using? I've never heard of such a high degree of non-automated nonsense. I almost don't believe your question is real. And what are you doing with a "business object" on the client?

You talk about coupling your data access, business and web service layers. That's exactly where not to couple!

Your business entities should match the actual entities used by your business. If they happen to map one to one with your database, then that's a coincidence. The business services offered by a web service should not be as finely-grained as the methods on your business entities, so, again, there should be no direct mapping.

It's definitely the case that more and more of this should be automated, with appropriate code generation, but it's never going to be free. You're going to pay one thing, or you're going to pay another. In an environment where everything maps directly to the database, all the way through, as soon as you break one table into two or three, you've suddenly got to change everything. And I don't mean just adding one column.

Be careful what you ask for!

John Saunders
I agree with you, I don't want to couple my data access, business and web service layer, because I know that web service should be coarse grained, whereas business object should not, and database design is also a very very complicated problem by itself. The only problem I see when I try to decouple, is that a little modification asked by my boss almost always ripple through several object in several layers. And for example I think that adding attributes/annotation on my properties, can really spare me to write a lots of code, although these attributes are coupled to some external technologies.
Nicolas Dorier
...some external technologies, and not really business related.Like I said I HATE to do that, but for my projects most of the time the database and the data contract, looks like my business objects and lots of code is written to translate one object from one layer to another... Take the example, the first chapter of http://weblogs.asp.net/scottgu/archive/2009/03/10/free-asp-net-mvc-ebook-tutorial.aspx, you'll see that a pretty good application (the nerd dinner) is done even if business objects (like a dinner) is coupled to Linq to SQL.
Nicolas Dorier
Those objects would better have been created with Entity Framework, which decouples the entities from the database design. Note how EF uses a declarative model: a model of the conceptual entities, and a model of the mapping between the entities and the logical database. From this it generates code. That's the future. See also the Service Factory (http://www.codeplex.com/servicefactory) as an example of a model of a service driving generation of the code for the service. Hint: I've combined the two models in the past.
John Saunders
Yes, but if these business objects are created with Entity framework or Linq to SQL or whatever, they are coupled with a database technology. For example, you have to create a setter and a getter for each property you want to save on the database, you have to add attributes, maybe you have to inherit from a class and that's what I don't want to do. What I've always done is creating my database classes with nhibernate/linq to sql/entity framework, then I created manually a translator between these generated classes and my BOs .What microsoft calls "Entity" should not be a BO to my mind.
Nicolas Dorier
@Slashene: It's "ADO.NET Entity Framework". It should work with any ADO.NET provider, including Oracle and DB2. It decouples from the DB schema. You do not have to play attributes and classes - you create a model and it generates the classes.
John Saunders
+1  A: 

The point of separating these things is

  • one developer works on one piece
  • each piece can be more easily unit tested

Unless you have 8 developers (to match your eight-piece pie), and are writing unit-test code to match production code, your arrangement is overkill.

Ian Boyd
A: 

Also consider the use of abstraction layers that can be implemented with a simple pass-through but overridden when needed.

Database views are a good example - I usually have the app-layer only reference the database tables via views (clearly indicated by _v suffix) rather than table names directly. These typically reference a single table and are just 2 lines of DDL each. This is quick to create and easy to maintain - but also can be expanded to provide a translation between the app, orm & database.

Another example is properties in python - where your code can directly reference class or instance variables rather than always go through setters & getters. Then later, if you need to translate between that variable inside the class and the code that is accessing it you can define a property function that gets called to deliver the variable. This happens transparently to the calling program.

So, in both cases you get the value of the abstraction layer but only add code & labor when you actually need the flexibility.

KenFar