简体   繁体   中英

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

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 ?

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.

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.

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...

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.

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.

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.

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!

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM