So the Coding Horror thread on boards.ie’s Development forum threw up an interesting post:
Originally Posted by COYW
[..] I was told not to comment my code, as it was a “waste of time”. Apparently, that is classic Agile!
A good code doesn’t need comments; a bad code doesn’t need comments either – it needs to be fixed!
The responses were about as you’d expect, but in the course of answering, I made the following suggestion:
you still have your code from college exercises, right? No? You don’t keep a private archive of old code you wrote? So… how do you tell if you’re improving or getting worse without a baseline?
So I figured I’d take a peek again (last time I looked must have been before Calum was born) and compare it to what I’m writing today.
The really low-level stuff came off pretty well. Some code for programming a GAL chip for 3D2 (where you build a thin client from a 68008 chip and a handful of other chips and what feels like a mile of hand-wrapped wire):
[cc escaped=”true” lang=”asm” lines=”20″]
‘ GAL1 PLDASM
‘ Address Decoding
‘
‘ 3D3 68008 Project
‘
‘ Group 5 :
‘ Mark Dennehy 93369425
‘ Ellen Delaney
‘
‘ This is the address decoding code for the board. It uses one
‘ GAL exclusively and the smallest selectable memory block is
‘ 1024 bytes. The CLK pin is attached to /AS via an inverter.
‘
‘ INPUTS :
‘ A10..A19
‘ BOOT
‘ /AS
‘ OUTPUTS:
‘ EPROM1
‘ RAMROM1
‘ RAM1
‘ RAM2
‘ RAM3
‘ ACIA0
‘ ACIA1
‘ LCD
‘ SYSTEMBYTE
‘ TIMER
‘
device 22v10
‘ Input pin definitions
as = 1
a19 = 2
a18 = 3
a17 = 4
a16 = 5
a15 = 6
a14 = 7
a13 = 8
a12 = 9
a11 = 10
a10 = 11
boot = 13
‘ Power & ground pin definitions
gnd = 12
vcc = 24
‘ Output pin definitions
/eprom1 = 14
/ramrom1 = 15
/ram1 = 16
/ram2 = 17
/acia0 = 18
/acia1 = 19
/lcd = 20
/sysbyte = 21
/timer = 22
/ram3 = 23
macro io a19*a18*a17*a16;
macro rom /a19*/a18*/a17*/a16;
start
‘ EPROM selection : $00000 -> $01FFF and boot
/eprom1 /= /as*/boot*&rom*/a15*/a14*/a13;
‘ RAM_ROM selection : $00000 -> $01FFF and not-boot
‘ $20000 -> $21FFF and boot
/ramrom1 /= /as*boot*&rom*/a15*/a14*/a13 + /as*/boot*/a19*/a18*a17*/a16*/a15*/a14*/a13;
‘ RAM 1 selection : $10000 -> $107FF
/ram1 /= /as*/a19*/a18*/a17*a16*/a15*/a14*/a13*/a12*/a11;
‘ RAM 2 selection : $10800 -> $10FFF
/ram2 /= /as*/a19*/a18*/a17*a16*/a15*/a14*/a13*/a12*a11;
‘ RAM 3 selection : $11000 -> $12FFF
/ram3 /= /as*/a19*/a18*/a17*a16*/a15*/a14*/a13*a12 + /a19*/a18*/a17*a16*/a15*/a14*a13*/a12;
‘ ACIA 0 selection : $F0000
/acia0 /= /as*&io*/a15*/a14*/a13*/a12*/a11*/a10;
‘ ACIA 1 selection : $F0400
/acia1 /= /as*&io*/a15*/a14*/a13*/a12*/a11*a10;
‘ LCD selection : $FE000
/lcd /= /as*&io*a15*a14*a13*/a12*/a11*/a10;
‘ SYSTEM_BYTE selection : $FF000
/sysbyte /= /as*&io*a15*a14*a13*a12*/a11*/a10;
‘ TIMER selection : $F1000
/timer /= /as*&io*/a15*/a14*/a13*a12*/a11*/a10;
end
[/cc]
And the assembler was about readable in most cases:
[cc escaped=”true” lang=”asm” lines=”20″]
;————————————————————
;
; Demonstration PICRAT program.
;
;————————————————————
; REVISION HISTORY :
;
; 13/10/97 First draft, preliminary modularisation
; of code.
;
;————————————————————
ERRORLEVEL 0
PROCESSOR PIC16C74A
LIST b=4
__CONFIG _BODEN_OFF & _CP_OFF & _PWRTE_OFF & _WDT_OFF & _XT_OSC
TITLE “Demonstration PICRAT program”
SUBTITLE “Version 1.00”
include ;———————————————————— CONTEXT UDATA 0x20 int_w RES 1 CONTEXT2 UDATA 0xa0 int_w2 RES 1 ;Dummy Register ;———————————————————— tmpChar RES 1 ;———————————————————— RESET_VECTOR CODE 0000 PAGESEL reset_isr ;——————–ROUTINE SPECIFICATION——————- INTERRUPT_VECTOR CODE 0004 EXTERN USART_Tx_isr ;INTERRUPT_VECTOR movwf int_w ; Check to see what caused the interrupt, BANKSEL PIR1 ; Jump to USART Rx ISR call USART_Rx_isr ; Ready to transmit byte ? BANKSEL PIR1 ; Jump to USART Tx ISR call USART_Tx_isr ; Unknown interrupt ? ; PAGESEL Exception ; Restore registers and return from interrupt. clrf STATUS retfie ;——————–ROUTINE SPECIFICATION——————- ;EXCEPTION Exception CODE goto Exception ;——————–ROUTINE SPECIFICATION——————- reset_isr CODE EXTERN MemoryTest PAGESEL MemoryTest PAGESEL USART_init ; PAGESEL LCD_Initialise PAGESEL USART_putc ; PAGESEL LCD_PutChar ; Enable perihiperal interrupts BANKSEL INTCON ; Enable all interrupts ; Print out startup message bcf OPTION_REG,7 BANKSEL PORTD BANKSEL PORTE PAGESEL MainLoop ;——————–ROUTINE SPECIFICATION——————- MainLoop CODE PAGESEL USART_getc ;———————————————————— ServiceSelect PAGESEL USART_getc PAGESEL AnalogRoot PAGESEL DigitalRoot PAGESEL DigitalRoot PAGESEL PWMRoot PAGESEL MotorControlRoot PAGESEL TimerRoot ;———————————————————— PAGESEL USART_putc goto MainLoop END Okay, so that’s not quite as good as it could be, but the libraries were better. What about the Java code? [cc escaped=”true” lang=”java” lines=”20″] package Tacan.RLC; import Tacan.util.LogFile; /** private int tmpPH[]; /** /** /** /** /** /** /** for (int i = 0; i public synchronized void LACupdate(int t,int desired_sector) public int clearPath(int bearing) LACupdate(3,desired_sector); if ((PH_[desired_sector] * LAC_[desired_sector]) PH_threshold) //Scan Right //Choose left or right, weighing size of sector with deflection return b; public String toString() What about the C++ though? [cc escaped=”true” lang=”cpp” lines=”20″] $Author: mdennehy $ /***** RCS Program Information *****/ /***** Header Files *****/ #include #include #include “udpif.h” /***** Main Comms Socket *****/ #ifdef DEBUG /***** Function prototypes *****/ /***** MAIN() *****/ // parse returned initialisation message from server #ifdef DEBUG What about you? Do you check back over long periods to see how your standard of code is actually doing, rather than through the hazy pink-spectacled fog of old memories?
; Context Saving registers
int_status RES 1
int_pclath RES 1
int_fsr RES 1
; Variables used in Main Loop
Main UDATA
;
; NAME : RESET_VECTOR
;
; FUNCTION : Executes reset interrupt service routine
;
;————————————————————
RESET_VECTOR
GLOBAL RESET_VECTOR
goto reset_isr
;
; NAME : INTERRUPT_VECTOR
;
; FUNCTION : Contect saving, correct ISR selection
;
; NOTES : Saves W, STATUS, PCLATH as per ex.14-1
; in datasheet
;
;————————————————————
; REVISION HISTORY :
;
;————————————————————
INTERRUPT_VECTOR
GLOBAL INTERRUPT_VECTOR
EXTERN USART_Rx_isr
;
; Save the W,STATUS,PCLATH and FSR registers,
swapf STATUS,W
clrf STATUS
movwf int_status
movf PCLATH,W
movwf int_pclath
movf FSR,W
movwf int_fsr
; Byte received ?
PAGESEL USART_Rx_isr
btfsc PIR1,RCIF
PAGESEL USART_Tx_isr
btfsc PIR1,TXIF
; Jump to exception handler
; call Exception
movf int_fsr,W
movwf FSR
movf int_pclath,W
movwf PCLATH
swapf int_status,W
movwf STATUS
swapf int_w,F
swapf int_w,W
;
; NAME : Exception
;
; FUNCTION : Called when an unhandled interrupt
; condition occours.
;
; NOTES :
;
;————————————————————
; REVISION HISTORY :
;
;————————————————————
; Endless loop
Exception
;
; NAME : reset_isr
;
; FUNCTION : Reset Interrupt service routine
; Determines correct action to perform
; on startup.
;
; NOTES :
;
;————————————————————
; REVISION HISTORY :
;
;————————————————————
reset_isr
GLOBAL reset_isr
EXTERN USART_init
EXTERN USART_puts
EXTERN USART_putc
EXTERN USART_hi_msg_tmp
EXTERN USART_lo_msg_tmp
EXTERN Startup_screen
; EXTERN LCD_Initialise
; EXTERN LCD_PutChar
EXTERN USART_getc
call MemoryTest
call USART_init
; call LCD_Initialise
movlw A’.’
call USART_putc
movlw A’.’
call USART_putc
movlw A’.’
call USART_putc
movlw A’\r’
call USART_putc
movlw A’\n’
call USART_putc
; movlw A’T’
; call LCD_PutChar
; movlw A’e’
; call LCD_PutChar
; movlw A’s’
; call LCD_PutChar
; movlw A’t’
; call LCD_PutChar
bsf INTCON,PEIE
bsf INTCON,GIE
PAGESEL USART_puts
movlw high Startup_screen
movwf USART_hi_msg_tmp
movlw low Startup_screen
movwf USART_lo_msg_tmp
call USART_puts
BANKSEL PORTB
clrf PORTB
BANKSEL TRISB
movlw 0x00
movwf TRISB
clrf PORTD
BANKSEL TRISD
movlw 0x7F
movwf TRISD
clrf PORTE
BANKSEL TRISE
movlw 0x07
movwf TRISE
call MainLoop
;
; NAME : MainLoop
;
; FUNCTION : Main Control Interpreter
;
; NOTES : A Finite State Machine
;
;————————————————————
; REVISION HISTORY :
; 9/1/98 First Draft
;————————————————————
MainLoop
GLOBAL MainLoop
EXTERN USART_getc
EXTERN USART_putc
EXTERN AnalogRoot
ExTERN DigitalRoot
EXTERN CounterRoot
EXTERN PWMRoot
EXTERN MotorControlRoot
EXTERN TimerRoot
call USART_getc
BANKSEL tmpChar
movwf tmpChar
PAGESEL MainLoop
movf tmpChar,W
xorlw A’.’
btfss STATUS,Z
goto MainLoop
PAGESEL USART_putc
movlw ‘-‘
call USART_putc
movlw ‘-‘
call USART_putc
movlw ‘\r’
call USART_putc
movlw ‘\n’
call USART_putc
call USART_getc
movwf tmpChar
movf tmpChar,W
xorlw A’a’
btfsc STATUS,Z
goto AnalogRoot
movf tmpChar,W
xorlw A’d’
btfsc STATUS,Z
goto DigitalRoot
movf tmpChar,W
xorlw A’c’
btfsc STATUS,Z
goto CounterRoot
movf tmpChar,W
xorlw A’p’
btfsc STATUS,Z
goto PWMRoot
movf tmpChar,W
xorlw A’m’
btfsc STATUS,Z
goto MotorControlRoot
movf tmpChar,W
xorlw A’t’
btfsc STATUS,Z
goto TimerRoot
; Error
movlw ‘*’
call USART_putc
[/cc]
/////////////////////////////////////////////////////////////////////
//
// TACAN – TeleAutonomous Control And Navigation
//
// Mark Dennehy, 93369425
// S.S. C.Eng.
// Final Year Project 1996/7
//
//////////////////////////////////////////////////////////////////////
//
// PolarHistogram.java
// implements the polar histogram
// —————–
// $Date: 1997/04/03 21:49:54 $
// $Revision: 2.0 $
// $State: Stable $
//
//////////////////////////////////////////////////////////////////////
import Tacan.util.MathUtil;
import java.util.*;
import java.io.*;
import java.awt.event.*;
* The Polar Histogram of the Certainty value grid. This is effectively a
* polar graph of obstacle density.
*
*@author
*@version
*@see Tacan.RLC.CVGrid
*@see java.util.Observer
*@see java.awt.event.ActionListener
**/
class PolarHistogram extends Observable implements Observer, ActionListener
{
private final static double A = 22;
private final static double B = 1;
private final static int maxFreeSectorSize = 18;
private RLC rlc_;
private int no_of_segments_;
private LogFile log_;
private LogFile data_;
private Vector segment_terms_[];
* The current Polar Histogram values
**/
protected int PH_[];
* The Local Autonomy Control graph values
**/
protected double LAC_[];
* The current maximum value in the Polar Histogram (for normalisation)
**/
protected int PH_max = 0;
* The current maximum value in the Local Autonomy Control graph (for normalisation)
*@see
**/
protected double LAC_max = 0.0;
* The threshold value for deciding what path is free and what is not
**/
protected int PH_threshold = 100;
* The maximum network lag permitted before full local autonomy is granted (in seconds)
**/
public final static double maxNetLag = 10;
* Constructor
*
*@param rlc The Robot Local controller instance associated with this graph
**/
protected PolarHistogram(RLC rlc)
{
rlc_ = rlc;
PH_max = 0;
segment_terms_ = new Vector[rlc.robot_config.PH_RES];
no_of_segments_ = rlc.robot_config.PH_RES;
PH_ = new int[no_of_segments_];
tmpPH = new int[no_of_segments_];
LAC_ = new double[no_of_segments_];
log_ = new LogFile(“Polar.log”);
data_ = new LogFile(“Polar.dat”);
}
}
{
double b = (t
}
}
{
int res = (int)360.0/no_of_segments_;
int desired_sector = (int)(bearing/res);
int b;
int l_centre =1;
int l_width = 1;
int r_centre =1;
int r_width = 1;
{
//Set centre of sector
l_centre = a+(int)(l_width/2);
break;
}
break;
}
for(int a = no_of_segments_-1; a > (no_of_segments_/2) ; a–)
//Start of first free sector
if ((PH_[(a+desired_sector)%no_of_segments_] * LAC_[(a+desired_sector)%no_of_segments_]) PH_threshold)
{
//Set centre of sector
r_centre = a-(int)(r_width/2);
break;
}
break;
}
b = ((l_width/l_centre) > (r_width/(no_of_segments_ – r_centre))) ? l_centre : r_centre ;
b += desired_sector;
b %= no_of_segments_;
b *= res;
}
}
{
String s = “[ “;
for (int i = 0;i
/****************************************************************
* *
* TCD Robocup Project 1996/7 *
* Intelligent Agents Group *
* (Artifical Intelligence Group) *
* *
****************************************************************
RCS Block :
$Date: 1996/09/07 15:57:18 $
$RCSfile: main.cc,v $
$Revision: 1.6 $
****************************************************************
$Log: main.cc,v $
// Revision 1.6 1996/09/07 15:57:18 mdennehy
// Final version by mdennehy.
// Now knows how to locate itself on the field and
// can determine the error in this measurement.
//
// Revision 1.5 1996/09/04 14:03:22 mdennehy
// Visual and Audio parsing working.
// Minor bug : if more than 5/6 agents connected, Bus errors/segmentation faufollow
//
// Revision 1.4 1996/08/30 17:31:38 mdennehy
// First Working Version
//
// Revision 1.3 1996/08/26 15:10:49 mdennehy
// *** empty log message ***
//
// Revision 1.2 1996/08/24 16:25:08 mdennehy
// Added Threads
//
// Revision 1.1 1996/08/22 14:34:30 mdennehy
// Initial revision
//
****************************************************************/
char RCS_revision[]=”$Revision: 1.6 $”;
char RCS_state[]=”$State: Exp $”;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include “posdata.h”
#include “communications.h”
#include “dmalloc.h”
UDPSocket comm;
/***** Debugging Log file streams *****/
extern ofstream commlog;
extern ofstream datalog;
extern ofstream intsyslog;
#endif
void usage();
void SignalHandler(int signal, siginfo_t *SignalInfo, void *ContextInfo);
int main(int argc, char **argv)
{
#ifdef DEBUG
print_statistics();
init_debugging_logfiles();
system_check();
intsyslog > s;
err = sscanf(s,”(init %[lr] %i %[^)]”,side.cstring(),&unum,playmode.cstring());
if (err == 3)
{
intsyslog si_code si_uid si_pid si_code == SI_NOINFO)
{
intsyslog si_code)
{
case BUS_ADRALN:
{
intsyslog si_errno si_addr;
intsyslog si_errno si_addr;
intsyslog si_errno si_addr;
intsyslog si_code == SI_NOINFO)
{
intsyslog si_code)
{
case SEGV_MAPERR:
{
intsyslog si_errno si_addr;
intsyslog si_errno si_addr;
intsyslog Erm. Yikes. I did get better though 😀
Occasionally, but in some cases it’s been so long that either the language has change a *lot* (PHP) or it’s been so long since I’ve coded in the language that I can’t properly understand it any more (C++).
I still have most of my code from college though, I’m a terrible packrat when it comes to code.
I doubt that my code is really getting better; I don’t think I care much. If my code is already good enough, I’d value productivity improvements and increases in the range of problems that I can solve, over making the code itself a little bit better. When I was a less experienced programmer (but not a beginner) I sweated a lot about code quality, sometimes implementing stuff multiple times to get the interfaces and style just right. Now that I have more experience I can usually come up with something reasonable on the first try, and move on to the next task, rather than spend a lot of time trying to improve the reasonable into the perfect.
I do remember some code I wrote in college, that took me a day or so to write, for a particular task; recently, I faced the same task again, but I didn’t have the old code, so I wrote a new solution and it took less than an hour. In that way I’m clearly getting better, whether or not the new code is itself better than the old code.
I keep all my code from my teenage years for that reason. Just to laugh at my past self.
That PIC assembly brought some memories back. I used to do some PIC programming as well… in assembly (http://viennot.biz/remote_car.pdf / page 33). It’s only later that I discovered what was a C compiler.
Turns out, what most of us need to get rid of comments is to create our own DSLs, but that’s hard. What’s even worse is that most of the time, trying to get there is pure intellectual masturbation.
I noticed your mention of base-lining in that discussion, was wondering if you actually did that yourself 🙂
I don’t code all that much myself these days so I reckon I’m probably on a down curve (or at best seeing a significant reduction in the rate of improvement). I need to get stuck in a bit to keep my head in.
Looking back at my code from college, what’s most interesting to me is the world of difference between what I wrote in 3rd year, and what I wrote in 4th year after working for a software house for 12 months. The code isn’t necessarily more advanced – I worked in 360/390 ASM for the 12 months, which wasn’t on our course – but the primary difference is the defensive coding and documentation. Designed for robustness and maintenance.
I’d be interested to know what the nature of the code improvements are that most people get from their first couple of years in industry – is it totally dependent on the company, or the language/environment? Or something else?
Nice post. Thanks.
I do keep my old code, but I rarely look at it. This is a good idea I’ll start doing it.
I do try and benchmark my self. I will do various coding exercises and look at the interview process for big companies. I also look at websites like the one below and see how I compare. Through the years I have “leveled up”, but as expected my advancement is slowing down as I get more specialized.
http://www.indiangeek.net/programmer-competency-matrix/