• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Junilu Lacar
  • Jeanne Boyarsky
  • Bear Bibeault
Sheriffs:
  • Knute Snortum
  • Tim Cooke
  • Devaka Cooray
Saloon Keepers:
  • Ron McLeod
  • Stephan van Hulst
  • Tim Moores
  • Tim Holloway
  • Carey Brown
Bartenders:
  • Piet Souris
  • Frits Walraven
  • Ganesh Patekar

Procedural programming shortcuts in OOD?

 
Ranch Hand
Posts: 125
1
Clojure Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I work on an app for assessment surveys. There is a comparatively large number of connected objects in the system.

All over the place in my code, I have to follow ridiculously long object links to get the data I want. If I have a Patient, I might have to go:
List settings = patient.getTrack().getProduct().getProductSettings().getThis().getThat()
.getSomeOtherThing().getCrazyReadingAllOfTheseSillyGets()
.getAWigBecauseIHaveTornOutMyHair();

I'm probably committing a positively unforgivable sin on the Object Oriented Design morality scale. I've started writing helper classes in each package whose sole purpose is to 'wrap' all of those ridiculously long calls. So the Site package has a SiteRetriever class that can give me a Site Object based upon an input Patient, Site Product, or SiteProduct Setting. The SiteProductSettings class has a SiteProductSettingRetriever class chat can give me a SiteProductSetting list based on a Site, Patient, or SurveyEvent.

Naturally, if the internal functions in an Object change substantially I have to go back and fix all of the ___Retriever classes, and that's a pain in the neck. But their presence makes the rest of the code so much more compact and easy to follow.

Any suggestions or comments?
 
Bartender
Posts: 2968
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Actually you are describing the bad code smell Message Chain or even Feature Envy.

You can always consult Refactoring: Improving the Design of Existing Codeand Refactoring Workbook if the on-line resources aren't enough.
 
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello, comrade

Look for forgiveness for you have sinned, brother

You�ve broken the sacred Law of Demeter


If from a Company object you need to know the employees of a department,
instead of using...



....you must create a method in the Company class that provides you the employess throught the department class, like this:





In other words:


According to the sacred LoD the Company Class never must interact directly with the Employee class.

I hope this is somehow helpful for you my fellow sinner.

Regards,
Edwin Dalorzo

P.S.
Remember to break the law from time to time in order to make your life a bit more real.

[ April 05, 2006: Message edited by: Edwin Dalorzo ]

[ April 05, 2006: Message edited by: Edwin Dalorzo ]
[ April 05, 2006: Message edited by: Edwin Dalorzo ]
 
author
Posts: 14112
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Originally posted by Edwin Dalorzo:
If from a Company object you need to know the employees of a department,
instead of using...



....you must create a method in the Company class that provides you the employess throught the department class, like this:





It might be even better to have no getter at all - don't ask the object to give you something, but tell it to do something for you:

 
Michael Swierczek
Ranch Hand
Posts: 125
1
Clojure Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I appreciate the feedback, thanks.
I've definitely broken the Law of Demeter (though I understood the concept before today, I didn't know it had a term). And I'm definitely engaging in feature envy.

So I've got to fix that. Here's the actual problem that pushed me to my misdeeds:
There are Sites (like a health clinic), Products (mental health surveys, smoking cessation surveys, etc..), Surveys associated with each product (initial survey, follow up survey, survey by a parent or caregiver, etc..), Product Parameters (configurable settings unique to each product and not universal to all products), Product Track (a set of rules governing which consumer gets what Product survey when), Site Products (A Product licensed for use by one site), Site Product Parameters (The Product Parameter Settings associated with a site product, a list of String values), Survey Event (an actual survey taken by someone on a given date). Plus of course there are Patients, Caregivers, and Counselors using the system.

So let's say I have a surveyEvent id and want to check a SiteProductParameter whose name is "foo" before generating a PDF report about that survey event, but only if the survey was taken by the patient and not if it was taken by someone else on behalf of the patient.
SurveyEvent survEvent = ManagerFactory.getSurveyEventManager()
.getSurveyEvent(surveyEventId);
Person pat = survEvent.getPatient();
Person st = survEvent.getSurveyTaker();
if (st != pat)
return;
Site site = pat.getSite();
Product product = survEvent.getSurvey().getProduct();
List sppList = ManagerFactory.getSiteManager().getSiteProduct(site, product).getSiteProductParameters();
int size = (sppList == null)? 0: sppList.size();
for (int i = 0; i < size; i++)
{
SiteProductParameter spp = (SiteProductParameter)sppList.get(i);
if (spp.getName().equals("foo")
{
// ... do something important
break;
}
}

... The code already does things like that in dozens of places, and I've added code that does it in dozens more.

So my cheat was to write a seperate set of helper functions that includes:
public static String getPatientSurveySiteProductParameter(String surveyEventId,
String productParameterName);
[ April 05, 2006: Message edited by: Michael Swierczek ]
 
Peer Reynders
Bartender
Posts: 2968
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Very first Impression:
Looks like somebody is trying to avoid learning SQL.

That's of course assuming that the ManagerFactory/SurveyEventManager is sitting on top of SQL-capable persistent storage.
 
Michael Swierczek
Ranch Hand
Posts: 125
1
Clojure Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
"Looks like somebody is trying to avoid learning SQL."

Why do you say that? I'm not asking to be combative, I'm just curious. That's the class architecture that was in place when I was hired, I didn't built it.

I want to learn. That's why I asked the question. I think all of the fancy links between the different SQL tables are handled in classes so that dozens of different SQL queries wouldn't need to be crafted by hand. Everything is handled by Hibernate.
 
Peer Reynders
Bartender
Posts: 2968
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Originally posted by Michael Swierczek:
"Looks like somebody is trying to avoid learning SQL."

Why do you say that? I'm not asking to be combative, I'm just curious. That's the class architecture that was in place when I was hired, I didn't built it.



I wasn't being facetious. I actually meant "somebody", not you personally � because of the exact reason you stated; I couldn�t know whether you wrote all of the software.

Originally posted by Michael Swierczek:
I think all of the fancy links between the different SQL tables are handled in classes so that dozens of different SQL queries wouldn't need to be crafted by hand.



Exactly � that is often the sign of "somebody" who would rather go through code contortions in the somewhat familiar Object-Oriented paradigm rather than familiarize themself with the Relational paradigm. This can be excused if "you" are dealing with an underpowered persistent storage � but if "you" are working with something like Oracle � use "your" assets! And if "you" want to be paranoid about exposing the data-model to the application simply create stored procedures.

Originally posted by Michael Swierczek:
Everything is handled by Hibernate.



Gavin King and Christian Bauer (Hibernate In Action) actually state that Hibernate was never intended to remove the burden of learning SQL from the developer (a refreshing change from EJB). In fact they state that a decent familiarity with SQL is required � otherwise you wouldn't know how to tweak the mappings to optimize the SQL statements Hibernate generates.

Anyway looking at the code I got this impression:
- Report on all self-administered patient surveys about products used (at the site) for/because of property 'x'.

My instinct would be to formulate an HQL/SQL query to select the relevant surveys first, i.e. letting Hibernate instantiate only the relevant surveys, and then report on them.

Now you may already be working with a pre-selected set, however it may still be more effective to flush all the modifications to the database and then query the relevant ones with additional criteria for the report.
[ April 06, 2006: Message edited by: Peer Reynders ]
 
Peer Reynders
Bartender
Posts: 2968
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Judging by this superficial glimpse the current object model seems to be mainly data and have very little behavior. See Anemic Domain Model.

The following is not compilable code - its just supposed to give you some ideas.


Now this is more code but it's a lot easier to unit test.

legacy code is simply code without tests. Michael C. Feathers in Working Effectively with Legacy Code.
 
Michael Swierczek
Ranch Hand
Posts: 125
1
Clojure Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I wasn't being facetious. I actually meant "somebody", not you personally � because of the exact reason you stated; I couldn�t know whether you wrote all of the software.

Okay, no problem. Even if I had written it, I wouldn't be offended by the commentary. I've five years' professional experience, and I couldn't count the number of times I realized a past design decision was foolish.

I'm definitely going to pick up a book or two on design. Between your example code and the explanation of the Anemic Domain Model, I think that describes the problem. I tried reading books on design back in college, but I didn't have the real world experience to really grasp the examples. I've got a little bit better of a foundation to work with now.

Is there any particular book you would recommend?

[EDIT] Actually, I think the "Working with Legacy Code" book may help me solve two problems at once. The project has 290 working JUnit tests (and a mountain of incomplete JUnit tests) but most of them are not really 'unit' tests at all. I've been making a hobby out of adding one or two unit tests per week. Maybe it will help if I pick up the pace.
[ April 06, 2006: Message edited by: Michael Swierczek ]
 
Peer Reynders
Bartender
Posts: 2968
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Originally posted by Michael Swierczek:
Actually, I think the "Working with Legacy Code" book may help me solve two problems at once.



I think that that one is pretty much at the top, just realize that it builds on Fowler's "Refactoring" so if you find any sudden wide "chasms" you may have to supplement it. Another one to look at is Robert C. Martin�s Agile Software Development: Principles, Patterns, and Practices.

You can immediately have a look at The Craftsman #1-8 articles for some interesting test-driven development and refactoring sessions.

Some time later you may want to have look at Eric Evan�s Domain Driven Design � Tackling Complexity in the Heart of Software.
 
Michael Swierczek
Ranch Hand
Posts: 125
1
Clojure Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Again, thank you for the information.
 
Yeast devil! Back to the oven that baked you! And take this tiny ad too:
Building a Better World in your Backyard by Paul Wheaton and Shawn Klassen-Koop
https://coderanch.com/wiki/718759/books/Building-World-Backyard-Paul-Wheaton
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!