[...] nobody clearly managed to explain to me WHY it's is so important
to restricting yourself with private scope to prevent others
programmers to break data organisation consistency of some kind.
In a small enough team with a small enough codebase that's really well-coordinated with good standards (could just be one person), you can often find reliable software that just leaves all the data out in the open for anyone to touch with all data fields of a
struct exposed wide open and with the
struct definition wide open for anyone who includes that header to access. Murphy's Law doesn't always apply in those cases.
But I have worked in the opposite scenario of an enormous codebase with many millions of LOC dating back to the 80s with a large team of developers from across the world where we only met face-to-face every few months, loosely-coordinated, sometimes barely speaking the same language, no coding standards except for the SDK which people often didn't follow anyway, no unit/integration tests, using SVN without branching and sometimes going 6 weeks without checking in code, only to bomb us with bugs, and it wasn't until then that I truly understood the value of information hiding and maintaining invariants.
I dealt with bugs where I couldn't even reproduce the issue consistently on my machine, and sometimes none of us could between the whole team. And when I finally could luckily reproduce the user-reported issue or something that resembled it after all kinds of trial and error (and the trial and error often took hours because the inefficiency of our software combined with running it in debug against user-end production data often took 15+ minutes just to get the data to load), I'd trace it down to something like a
struct for a string type which had a
len set to a garbage negative number, like a string length of
That should never happen, but who done it? So I had to set memory breakpoints and find out, and when I finally did, it was like a cascading interaction of uninitialized variables being used arithmetically which ultimately added up to a string
len field being set to a negative garbage number, and that code had not been modified in years. It flew under the radar.
And all that time after encountering many bugs like this, I thought to myself, how much more reliable would our software be if it just used
setters? Getters and setters are generally indicative of the worst kinds of interface designs possible, but a setter could at least trigger an assertion failure if someone tried to set the length of a string to a negative value. We could have caught that bug years before at the the precise time it was introduced in seconds, not the culmination of hours of investigative effort. And that's just thinking selfishly as a developer; it doesn't cover all the hours of grief it could have saved the users and QA team as well. You know your system is in a pretty bad place when you're dreaming about how much better it could be if it used setters and getters in the face of the last 35 bugs you spent all-nighters fixing.
We even had cases where
structs were documented in a way stating that no one else should be accessing those data fields, only to find places in the system accessing those data fields.
So these are the types of things you can only really appreciate to the fullest by facing that worst-case scenario, but you often will unless you're lucky enough to spend the rest of your life working on smaller codebases with well-coordinated teams and strong coding standards.
What is beautiful code in C++ [...]?
That's a tough one. I'm still trying to figure that out. Most of the code I consider beautiful that I've written over the years, or at least reliable and relatively timeless and stable (not needing/wanting changes) was written in C and recently Lua. I still struggle to write C++ code that seems to pass the test of time to the point where I don't reflect back on it a few years later and at least wish I could change it. I do feel like it has gotten easier ever since C++11, but I need some years to find out how well my code manages to survive without needing changes to tell for sure. To me the ultimate "beauty" is "stability", as in code that doesn't need and doesn't even tempt any further changes but still remains relevant and useful for years to come, since that's code that incurs zero maintenance cost.