Sign in to follow this  
  • entries
    9
  • comments
    41
  • views
    11328

The No-OOP back to basics experiment

Sign in to follow this  

1629 views

I'm about to embark on a journey where I let go of the typical way I program and try something radically different as an experiment. I've been programming for a little over 15 years now and I have grown tremendously, but recently I've felt like I haven't been as productive as I've been in the past. This feeling has become stronger watching Casey Muratori code live on stream for his Handmade Hero project. The man is just non stop pumping out code like there's no tomorrow with seemingly no effort. What's funny is that I feel I've been the same way when I was less experienced, but nowadays I feel like most of my time is spent on thinking on what should go where, how objects should interact, what should be private or protected, should I have a move constructor or delete the copy and assignment constructor etc. What I want to find out for myself with this experiment is whether I can be more productive in a large project over a reasonably long time following a new, or rather old, way of programming.


Every experiment needs an hypothesis!
I'm not going to be all scientific about this, but I have an hypothesis. As you're learning to program, you're unfamiliar with a lot of concept and you make a lot of mistakes that you learn from. Often times you don't really know what the correct solution is, feeling like there is such a thing (there rarely is :(). You'll scour the internet and you find all sorts of patterns and paradigms, you'll love them and start applying them everywhere. If they don't fit the problem, you'll make it fit god damn it, silver bullets everywhere. Eventually you come to your senses and you start applying things where they fit instead of forcing it onto everything. You're experienced now, know what to do and when to do it, you make less silly mistakes and you only go "fuck, did I write that?" 9 out of 10 times now. Mistakenly you've attributed this success to the use of OOP, not the experience you've gained. That's what this experiment is about.


What I'll be doing and what not
I will program a complete game (the one I've wanted to make for so long now!) without the use of OOP and some typical C++ features.
If you're wondering what my definition of OOP is, I honestly don't know... or care much, but these are some of the things I'll be doing differently:


  • Solve the problem at hand in the most simple possible way, no generalizations until they're actually needed.
  • No more combining data with procedures, so no member functions.
  • No more templates, I want my compile- and turnaround times to be as fast a possible.
  • Start making use of some macros. I've been very opposed to using them before, but I will use them sparingly where they make sense.
  • Everything is public, yikes!
  • No constructors, destructors, copy/assign/move constructors. But what about RAII!? Well I did say radically different, so I'm going to give this a shot.

    That's enough to give most programmers a heart attack. But I wonder, how many have actually tried programming in a different way after they've become experienced and how many just got set in their way? I love programming and I want to keep growing at it, that means sometimes you'll have to visit the no fly zones, just to test if your presumptions are (still) correct.

Sign in to follow this  


9 Comments


Recommended Comments

Interesting experiment. Speaking personally, years ago I was forced back to using C after many years of C++ and I found the only major issue for me was a lack of destructors for resource management. I ended up writing an outer and inner version of any function this affected, the outer to allocate resources, call the inner then free the resources. This allowed me to just return from the inner in the way I was used to in C++ but was a lot of boilerplate overhead. I'm sure in most ways you will find your approach very liberating. We all tend to get caught in over-engineering.

Share this comment


Link to comment

Thanks for sharing Aardvajk, how long did you have to use C for? I've already run into a case where I wanted to use a destructor, but I realized that it would only be used once and that I'd only have to manually call a shutodwn procedure once. Normally I'd be wary of this as future me or someone else might forget that manual call, but I'm trying to let go of that and see how much of an actual problem it will become. Over-engineering is the deadlock equivalent of my brain :P

Share this comment


Link to comment

Thanks for sharing Aardvajk, how long did you have to use C for? I've already run into a case where I wanted to use a destructor, but I realized that it would only be used once and that I'd only have to manually call a shutodwn procedure once. Normally I'd be wary of this as future me or someone else might forget that manual call, but I'm trying to let go of that and see how much of an actual problem it will become. Over-engineering is the deadlock equivalent of my brain :P

 

I have been using C for a quite a while.  Mostly programming for hobby type stuff in C and ASM on really tiny devices with little to no processing power or memory.  They call these things Microcontrollers.  The thing is with C you don't necessarily need a shutdown procedure it all depends on what you are doing.  The one thing I tell everyone that is going to do things the non OOP way and use the C way is the golden rule of what allocates the memory frees the memory.  If you remember this things become very smooth and less over engineered.  So you you have a function that allocates memory say for a structure make sure you have a function that frees the memory of that structure.  So what you get is a very smooth flow chart like experience.  It also makes potential memory leaks easy to fix if you forget to call your function that frees up the memory you allocated. When I code in C I usually dedicate specific code files for tasks as well.  So if you are creating a structure or a linked list or whatever have a file that is dedicated to operating on that data which would include manipulation, creation and freeing of the memory.  It makes for some smooth organization and prevents your code cluttering up one file.

 

I will agree it can seem like a lot of boilerplate but in reality I much prefer the non object oriented style of Functional and Procedural languages it just makes more sense and I feel leads to better code design as there are less over engineering pitfalls you can corner yourself into getting carried away.  Much more linear and understandable.

Share this comment


Link to comment

I look forward to your results. I suspect you'll be fine in the shoot from the hip style because you're far more skilled than your 15 year ago self. As the project continues, things might get a little tangled. Fixing bugs or adding new features might be a little tougher, but that's a problem for future self to deal with. :)

 

What game are you testing this hypothesis with?

Share this comment


Link to comment

Thank you for the replies, lovely to see others showing interest.
 

Much more linear and understandable.

 
Yeah I agree with that. I often see deep inheritance trees in other code bases where methods are overloaded on various levels and it's a hell to figure out and work with.
 
 

What game are you testing this hypothesis with?

 
I'm making an online multiplayer arena based action RPG, that's a mouthful :P. I have some experience with mutliplayer games and I've written most of the fundamentals already, but I'm rewriting those now. It'll be fun to see how that turns out.
 
I'll be posting some of my experiences in the near future. I've already switched from CamelCase with the first letter capitalized to first letter lower case because that was quite handy for functions that construct an object so I can do something like:

Address address = address(...);

Which you'd normally be able to do with constructors, but now initialization is separated from allocation.

Share this comment


Link to comment
[quote name="Mussi" timestamp="1460581329"]Thanks for sharing Aardvajk, how long did you have to use C for? I've already run into a case where I wanted to use a destructor, but I realized that it would only be used once and that I'd only have to manually call a shutodwn procedure once. Normally I'd be wary of this as future me or someone else might forget that manual call, but I'm trying to let go of that and see how much of an actual problem it will become. Over-engineering is the deadlock equivalent of my brain :P[/quote] It was many years ago before home internet was standard and I only had an old PowerC compiler on a floppy disk. Kids today probably wouldn't even understand that sentence :). Wasn't for long to be fair. Had some interesting bugs when I forgot to prototype some functions returning pointers and the compiler was converting them to integers at the call point (shudder). A lot of the criticisms of C++ seem to me to be more criticisms of bad OOP. I find C++ to be very flexible in terms of programming paradigms. I fell into the bad OOP trap when I started with C++ and it took many years of experience to claw my way back out again.

Share this comment


Link to comment

I'm definitely more productive without OOP baggage. There's practically nothing of value in it. It's a cargo cult we're more or less forced into by trendy language designers and OS/library developers. C++ is not a good language (IMHO), it's merely a path of least resistance, like PHP for webdev. In those languages most of my code does not look very OO-ish.

 

I've been using C++ for a few years (for the first time since the 1990s when it really sucked), basically just the "C with Objects" subset. Everything "public"; some macros; no Templates, no Exceptions. Initially I had a small inheritance hierarchy for sprite types but that was a mistake; it's all compositional now, sort of "Data Oriented Design" style. I'm also trying to avoid STL now; too many surprises, crazy iterator syntax, and horrible performance for Strings especially (but I do use them at startup and level loading, just in gameplay). I do use methods where they make sense (a function clearly belonging to an object) but I don't think they're "good OOP", they're just one of the few organizational devices available in C++.

Share this comment


Link to comment
Solve the problem at hand in the most simple possible way, no generalizations until they're actually needed.

Started doing that about 10 years ago, reduces thinking about the future, but adds more work when making an extension. In all, I think it was a good move.

 

No more combining data with procedures, so no member functions.

OOP is not about member functions. You can write OO code in C too. Just use the first parameter as "this" variable which is a pointer to a structure, et voila object functions, just written differently, syntactically.

 

I don't think it's a bad pattern, you struct has meaning, and having a function to operate on a struct is a natural next step. The typical OO way of having member functions just makes this marriage more explicit.


 

No more templates, I want my compile- and turnaround times to be as fast a possible.

Templates have been invented to replace #define macros that contained code fragments. I would say a template is better than writing the same code 20 times, or doing #define macro expansion magic.

 

However, I would also argue that you have very few places with repetitive code, unless you over-engineer or over-generalize. Typical places are with standard containers as lists and sets, but those are in STL already.

 

Start making use of some macros. I've been very opposed to using them before, but I will use them sparingly where they make sense.

Never used macros much, as finding errors in them is a mess. I do use lots of static inline functions though, which the compiler then hopefully merges.

 

Everything is public, yikes!

Have been doing that for a lot years too. If you use the rule, everybody can look at anything, but respect its owner, it works nicely (until you start using threads :p )

 

You'll come to see getters and setters mostly as useless clutter :p

 

 

No constructors, destructors, copy/assign/move constructors. But what about RAII!? Well I did say radically different, so I'm going to give this a shot.

Ha, fun :)

 

I started coding C again after 20 years of OO, and oh boy, it's really getting used to that level of programming again :)

You need to write a lot more code than you'd would in OO.

 

I am less sure it counts as "more productive". Sure you type more lines of code, so it feels asif you're making more progress, I can see that. On the other hand, all the thinking you do when you are more experienced is because you're more focused on what you need to make, rather than just random trying. You don't just code, you also make sure it works in the context you want it, and you try to ensure it won't blow up if you change or extend the program tomorrow.

 

Arguably the latter time can be reduced, if you don't have plans in that direction.

 

 

In all, a good experiment, I think. At the very least you'll improve your understanding of what OO offers you, and maybe a few other things as well. good luck!

Share this comment


Link to comment

Thanks for sharing your experiences everyone.

 

 

OOP is not about member functions. You can write OO code in C too. Just use the first parameter as "this" variable which is a pointer to a structure, et voila object functions, just written differently, syntactically.

 

I agree, it's not about member functions. Conversely, you can write non OO code with the use of member functions. I don't think passing the first parameter as the this pointer, or even using the this pointer counts as OO. It's a bit of a vague term, so I try to avoid using it most of the time.

 

 

Never used macros much, as finding errors in them is a mess.

 

Yep I've seen this happen. I'm using some single line macros now, they're actually quite nice and can make things clearer and less error prone.

 

 

You'll come to see getters and setters mostly as useless clutter :P

 

I rarely use those so not much change for me there :P, but I am used to making things that belong to an object's internal state protected/private. So far I haven't encountered any problems with having everything public, but I haven't nearly written enough code yet to draw any conclusions.

 

 

You need to write a lot more code than you'd would in OO.

 

I am less sure it counts as "more productive".

 

This is an interesting point. On it's own merit, I wouldn't count it as being more productive either, but what if feeling that you are actually has a positive influence on your productivity? I don't know and I'll probably won't be able to tell even after having conducted my experiment. I don't even know if it'll result in more code.

Share this comment


Link to comment

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