Jump to content
  • Advertisement
HappyCoder

My main complaint with OOP

Recommended Posts

The religion
Simplicity is not an art to be frowned upon, for it takes courage to stand with the inexperienced and see the world with their fresh untainted eyes. Bless thee who admits having the sin of personal bias and learns common sense, for thou shall ascend into a multi-paradigm programmer.

The bizarre
We used to have a rule at the company against global functions. Ended up with expressions like "(x.cos()+1).sin()" instead of "sin(cos(x)+1)" because the language's core math library wasn't OOP enough. The developers making advanced algorithms could barely work anymore and it was later replaced with normal math functions again.

The milking cow
Workers who feel that their skills are no longer needed at the company will always find new ways to pretend that they're doing something useful. Mostly to protect the fragile ego, otherwise they would idly browse Facebook in plain sight like the others. OOP was something that allowed solving complex problems that didn't exist to begin with. One can spend years maintaining bloated frameworks or go around changing the style back and forward while causing version conflicts, adding administrative overhead and introducing defects without having to solve any real problems for the customers.

Share this post


Link to post
Share on other sites
Advertisement
8 hours ago, dmatter said:

You can pass renderers around in the form of the Renderer interface and invoke DrawToCanvas without ever knowing that you'll be drawing a circle. Imagine a function that takes a List<Renderable> and draws all the shapes in batch. Of course there are languages out there that support partial-application more succinctly than this.

A renderer instance is a global state. This can lead to flickering colors caused by other people's modules. Turning off one module can break completely unrelated features.

Adding a base class Renderable is easy, but removing it two years later will break things. Then you somehow ended up with seven layers of inheritance and have no idea which function will be called because they all have the same name.

You'll later see that you needed Printable, Listener, Serializable, FactoryConstructable, et cetera and create more helper classes trying to wrestle the growing complexity. Compile time type safety goes out the window when you don't have time to implement virtual methods for all 47 types, so you end up leaving an error message in the base class. Then you realize that you never needed polymorphic storage to begin with and can drastically reduce the number of heap allocations that caused memory leaks and cache misses. A basic API using overloads and templates then brings back type safety and allow customers to call the API from another programming language using simple type prefixes, so don't add inheritance just because you can.

Edited by Dawoodoz

Share this post


Link to post
Share on other sites
On 9/28/2019 at 10:44 PM, HappyCoder said:

Now imagine we want to add functionality so the circle can

  • Calculate area/circumference of the shape
  • Draw it to a canvas
  • Add the shape to a spacial index
  • Serialize the shape to a file 

In a good OO design, this doesn't happen. The Circle class

  • Must be the representation of a circle in the geometric sense and nothing else. It cannot be allowed to depend on something that isn't geometry, such as a spatial index, a Canvas, or a file. This is called the "single responsibility principle": forcing together multiple responsibilities means creating tensions when anything changes.
  • Should derive from a Shape interface or abstract class, together with other shape types. This makes clear that there are functions that apply to any shape (e.g. computing area, perimeter, bounding shapes), and operations that only make sense for circles (e.g. construct a regular polygon with the same center and the same area and a given number of sides, which can be useful as an approximation)

In practical terms:

  • The renderer should find a way to treat all shapes the same way (e.g. if the Shape interface offers a point containment test and a bounding convex polygon the renderer can test samples inside the region of interest) or segregate different Shape subclasses by their different rendering methods (e.g. scanline rendering of circles, scanline rendering of whole convex polygons and scanline rendering of a triangle decomposition of nonconvex polygons)
  • A spatial index should probably deal with Shapes and their bounding shapes only.
  • Serialization could be allowed in Shape classes because it's so basic and intrusive, but keeping it outside would be cleaner.

Share this post


Link to post
Share on other sites
3 minutes ago, LorenzoGatti said:

In a good OO design, this doesn't happen. The Circle class

  • Must be the representation of a circle in the geometric sense and nothing else. It cannot be allowed to depend on something that isn't geometry, such as a spatial index, a Canvas, or a file. This is called the "single responsibility principle": forcing together multiple responsibilities means creating tensions when anything changes.
  • Should derive from a Shape interface or abstract class, together with other shape types. This makes clear that there are functions that apply to any shape (e.g. computing area, perimeter, bounding shapes), and operations that only make sense for circles (e.g. construct a regular polygon with the same center and the same area and a given number of sides, which can be useful as an approximation)

In practical terms:

  • The renderer should find a way to treat all shapes the same way (e.g. if the Shape interface offers a point containment test and a bounding convex polygon the renderer can test samples inside the region of interest) or segregate different Shape subclasses by their different rendering methods (e.g. scanline rendering of circles, scanline rendering of whole convex polygons and scanline rendering of a triangle decomposition of nonconvex polygons)
  • A spatial index should probably deal with Shapes and their bounding shapes only.
  • Serialization could be allowed in Shape classes because it's so basic and intrusive, but keeping it outside would be cleaner.

Separation is always good, but I've never seen a single case where run-time polymorphism offers any advantage for generic geometry, because the types are always stored by value or given directly as arguments for performance reasons.

Share this post


Link to post
Share on other sites

In addition (it is a paradigm/philosophy with pros and cons like any other), you can mix more than one together.

You can have code that follows Object Oriented Programming principals, and also follows Data Driven Programming principals, and also follows Event Driven Programming principals, and also follows SOLID principals, and also follows more besides those.

For example, carefully crafted objects with a clearly defined interface and abstractions that allow for extension can fit with OOP principals, the interface can be built around arrays that minimize hardware calls and enable fast bulk processing to follow Data Driven principals.  Those calls can be triggered in response to user events, hardware events, and similar that follows Event Driven models, and so on.  

Very few sets of paradigms, principals, and practices are mutually exclusive.

Share this post


Link to post
Share on other sites

"Principals" are heads of schools. Here we are talking about "principles".

I don't usually point out spelling mistakes if the message is understandable, but that was too many "principals".

Share this post


Link to post
Share on other sites
Posted (edited)

Suggestion to refactor to point out the "has a " relationship between principals and principles. Like

principal.getPrinciples()

Just trying to be funny ... 🤐 🙂

Edited by Green_Baron

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!