2

I've studied design pattern and oop principles, still feel that there is something missing in most design theories. Maybe the fact is that there is not a 'theory' as it is in database design.
Let me explain with an example.

Suppose that i want to model different ways to produce orange juice.

Let say that i start by a class Oranges, that models a lot of oranges that will be of a certain variety, of a certain ripeness, they may have been froozen etc., ant these will by my Oranges class properties.

Then i continue by providing Orange with a squeeze method.

This seems to be correct, because ties togheter the method to the data it applies to, that is the precondition to achieve encapsulation and other valuable oop principles.

But quickly it comes out that it has not been a good choiche because there is not just one way to squeeze an orange. It would be preferrable to have a Juicer class whose instances contains details of the juicing method: by hand, with an electric juicer, including the pulp, not to mention mixing different varieties of oranges. Where the latter opens an whole new cathegory of possibilities that were not available (or not achievable with ease) if each Oranges instance would have been processed using its squeeze method.

Say that we have performed a 'refactoring' of our oo architecture and move to another similar example that will get us to the point.
It is now a common practise to use an ORM to save class instances to database and get them back later. In what is it similar to the Oranges class example? Well, here i have a class whose instances may be persisted to a database, that is 'allow a particular process'. But the class itself does not contain the logic for doing so, that actually is in the ORM classes. So it seems that the same process of 'externalization' of the Oranges example has taken place in this case too.

And here is the question

Given that it is desireable to reduce the number of attempts-and-refactorings to the minimum, what are the questions that a programmer should put in order to determine precociously if a method should be externalized to another class? Are all the methods of a class exernalizable or is there a set of core methods that are inherently of the class itself and so not externalizable?

Ideas

As i said in the beginning, i'm not completely clueless, i feel more like that a 'comprehensive' theory is missing.
It's easy to put some examples:
if i have a class whose instances represent invoices, i will have a method 'calculateTotalAmount'. This is clearly an inthrinsic, core method of that class, as oppsed to the methods for saving that invoice to the database that will be 'external' of the class itself. But this is not a 'final answer', but a starting point that serves to demonstrate that 'not all methods are equal', but methods may be divided into cathegories. How many (useful) cathegories can we make, and are there methodologies that put these questions?

6 Answers 6

2

Given that it is desireable to reduce the number of attempts-and-refactorings to the minimum...

Desirable, yes. Practically possible in every case, no: because you don't know everything about the solution yet.

I don't see this as a lack of a formal methodology (you'll have the same issues with a relational model of your orange-juicer as you discover new ways of extracting juice), but as an intrinsic process of thinking about and evolving your design and application.

EDIT: I missed an assertion on first reading, added here for further illustration (not to hammer you or anything, you've asked a very good, fundamental question, just trying to be thorough) -

...if i have a class whose instances represent invoices, i will have a method 'calculateTotalAmount'. This is clearly an inthrinsic, core method of that class...

No, it isn't. The total may be maintained incrementally instead as invoice items are added, deleted, or edited. Or 'CalculateTotalAmount' might be convenient if the Invoice class has only a few simple InvoiceLineItem objects in a collection in memory, but even then the actual calculation may be ridiculously complex, time-dependent, require a boatload of supporting objects and be subject to multiple varying discount levels based on the purchaser, billing agent, line item codes, service provider, location, time of day, and so on (think 'insurance claim invoice').

The methods and properties of classes (and thus the protocols of the application) depend on what you are trying to do, which influences what structures will be more (or less) convenient to do so. And you only know all of that after you're done.

(Which is why refactoring is crucial for code longevity, but that's another discussion)

1

I think you are looking for SOLID. More precisely, Single Responsibility Principle.

These are not methodologies, but more like way you should think about your solution and guidelines to validate this solution. In the end, you still need to use your experience and common sense to judge your final design.

The reason non existence of such rigid methodology, that would allow you to validate your solution, is simply because scope of such validation is huge. Correctness of OO design depends on requirements for not only the classes itself, but also on classes that depend and are depended on by this design. And also context of the whole application. If we take your Orange and Invoice examples, they might have radically different designs depending on application, yet they might be "correct" implementations in all those cases.

1
  • 2
    SRP is about as nebulous as you can get. "Your class should do one thing." OK, great. Now what? Commented Aug 10, 2013 at 16:19
1

Presumably there is some human being somewhere who wanted you to model the making of orange juice. Perhaps instead it is you, and you just wish to model it for the fun of it.

Start by writing out, in English (or the language of your choice) how you would describe the process. Keep track of the nouns, verbs, and other parts of speech.

You might end up with something like "I take an orange out of the bowl and roll it around on the table to "soften" the inside so that it will produce more juice when cut. Then I cut the orange in half, and use a handheld squeezer to squeeze the juice into a glass. Sometimes, if I'm lazy, I will use the mechanical juicer in my cupboard, but it usually makes too much pulp. Then I drink the glass of juice and go sit on the couch for an hour"

Now you have a description of what is going on, and what you need to model.

So you find the nouns, and make those the classes. You find the verbs, and make those the methods. It is just a starting point, but it is important to note the following:

Software always models something, and the actual thing that you are modelling is what drives how you design the classes and their relationships. And now the most important part: someone else might describe the same process differently. The order might be different, some parts might be different, and so they need a different model in software to describe what is going on. BUT NO MODEL IS BETTER or MORE ACCURATE than other, they simply are different models.

Some software systems may even need more than one model for the same process, even. So remember, your OOP design is about matching a model for a specific purpose in a particular domain. The "correct" OOP design is the one that best captures the model in the particular domain.

1

Are all the methods of a class externalizable?

Yes, you can completely separate all methods that operate on a class from the class its self. Should you completely separate all methods from a class? Well, that depends on how you want to organize your code.

is there a set of core methods that are inherently of the class itself and so not externalizable?

Yes, any method that requires only the values associated with an object. Anything else should probably be externalized and handled by another class.

You mentioned the database and ORMs, if you wanted to include the method for saving an orange to the database within an orange class, now your orange needs to know about your database. Why does your orange need to know about your database and what are the pros and cons of this decision? Well, the method for saving an orange is close to the data that is being saved, that seems good. However, now you cannot have an orange without having the database.

To me, that last line really drives it home. In the real world, oranges don't know about databases so why should they in your code. In short, there is no one size fits all theory/pattern, it is up to you as an engineer to see how all the pieces fit together.

0

What are the questions that a programmer should put in order to determine precociously if a method should be externalized to another class? Are all the methods of a class exernalizable or is there a set of core methods that are inherently of the class itself and so not externalizable?

As I have learned about design ("Agile Principles, Patterns, and Practices in C#" by Robert and Micah Martin) one should fully understand the real process in order to create the correct abstraction. And once you have it -provided you base that abstraction on interfaces- you're rewarded with a "polymorphism gain". Having that in mind I see an important question is "Is this behavior something this element does for itself or it's another element's behavior -acting on this- that produces the result? (orange juice, persistence, whatever)".

Additionally in Craig Larman's "Applying UML and Patterns" you find what he called "GRASP" (General Responsibility Assignment Software Patterns). For example:

  • Information Expert A general principle of object design and responsibility assignment? Assign a responsibility to the information expert— the class that has the information necessary to fulfill the responsibility.
  • Low Coupling How to support low dependency and increased reuse? Assign responsibilities so that (unnecessary) coupling remains low.
  • High Cohesion How to keep complexity manageable? Assign responsibilities so that cohesion remains high.
  • Pure Fabrication Who is responsible when you are desperate, and do not want to violate high cohesion and low coupling? Assign a highly cohesive set of responsibilities to an artificial or convenience "behavior" class that does not represent a problem domain concept — something made up, in order to support high cohesion, low coupling, and reuse.
  • Indirection How to assign responsibilities to avoid direct coupling? Assign the responsibility to an intermediate object to mediate between other components or services, so that they are not directly coupled.

I've seen that when you manage to produce a good model you really have a group of cohesive objects sending messages to each other and everything runs smoothly. On the other hand you know that "something" is wrong because the interactions are not natural.

0

going directly from your example:

"certain ripeness" - is a core business rule that has control over the behavior of whatever is built. there are oranges that are unripe, and oranges that are ripe.

this is either automated - the oranges are compared against a ripeness scale. OR this has to be done manually by an Orange Juice Manager. either way thats where the implementation requirements of the objects comes from. the first question is - does the Orange Juice Manager also control the Juicing ? Or does the Orange Juice Manager hand off a "ripe" set of Oranges to a Orange Juicer Person?

if yes then that is the first clear boundary. the orange juice manager approves the oranges, determines the amount to be squeezed - and then hands it off to the Orange Juicer person. The Manager does not know how the juice is going to be squeezed or what kind of device is used.

Those are the important details of the design. the specifics of the oranges and how they are squeezed are implementation details and as such -- they are volatile and we expect them to change.

The Orange juice manager acts upon objects, but they will always be approving oranges and orders. The Juicer will always act upon objects - he always return orange juice. That is an abstract concept - it is stable and it does not change. HOW he squeezes the oranges is a specific concept - therefore it it unstable, therefore it will change, therefore it is further down the class responsibility chain.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.