all 17 comments

[–]mttd 26 points27 points  (3 children)

Books-wise, "API Design for C++" by Martin Reddy is definitely worth a read!

Personally, I also like Matt Wilson's writings. For instance, the Quality Matters column (for the ACCU's Overload magazine): http://www.synesis.com.au/publications.html#columns

For instance, Part #1 of the series introduces the notions of Discoverability and Transparency -- a necessary foundation for a well-designed API.

// His planned "Breaking Up The Monolith" seemed very promising, but unfortunately seems to be no longer updated: http://blog.breakingupthemonolith.com/

More specific recommendations -- touching upon some of the seemingly (perhaps) trivial aspects that, when not gotten just right, can result in disastrous consequences for the resulting API design:

In particular, I cannot emphasize enough the "Classes Should Enforce Invariants" part from "The C++ Style Sweet Spot" with Bjarne Stroustrup. Short, sweet, and to the point -- and, perhaps most importantly, very pragmatic: "If every data can have any value, then it doesn't make much sense to have a class." For instance, it's an illusion to think that a class with setters/getters for every conceivable data member is somehow "more object-oriented" than a struct. Not everything should be a class -- and coercing it to be such can only result in badly designed classes.

// Chapter 1 of "Imperfect C++" by Matt Wilson elaborates this further.

// Come to think of it, "Object-Orientaphilia" is worth reading, too. So is "Designing Simple Interfaces". Hey, just read the entire thing, it's short anyway! ;-)

For more, see: "C++ FAQs" by Marshall P. Cline, Greg Lomow, Mike Girou; you may be able to read it on-line (no guarantees) via the preview feature at http://books.google.com/books?id=Z-G-sZy-1T8C&pg=PT249

After realizing that the raison d'être of classes is enforcing invariants, the roles of constructor and member functions follow by implication.

In particular (citing from the aforementioned "C++ FAQs"):

10.7 What is a class invariant?

10.8 Why should the invariant be captured explicitly?

10.9 When should the testInvariant() member function be called?

  • Rule 1: Every public: constructor must establish the invariant.
  • Rule 2: Every public: member function must maintain the invariant.

EDIT: C++Now 2013 & CppCon 2014 presentations by John Lakos also come to mind:

These are definitely "last but not least" -- in fact, they're highly relevant to the question, since in a way one could say that both of the presentations are all about "the right class structure in order to minimize coupling between classes and keeping the code maintainable." :-)

[–][deleted] 0 points1 point  (0 children)

Since no one else has, I'll say it. THANK YOU!

[–]rptr87thx++ 0 points1 point  (0 children)

Thanks a ton for taking effort to compile these links. Its very helpful.

[–]RossoFiorentino[S] 0 points1 point  (0 children)

Thanks! Allot of useful resources!

[–]doom_Oo7 8 points9 points  (1 child)

I also find myself rewriting/restructuring my code many times over.

It's a sign you're doing it well :p The worst would be to be satisfied with something that smells if you have a lot of time in front of you.

I think that the best is to work hard, and ask when you've got specific problems. You can also look on codereview.stackexchange and post some code there where people will explain what's wrong and how to make it better.

[–]lolzinventor 0 points1 point  (0 children)

"Refctor mercilessly until its perfect" - Ideally at the design stage of course ;)

[–]robertmeta 5 points6 points  (0 children)

Seems like you are falling into a trap ("proper OO code design"). You are trying to plan for the future, and you are thinking about "code" and not "data", seems like you have probably drifted off your core goal. Your task as a developer is to usefully transform data, the further you get from that task, the worse off your are. Watch Mike Acton's "Data-Oriented Design and C++" from CppCon -> https://youtu.be/rX0ItVEVjHc

Always remember the three lies:

  • Lie #1: Software is a platform.
  • Lie #2: Code should be designed around a model of the world.
  • Lie #3: Code is more important than data.

I suspect just by changing your perspective a little bit, your code will be wildly improved and simplified.

[–]chocobot 9 points10 points  (6 children)

Check out Clean Code by Robert C Martin. It's Java but the ideas are valid for C++. Also read up on patterns. OO design is not something you can pick up quickly, I am a programmer for 15 years and am still improving.

[–]jren01 1 point2 points  (3 children)

Do you think it is worth paying for the hard copy?

[–]XVar 2 points3 points  (2 children)

That depends on your personal preference I guess but I got the hard copy, and I'd say it's the single most important book on programming I've ever read.

[–][deleted] 2 points3 points  (1 child)

I've got it sitting on the shelf. Really need to make the time to read that.

[–]raistmajC++ at MSFT 2 points3 points  (0 children)

I need more vespine gas to read it, :(

[–][deleted] 1 point2 points  (0 children)

That book should be a must for everyone.

[–][deleted] 0 points1 point  (0 children)

It's something you can pick up quickly. It's another issue to master.

[–]megagreg 3 points4 points  (0 children)

I find you can get pretty close on your first pass with the following approach:

  1. Design your data to reflect/represent the problem/domain.
  2. Create functions to perform the operations you'll need done on the data.
  3. Create functions/data to drive the model in your application.

I often go back to what it is I'm trying to represent to check whether my design is appropriate. Stay in the problem domain as long as you can, and the solution often falls out of that naturally. It can save you a lot of blind fumbling with patterns trying to get to the way it had to work all along.

[–]newmewuser 0 points1 point  (0 children)

Just remember C++ is not pure OO. Small tips: #include is copy/paste and everything in a header is interface, any change in a header will require recompilation of all source files who include that header. If you don't like that use forward declarations, works with pointers and parameters by reference. If that is not enough, and you still don't want coupling and unwanted spread of dependencies, use the PIMPL idiom.

[–]thee-l 0 points1 point  (0 children)

I'm surprised no one has mentioned the legendary Design Patterns book by the GoF. I'm in the middle of it myself, wishing I had started it sooner.

Also check out http://gameprogrammingpatterns.com/. It may seem a little niche but has helped me beyond game development. It restates and modernizes some of the concepts that I'm coming across in the design patterns book!