Even though more than 20 years have passed, I still remember wondering what it would be like to finish university and start working. Up until that point, I had pretty much spent my whole life in school, with only a few, non-programming summer jobs thrown in. My expectations of what it would be like to work as a software developer were mostly correct, but there were a few surprises in the first few years, and here are the top five:
5. People Interaction
Programming seemed like quite a solitary job – a feature needs to be done, so you sit down at your computer and code it up. The truth is there is quite a lot of interaction with other people. You discuss your designs with your colleagues, you are in meetings reviewing new features, and you talk to the testers testing your code.
It really helps to be tactful and diplomatic during these interactions; if this doesn’t come naturally, learn how. One of the best books on the subject is How To Win Friends and Influence Peopleby Dale Carnegie. If you haven’t read it, I really recommend that you do.
4. Writing Matters
It helps a lot to be able to write clearly in order to get your points across. To some extent, coding and writing are quite similar. In both cases you need to express your ideas clearly and unambiguously in a structured way. There are of course lots of e-mails that need to be written, but there is also documentation of the features you have developed, describing bugs in bug reports so that it is clear what the problem is, as well as writing good explanations for bugs you have fixed. There wasn’t much emphasis on writing at university, but being able to write well definitely is an asset at work.
3. Software is Never Done
Before I started working, I thought that you developed a feature, and then you were done with it. However, in reality you quite often come back to features. Maybe it was not exactly what the customer wanted, or you are adding more functionality to it, or similar funtionality so you want to combine it, or you are fixing a bug in it. One way or another, you often return to code you wrote before.
I didn’t really understand either that new features are almost always inserted into existing code. At university, we always developed programs from scratch, but that is almost never the case in the real world. Sure, you create new functionality, but it always has to fit in to what is already there. Therefore, a large part of creating a new feature is understanding the existing code in order for the new feature to fit in. This is something we never practiced at school.
2. Few Clever Algorithms
At university I did an M.Sc. in Computer Science and Engineering. I studied communication systems, which included signal processing, error correcting codes, queuing theory and so on. We also had core computer science courses like algorithms and data structures, and I loved all of it. I thought it was really cool to be taught all these clever algorithms and data structures, and I expected to see them in use at work.
My first job was as a software developer at Ericsson in Montreal, working with the mobile switching center that handles calls in a cellular network. There was a lot of code controlling call set-up, hand-offs, roaming etc, but I was pretty disappointed to see that it was all done with quite basic data structures and algorithms. The most interesting part I found was the code keeping track of roaming subscribers currently in the system. It consisted of one thousand binary trees, where the last three digits of the subscriber number determined which tree a given subscriber belonged to. To find a subscriber, you picked the tree based on the last three digits of the number, then traversed the tree to find the subscriber. Apart from that, it was pretty much only linked lists or simpler.
1. Complexity from Aggregation
So, given that there were no clever algorithms in use, and that the whole application was only using pretty basic data structures, it seemed at first that there wouldn’t be many challenges working on the system. Wrong! I quickly realized that the system is hugely complicated, not with complicated features, but in having lots and lots of simple features aggregated together. This is something I have seen in all systems I have worked with. Most features are dead simple, but because there are so many of them, you get subtle (or not so subtle) interactions between them causing bugs. The complexity of the system comes from the aggregation of many simple parts, not from any complex parts.
My biggest surprise was #5, since I somehow went through college mostly doing assignments on my own, which was great on the purely technical side of things.
Next was #2, although that was more of a disappointment than a surprise.
I suspected #1 would be an issue, but I never fully grasped it until I got to work with a 25-year-old code base. 🙂
I work at a research company, so I write quite a bit of algorithms that are supposed to be clever. So i guess #2 depends on what you are working on.
What I found surprising is that many simple algorithms or data structures are usually faster than more complex ones that are better in theory, because theory usually neglects caching issues.
Understanding how algorithms and data structures work can be very helpful when you are using a modern OS or database. For example: knowing how b-tree indexing works in MySQL can be key to fixing a performance problem.
Also, I find myself regularly using trees, graphs and hash tables to build simple features.
Martin, modern clever algorithms tend to be cache-aware. The ones that are focussed on big O, though – they were clearly missing the point eve 15 years ago when I was in school.
Totally agree with your point #1: Complexity from aggregation. Seems like anymore, a whole lot of what might actually be complex has been abstracted away from us by the various frameworks we use today. However, creating a working whole out of the many related (yet simple) parts still requires careful design.
Terrific post. Thank you for sharing your thoughts and experience. As an aspiring developer I am always on the lookout for tips and methods that would benefit me in my journey to become a software developer. Thanks again.
Great post, I think that #1 was my biggest surprise at my first developer position. It amazed me how a project plan/documentation could look so simple on paper because all of the parts were created with very simple/easy-to-implement algorithms, yet the biggest bugs/problems would stem from all of these simple segments interacting with each other. This was often compounded by the fact that each developer had his own way of coding these simple parts, so debugging became a nightmare when examining code that had contributions from many developers. The way I solved (or at least attempted to reduce) this issue was by making a library with a bunch of common functions/algorithms for all of the developers to use, thus standardizing some of these simple routines (although there was still a TON of complexity added through the aggregation of these routines). I guess the lesson here is that simple to understand does not always mean simple to implement/debug (etc).
#2 is actually a relief. Brushing up on a data structure I barely remember would waste work time. And I found out only at my first job that Software is Never Done. It really sucks having to insert new code into something that’s outdated, overly complex, or not very efficient.
I went into coding from a completely academic background. My biggest shocks were:
* Devotion to source control. In retrospect, it’s obvious, but at the time I hadn’t really considered how a big project stayed sane.
* Aversion to churn. Where I come from, you’d clarify — for instance — comments or variable names at the drop of a hat. That was Strongly Discouraged because it made it harder for other people to find specific bugs.
* Bureaucracy. You couldn’t just say ‘this is a neat idea! let’s ship it.’ It had to go through a huge design process. Again, that makes sense in retrospect.
* Most coding is debugging. Responding to problems made up a much bigger proportion of my day than writing anything new. I found that quite crippling.
* Don’t solve solved problems. I’m an applied mathematician, and most of my education involved solving problems we already knew the answers to. Now, it was a case of finding the right library. Once more, it makes much more sense — and a mockery of the education system.
An a-ha moment for me was when realizing that I actually as a programmer was solving other peoples problems and a big part is to listen and really take in and understand the domain and goals.
Really good points. I started as a professional software developer about 11 years ago, and I would say I had much the same experience as you. Despite working on complicated 3D visualization systems I never had much use for the advance geometric algorithms I learned about at Uni. It is more about finding the correct framework and library and understanding how to use it.
I think Universities should do more to deal with your point on “Complexity from Aggregation”. I takes a while to develop the skill to work efficiently with say millions of lines of code. E.g. one could have programming assignments where you have to add a feature to a big open source project.
Enlightning post! (I think that #1 and #2 are the hardest to learn..),
and I totally agree on “Universities don’t prepare people to WORK as software developer/sysadmin/everything else”, especially in Italy, were I live.
Pingback: 20120827 | umgeher's changelog
– tech stack changes (i.e. MS –> Linux on AWS)
– never-ending requirements update…!
Working with legacy code is usually hell. In the academic environments, your assignments don’t usually involve constraints. I worked on a project that involves writing a new database system that works with the file structure (undelimited binary files) utilized by a poorly documented legacy system. Only then did I understand constraints 🙂
Pingback: Top 5 Surprises When Starting Out as a Software Developer | Henrik Warne’s blog « Sutoprise Avenue, A SutoCom Source
Pingback: Top 5 Surprises When Starting Out as a Software Developer | Henrik Warne’s blog | Brent Sordyl's blog
My biggest shock was the horribly-incomplete Microsoft “documentation”.
The early MFC versions were a nightmare! Over and over, simple things would fail to work, and the Internet was in its infancy, so there was no way to google for a solution.
I was shocked, frustrated, and infuriated that tasks which should have taken minutes, took days or weeks with the poorly-documented Microsoft crap we were forced to use.
We always sadly laugh that there is never enough time to do it right but there always seems to be time to do it twice…
haha, cool article!
My first job: in school we had been studying NP complete algorithms, cool graph searches etc… One of my first tasks: “A strange purple i keeps popping up on the screen. Fix”. haha
I went back for a PhD and got into more research programming, things got better.
Very nice post for us the less experienced ones 🙂 the #1 is much a surprise as it’s disappointing for a recent graduate with big thirst for doing mighty things (not my case)…oh, and yes, aggregation of many simple interacting things (…really many) leads to very or extremely complex systems – take our brain for ex, everybody knows or can learn how a neuron, synapse or axon works, what it does etc, but it’s the interaction of those “simple” 100 billion cells, acting as a parallel distributed system, that generates the yet unable to be explained, consciousness…
my biggest shock was “i get payed to do this”
2#: Unfortunately most programming jobs now require more GUI work then creating complex algorithms especially with the advent of apps (Unless you’re creating games!).
#5: There have been countless times when I have created an elegant solution to a complex problem only to go completely under the radar and then get an abundance of praise for creating a simple GUI element.
Unfortunately uses / clients only appreciate what they can see.
The first surprising thing I learned when I first worked professionally was: It pays to know how to type well! Fortunately I learned typing in High School. I felt bad for the colleagues I’d encounter every now & then who had to hunt & peck their way thru writing code or documentation.
This post was quite popular on reddit, and it was also discussed on Hacker News.
I think #4 has always been an issue in most forms of engineering.
Most of the engineers I have worked with (myself included) are generally visual thinkers. So thinking in textual terms or converting mental images to prose is very difficult.
Back when my role involved writing documentation for end users, I used to joke that I wrote Mockumentation. These are instruction manuals that go into great depth on the bleeding obvious and skip steps or details the user has absolutely no way of knowing. The end result was leaving the end user feeling angry, frustrated and just a little bit foolish for not being able to follow the deceptively simple steps and get the thing to work.
From my own experience as an end user, this seemed a very popular approach to writing user manuals.
Very good point, I agree completely!
Too true. I love the reference to user manuals – I remember this phenomenon well!
Pingback: 10 Tech Stories To Read – September 4 Edition » iRomin
Pingback: Starting as Software Developer? Look at these 5 surprises « /home/tech
Pingback: Link Dump – September 15, 2012 Edition | Wern Ancheta
Communication is big aspect of software job. Ability to articulate complex issue is a rare skill
Pingback: LATW Episode 19 (August 1–September 30, 2012) « shahriar
For the subscriber lookup problem, I guess the solution uses binary trees, so lookup is O(1 + log2(10^7)) ~= 24 (worst case; average will be better depending on the dataset size). Doesn’t look terribly good. 🙂
A Trie would be the obvious “CS data structure” to pick, so let’s analyze that solution. The Trie is a little obscure because it’s not present as a built-in library of most languages, but it’s a simple idea. Create a custom tree where each node has an array of slots, in this case 10 slots (one per digit 0..9, so each node resolves one digit). This needs 10 levels for an US/CA 10-digit subscriber number. To optimize for density you can scan the digits backwards (because the last digits have denser distribution) and have bigger slot arrays in the top levels; say 1000 for the root node, 100 for level-2 nodes, then 10 for levels 3+. This maintains excellent space efficiency (dense nodes) while optimizing lookup in a few steps (7 per number, with 1000/100/10…). Notice there’s no need for rebalancing, which is 99% of the complexity of implementing most fancy trees.
Finally, concurrency is awesome because only a single node (at most) must be locked at any time, for any single-element search or update operation. And you can do even better with a “persistent” design (like Clojure’s data structures); this trick can be applied to many data structure but in practice it begs for trees. No synchronization required for lookups, and for updates you can use optimistic locking and reconcile concurrent updates (even in the same nodes), and you can do that in a maintenance thread so the threads that perform application work, including updates, are completely lock-free as long as perfect serialization is not required, i.e. after some update it’s OK if the changed elements only appear in lookups a couple milliseconds later. Which looks like an awesome tradeoff for a switching system that needs both hard-RT performance and online updating of subscriber numbers.
Thanks for your interesting comment and analysis! Yes, tries are pretty cool.
The data in this case was pretty sparse – I think having one million roamers in the system would have been quite a lot. Evenly distributed between the trees, there would then be 1000 subscribers per tree, or around 10 comparisons in a given tree for the worst case (if it’s balanced). But in either case (24 or 10) this part would be one small part of call processing. In the course of a call, there would also be several instances of signaling (in modern terms, sending and receiving on a socket, but in that case it was SS7) that would use up CPU cycles. So the performance from these simple binary trees was quite alright.
As for concurrency, this was on the AXE platform, developed during the 1970s. The call processing was done on a single CPU, and all jobs were serialized using a job buffer and an actor model (I think Erlang has its actor model in part because of AXE). Each job completed before the next was executed (at least on the same priority level – there were four job levels, A – D, and traffic processing was on level B). So there was no concurrency issues in terms of updating or accessing the trees.
Of course, in a modern processing environment with many thread, and with more intense inserts/deletes/lookups, something like you describe would probably have been quite beneficial. And it’s certainly fun to see how fast/space efficient/concurrent of a solution we can find. Thanks again for your comment.
Pingback: “Anyone who has never made a mistake has never tried anything new” | My journey in Computer Science
Not to forget, general skills matters a lot in programming jobs, including common sense, ability to negotiable, ability to speak, courage, keen observation.
Pingback: 做程序员之后才知道的 5 件惊奇事 - 赵榕笔记
Pingback: [怒转]做程序员之后才知道的 5 件惊奇事 | 52 Coding
Pingback: 做程序员之后才知道的 5 件惊奇事 | 小四 - 个人博客
Pingback: 做程序员之后才知道的 5 件惊奇事 | 说个啥自媒体，能说出你的想法的媒体平台！
Pingback: 做程序员之后才知道的 5 件惊奇事 | 晓的博客
Pingback: 成为程序员的五大惊喜 | IT新闻 | html5tricks
Pingback: 成为程序员的五大惊喜 | 我爱互联网
Pingback: 成为程序员的五大惊喜 | | Evolution Unit 进化Evolution Unit 进化
Pingback: 成为程序员的五大惊喜 - IT新闻