Development Today

Introduction

I`ve read a couple of articles recently on developers and IT recently. One was about the expectations of new developers joining an IT team from uni and expecting to immediately write a swathe of new code. The second was about writing overly defensive code, and I thought about the different environments that I have worked in, and the different roles that I`ve had, and realised that things are not as simple as they might seem.
 

Training

I started out as a trainee COBOL programmer straight from school in July 1979. I didn`t go to uni, I wanted to be a rock star and earn some money to buy some decent bass gear. I had not written a single line of code in any computer language at this point. I was offered the job only on my performance in the aptitude test that I was given. I saw that as a simple arithmetic and logic test, and later I realised it was a taster of assembler language.
 
I equally had no understanding of what an IT company did. You train up by reading the IBM COBOL manual for 2 weeks, then writing small routines to learn the language. All the code that you write is new, and your own. The final training task was to write a program from a 14-page flow diagram (which was flawed, as it turned out, though not deliberately!).
 
When I was assigned to a team I was introduced to some of the existing systems that other team members were looking after. Being a new-ish batch processing data centre; the users were shadowing the computer systems with paper trails, and still figuring out what they wanted from the computer. Thus there was a fair amount of new code to be written. In those days the main design was to read your data in from tape, one record at a time, do some processing, write out your results to a new tape. The other design was the end of the line where you read your tape file in with the results and print out a formatted report. We only got our first databases a couple of years later, and they were VSAM, relational databases were still a glint in the eyes of scientists.
 
So I guess I was lucky that I got to work predominantly on new programs at first. Only later as the senior project members moved upwards or onwards did the likelihood of me inheriting a big blob of old code increase. I wasn`t looking forward to that, as it was all written years previously and was getting quite gnarled. Actually, I didn`t take too much interest in what the batch systems did, and I still don`t know! I got out within weeks of being given a system to look after in order to start writing games.
 
Before I bailed I got to see the spaghetti that existed in some of the older systems. There was stuff like:
 
   if RunNumber = 6 then
      move 587 to CompanyNumber.
 
The RunNumber was increase by 1 every week and was currently set to 278, so the above test would never, ever, ever kick in again. There were plenty more similar patches in the code, each with a different RunNumber value to fix a one-off late-night problem. Just why did they leave those lines in? Code developed with flow-charts is always fun. They taught me Jackson Structured Programming later. I resisted at first as it was quirky for some solutions, but it works. Steve Turner and I used this design methodology to share code between the Spectrum and the C64.
 
From talking to some of the new lads that had been to uni, they seem to get a grounding in quite a few languages and environments and systems. There are so many really: web development, databases, client side, server side, Windows server, Unix, and plenty of languages. Plus hopefully they get some grounding in good software design that could apply to many languages. Environments have also changed from mainframes to banks of servers, to cloud servers, that`s a lot to take in. By the time the course is ready, sometimes the content is obsolescent, if not obsolete. 
 

Control

When you join a company as a new developer, you`ll get assigned to a team. You get given your tasks to do, usually designed by a systems analyst or analyst/programmer. On big systems the tasks are likely to be bug fixes that might take a bit of finding, but may well only involve one or two line changes. You get to code and test that change, usually on a tight time budget. You might see any number of other horrendous lines of code, but you won`t be invited to indulge yourself in ad-hoc improvements.
 
I get why you don`t get to tidy up code. The short answer is: no-one`s interested! If the code is hanging together then so be it. In business the speed performance of the code is only brought into question if someone has had to sit there a minute or a second too long, and is prepared to pay for a change, Sometimes they`ll demand a speed-up and you can`t find one!
 
You have to get used to the idea of controlled code. Quality checks are done on your changes, which are logged by your configuration management system, and any unauthorised changes should get spotted and rejected. Your end users are expecting to test the programs for the changes they`re paying for, and not get any surprises by being asked to check something else, just because you`ve made the code slightly shorter or safer.
 
I once delivered a code fix we'd done one release too early and they made me take the change out and re-deliver with the bug back in, and that left a nasty taste in my mouth. They didn`t want to test my fix. It was only a one-liner, and we'd tested it. Since the code was already broken and they couldn`t use that feature, then I couldn`t have made it any worse so they might as well go with it, but hey, you can`t argue with the customer. Well, I did try. "We'd rather have the program that`s definitely broken than the program you can demonstrate is fixed if we only had the time to look, but we're just too busy."
 
Contrast this to when you`re the lead programmer on a game project. If some big change has to be made to get the performance up to maximum then you`re likely going to do it, on your own. Games have somewhat changed since the 16-bit days when there was usually a lead programmer and maybe a tech support programmer only. We used to have to try to eek out every last CPU cycle to get the performance we needed. We tended to hit the buffers of what we could achieve in a 50th of a second fairly quickly and then have to optimise where we could or cut down on something to get the performance, Nowadays every PC is different but sufficiently fast that we can put as much on the screen as we want, all built from scratch every frame.
 
Many of my 16-bit title sequences relied on text being plotted onto two buffers and just left there. Provided nothing went over them, the images would persist because the background was not rebuilt every frame. Paradroid 90`s high score table text is done like that, and the moving game logo wipes the text out as it passes over. Fire and Ice also uses this technique but allows the scrolling to wipe the text. You can get more stuff on screen for free as no-one realises that the images have been abandoned there.
 
Back to our new staff though. Many are disappointed to find that they rarely get to write anything new, but spend their time maintaining monolithic code that the company has been developing for years, and re-purposing as required for new customers. Sadly they do not get to write some new monolithic code of there own. I see that as a good thing though. When you have to find bugs in other people`s code; you start to see just how many different ways people can get something nearly right. It can take a lot of thought to logically deduce what must be going wrong in the code, and find the right fix.
 
It`s all good experience on your way to becoming an expert detective/problem solver. You will have to find problems in your own code at some point, finding them in other people`s code is harder, of course. You are getting to see other people`s code though, and some of it will be good code. It also takes a while before you can spot the good code from the bad, as there are many ways to code things. 
 
As long as the old monolithic code had a good design philosophy then it has only got gnarled later on as people re-purpose and patch it in ways that were not quite in tune with the original design. This can easily happen when a large team is tasked with making a lot of changes quickly and on a budget. Maybe some of the less experienced people will go a bit off-piste in their coding, I know I did in my early days. I thought I knew better, but I hadn`t realised how the code architecture locked together. It was originally thought out pretty well, and time was certainly given to getting all the pieces right. Over time though it did get battle-scarred.
 
Upgrading the system can cause trouble. Do you replace all the old calls with new ones? Do you leave all the old calls in there and add new ones? Do you wrap the old calls to call the new code, or wrap the new calls to call the old code? That becomes a battle between backwards compatibility and code simplicity that no-one wins. The experienced programmers know which are the new calls to use and the old ones to avoid. New programmers just see two calls and will use whichever one they last saw being used. Slowly the code deteriorates.
 

Safer Testing

When I was working on functions that could be called from a hundred places and counting; I would want to make sure that function was as sound as possible. You can test the function to prove that it does what you intend with the parameters it`s expecting. Are you then going to test all hundred calls to it to make sure they`re all working? Good luck getting that signed off! You could test a random selection, that`s better than nothing. You need clear documentation of what the expectations are of this function you`re working on. Sometimes there will be some validation. You can always make the validation DEBUG only, so that it disappears in the RELEASE build. Programmers should always test first in DEBUG mode, and do the final testing in RELEASE mode. That way you can use breakpoints to check all the paths through the code, at least the one's you`re changing.
 
I would never advocate the sort of test that detects bad input and substitutes something of it`s own if it fails validation and then carries on. I found a test once in a logging function to check that a folder directory path passed in existed, and if it didn't it used "C:\Temp\". Firstly that then relied on every test and production machine having a C:\Temp\ folder just in case. Secondly, when MS started locking down folders, about Vista time, even if there was a C:\Temp\ folder, you might not be able to write to it any more. We found that our German cousins were particularly hot at locking down their PCs for security purposes and we couldn`t even create that folder, let alone write files into it.
 
You do need to send back a bad status and a decent error message to the caller if they`ve passed in bad input and get it sorted straight away during testing. You could cause an assertion failure and hit a breakpoint in DEBUG mode, just to make sure the caller notices. Of course the end user running on production code in RELEASE mode doesn't want to see programmer`s rants at each other. We once had a user report the following message: "It`s not possible for the code to get here." Nice and embarrassing. I once got this helpful gem: "Can`t do this with that." Good old object-oriented nonsense successfully removed any context from that one. I was running a loop that made a thousand sub-routine calls in quick succession and all I get is: computer says "No!" Didn`t have a clue even which subroutine spat that into the log.
 
Sending back a bad status code is not always enough either, as we found. Many programmers are so confident in their code that they don`t bother to check status codes passed back from functions anyway. Equally some programmers don`t bother to send one back at all. That`s straight out of the manual of failure-proof code. There`s so such thing, as I have learned in my 37 years in IT. The computer will find a way. 
 

Conclusion

In order for you to write your own monolithic super code then, you have to do one of two things: work for yourself, on your own, and never ever ask anyone else to work on your code, or, bide your time in a team and learn how to do it. Be quick though, it`s not getting any easier as the code is getting bigger all the time.
 
Come to realise how much you need to know to create such a big lump of near-unmanageable code so that when you get to write a big lump of near-unmanageable code of your own, you`ll figure out how not to.