I came across this must-read article. I was a maintenance programmer for 29 years and I've come across many of the deadly sins that he discusses and maybe even one or two that he does not. How to Write Unmaintainable Code by Roedy Green.
Reverend Jim 5,070 Hi, I'm Jim, one of DaniWeb's moderators. Moderator Featured Poster
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster
Yeah, definitely a must-read! It makes you laugh and cry. There are things in there that just sound so outrageous and deliberately vicious against the maintainers. And it makes you laugh until you realize that you've seen exact examples of that in real-life production code.... and it really turns bitter when you realize you've written code like that before.
I can also easily think of a few main-stream production-grade projects that easily obey at least half of those rules for writing unmaintainable code (cough.. cough.. LLVM/Clang cough.. cough..).
taichichuan 0 Newbie Poster
At one time, I used to write a lot of FORTRAN code. In FORTRAN, many of these gems were ingrained in the way you were taught (i,j,k as integer variables, etc.). As I read through this, I had deja vu all over again with some of the code I've come across. However, the height of obfuscation is not making the code look obfuscated. That is a black art unto itself. ;-)
Reverend Jim 5,070 Hi, I'm Jim, one of DaniWeb's moderators. Moderator Featured Poster
I did maintenance/development (mostly maintenance) with FORTRAN code for 15 years. I was really pissed when I found
INTEGER NINE /5/
but the worst ever code was
SUBROUTINE READALL(UNIT,BUFF,*,*,IFIRST)
C*TTL READALL READ FROM ANYTHING
C
C
C
C THIS SUBROUTINE IS USED FOR READING COMPRESSED OR UNCOMPRESSED
C DATA INPUT FILES FROM LFC 'UNIT' INTO 80 BYTE ARRAYY BUFF.
C END RETURNS TO FIRST RETURN, ERROR RTETURNS TO SECOND
C IFIRST IS LOGICAL WHICH CALLER PROVIDES TRUE ON
C FIRST READ OFF OF THIS ALLOCATION OF THIS LFC, ELSE FALSE
C*PGMXX READALL SAVD TOOLS FS$READA ON 07/23/80 17:43:51 01819B00R01
LOGICAL IFIRST
INTEGER*1 BUFF(80)
INTEGER*4 UNIT
INTEGER*1 BYTE(120,2)
C
C
INTEGER*1 IN(2)/2*0/,ISP(2)/2*0/,ITX(2)/2*0/,NB(2)/2*0/
INTEGER*1 NBT(2)/2*1/
INTEGER*1 KCR/ZBF/,KLR/Z9F/
INTEGER*1 EOR/ZFF/
INTEGER*2 NSEQ(2)/2*0/,ITY(6),ISEQ(60,2),ICKS(60,2)
INTEGER*4 LFC(2)/2*0/
INTEGER*4 K,N,IERR,IN0,ISP0,ITX0,NB0,IS,I,ISUM,J
C
C
EQUIVALENCE (BYTE(3,1),ICKS(1,1)),(BYTE(5,1),ISEQ(1,1))
C
C
IF(.NOT.IFIRST) GO TO 21
DO 19 K=1,2
IN(K) = 0
ISP(K) = 0
ITX(K) = 0
NB(K) = 0
NBT(K) = 1
NSEQ(K) = 0
LFC(K) = 0
19 CONTINUE
21 CONTINUE
DO 101 N=1,2
IF (UNIT.EQ.LFC(N)) GO TO 103
IF (LFC(N).EQ.0) GO TO 102
101 CONTINUE
GO TO 94
102 LFC(N) = UNIT
CALL W:PDEV(UNIT,ITY)
NBT(N) = 1
IF (ITY(3).GE.4.AND.ITY(3).LE.6) NBT(N)=2
103 IERR = 0
IN0 = IN(N)
ISP0 = ISP(N)
ITX0 = ITX(N)
NB0 = NB(N)
1 IF (IN0.NE.0) GO TO 8
2 CALL BUFFERIN(UNIT,0,BYTE(1,N),30)
CALL M:WAIT(UNIT)
CALL STATUS(UNIT,IS,NB0)
IF (IS-3) 3,80,90
3 IF (BYTE(1,N).EQ.KCR.OR.BYTE(1,N).EQ.KLR) GO TO 6
NB0 = NB0*NBT(N)
DO 4 I=1,NB0
IF (BYTE(I,N).EQ.10.OR.BYTE(I,N).EQ.13) BYTE(I,N) = 1R
4 BUFF(I) = BYTE(I,N)
IF (NB0.GE.80) GO TO 20
I = I+1
DO 5 I=I,80
5 BUFF(I) = 1R
GO TO 20
6 NB0 = BYTE(2,N)
IF (NB0.GT.114) GO TO 91
ISUM = 0
DO 7 I=1,NB0
7 ISUM = ISUM+BYTE(I+6,N)
IF (ISUM.NE.ICKS(1,N)) GO TO 92
IF (ISEQ(1,N).NE.NSEQ(N)) GO TO 93
NSEQ(N) = NSEQ(N)+1
IN0 = 7
8 DO 16 I=1,80
IF (ISP0.NE.0) GO TO 9
IF (ITX0.NE.0) GO TO 12
IF (BYTE(IN0,N).EQ.EOR) GO TO 9
ISP0 = BYTE(IN0,N)
IF (ISP0.GT.81-I) GO TO 91
IN0 = IN0+1
GO TO 10
9 ISP0 = ISP0-1
10 IF (ISP0.EQ.0) GO TO 11
BUFF(I) = 1R
GO TO 16
11 IF (BYTE(IN0,N).EQ.EOR) GO TO 9
ITX0 = BYTE(IN0,N)
IF (ITX0.GT.81-I) GO TO 91
IN0 = IN0+1
12 BUFF(I) = BYTE(IN0,N)
IF (BUFF(I).EQ.10.OR.BUFF(I).EQ.13) BUFF(I) = 1R
ITX0 = ITX0-1
13 IN0 = IN0+1
IF (IN0.LE.NB0+6) GO TO 16
CALL BUFFERIN(UNIT,0,BYTE(1,N),30)
CALL M:WAIT(UNIT)
CALL STATUS(UNIT,IS,NB0)
IF (IS-3) 14,80,90
14 IF (BYTE(1,N).NE.KCR.AND.BYTE(1,N).NE.KLR) GO TO 91
NB0 = BYTE(2,N)
IF (NB0.GT.114) GO TO 91
ISUM = 0
DO 15 J=1,NB0
15 ISUM = ISUM+BYTE(J+6,N)
IF (ISUM.NE.ICKS(1,N)) GO TO 92
IF (ISEQ(1,N).NE.NSEQ(N)) GO TO 93
NSEQ(N) = NSEQ(N)+1
IN0 = 7
16 CONTINUE
IF (BYTE(IN0,N).NE.EOR) GO TO 91
ISP0 = 0
IF (ITX0.NE.0) GO TO 91
IN0 = IN0+1
IF (IN0.GT.NB0+6) IN0 = 0
IF (BYTE(1,N).EQ.KLR.AND.IN0.EQ.0) NSEQ(N) = 0
20 IN(N) = IN0
ISP(N) = ISP0
ITX(N) = ITX0
NB(N) = NB0
RETURN
80 NSEQ(N) = 0
IN(N) = ISP(N) = ITX(N) = 0
RETURN 1
90 IERR = 1
91 IERR = IERR+1
92 IERR = IERR+1
93 IERR = IERR+1
94 IERR = IERR+1
IN(N) = ISP(N) = ITX(N) = 0
BUFF(1) = IERR
RETURN 2
END
The vendor (in order to save space on a 300 MB disk) wrote this gem for their line editor to read from (somewhat) compressed text files. I eventually rewrote it but it took days to recode (most of the time was taken up in testing). Dontcha just love the extensive documentation?
Edited by Reverend Jim
taichichuan 0 Newbie Poster
@Jim, wow this code is a real piece of work. My head hurt just looking at all those labels and gotos. Now, I do use gotos in my C code in the Linux kernel, but that's pretty much the standard way to write drivers in Linux. Still, none of that even compares to the gem you've just shared.
Thanks for reminding me just how bad code can get.
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.