Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

InvisibleDuncan

New member
Joined
May 10, 2001
Messages
819
Does anyone fancy weighing in on a disagreement we're having regarding object-orientation and encapsulation?

If you have a class - let's say it's a Policy class, for example - that holds all of its relevant properties, where would you expect to find the process that saves any edited properties back to the underlying database? Would you expect the class to have its own Save method, or would you expect the Save method to be in a completely separate servicing layer that accepts your Policy instance as a parameter and then saves it?
 

FunkyDexter

Super Moderator
Joined
Apr 12, 2005
Messages
7,519
In terms of OO either's valid, along with a bunch of other options too.

Encapsulation doesn't say that a class needs to hold all the implementation that's relevant to that class - it says that a class should not expose implementation to it's consumer.

In other words the thing that consumes a Policy should just know it has to call Save. It shouldn't know whether the Policy class actually implements the save or delegates it.

In a reasonably small system it might be a good design decision to have your domain classes implement their own DB code, to keep things simple. The downside would come when you wanted to change the underlying DB to, for example xml files. At that point you'd need to crack open every one of your domain classes which would be lots of work and high risk. If you'd implemented a separate data access layer (or DAL) you could simply implement a new, xml based DAL and drop it in in place of the old DB one. So the DAL adds complexity in the short term but aids flexibility in the long term.

Personally I'll always implement a separate DAL as I feel the flexibility more then pays for the extra complexity but it's not an encapsulation/OO issue.
 

InvisibleDuncan

New member
Joined
May 10, 2001
Messages
819
Excellent - thanks, Funky. I've been having a bit of an uphill struggle, so an independent opinion like this will hopefully be a big help.
 

InvisibleDuncan

New member
Joined
May 10, 2001
Messages
819
Incidentally, there's a disadvantage to the fact that you tend to be one of the few people that answers my questions: I can't rate your post unless I go and rate some other people's posts first.
 

FunkyDexter

Super Moderator
Joined
Apr 12, 2005
Messages
7,519
Meh, I'm long past caring about ratings. I'd have thought the bigger disadvantage would be that I'm invariably wrong... about everything.
 

techgnome

PowerPoster
Joined
May 15, 2002
Messages
32,778
Generally speaking, I prefer the middle DAL as well... the DAL returns either single objects, or list(of) of objects.... the DAL then becomes the object factory, that allows me to not have to worry about the data source from the consuming side... I don't care if it's a database, xml, csv, flat-file, web source. When it comes to saving through, I may call a .Save method on my object, but that will be just a wrapper/shared method that then defers to the DAL for the actual storage. Depending on the architecture or circumstances, I might also do the same with the .Load ... but that's rare that I have a .Load method.

-tg
 

Sitten Spynne

You don't want to know.
Joined
Aug 18, 2010
Messages
4,580
The book Clean Code makes a suggestion early on: types should either be:
  • 'Data types' that are just properties and simple methods that act on the properties.
  • 'Logic types' that represent operations performed on data types.
It strongly recommends against mixing the two. I didn't like this stance at first. It's been 2 years since I read that book, and now I agree.

I would write Policy such that it's just a collection of properties that describe whatever a "policy" is in your domain, and methods that answer questions/make changes that the properties don't neatly represent. I would have a PolicySerializer class responsible for saving it to a file, database, etc.

It turns out the flexibility this affords is invaluable, but not visible in many people's careers.

On one project, I didn't even know which database I'd be using when I started. So I wrote an IDatabase interface and, for the first couple of months, used a "MemoryDatabase" that was little more than an array. When I figured out I wouldn't have access to any of our networked databases, I chose SQLite. So I wrote a new "SqliteDatabase" that supported this. 5 months later, I found out I'd have to run on Linux instead of Windows, and that the SQLite API I'd chosen only worked on Windows. It took about 8 changes in 2 files to make that swap, because I took care to hide API-specific details behind another layer of interfaces. If I had put a Save() method on every one of my data classes in that program, it would've taken dozens of lines of updates across as many files to adapt to each change. Because I put that logic somewhere else, my changes were isolated to one corner of the program and nothing else had to know.

Using more classes and depending on interfaces instead of concretion is a technique for isolating yourself from change. It pays off in many other ways, most importantly enabling unit tests. The myth goes it increases project complexity, but in my experience that's only true in the eyes of novices. You should spend far more of your life as a 'veteran' than a 'novice', so it seems silly to optimize towards novice practices in all work.

If you don't feel like you'll ever be facing change, you can bend those rules and write larger classes that depend on concretions instead of abstractions.

But my personal experience, having written code in that manner for almost 10 years, is we're usually wrong about whether change will happen. And code that does not separate its concerns spends more time in the debugger than the 'more complex' code that focuses on composition of smaller units.

Put another way, which seems better: having a hammer and a pair of boots, or owning a pair of 5 pound boots with a steel heel?
 
Top