Uli's Web Site |
|
blog |
Let's talk about Coding StyleEveryone has their own way of writing code. Their own conventions of where spaces go, how much something is indented, their own preference what color certain elements should be shown in on screen. As soon as you work in a team, be it as part of open source software or among colleagues in a company, you have to find common ground to ensure the code stays an understandable, coherent whole. Here I'll present a few conventions I usually go by, plus my reasons for it. Most of it is based on hard, practical considerations, though a few are just personal preference. Brackets in the same columnif( myVar ) This is easily the most important formatting issue. People fight religious wars about whether to put the opening bracket on the same line as the "if" statement or method name, whether to put it at the same level as the "if" or indent it one tab deeper etc. I don't care at all about the actual indentation level too much (as long as inner is somehow deeper), but an opening and closing curly bracket have to be in the same horizontal column, so you can easily match them up with your eye. While Xcode may have auto-indentation and may automatically insert brackets, I spend a lot of my time in SmartSVN, GitX or FileMerge, and these tools have very limited syntax coloring and no auto-indentation, and don't highlight blocks like Xcode's code collapsing feature does. While I do a merge, I need to be able to quickly see which brackets go together, so I can easily generate code that still compiles. Which is also why I prefer my curly brackets on their very own line: That way they're separate from the actual loop construct or conditional, and are more easily merged. Xcode actually lets you customize its behavior in this case using the XCCodeSenseFormattingOptions user defaults dictionary in its preferences, and the BlockSeparator entry in it. Consistent Uppercase/LowercaseAforementioned limited syntax coloring in all other tools I use daily also dictates the use of naming conventions: I like my macros ALL_UPPERCASE(). You can then easily tell the bits of code you need to be careful with (don't want a side effect to be executed twice because min(a,b) is actually a macro, not a function). The exception being macros like UKLog(), my variant of NSLog() that only gets compiled into debug builds. But that ends up being a function call (and is pretty much guaranteed to hand its stuff directly to NSLog()), so it's not a problem here. Mind you, I don't care much about constants declared using #define. I try to use enum for constants where possible, because those are handled in the compiler, which produces much more predictable and less surprising results than the preprocessor because it actually knows the context it is in. Those and #defined simple, parameterless constants usually are camel-cased with a prefix, e.g. eMyEnumeratedConstant or kMyConstant. Or in Objective C code, I grudgingly tend to do as the Romans do and use the class-style prefix, UKIncrediblyUsefulNotification. Only preprocessor switches used in #if statements are all uppercase, because they may massively modify the code flow and have to stand out, like DEBUG or IS_LITE_VERSION or USE_FANCY_EXPERIMENTAL_FEATURE. Consistent prefixesWhile I'm talking about prefixes, a fairly new development is also that I've started to adopt C++-style mMemberVariable-prefix syntax for my Objective C instance variables. Now that @synthesize is there and supports different names, and Interface Builder understands IBOutlet @property..., this is actually feasible, and it's easier to distinguish member variables and local ones in code so you don't have dangling pointers from autoreleased objects. Before that, I used to prefix local variables with a lowercase "v", as in vItemIndex, or call them theItemIndex, just like parameters were called inMessage or outMessage and static variables get named sLookupTable. The actual conventions used here aren't that important, but these have been used historically in various languages and frameworks I started out with, or on projects I've worked on. Some projects include external code that has different conventions. While ideally you'd have one convention throughout the entire code, as long as one tries to match the coding style of the surrounding code, one can at least maintain readability. And since you want to commit code back upstream in an open source project so the codebases don't diverge too much and you can take advantage of upstream bug-fixes, you'll sometimes just have to stick to their conventions. Local variables get lined upint foo = 0,When I declare several local (including static) variables in a row, I usually line them up using tabs. That way, you have an easily scannable list of variable declarations in the current scope. Since code is written only once, but is read hundreds of times, and often you have to remind yourself what type that variable is declared as, I find it terrible to lump all variables together on one line. Also, I don't really like the asterisk indicating a pointer type to be on the left. Well, I would like it, but sadly ptrB above would need a second asterisk without the int part, as the asterisk associates with the right-hand side. I know it helped simplify C's parser, but it's still terrible. But what am I complaining, it's too late now. I also feel kinda queasy about placing the asterisk right next to the variable name, because reading a line like *ptrB = NULL Just looks wrong. You don't assign NULL to an int! So I generally try to sort-of center it in the middle. Correct use of NULL, nil, Nil, true, false, YES and NOSometimes I'm lazy, or in a hurry, and I don't look up what type a variable is at the top of a function. Usually, I do this when I can tell the type from the values that are assigned to the variable. If it's foo = true, foo is obviously a bool. If it's var = nil, var is necessarily an ObjC object. Correct use of constants makes reading and understanding code much faster. If I see someone assigning true in Objective C code, my "someone must be mixing ObjC and C++ here!" warning bells immediately go on. You wouldn't want all that noise and flashing lights just because you forgot to write YES. Method parameters and their types go together-(void) showString: (NSString*)inMessage toUser: (UKUser*)desiredUser;My style of formatting methods (top) is also a little more spacious than Apple's default (bottom). The main reason is that I want to have each parameter and its type as a visually distinct element that can easily be spotted. Same goes for the return type. Again, this is fairly unimportant, but with limited or no syntax coloring in a helper tool, it suddenly becomes very helpful. In headers, I also prefer the method names to start at the same horizontal column, so it's easier to scan for a method in a header. The method name is the most specific part of a method, and also serves as a quick user-readable explanation, so it should be easy to extract from a line. Like in UI design, brackets may function as separator lines, but make the design more busy and force the eye to distinguish them from other symbols. Whitespace only exists as empty space the eye has to jump over, and isn't ambiguous because it can't be a symbol. So adding a few spaces here makes all the difference in the world. Brackets touch their identifierif( condition == true )Conditionals, loops and function calls require their own special brackets around parameters. In this way, they are different from the optional brackets that one uses to control execution order in expressions. To express this distinction in my code, I don't put a space between a function name and its parameter list opening bracket. However, I do put a space after the opening bracket and before the closing bracket. This exposes the parameters a bit more explicitly, and also gives the first and last parameters a little breathing room, just like the space after the comma. However, I don't do this if there are no parameters to be exposed, or for one-parameter function calls nested inside a more complex function call. That way, the one-parameter call becomes a single unit, and it is easier to distinguish each parameter of the surrounding function. Again, this is one of my personal idiosyncrasies, but I find it helps readability. You can make Xcode mostly support this in the XCCodeSenseFormattingOptions user defaults dictionary in its preferences, by adjusting theInExpressionSpacing, InFunctionArgsSpacing, PostColonSpacing, PreExpressionsSpacing and PreMethodTypeSpacing entries, however you'll get MyFunction( ) for parameterless function calls from auto-completion. Syntax coloringThis is very much a personal preference, but Mac OS X has inherited the terrible Unix notion of using ugly shades of undefinable colors like brown, purple and pink. If you look at these colors in code, you see that they're generally only pretty when you look at them as numbers. They're colors I imagine a programmer would choose who doesn't care too much how they get displayed in the end. I prefer using primary colors for the most important symbols (usually red comments, blue identifiers, green macros), plus slight brightness variations (light blue for project types, mid blue for language keywords, dark blue for Apple system types). I also use a mid grey for strings, so I immediately see my whole code as "disabled" if I forget to close a string. I usually start out with a modified version of the "Spartan" color scheme. The advantage of these colors is that, when I show something on screen, I can actually communicate "the line to the left of the blue 'void'" or whatever. People who didn't major in arts generally look quite flummoxed when I tell them about a "reddish cobalt blue" or a "brownish purple".
|
Created: 2009-12-15 @315 Last change: 2024-12-26 @235 | Home | Admin | Edit © Copyright 2003-2024 by M. Uli Kusterer, all rights reserved. |