8

As most projects use a C++ API, they deal with constraints of the API and constraints of the project itself.

I'm a beginner at programming, I don't like to use OOP at all because 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.

I still can be ok with OOP, since it still allows to make some great things like Qt and Ogre3D, but those are only APIs, not applications, and those codes need to be perfect so nobody can criticize the work.

I don't understand why do most programmers, since they make apps and not APIs, want to do perfect code like they design some genius piece of code, and waste time on this.

  • 19
    Give it a couple of years of having to go back to your old non-perfect code and trying add features to it, fix bugs in it, etc. You'll see why people care about getting it as right and clear as possible the first time around. – R0MANARMY Jul 8 '11 at 12:37
  • See (this question)[programmers.stackexchange.com/q/65216/8823]. Not because you're not a programmer, but because there's some good description of why beautiful code is good – Austin Hyde Jul 8 '11 at 13:44
  • 2
    Is this question about beautiful code, OOP, or private scope? I really can't tell. – Sean McMillan Oct 3 '11 at 13:59
  • 1
    Wow...don't know where to start. Hope I never have to see or work with your code... – Rig Mar 10 '12 at 23:27
  • 1
    Good code and good API have a lot of things in common. Good OOP code should have an interface that looks exactly like a well-designed API. – rwong Mar 11 '12 at 4:15
12

Have you ever heard the saying "No man is an island"?

For most programmers this is true. Hardly anyone writes code that is "just an app". On many non-trivial apps one programmer writes the UI which needs to be easily modified by a designer. It also must allow for clear data binding to the business logic (Controller, ViewModel, or whatever you want to call it). Another programmer writes that controller, which can often be extremely complex, but needs to be simple enough to be easily consumed by the front end programmer. That business logic coder is consuming code from whoever wrote the data layer (Model, Repository, etc.). You do not have to use OOP, however, what OOP is pretty good at is allowing you to encapsulate logic behind an interface so that other people you work with can use your code without breaking it (assuming you tested that interface!). Abstraction is not the silver bullet, but you certainly enjoy it when you use libraries like Ogre3d, that allow you to do things you would be very unlikely to accomplish entirely on your own.

So you might be saying now "Seriously, I'm an exception and no one will see my code or work with it at all". Fair enough, but when you need to fix a bug in that app a few months from now, or want to add a couple features, you will probably see that the person who wrote that code back then and the person who is modifying it now are two totally different people. We often assume we will remember things, which is at the core of why we write sloppy code, but the truth is that yourself six months from now will not remember the hacks you put into your application now. Your future self will have enough to deal with, so why not give him/her a break?

43

Any fool can write code that a computer can understand. Good programmers write code that humans can understand. ~Martin Fowler

That, in a nutshell, is why you want to care about beautiful code.

You don't write code for the computer. The computer only understands binary code anyway (which is produced from your source code by way of compilers and interpreters). It doesn't care about beauty or clarity or even whether your code does what it is supposed to do.

You write code for your fellow programmers. And they do the same for you. If you can't understand a piece of code written by somebody else, then what do you think your chance's are of finding and fixing a bug or adding new functionality?

  • 1
    I would add that it's especially easy to write totaly cryptic code in C++, and this is why this is even more important in this language ! – deadalnix Jul 8 '11 at 14:45
  • 1
    Well I don't really agree with this quote, reusable code is good code, true, but languages are made so that programmers can work faster, not necessarily to be read by other programmers. It's painful to read code, so either put comments, or changing the design to make it more understandable for a human, yes, but good design does not always come with "easy to understand". A program can execute both simple and complicated tasks, and programming languages can limit how well you can design sophisticated apps. Programming language make things easier, not fancier. – jokoon Mar 13 '12 at 15:37
3

What others have said like you never know if you may need your code again in the future is right of course.

But for me there is one major point, why I always try to write beautiful code:

It's training to get better.

If I learn something new about a language I use or about some general programming concepts, I immediately try to make use of it, try to make it part of my daily workflow and mental toolchain.

If you only read about something like OOP, you will forget most of it within a few weeks. And you will never get the training how to properly apply it to big problems as long as you don't teach yourself by applying it to small problems.

Example:

Why is it important to restrict yourself with private scope?

In small projects it isn't. Some languages (for example Ruby) even discourage this kind of encapsulation to some degree. But there are uses for it. Many.

And using it comes with certain problems and many details you have to learn. Using it in small projects will teach you this. You will get to see some error messages from your compiler that are new to you and in a small project you will be able to find the source of the problem more easy.

You learn about namespaces in C++. There is not that much need for them in small projects. Same goes for genaral structure of header files and includes. You can learn all of this early on in the protection of a small code base.

1

It's all about having to maintain legacy code. And in a few months the code you're writing now will become legacy code that you will also have to maintain.

Coding for Violent Psychos

1
  1. What R0MANARMY said in his comment. Clean & "beautiful" code makes it easier to read, understand, maintain, change, and fix in the future, not only for yourself, but for others that come after you.

  2. Some people, when they do something, try to make it the best they possibly can, in the best possible way, so it is "perfect", or in this case, "beautiful". I've found that there is a large overlap between this set of people and developers (myself included!).

Keep in mind though, that "beautiful", "clean", or "elegant" are highly subjective terms that mean different things to different people. From what I've seen though, code that is widely regarded as beautiful, clean, and/or elegant,

  • Is easy to read and understand
  • Has no, or little, unnecessary code laying around
  • Is easily extensible and/or modular
  • Is well documented
  • Follows any standards for related languages/technologies
  • And doesn't do anything unexpected (e.g. side effects in an accessor method)
1

I agree on maintainability thing. Just try to make a relatively big project yourself, and you'll see all the mess that ties your hands upon bug fixing, adding new features, etc.. But to speak about beauty:

Beautiful code is the desired product quality because (at least, C++) programming is an ART.

  • 1
    Although with the introduction of lambdas does now involve less sharks in formaldahyde – Martin Beckett Jul 8 '11 at 15:32
1

[...] 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 -921141282.

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 getters and 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.

0

Well, defining clean and useful ("beautiful" is a poor qualifier) interfaces is all about making sure that :

  1. The user understands with minimal pain how to use your object (or system of objects) just by reading it's interface.
  2. The user will have a hard time using the object/system in a wrong way - the interface makes it hard to do something wrong or signal problems early.
  3. The interface describe a useful abstraction.

The points 1. and 2. requires you to think a lot about the contract you're making with your user. That contract, or protocol, is the way to communicate to the user how he can use your system. For example, read-only member functions (const member functions) tells a lot about in wich situations you should be able to call that function. In the same way, the attributes of each function dives the user to gather and provide the minimal informations required for the system to work.

All points together suggest that your interfaces should only show services that are useful to the user. First to limit user's use of the system to only what the sytem was made for. Second, by avoiding him to manipulate internal state in a wrong way. So, the easiest way in C++ to achieve this is to put all members private and explicitely state which services your system provides, using member or global functions (in namespace(s)). Another way is to use the PImpl idiom.

Third, and the most important : your interface should provide a useful abstraction, meaning that the user shouldn't have to understand implementation. When I drive a car or a washing machine, I don't want to know how it's built inside (even if I'm a technology geek...). I just need to use it and not have to bother about what's inside.

It's hard.

Any protocol definition, like designing a programming language or designing a class is not as obvious asa you may have thought first. A lot of experience is required to apreciate the subtelties of desiging interfaces.

All that isn't revelant when you're defining structures or classes that represent very low level concepts. The higher you get from hardware, the most you need to have clean, clear & useful interfaces.

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