I work with a team of developers who all have several years of experience with languages such as C# and Java. Most of them are young enough to have been shown OOP as a standard way to develop software in university and are very comfortable with concepts such as inheritance, abstraction, encapsulation and polymorphism.

Yet, many of them, and I have to include myself, still tend to create classes which are meant to be used in a very functional fashion. The resulting software is often several smaller classes which correctly represent business objects which get passed through larger classes which only supply ways to modify and use those objects (functions). Large complex difficult-to-maintain classes named Manager are usually the result of such behaviour.

I can see two theoretical reasons why people might write this type of code:

It's easy to start thinking of everything in terms of the database

Deep down, for me, a computer handling a web request feels more like a functional operation than an object oriented operation when you think about Request Handlers, Threads, Processes, CPU Cores and CPU operations...

I want source code which is easy to read and easy to modify. I have seen excellent examples of OO code which meet these objectives. How can I start writing code like this? How I can I really start thinking in an object oriented fashion? How can I share such a mentality with my colleagues?

This question came from our site for professional and enthusiast programmers. Votes, comments, and answers are locked due to the question being closed here, but it may be eligible for editing and reopening on the site where it originated.

There are either too many possible answers, or good answers would be too long for this format. Please add details to narrow the answer set or to isolate an issue that can be answered in a few paragraphs.
If this question can be reworded to fit the rules in the help center, please edit the question.

14

When you say "functional", do you mean "procedural"?
–
Adam RobinsonMar 17 '11 at 20:54

I would have to say, practice and experience...Maybe check out OO design patterns and some books on OO...You wont be able to write nice OO code if you dont sit down, figure what the problem is, and through your experience and what you have learned about OO, come up with a good OO design...
–
DanielMar 17 '11 at 20:57

"tell don't ask" is a great way of putting it. For example, all those manager classes shouldn't modify the other objects, they should tell the other objects to modify themselves.
–
jhockingJul 2 '11 at 13:26

Read up on design patterns. OO seems like a solution in search of a problem until you understand these. Design patterns can be thought of as hints about how to apply OO to real world problems. It will also help you see what contexts OO is useful in.

The idea that OO is the only "right" way to program is fingernails on a blackboard to me. OO certainly has its uses, but if a problem is easier to represent with functional or procedural programming, then there's nothing wrong with using functional or procedural programming. OO for the sake of OO (or any paradigm for its own sake instead of because it makes the problem easier to represent) is just plain silly.

@Kamil: What if you're writing something where the data and the behavior are not strongly linked? A good example would be numerics code. The numerics algorithms can pretty much operate on any bag of numbers. What data should go in the class with the algorithms? Clearly the numerics algorithms don't belong in a class that also holds a bag of numbers.
–
dsimchaMar 17 '11 at 21:36

@dsimcha: There are some cases, but it is very rare.
–
Kamil TomšíkMar 17 '11 at 21:45

@Kamil: It becomes a lot more common when a language allows some kind of duck or structural typing and make it easy to write generic code. For example, see D's std.algorithm. The main point of this design style is that it separates behavior from data.
–
dsimchaMar 17 '11 at 22:13

@dsimcha, algorithms shouldn't be dependent on the data type. That's the point behind OOD. The numerics framework sends messages that describe the desired (in this case understood) behavior of mathematical functions. The type will determine how to interpret that message in a way appropriate for the data. Contrary to @Kamil's comment, OO actually decouples behavior (interfaces actually) and data whereas procedural code is dependent on them. OOD reduces dependency on what the data is, focusing instead on what your procedures need to do.
–
HuperniketesJul 1 '11 at 10:56

I would turn this inside-out. It looks like you're experiencing some cognitive dissonance because you're trying to do things that don't map well to the object paradigm in a language where everything is supposed to be an object. You're recognizing that something is wrong, and you think it's with you.

It's not; the problem's with your language. It gets easier when you recognize that object oriented programming is a tool, not a Gospel principle. It's a very useful tool for solving many types of problems, but there are also lots of other problems that it's not so helpful for. But when you're stuck with a language that doesn't accept that, then pretty much the only thing you can do is what you've been doing so far: use objects and classes when you can, and hacks that look like objects and classes when no better alternative presents itself.

I disagree. I'm not looking for OOP just by principal. We're using an OO language and our code is hard to read and hard to maintain. OOP is a tool that makes code more reusable and more easily maintained. I'm just not very good at using that tool
–
Mr GrievesMar 18 '11 at 14:37

I found the words IS, HAS, CAN, and WILL very useful in thinking OO.
For example lets say I am creating a OO CMS, So I am trying define a WebPage object.

I use IS to help define inheritence:

No Inheritance

I use HAS to define attributes:

The WebPage HAS html content

The WebPage HAS a URL

I use CAN to help define functions.

The WebPage CAN Display.

The WebPage CAN be modified.

I use WILL to define potential outputs, and interactions with other objects.

None for WebPage

Now take a WebForm

A WebForm IS a WebPage

A WebForm HAS input fields

A WebForm CAN Validate Inputs

A WebForm WILL email the inputs to a defined address.

I find this technique useful, because after doing this with a lot of objects you can see say a bunch of objects have the same set of functions, perhaps that set of functions should be an interface or a more basic object you didn't think of. Well perhaps.

Remember that Object Oriented Programming was originally invented as part of simulation. An object should represent one farmer, one bale, one truck, one station, etc. A class is a category of objects that all work more-or-less the same. If you keep this real-world grounding in mind then OOP comes naturally, if you think of OOP as a purely mathematical abstration and you'll soon be swimming in vaporware.

I'm not entirely sure if I understand your question, but it sounds to me that you're using objects as a way to bundle data together in a class, provide getter and setter methods for the data, and then send the object around between classes which does various work on that object or objects.

The most important thing about object-oriented programming is, I think, division of responsibility. Each class should be responsible for a single area, and should provide all functionality that you require from that area. You shouldn't have to ask an object for data that then needs to be processed if the object could already do that for you.

A trivial example: Say you have a Date class. It holds the necessary information to represent a date, and you can get and modify that information through getDay, setDay, getMonth, setMonth, getYear and setYear methods. So far it's just a wrapper for data - it doesn't actually do anything, it's not responsible for anything more than holding that data.

So say you want to add a day to a given date object. What would you need to do? Of course, get the day, increment it, and return it by setting a new day. But if it overflows to a new month then you would need to increment the month, and maybe even the year if the month overflows to a new year. But this shouldn't be your responsibility to handle this - this should be part of the Date class, which should provide you an addDay method and take care of incrementing the date accordingly.

Take it a step further, and say you wish to find out if a date is a leap year or not. You can do that by checking the year yourself. But that shouldn't be your responsiblity - the Date class should do that for you through a isLeapYear method or something. Or say that you want to check if two dates are the same. You can do this yourself by getting and checking the day, month and year yourself, but this should also be the responsiblity of the Date class - it should provide you with a isEqual(Date) method.

Let us further say that you have an Order class, which contains various stuff that any order should, including a Date of when it was issued. Say you want to check if two orders were issued on the same date; you can get the date from both orders and check it yourself through order1.getDate().isEqual(order2.getDate()). But this sounds like something the Order class should be responsible of - it should have an areDatesEqual(Order) method and do the work for you.

On the other hand, if you had an Order object and a User object and both happen to have a date that you want to compare, then in this case you should do that yourself; the Order class is only responsible about orders, and the User class about users. Thus there can be no areDatesEqual(User) in the Order class and no areDatesEqual(Order) in the User class - that would be a violation of responsibility.

My eye-opener was realising that there is no 'one' type of perfect class.

Regarding:

"The resulting software is often
several smaller classes which
correctly represent business objects
which get passed through larger
classes which only supply ways to
modify and use those objects
(functions). Large complex
difficult-to-maintain classes named
Manager are usually the result of such
behaviour."

I don't think that your description is necessarily an example of bad OOP.

The "several smaller classes which correctly represent business objects" - those look like 'model' classes.

The "classes which only supply ways to modify and use those objects" - those look like 'controller' classes or 'services' to me.

You might clear things up by simply renaming these large 'manager' classes into either 'controllers' or 'services'.

There might be a problem if your 'services' / 'controller' classes are trying to do too many things...hence their large size. In that case there may be potential to move more behaviour closer to the data in the models.

Another thing to keep in mind is 'layering'. It helps to have a clear idea about where groups of classes sit in the great scheme of things. Most importantly "which other classes can they know about and 'use'". Before I create a class I'm always asking which layer it is in.

I thought that I understood object orientated programming until I was tasked to create UML diagrams for a program I had already written. It was a humbling experience to say the least.

Get your team to draw up some basic object diagram's that illustrates how the objects interact as well as their methods and properties. Chances are, if it is a tangled, incomprehensible mess then it is not good OOP.