About | ACP | Buy | Forum | Industry Watch | Learning Curve | Search | Twitter | Xnews
Home » Learning Curve » Developers Workshop

Managing Code

It's an uphill battle but there's a payoff.


Buy It

Try It

Project management in IT can often seem to work OK but most of the time the view isn't the same from the ground up. Programmers who really care about what they're doing often find little or no use for their project managers.

And little wonder: project managers are often little more than smooth apparatchiks who know less than nothing about programming.

But for those unusual critters who actually do know something about programming: what constitutes an effective work team? So herewith a few pointers - all from the perspective of the use of Objective-C and Cocoa. But most principles apply everywhere.

1. Organise

Organisation is the end-all of coding - mise en place as the Michelin chefs call it. This organisation must be felt everywhere. A good project manager knows about the code being created and regularly reviews it.

Many programmers feel nothing matters as long as the software works. But this is patently untrue: software is organic in nature. It's maintained and cared for over a period of months and years. Things will be messy during those months and years if the code is left in a messy condition.

This isn't so much about 'documentation' as it's about getting one's subordinates to simply write good code. And writing good code requires possession of that elusive quality known as common sense. Throw out all your methods manuals and concentrate on using your own judgement. You can use methods manuals later - when it's time to write your own.

2. The Header File

Don't let your subordinates be wasteful or sloppy. Their software will be sloppy if you see sloppiness already here. They can't excuse themselves with an inability to type well - if they can't type then they should drive a bus. Period.

Things like this are certainly not good enough.

@interface PatternView : NSView {
    NSColor *patternColor;

}
@interface CPDemoView(CustomPagination)


- (BOOL)knowsPageRange:(NSRangePointer)aRange;
- (NSRect)rectForPage:(int)page;

@end
@interface AppDelegate : NSObject {

    IBOutlet NSTextView *textView;
}

- (IBAction)decompose:sender;
- (IBAction)decomposeLongestEffectiveRange:sender ;

@end

Why the waste of space? Most likely because the programmer is himself a waste of space.

Sloppiness in header files is not as self-destructive as it can be in other places but it's a good indication your programmer is not good enough.

3. The Method File

It's when you get to the method (definition) files you see how lazy feeble minds can hurt you. Most programmers are mediocre - and Steve Jobs believes 'good' programmers are several hundred times better (and he's right). That's the type of programmers you want.

You can spot bad programmers a mile away: their source files are sloppy, have inconsistent formatting, and are horrendously unorganised. Trying to find something in these files is troublesome and time consuming.

Good programmers organise their source files so they find things faster. Sloppiness isn't allowed as it's both distracting and a royal pain. Good programmers put as much effort into formatting and organising their source as they do into their products.

  • What type of order? Mediocre programmers stuff things in their header files in haphazard order. And do the same for their source files. Finding things when you need to is time consuming. There has to be an easily recognisable system of order.
  • Alphabetical. The mediocre programmer will be able to explain why each dropping is exactly where it's been put - but those who come after won't understand the system. And most likely the original programmer will forget after a week as well. Put everything in strict alphabetical order everywhere. Its connotations cannot be misconstrued.

Consider the following abbreviated layout for an essentially trivial source file.

@implementation PatternView

- (id)initWithFrame:(NSRect)frame {
    /* * */
}

- (void)drawRect:(NSRect)rect {
    /* * */


}

@end

What's wrong with it?

  • It wastes space. Given larger nontrivial files it means a lot more scrolling. [More on this later.]
  • Needles in needle stacks. There's no order to the method listing - save in the feeble mind of the programmer. initWithFrame: comes first because it was written first. Add another 20-30 methods and the confusion level becomes unbearable.
@implementation PatternView
-(void)drawRect:(NSRect)rect {
    /* * */
}
-(id)initWithFrame:(NSRect)frame {
    /* * */
}
@end

The 'good' code is more compact, affords an easier overview, and offers no obstacles when the 'next' programmer comes in and tries to find things.

4. The Dragon Books

Most programmers do not have a deep understanding of Objective-C - or more importantly the underlying C. Most of them never opened a 'dragon book' and even fewer struggled through one.

Grokking Al Aho isn't completely essential - but knowing what's involved in code generation is. And that's obvious - because mediocre programmers write incredibly sloppy and stupid code.

A few examples.

- (NSAttributedString *)attributedStringForPageNumber:(int)i
{
    NSAttributedString *pageString;
    NSString *page;
    page=[NSString stringWithFormat:@"PAGE %d",i];
    pageString=[[[NSAttributedString alloc] initWithString:page] autorelease];
    return pageString;
}

The above is so horrendous that it's obvious no thought at all was involved in writing it. What one is really after is an NSAttributedString - and it can and should be done without wasting automatic variables. The 'lamers' (the mediocre programmers) think none of this matters because to them nothing ever does. They didn't study Aho; they just don't know.

-(NSAttributedString *)attributedStringForPageNumber:(int)number {
    return [[[NSAttributedString alloc] initWithString:
        [NSString stringWithFormat:@"PAGE %d", number]] autorelease];
}

Another example. Note it's formatted differently - not better, just differently - even though it's from the same programmer.

- (void)drawRect:(NSRect)rect {
    if (![[NSGraphicsContext currentContext] isDrawingToScreen])
    {
        int page;
        NSAttributedString *attrString;
        NSRect destRect;

        page=[[NSPrintOperation currentOperation] currentPage];
        attrString=[self attributedStringForPageNumber:page];
        destRect=[self rectForPage:page];
        [attrString drawInRect:destRect];
    }

}
-(void)drawRect:(NSRect)rect {
    if (![[NSGraphicsContext currentContext] isDrawingToScreen]) {
        int page = [[NSPrintOperation currentOperation] currentPage];

        [[self attributedStringForPageNumber:page] drawInRect:[self rectForPage:page]];
    }
}

You don't waste LOCs (lines of code) declaring automatics and then initialising them. This is C 101 (if that). And two of the automatics aren't even needed.

Here we go again.

- (NSRect)rectForPage:(int)page {
    NSAttributedString *attrString;
    NSSize attrStringSize;
    attrString=[self attributedStringForPageNumber:page];
    attrStringSize=[attrString size];
    return NSMakeRect(0.0,0.0,
                      attrStringSize.width,
                      attrStringSize.height);
}
-(NSRect)rectForPage:(int)page {
    NSSize attrStringSize = [[self attributedStringForPageNumber:page] size];

    return NSMakeRect(0, 0, attrStringSize.width, attrStringSize.height);
}

One automatic initialisation and then a return through a macro. All the rest is bullshit. There's no line between variable declarations and code either - it's a sloppy mess.

5. Where to Scroll

Maintainers - even the original programmers - have to scroll. This takes time and cuts down on efficiency. Even if you're already getting them to put everything in alphabetical order and stopping them from artificially inflating their files with bogus blank LOCs, there's still the matter of scrolling - and further tricks the mediocre will try. One of the best is to waste LOCs on automatic declarations.

But you're not working with a COBOL stack. C is a context-free parsed language. Your programmers know it; and BWK showed them (if they read his book which isn't certain). But it takes more work to organise so invariably the mediocre don't bother. And you don't want the mediocre around anymore.


- (IBAction)decomposeLongestEffectiveRange:sender {
    NSAttributedString *attrStr;
    NSRange limitRange;
    NSRange effectiveRange;
    id attributeValue;
    /* * */
    }

}


@end

That's so sloppy the lamer should be sacked on the spot.

-(void)decomposeLongestEffectiveRange:(id)sender {
    NSAttributedString *attrStr; id attributeValue; NSRange effectiveRange, limitRange;

    /* * */
    }
}
@end

Again.

- (void)drawRect:(NSRect)rect {
    int x,y;
    NSString *letterConstants;
    NSMutableDictionary *seatTextAttributes;
    NSMutableDictionary *nameTextAttributes;

If Mr Mediocre can combine two ints on one line then why the short circuit on the rest? Especially with an egregious variable type as 'pointer to NSMutableDictionary'? Perhaps there's a suspicion you the manager check actual file sizes?

-(void)drawRect:(NSRect)rect {
    NSMutableDictionary *nameTextAttributes, *seatTextAttributes;
    NSString *letterConstants; int x, y;

There are more text columns per screen than there are text rows. String things out if you have to - put as much as you can on screen at any one time.

6. Don't Call Back

Mediocre programmers don't know unnecessary automatics cost code and slow software down; what's even worse with Cocoa is their sloppy abuse of the Objective-C message.

Objective-C messages are almost as efficient as C function calls - almost. And function calls are already the (by far) most costly operation in what otherwise is the leanest and meanest programming language ever.

Using an automatic in such a case is significantly more efficient. You never call the same receiver twice in a row for a static return value unless you 1) are retarded; and 2) don't care if you keep your job (because you shouldn't).

- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
    [super windowControllerDidLoadNib:aController];
    [self setPrintInfo:[[[NSPrintInfo sharedPrintInfo] copy] autorelease]];

    [[self printInfo] setHorizontalPagination:NSAutoPagination];
    [[self printInfo] setVerticalPagination:NSAutoPagination];
}

The worst (most retarded) part about the above code is that it first sets the NSPrintInfo object - and then calls back twice to get it back? Twice?

-(void)windowControllerDidLoadNib:(NSWindowController *)controller {
    NSPrintInfo *printfInfo = [[[NSPrintInfo sharedPrintInfo] copy] autorelease];

    [super windowControllerDidLoadNib:controller];
    [printfInfo setHorizontalPagination:NSAutoPagination];
    [printfInfo setVerticalPagination:NSAutoPagination];
    [self setPrintInfo:printfInfo];
}

You create the NSPrintInfo so hang onto it. Then change it as you want. Then set it. It's so bloody easy. It's amazing anyone could screw up something as easy as this. But it happens.

7. Weed Them Out

So look over shoulders a bit more. Learn to recognise what you appreciate in good code and learn to ferret out programmers in your organisation who will just never fit.

About | ACP | Buy | Forum | Industry Watch | Learning Curve | Search | Twitter | Xnews
Copyright © Rixstep. All rights reserved.