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):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | ' 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<reserved> ' 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 |
And the assembler was about readable in most cases:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | ;------------------------------------------------------------ ; ; 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 <p16c74a.inc> ;------------------------------------------------------------ ; Context Saving registers CONTEXT UDATA 0x20 int_w RES 1 int_status RES 1 int_pclath RES 1 int_fsr RES 1 CONTEXT2 UDATA 0xa0 int_w2 RES 1 ;Dummy Register ;------------------------------------------------------------ ; Variables used in Main Loop Main UDATA tmpChar RES 1 ;------------------------------------------------------------ ; ; NAME : RESET_VECTOR ; ; FUNCTION : Executes reset interrupt service routine ; ;------------------------------------------------------------ RESET_VECTOR CODE 0000 RESET_VECTOR GLOBAL RESET_VECTOR PAGESEL reset_isr goto reset_isr ;--------------------ROUTINE SPECIFICATION------------------- ; ; 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 CODE 0004 INTERRUPT_VECTOR GLOBAL INTERRUPT_VECTOR EXTERN USART_Tx_isr EXTERN USART_Rx_isr ;INTERRUPT_VECTOR ; ; Save the W,STATUS,PCLATH and FSR registers, movwf int_w swapf STATUS,W clrf STATUS movwf int_status movf PCLATH,W movwf int_pclath movf FSR,W movwf int_fsr ; Check to see what caused the interrupt, ; Byte received ? BANKSEL PIR1 PAGESEL USART_Rx_isr btfsc PIR1,RCIF ; Jump to USART Rx ISR call USART_Rx_isr ; Ready to transmit byte ? BANKSEL PIR1 PAGESEL USART_Tx_isr btfsc PIR1,TXIF ; Jump to USART Tx ISR call USART_Tx_isr ; Unknown interrupt ? ; Jump to exception handler ; PAGESEL Exception ; call Exception ; Restore registers and return from interrupt. clrf STATUS 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 retfie ;--------------------ROUTINE SPECIFICATION------------------- ; ; NAME : Exception ; ; FUNCTION : Called when an unhandled interrupt ; condition occours. ; ; NOTES : ; ;------------------------------------------------------------ ; REVISION HISTORY : ; ;------------------------------------------------------------ ;EXCEPTION ; Endless loop Exception CODE Exception goto Exception ;--------------------ROUTINE SPECIFICATION------------------- ; ; NAME : reset_isr ; ; FUNCTION : Reset Interrupt service routine ; Determines correct action to perform ; on startup. ; ; NOTES : ; ;------------------------------------------------------------ ; REVISION HISTORY : ; ;------------------------------------------------------------ reset_isr CODE reset_isr GLOBAL reset_isr EXTERN MemoryTest 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 PAGESEL MemoryTest call MemoryTest PAGESEL USART_init call USART_init ; PAGESEL LCD_Initialise ; call LCD_Initialise PAGESEL USART_putc 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 ; PAGESEL LCD_PutChar ; movlw A'T' ; call LCD_PutChar ; movlw A'e' ; call LCD_PutChar ; movlw A's' ; call LCD_PutChar ; movlw A't' ; call LCD_PutChar ; Enable perihiperal interrupts BANKSEL INTCON bsf INTCON,PEIE ; Enable all interrupts bsf INTCON,GIE ; Print out startup message PAGESEL USART_puts movlw high Startup_screen movwf USART_hi_msg_tmp movlw low Startup_screen movwf USART_lo_msg_tmp call USART_puts bcf OPTION_REG,7 BANKSEL PORTB clrf PORTB BANKSEL TRISB movlw 0x00 movwf TRISB BANKSEL PORTD clrf PORTD BANKSEL TRISD movlw 0x7F movwf TRISD BANKSEL PORTE clrf PORTE BANKSEL TRISE movlw 0x07 movwf TRISE PAGESEL MainLoop call MainLoop ;--------------------ROUTINE SPECIFICATION------------------- ; ; NAME : MainLoop ; ; FUNCTION : Main Control Interpreter ; ; NOTES : A Finite State Machine ; ;------------------------------------------------------------ ; REVISION HISTORY : ; 9/1/98 First Draft ;------------------------------------------------------------ MainLoop CODE MainLoop GLOBAL MainLoop EXTERN USART_getc EXTERN USART_putc EXTERN AnalogRoot ExTERN DigitalRoot EXTERN CounterRoot EXTERN PWMRoot EXTERN MotorControlRoot EXTERN TimerRoot PAGESEL USART_getc call USART_getc BANKSEL tmpChar movwf tmpChar PAGESEL MainLoop movf tmpChar,W xorlw A'.' btfss STATUS,Z goto MainLoop ;------------------------------------------------------------ ServiceSelect PAGESEL USART_putc movlw '-' call USART_putc movlw '-' call USART_putc movlw '\r' call USART_putc movlw '\n' call USART_putc PAGESEL USART_getc call USART_getc movwf tmpChar PAGESEL AnalogRoot movf tmpChar,W xorlw A'a' btfsc STATUS,Z goto AnalogRoot PAGESEL DigitalRoot movf tmpChar,W xorlw A'd' btfsc STATUS,Z goto DigitalRoot PAGESEL DigitalRoot movf tmpChar,W xorlw A'c' btfsc STATUS,Z goto CounterRoot PAGESEL PWMRoot movf tmpChar,W xorlw A'p' btfsc STATUS,Z goto PWMRoot PAGESEL MotorControlRoot movf tmpChar,W xorlw A'm' btfsc STATUS,Z goto MotorControlRoot PAGESEL TimerRoot movf tmpChar,W xorlw A't' btfsc STATUS,Z goto TimerRoot ;------------------------------------------------------------ ; Error PAGESEL USART_putc movlw '*' call 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?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | ///////////////////////////////////////////////////////////////////// // // 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 $ // ////////////////////////////////////////////////////////////////////// package Tacan.RLC; import Tacan.util.LogFile; 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 int tmpPH[]; 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"); for (int i = 0; i<rlc.robot_config.PH_RES; i++) segment_terms_[i] = new Vector(); generateSegmentTerms(); } public int getThreshold() { return PH_threshold; } public void setThreshold(int i) { PH_threshold = i; } public void actionPerformed(ActionEvent e) { if(e.getActionCommand() == "Reset") reset(); } protected void reset() { PH_ = new int[no_of_segments_]; } private void generateSegmentTerms() { double theta, r; int x,y; int seg_no; double res = 360/no_of_segments_; int max_x = (int)(rlc_.robot_config.ACTIVE_WINDOW_SIZE/2) ; int max_y = max_x; SectorCell cell; System.out.print("Calculating segment terms : "); System.out.flush(); for (x = -max_x ; x <= max_x ; x++) { for (y =-max_y ; y<=max_y ; y++) if ((x!=0) || (y!=0)) // Avoid (0,0) { cell = new SectorCell(0,0,0); theta = MathUtil.rad2deg(Math.atan2(y,x)); //No, not a typo, atan2 takes (x,y) as (y,x) theta = (theta < 0) ? 360 + theta : theta ; r = Math.sqrt((x*x)+(y*y)); cell.x = x; cell.y = y; cell.term = A - B*r; seg_no = (int)(theta/res); segment_terms_[seg_no].addElement(cell); } System.out.print("."); System.out.flush(); } for (int i = 0; i<no_of_segments_; i++) segment_terms_[i].trimToSize(); System.out.println(" Done."); System.out.flush(); } public synchronized void update(Observable o,Object arg) { Thread.currentThread().setPriority(Thread.MAX_PRIORITY); Enumeration sector; int sector_sum; SectorCell cell = new SectorCell(0,0,0); int x_offset = (int)(rlc_.robot_config.RLC_LOCAL_MAP_MAX/2); int y_offset = (int)(rlc_.robot_config.RLC_LOCAL_MAP_MAX/2); int cv; for (int i = 0; i < no_of_segments_; i++) { sector_sum = 0; sector = segment_terms_[i].elements(); while(sector.hasMoreElements()) { cell = (SectorCell)sector.nextElement(); cv = rlc_.cv_grid.local_map[cell.x+x_offset][cell.y+y_offset]; sector_sum += cv*cv*cell.term; } tmpPH[i] = sector_sum; } smooth(5); setChanged(); notifyObservers(); Thread.currentThread().setPriority(Thread.NORM_PRIORITY); } /** * Averaging filter on Polar Histogram * The values for the PH can vary widely, so a smoothing filter is required * *@param filterSize The number of samples to use to smooth the graph *@return void */ protected synchronized void smooth(int filterSize) { int sum = 0; PH_max = 0; if ((filterSize%2)==0) //If even, make odd filterSize++; int df = (int)((double)filterSize/2); for(int i = 0; i < no_of_segments_; i++) { sum = 0; for (int j = -df; j <= df; j++) sum += tmpPH[(df+i+j)%no_of_segments_]; sum = (int)((double)sum/filterSize); PH_[(i+df)%no_of_segments_] = sum; PH_max = (sum > PH_max) ? sum : PH_max; } } public synchronized void LACupdate(int t,int desired_sector) { double b = (t<maxNetLag) ? (double)t/maxNetLag : 1.0 ; LAC_max = 0; double slope = (1-b)/(no_of_segments_/2); for (int i = 0 ; i < no_of_segments_ ; i++) { LAC_[(desired_sector+i)%no_of_segments_] = b; LAC_[(desired_sector+i)%no_of_segments_] += (i < (int)(no_of_segments_/2)) ? (double)i*(slope) : (-slope)*(double)(i-no_of_segments_); LAC_max = (LAC_[i] > LAC_max) ? LAC_[i] : LAC_max; } } public int clearPath(int bearing) { 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; LACupdate(3,desired_sector); if ((PH_[desired_sector] * LAC_[desired_sector]) < PH_threshold) return bearing; else { //Scan Left for(int a = 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) { //For up to maximum sector width for (l_width = 1; l_width <= maxFreeSectorSize; l_width++) //Look for end of free Sector if ((PH_[(a+l_width+desired_sector)%no_of_segments_] * LAC_[(a+l_width+desired_sector)%no_of_segments_]) > PH_threshold) { //Set centre of sector l_centre = a+(int)(l_width/2); break; } break; } //Scan Right 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) { //For up to maximum sector width for (r_width = 1; r_width <= maxFreeSectorSize; r_width++) //Look for end of free Sector if ((PH_[a-r_width] * LAC_[a-r_width]) > PH_threshold) { //Set centre of sector r_centre = a-(int)(r_width/2); break; } break; } //Choose left or right, weighing size of sector with deflection 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; return b; } } public String toString() { String s = "[ "; for (int i = 0;i<no_of_segments_;i++) s += String.valueOf(PH_[i]) + " "; s += "]"; return s; } } |
Oh dear. That’s very much a curate’s egg. Some parts are okay, but some… well, I wouldn’t give them an okay in a code review session today. Still, I suppose that’s a good thing – remind yourself that you were just not as hot as a teenage coder as you thought you were, and that you’ve gotten better in the interim.
What about the C++ though?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | /**************************************************************** * * * TCD Robocup Project 1996/7 * * Intelligent Agents Group * * (Artifical Intelligence Group) * * * **************************************************************** RCS Block : $Author: mdennehy $ $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 // ****************************************************************/ /***** RCS Program Information *****/ char RCS_revision[]="$Revision: 1.6 $"; char RCS_state[]="$State: Exp $"; /***** Header Files *****/ #include <thread.h> #include <synch.h> #include <pthread.h> #include <semaphore.h> #include <signal.h> #include <siginfo.h> #include <signal.h> #include <ucontext.h> #include <stdio.h> #include <stdlib.h> #include <GetOpt.h> #include <sys/time.h> #include <sys/resource.h> #include <unistd.h> #include <errno.h> #include <LEDA/string.h> #include "udpif.h" #include "posdata.h" #include "communications.h" #include "dmalloc.h" /***** Main Comms Socket *****/ UDPSocket comm; #ifdef DEBUG /***** Debugging Log file streams *****/ extern ofstream commlog; extern ofstream datalog; extern ofstream intsyslog; #endif /***** Function prototypes *****/ void usage(); void SignalHandler(int signal, siginfo_t *SignalInfo, void *ContextInfo); /***** MAIN() *****/ int main(int argc, char **argv) { #ifdef DEBUG print_statistics(); init_debugging_logfiles(); system_check(); intsyslog << "int main(int argc,char **argv)" << endl; struct sigaction h; // Install Signal handlers h.sa_flags = SA_SIGINFO; h.sa_sigaction = SignalHandler; sigaction(SIGBUS,&h,NULL); sigaction(SIGSEGV,&h,NULL); #endif int option_char ; char *serverhost = "localhost"; int serverport = 6000; //Get command-line options GetOpt opt(argc,argv,"?h:p:") ; while (option_char = opt(), option_char != EOF) switch (option_char) { case 'h': #ifdef DEBUG intsyslog << "Hostname CLI option : "; intsyslog << opt.optarg << endl; #endif serverhost = opt.optarg; break; case 'p': #ifdef DEBUG intsyslog << "Port CLI option : "; intsyslog << opt.optarg << endl; #endif serverport = atoi(opt.optarg); break; case '?': #ifdef DEBUG intsyslog << "Help CLI option selected" << endl; #endif usage(); exit(-1); }; //Setup socket connection to server #ifdef DEBUG intsyslog << "Attempting to open socket connection" << endl; intsyslog << "Hostname : " << serverhost << endl; intsyslog << " Port : " << serverport << endl; #endif comm.init_connection(serverhost,serverport); //Player Initialisation sequence #ifdef DEBUG intsyslog << "Sending Team Init" << endl; #endif leda_string s("(init TCD)"); leda_string side,playmode; int unum,err; comm << s; comm >> s; // parse returned initialisation message from server err = sscanf(s,"(init %[lr] %i %[^)]",side.cstring(),&unum,playmode.cstring()); #ifdef DEBUG if (err == 3) { intsyslog << "Side : " << side << endl; intsyslog << "Uniform Number : " << unum << endl; intsyslog << "Play Mode : " << playmode << endl; } else { intsyslog << "Initialisation response parse failure" << endl; intsyslog << "Errno : " << err << endl; exit (-1); } #endif //Start main threads thread_t main_thread_id; thread_t communications; //thread_t planning; //thread_t execution; thr_create(NULL,0,(void *)Communications,NULL,NULL,&communications); //thr_create(); //thr_create(); main_thread_id = thr_self(); #ifdef DEBUG intsyslog << "Main thread ID : " << main_thread_id << endl; intsyslog << "Communications thread ID : " << communications << endl; //intsyslog << "Planner thread ID : " << planning << endl; //intsyslog << "Executer thread ID : " << execution << endl; #endif wait(2); comm.send_message("(say -A1T1.PA.0000.0000.PB.1234.4321.PO2.5678.0123)",comm.S); wait(3); comm.send_message("(move 12 12)",comm.S); wait(5); while (1) // Just moves the agent about a bit to demonstrate the self-location system // Is an infinite loop so the rest of the code isn't much use here for now { comm.send_message("(turn 20)",comm.S); wait(2); comm.send_message("(dash 50)",comm.S); wait(3); } while (thr_join(communications,NULL,NULL) == 0); // Wait for other threads to finish #ifdef DEBUG intsyslog << "Shutting Down" << endl; commlog.close(); datalog.close(); intsyslog.close(); #endif } void usage() // Prints out correct command-line format via STDERR { #ifdef DEBUG intsyslog << "void usage()" << endl; #endif cerr << "Usage:\n"; cerr << " % agent [options] TEAMNAME\n"; cerr << " options: \n"; cerr << " -h HOSTNAME \n"; cerr << " -p PORTNUMBER\n"; cerr << endl; } #ifdef DEBUG void SignalHandler(int signal, siginfo_t *SignalInfo, void *ContextInfo) // this is UNIX-specific code to handle a signal sent to the agent to signal a system-level error, // such as a bus error or a Segmentation fault. These are the only two such signals currently specially // processed { dmalloc_log_heap_map(); dmalloc_log_stats(); dmalloc_log_unfreed(); perror ("Last Error "); if (SignalInfo->si_code <= 0) { intsyslog << "User Generated Signal" << endl; intsyslog << "User ID : " << SignalInfo->si_uid << endl; intsyslog << "Process ID : " << SignalInfo->si_pid << endl; } switch(signal) { case SIGBUS: { intsyslog << "********** ERROR : Bus Error **********" << endl; cerr << "********** ERROR : Bus Error **********" << endl; if (SignalInfo->si_code == SI_NOINFO) { intsyslog << "No Debugging information given by system" << endl; exit(-1); } switch (SignalInfo->si_code) { case BUS_ADRALN: { intsyslog << "Errno : " << SignalInfo->si_errno << endl; intsyslog << "Invalid Address Alignment" << endl; intsyslog << "Address : " ; intsyslog << (unsigned long)SignalInfo->si_addr; intsyslog << endl; break; } case BUS_ADRERR: { intsyslog << "Errno : " << SignalInfo->si_errno << endl; intsyslog << "NonExistant physical address" << endl; intsyslog << "Address : "; intsyslog << (unsigned long)SignalInfo->si_addr; intsyslog << endl; break; } case BUS_OBJERR: { intsyslog << "Errno : " << SignalInfo->si_errno << endl; intsyslog << "Object Specific Hardware Error" << endl; intsyslog << "Address : " ; intsyslog << (unsigned long)SignalInfo->si_addr; intsyslog << endl; break; } } } break; case SIGSEGV: { intsyslog << "********** ERROR : Segmentation Fault **********" << endl; cerr << "********** ERROR : Segmentation Fault **********" << endl; if (SignalInfo->si_code == SI_NOINFO) { intsyslog << "No Debugging information given by system" << endl; exit(-1); } else switch(SignalInfo->si_code) { case SEGV_MAPERR: { intsyslog << "Errno : " << SignalInfo->si_errno << endl; intsyslog << "Address not mapped to object" << endl; intsyslog << "Address : "; intsyslog << (unsigned long)SignalInfo->si_addr; intsyslog << endl; break; } case SEGV_ACCERR: { intsyslog << "Errno : " << SignalInfo->si_errno << endl; intsyslog << "Invalid Permissions for mapped object" << endl; intsyslog << "Address : "; intsyslog << (unsigned long)SignalInfo->si_addr; intsyslog << endl; break; } } } break; } exit(-1); } #endif |
Erm. Yikes. I did get better though
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?


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/