36

When the concepts of Object Oriented Programming were introduced to programmers years back it looks interesting and programming was cleaner. OOP was like this

Stock stock = new Stock();
stock.addItem(item);
stock.removeItem(item);

That was easier to understand with self-descriptive name.

But now OOP, with pattern like Data Transfer Objects, Value Objects, Repository, Dependency Injection etc, has become more complex. To achieve the above you may have to create several classes (e.g. abstract, factory, DAO etc) and Implement several interfaces

Note: I am not against best practices that makes Collaboration, Testing and Integration easier

11
  • 23
    Creating a good software architecture has always been hard and will (most likely) always be.
    – johannes
    Commented Jun 10, 2012 at 14:21
  • 6
    I would rename addItem for add and removeItem for remove. Because It's easier to read. stock.add(item) or stock.remove(item). And more OOP oriented.
    – razpeitia
    Commented Jun 10, 2012 at 18:28
  • 1
    Original OOP looked almost nothing like what you’ve shown. OOP isn’t about syntax, it’s about a kind of abstraction popularised by Smalltalk. This doesn’t necessarily prove your point wrong, nor is the premise flawed; rather, it’s even more true than you realise. Commented Jun 10, 2012 at 22:12
  • 1
    you're comparing apples and orange, by your logic, then imperative programming (i.e. loops and if-condition) is simpler than all the things we have today. Imperative programming is the building blocks for classes/OOP, and classes/OOP is the building blocks for design patterns. Things become more complex as you progress because you're solving more complex problems.
    – Lie Ryan
    Commented Jun 11, 2012 at 1:25
  • 2
    @LieRyan - I've seen problems become complex just because nobody in charge was able to solve them with simple imperative programming and attacked them with design patterns on top of OOP on top of the simple imperative solution that should have been implemented alone.
    – mouviciel
    Commented Jun 11, 2012 at 7:26

8 Answers 8

35

OOP itself hasn't changed much since its inception. A few new angles to it have been explored, but the core principles are still the same. If anything, the collective knowledge gathered over the years makes the programmer's life easier rather than harder. Design patterns are not a hindrance; they provide a toolbox of solutions to standard problems, distilled from years and years of experience.

So why is it you perceive OOP today as more complex than when you started using it?

One reason may be that the code you are being exposed to becomes more complex - not because OOP has become more complex, but because you have advanced on the learning ladder, and get to read larger and more complex code bases.

Another reason may be that while the complexity paradigm hasn't changed, the size and complexity of an average software project may very well have. With processing power available on customer-grade cellphones that would have been a developer's wet dream on a server less than two decades ago, the general public basically expecting slick animated GUI's for even the cheapest throwaway app, and entry-level desktop PC's being more powerful than a 1980's "supercomputer", it is only natural that the bar has been raised since the early days of Smalltalk and C++.

And then there's the fact that in modern applications, concurrency and parallelism is the norm rather than the exception, and applications frequently need to communicate between different machines, outputting and parsing a whole zoo of protocols. While OOP is great as an organizational paradigm, it does have its limitations, just like any other paradigm: for example, it does not provide a lot of abstraction for concurrency (most implementations being more or less an afterthought, or outsourced to libraries entirely), and it's not the best possible approach for building parsers and transforming data. Modern programming frequently runs into the limitations of the OOP paradigm, and design patterns can only take you so far. (Personally, I consider the fact that we need design patterns a sign of this - if the paradigm provided these solution out-of-the-box, it would be more expressive for these problems, and the standard solutions would be obvious. There is no design pattern to describe method inheritance, because it is a core feature of OOP; but there is a Factory Pattern, because OOP does not provide an obvious natural way of constructing objects polymorphically and transparently.)

Because of this, most modern OOP languages incorporate features from other paradigms, which makes them more expressive and more powerful, but also more complex. C# is the prime example for this: it has obvious OOP roots, but features like delegates, events, type inference, variant data types, attributes, anonymous functions, lambda expressions, generics, etc., originate from other paradigms, most notably Functional Programming.

2
  • So design patterns added the complexities. Meaning design patterns are not necessarily OOP but added to enhance OOP. Commented Jul 17, 2012 at 10:01
  • @tunmisefasipe: Not quite. Design patterns are just proven solutions to standard problems; they are not an 'addition' to OOP, but a consequence. The complexity was already there; design patterns just provide cookbook strategies to tackle it.
    – tdammers
    Commented Jul 27, 2012 at 21:33
17

No, it's becoming more over-engineered. And you're right- in the SO C++ chat we frequently joke about the AbstractSingletonFactoryProxyBeanBridgeAdapterManagers we see in Java code.

But good code does not exhibit this property. In good code, you can still say

std::stack<int> s;
s.push(5);
s.pop();
8
  • 5
    Not clear from your post, but I think the over-engineering is evident in both Java and C++ code. It's not a property of either language by itself, but of programmers' practice... Both languages allow writing good code, though neither (IMO) is particularly suited for it :) Frameworks in Java do suck, regrettably.
    – Andres F.
    Commented Jun 10, 2012 at 14:55
  • 12
    Talking about over-engineering, this thread is mandatory: discuss.joelonsoftware.com/default.asp?joel.3.219431
    – Secure
    Commented Jun 10, 2012 at 15:17
  • 3
    @AndresF. true, but you don't seem to get so much of it in C++ code, whereas you do in Java and .NET: just look at the MVVMVMMD design pattern msdn.microsoft.com/en-us/magazine/hh965661.aspx as one example of how you take 'simple code' and slap a design pattern on it to make it look 'easier' and then slap another design pattern on the design pattern because the original pattern wasn't as simple as advertised. Over-engineering is becoming more and more commonplace.
    – gbjbaanb
    Commented Jun 10, 2012 at 16:13
  • 5
    I'd argue with the "becoming" bit. Over-engineering is as old as engineering.
    – user53141
    Commented Jun 10, 2012 at 16:13
  • 4
    @AndresF. We’re particularly anti-Java in the chat but it’s true that Java, more so than C++, encourages over-engineering because it makes it more affordable (GC), and popular enterprise Java libraries have popularised this style, as you’ve noted yourself. Commented Jun 10, 2012 at 22:14
10

I would say that the problems with "complexity" you mention has nothing to do with OOP. It has more to do with separating concerns.

Many years ago I worked on a system, where the domain class had the responsibility of loading itself from the database, e.g.

var userId = Request.QueryString["UserID"].ToInt();
var user = new User(userId);
user.Name = ...;
...
user.Save();

This is very clear code. No problem in understanding this. The problem however would be in unit testing the code. Namely, how would I unit test the User class without having to load one from the database? And how would I test this web request handling code without having access to the database? It is simply not possible.

That is why we have a pattern like a repository, to separate the responsibility of handling the domain logic from a user from the functionality of actually loading and saving one in a data store. IOC helps in reducing coupling, also making code more testable, etc.

So if we go back to the example you write, what would you do with the stock after you create it? Save it in the database

Stock stock = new Stock();
stock.addItem(item);
stock.removeItem(item);
this.StockRepository.Add(stock);

There, done! There is no movement in the progression of OOP that suggests that it should be any harder. Unfortunately, if you choose to use an OR mapper for your data access code, you could run into the problem that the OR mapper is placing restrictions on how you can write your system. But that is another matter.

If you are new to these patterns, you may require to learn a new style of programming. But that style of programming is in no way more hard than old school OOP programming.

4
  • You know the effort you have to make to set up your repository. Though after setting it up, it become reusable. Commented Jun 10, 2012 at 15:17
  • perhaps the problem is with unit testing, if we had better tools to test the whole (as you have to anyway) instead of the tiny pieces, we'd have systems that had fewer bugs?
    – gbjbaanb
    Commented Jun 10, 2012 at 16:15
  • 2
    @gbjbaanb: we already have that, its called integration/functional testing. Unit testing serves a different but equally necessary purpose
    – Kevin
    Commented Jun 11, 2012 at 1:14
  • @gbjbaanb - We already have great tools for system-wide/acceptance testing, e.g. Cucumber on the Rails platform. But the teams that are really good and writes very few bugs, but also delivers fast, they write a lot of unit tests, and just a few system-wide tests. See about the "Testing triangle", e.g. here jonkruger.com/blog/2010/02/08/the-automated-testing-triangle
    – Pete
    Commented Jun 11, 2012 at 6:52
4

Neither. Our problems haven't really changed; the bar for acceptable code has been raised.

To achieve the above you may have to create several classes (e.g. abstract, factory, DAO etc) and Implement several interfaces

You don't have to do that. But if you don't then problems crop up; problems that have always been there. Now though, programmers have enough experience doing it to identify those problems and provide mechanisms to alleviate them (if needed). We learn more about those, and come up with better solutions (see - programmers' views on the singleton for example).

But you also have to realize that introducing programmers to OO (or anything for that matter) will tend to gloss over the exceptional circumstances. It's simply easier to explain the happy path, and worry about the rest once the beginners have that down. There is no silver bullet; so yeah, I suppose things will always seem harder when that idyllic delusion is broken...

3

The "intro to OO" examples are a lot simpler than a real world application. You only need one class to achieve the above. The problem is it doesn't do much. Some design patterns try to come close (like ActiveRecord.) But ultimately, any example that isn't trivial will have more than one class; that is ok.

1
  • Also note that frameworks build up over time. So yes, programming does require more knowledge. It also means one can do more in less time. Commented Jun 10, 2012 at 14:26
3

The programming languages using OO today are trying to cater for complex requirements and environments that keep on changing. OO allows its adopters to hide variety of levels of complexity (amongst other features) so that coding becomes more clear and more easy to build and understand. However, this feature is not always out of the box. In your example, OO has allowed you to hide some details from me by providing a method to manage items in a collection and may be even to persist it using the "AddItem" method. Spending effort in hiding complexity may result in an easy to use and a re-usable framework that makes life simpler. For example, Many ORM implementations allow you to communicate with databases without having the programmer write the SQL details. This is indeed powerful and does make it simpler on the developer.

The patterns you refer to are just that. They are supposed to make your life easier. But it is up to you to adopt them and adjust them. The fact that more work is required is just because you gain more benefits. It is like paying more for a Ferrari. If you want the extras you pay for them. So, if you decide to build a scalable N-Tier solution that can be run on several servers and different back end databases, there is a cost for that. If your application does not require this complexity, ignore the extra pieces and fall back to the simplest solution that covers your need (KISS & YAGNI).

So, to wrap up, I don't think that OOP as a concept itself is getting more complex, we, the users of OOP have the choice to use it in different ways, and that is a good thing.

4
  • Clear points. I know YAGNI. What is KISS? Commented Jun 10, 2012 at 15:00
  • 2
    @tunmisefasipe, KISS is a short name for a design principle. The original words are "Keep It Simple (Stupid)" (ref: en.wikipedia.org/wiki/KISS_principle) but a more polite phrasing may be "Keep It So Simple".
    – NoChance
    Commented Jun 10, 2012 at 15:18
  • 3
    @tunmisefasipe - KISS = Keep It Simple, Stupid. A phrase I repeat to myself OVER, and OVER, and OVER, and it still doesn't always seem to sink in. Commented Jun 10, 2012 at 15:18
  • @MichaelKohne, we all do! I guess that it is an art to be able to simplify things. E=MCC says a whole lot in a very concise form!
    – NoChance
    Commented Jun 10, 2012 at 15:21
3

Short Answer: Yes, because you deal with harder problems.

Long Answer (strongly biased): For me the design patterns usually indicates that some paradigm have problems in given area. The OOP patterns deal with problems of OOP (on lower level the Java patterns deal with problems of Java), FP patterns deal with problems of FP etc.

During programming you may have different priorities. You may want to have correct program, you may want to have shortes time-to-market, fastest program possible, long-term maintainability or instant maintainability by a new hire. Depending on bushiness you are in you will have vastly different - if you are programming controller of power plant you want to do it right first time and not bugfix every time now and then ("Does meltdown occurs every time you press Ctrl+Alt+Del?"). If you are in HPC the logic can be relativly simple but you want to execute it as fast as possible etc. etc. Additionally some paradigms fits certain problems better (say AI and logic programming, data and relational databases).

OOP is to some extend 'too good' in simple cases and it's "modelling real live" story. For example in first book about OOP I read there were classes Person, Employee and Manager with is-a relationship. So far so good but what if employee is promoted to manager?

On the other hand other paradigms have harder first-time lessons - for example FP with immutable variables (funny thing is that people who had experience with programming often find it harder to learn than those for whom this is first language) - however ultimately they are not harder than OOP. Testing pure functions is trivial and in Haskell/Scala/... you have tools that generate tests for you.

PS. Yes - answer is biased against OOP and I admit that to some extend it is 'in reaction' to OOP. OOP have its uses but it is not the only, ultimate solution in my opinion.

PPS. Yes - use design patterns - they make OOP programming ultimately simpler.

PPPS. I used OOP as synonym of OOP imperative programming.

2

I think its more a case of the documents and examples becoming more realistic.

Early OOP books (particularly early Java books) presented an absurdly simplified view of application programming. The "Debit a bank account with a 10 line Java program" examples was always particularly annoying as I have seen real life examples of this simple task running to 6000 lines of COBOL code (and the Java replacement attempt running to 3500 lines before it was abandoned as unfeasible!).

Thankfully OO books now tend to acknowledge the complexities of real life, and, provide useful examples of how to deal with them.

But if you want to see how to run a bank account in only 15 lines of code functional programming is your man

Not the answer you're looking for? Browse other questions tagged or ask your own question.