What Workplace Coding Practices Do You Use? 682
Agent_9191 asks: "Recently I've been promoted to what essentially amounts to a project lead role for every project we do, in house. Since my company has run for the past 35+ years with no form of central IT department, there has been no standards put into place for developers to abide by. One of my tasks is to set up standards in how projects will be implemented and produced. Right now I'm more concerned about trying to set up coding standards, so that any developer can jump into any part of a project and be able to figure out what's going on, without wasting a couple hours just to figure out the code. I've come across some documents in this area from a few sources (of course can't remember them off the top of my head). What practices/standards do you use in your workplace?"
Joel on Software (Score:5, Informative)
Project Automation (Score:1, Informative)
Re:Comments (Score:5, Informative)
And make sure they update comments if changes necessitate it. There's nothing worse than reading through a function's description, complete with well-documented inputs/outputs/conditions/etc. and finding out that those things no longer apply because somebody changed a 1 to a 2.
Our style! (Score:2, Informative)
int* gpiGlobalInt;
int FunClass::GetSize(int _iArg1, bool _bArg2)
{
bool bBool;
float* pfFloat;
static int siStaticInt;
for(;;)
{
}
}
Seems to work out well enough.
Project Management (Score:2, Informative)
code complete has some good things to say (Score:5, Informative)
1) document things thoroughly using a tool like doxygen. there is no excuse for interfaces not to be thoroughly documented
2) adopt a standard naming convention. in java, this is easy -- just use the default. in other languages, you'll probably have to make your own up.
3) pick an indentation style. it really doesn't matter which since tools like indent can convert between them almost painlessly. all code that goes into the repository is run through indent to put it into a standard format
4) require that code compile cleanly with no warnings at the most anal retentive compiler settings before it can be checked in unless there are good reasons to ignore the compiler warnings
5) average devs are only able to commit to the "head" fork (or equivalent in your sccs). the code is not committed to the "real" fork until it passes whatever tests you have
6) incorporate tools like valgrind into your testing cycle --- they should come back largely clean. if they don't, things need to be fixed unless there's a really good reason not to.
7) people who check in code which breaks cvs or, upon a code review, are found to not sufficiently adhere to your guidelines owe their dev group donuts.
Doxygen (Score:3, Informative)
Segfault
We don't need no coding standards! (Score:3, Informative)
A few other details that I'd like to add. K&R braces were invented, not by K&R but by the guys who typeset their book. It is a severe roadbump to try and read code where the braces are at the end of an if statement instead of vertically alligned.
Try spinal alignment for variables. Most people align their variables like this:
int something;
void somethingelse;
longobjectname theThirdThing;
Those with more of a clue align them so that you can find the variable name easily in a mess of them:
int something;
void *somethingelse;
longobjectname theThirdThing;
This puts some major space in some cases between names and short type declarations. Try aligning them like this:
The problem with this technique is that, if you ever post your code on Slashdot, you'll have to replace spaces with dots and spend fifteen minutes trying to get it to render correctly because SD doesn't support a simple PRE tag.
Other tidbits that have helped. camelNotation rules. Don't use hungarian notation, it doesn't work in a severely object oriented enviornment. Instead, preceed your variables with a single letter that tells you where it's declared. l for local, m for member (of a class or struct), g for global, that kind of thing. I've seen "my" used for member and "the" used for static very effectively, also, but stick to one.
Most of all, good luck. Remember that a lot of people's beliefs in this matter have no foundation except for what they've been doing for years. I have faith in my standards simply because I've seen what happens when you don't follow them, and that's mostly confusion.
Re:Comments (Score:5, Informative)
Is this supposed to be a joke??! Both of them are worst comments, because they only formulate in english what the code already says by itself. Everyone can see that this is an if-statement, everyone is able to identify the condition, and everyone knows the semantics of an if-statement.
A good comment is not describing what is done (since everybody can see that from the code itself), a good comment describes why something is done, or what the overall objective of the statement is.
For example:
This is ways more useful. Even more useful would be to already use self-describing symbol names in the code itself, like
#defun is sooo 70s... (Score:4, Informative)
enum {LOAD_DATA, SAVE_DATA, DESTROY_DATA}
Paul B.
P.S. And of course my all-caps enum values were considered too lame by lameness filter...
Ahahahahaaa... heh... Snrrrrrkkk. Kidding, right? (Score:5, Informative)
A couple hours???
Look, no offense, but you either only deal in "toy" code, or you have such high expectation that you will fail, and quite spectacularly.
A new coder, even an experienced one, takes days or even weeks after coming into an existing project before he can contribute anything but the most trivial of changes. For a truly massive project, or one that requires intimate domain-specific knowledge in a niche industry, extend that to months.
If you can find a way to get an unfamiliar newcomer up to speed on any "real" project in a matter of hours, consider your talents wasted in your current position.
Re:Comments (Score:5, Informative)
Amen to that.
In addition to the original comments being redundant, there's also the issue of the code and the comments getting out of sync...
The company I work for just wrote up a formal coding standard, which includes everything from a guide to our internal hungarian notation, indentation guidelines, and even which C++ features/paradigms are supported, frowned upon, or not allowed. All the coders got a chance to send in feedback before it was finalized, and we even ended up with a list of recommended reading on the subject, including:
The idea is to keep the code readable and maintainable with the least amount of re-invention of the wheel. With good coding practices, it's easier to avoid bugs in your own code and spot them in others (reviews are also a big plus on both counts). And it gets any religious battles out of the way up front, so you don't have to waste time bickering later on.
Coding Standards (Score:2, Informative)
For .Net, here is what we use (Score:5, Informative)
VB -
Version Control -
Server: Subversion + Apache
Client: Tortoise SVN (Excellent) [We also use Perforce, CVS, VSS(Commercial apps)]
Continuous Integration - Cruise Control.Net
Intranet, Knowledge Management - DotNetNuke (www.dotnetnuke.com)
Project Management - dotProject (PHP) (www.dotproject.com), MS Project
Unit Testing - NUnit (www.nunit.org)
Doxygen (Score:3, Informative)
-everphilski-
Excellent Book (Score:2, Informative)
Code Complete (Score:3, Informative)
Don't just worry about coding pratices... (Score:2, Informative)
You should also worry about development practices. Just having good coding pratices will not gain you much in the way of robust and easily changed systems. Having good development pratices will.
Specifically, I'm referring to having a complete system of specifying the requirements for any system. Too many coders these days start a project by hacking up the first thing they think is necessary, then the second, then the third, etc. While this ends up working out for most small projects, big projects can quickly become unweildy. Not to mention, if you bring in a new developer after years of working like this, the learning curve for that developer is very steep.
Enter Hatley & Pirbhai's Strategies for Real-Time System Specification [amazon.com]. In this book, the authors outline a set of strategies for developing complicated systems and making them as robust as possible. Now, you may be thingking "Who are these guys and why should I care what they have to say?" Well, they used to work at Boeing and they developed their strategies while working on designing a plane. (I think it was the 777, but I could me wrong.)
You should definately read the book, but the strategies they present basically boil down to defining the whole system from the perspective of what, how and when--separately. Here's how it works:
This may seem like overkill, but it's not. I've been working like this for a few years at college now and it has huge advantages. Development tends to go faster, problems can be fixed faster and--most importantly I think--new developers can sit down with the specifications and get up to speed very quickly.
Overall, I think using strategies like Hatley and Pirhbai have developed is far more important than all the coding practices and code commenting in the world.
Of course, YMMV, etc.
--JamesRe:Comments lie (Score:5, Informative)
Pragmatic (Score:3, Informative)
Re:#defun is sooo 70s... (Score:2, Informative)
enum DataAction
{
eLoadData,
eSaveData,
eDestroyData
};
Meaningless Standards (Score:2, Informative)
Domain Driven Design (Score:3, Informative)
For that you need an understandable design and the best advice I've ever seen for that is in Eric Evens' "Domain Driven Design" http://domaindrivendesign.org/ [domaindrivendesign.org]. The advice there will work for both Agile and non-Agile projects and its core themes are pretty much unavoidable truths about how to write code for a project that is also written about the project: use language that comes from the projects domain, insulate code from each domain or sub-domain from the rest of the world, keep each method at the same level of abstraction (that's big) and make implicit concepts explicit, to name a few. The key is for your developers to consider themselves to be authors and to strive to keep each little piece of code they write on-topic. Not only will it be easier for new developers to come up to speed but the code will work a heck of a lot better too.
Re:Comments (Score:3, Informative)
Re:Comments (Score:3, Informative)
1) Don't use variable names like x, use something that indicates the meaning of the variable - so maybe in this case lErrorStatus
2) Don't hardcode magic values, use a meaningful constant - which also means only one point in code needs to be changed if we switch CPU and find there is a different on-fire code
Then we get
if lErrorStatus == CPU_ON_FIRE then
Which I think is pretty self-explanatory.
One thing that isn't clear yet is whether this bit of code is sitting in a little function or part of a big block - i.e. what it's going to do on the 'then'.
Now at some future point we might find ourselves needing to check CPU_GETTING_QUITE_HOT. So we will still have to impact all occurrences of
lErrorStatus == CPU_ON_FIRE to add an extra test.
This leads to
3) Encapsulate tests in meaningfully named BOOLEAN functions.
I'd say it is swings and roundabouts as to whether (3) is worth the effort.
If the _cpu_on_fire(ErrorStatus) test is just done once, then we've had to go to a lot of effort to encapsulate a single line of code (as the expression is already boolean). If it is used >1 times it is definitely worth wrapping, ditto if the expression is complex - just to make sure developers get into the habit, as much as to protect against any change. (I think it's better to get into a slightly more time-consuming habit of doing the right thing and break it occasionally, than into the habit of doing the quickest thing and having to think to do the right thing).
The other principle that points to (3) is the one that blocks of code should be 'readable' and if possible a block should fit on one page - i.e. when you have an
if . . then . .
Again, _cpu_on_fire(ErrorStatus) isn't a good example as we'd be replacing one line with one line.
However, if you have a standard logging mechanism (say log4j), and template code for functions/methods, you can use this encapsulation to record the fact that the test occurred, input and output values, rather than leaving it to the individual developer to remember to add logging before their 'if' and on each conditional path.
Coding standards (Score:3, Informative)
1. As for code comments, rely on "Use The Source, Luke" as much as possible. Force people to write readable code, so that this actually works. Logical variable names, no unnamed magic numbers, no cryptic constructs. No loop bodies consisting of only a semicolon, e.g. "for(...;...;...);". Comment only on the things that aren't obvious. Any extraneous comments are bound to be outdated by the code, and will confuse more than help.
2. Write down the design in comments in the source files, as a readable piece of prose containing all of the design considerations and decisions. Design of an algorithm goes in the function body, design of a class goes above the class definition. Programmers are aware that designs are often outdated, so when they read them this is not a problem. Having the design in the code has the advantage that you can actually *find* the design for the code you're looking at. There have been too many times where I've been looking for a design document that was "somewhere on the network". Or that I've been looking at a design document on the network that had been superseded three years ago. Having your design under source control fixes that.
3. Build at least every day, or even better: continuously.
4. Automated testing. Run automated tests on every build, if possible.
5. Code reviews. Sit together once a week with one other team member who then reviews all your code for the last week (all of it, based on reports from source control). That shouldn't cost more than an hour or something, it's a good way of keeping the knowledge going around, it works as a very good "desensitization therapy" for those programmers who can't handle criticism, it increases communication within the team because people get to understand each other's work better. The only downside is that there is usually a lot of opposition against this -- I know a *lot* of programmers who don't like to have their code criticized. And there's a very clear risk that people will get into endless discussions about very small details of style ("should there be a space between the if and the parenthesis?") or other inconsequential things. To prevent these issues hogging the review, there should be a formal "escalation procedure", where the issue is passed on to an arbiter (team lead) with arguments from both parties. If a disucssion on an issue seems to go in this direction, either party *or* somebody else in the room whom the discussion irritates the hell out of should be able to cut off the discussion and "escalate" it.
Note that I'm currently working in an environment where we have (1) to (4) implemented. I'd like to have (5), because there is too many crap code being committed, and there's no check on that. It's been all too often that we've had to replace the *entire* work of a team member after he/she left, because the team member had been able to commit crap code without check during all the time (s)he was on the team.
The Practice of Programming (Score:2, Informative)
Has Someone forgot the GNU Programming Guidelines? (Score:1, Informative)
The GNU Coding Standards were written by Richard Stallman and other GNU Project volunteers. Their purpose is to make the GNU system clean, consistent, and easy to install. This document can also be read as a guide to writing portable, robust and reliable programs. It focuses on programs written in C, but many of the rules and principles are useful even if you write in another programming language. The rules often state reasons for writing in a certain way. Best, url80 [bountynetwork.com]
!(How to write unmaintainable code) (Score:2, Informative)
looong functions (Score:5, Informative)
This is so fucking wrong and wicked the programmer who did it should go straight to hell. I'm sure there's no functional coesion in there: most likely there are many disparate tasks that should be each in its own function and called from there. I'm sure there is a lot of cut-n-paste in there that should be each in its own function and called from there.
I'm sure you can guess where i'm willing to get to... more important than hungarian notation, comments or documentation in PDF format is abiding for these 2 simple rules: KISS -- keep it simple, stupid -- and DRY -- don't repeat yourself. Once you do it, coding and reading code is a lot easier.
So, my advice:
* Give meaningful names to important, global, business rules variables ( local variables like i or c are ok, since they are mostly irrelevant ) or functions/methods/procedures/subroutines
* Write short, highly coesive functions/methods/procedures/subroutines
* Stop the cut-n-paste madness! If you do it a lot, it's obvious the copied code if begging to be parametrized and be given a name. Programmers altering your original code will be thankful
* Write modular code, not a plain, huge, stupid monolithic wall of letters. Even in languages with no namespace support ( C/PHP etc ) a good naming convention for functions of a certain module/header can do wonders...
* and please: meaningful names don't mean phrase-like names like thisLocalVariableIsCool. Conciseness go a long way towards good readability...