Read the companion post “So, you want to be a software product manager“
20 years might be a short time in human history, but in programming, it feels like eternity. Programming is a field that evolves at warp speed. As a programmer for many years, I’ve seen my fair share of changes in libraries and frameworks, the rises and falls of many, many software development methodologies. But there are timeless principles which I come to realize and summarize and I hope to share them here.
First, forget about the thought that you can learn programming in 21 days. As Peter Norvig said, why in a rush? You can learn programming in 10 years. Of course, this notion doesn’t make sense if you are just repeating the first year experience ten times rather than having a complete 10 years experience, or if you think ( as a lot of MBA style executives seem to) that then first year programmers are equivalent to a 10 year programmer. But let me just tell you that a complete 10 years experience is much superior than ten times a one year experience. You have to take my word for it.
Programming is as much of an art as science. Which means that you need to improve like how you improve on a craft such as playing piano or guitar or computer games: through deliberate practicing.
So here are how:
You don’t stay in the same pond forever. The best way to grow is to handle increasingly difficult tasks. The point is that if you don’t feel your head exploding when you are handling a task, then probably you aren’t learning as much. Always ask for assignments that are slight beyond your capability, that’s the sure fire way to learn.
And there will always be new things to learn, even if you are only handling legacy applications and you are tasked with only bug fixing and feature enhancements. To many, legacy applications are not nearly as exciting as greenfield projects. Consequently, the care for code quality is also minimal and sometimes one just copy and paste the patches with total disregard for code hygiene. But it may be worthwhile to pause and ask yourself: how can I refactor old code so that it is more robust to future changes? Is there anything I can do to make the fix more general? What can I do to make the other developers change the code easily? How readable is it? You might be surprised how much your sense of code can improve out of these exercises.
Of course, this is not to ask you to re-architect the whole application every single time when you are tasked with fixing a minor bug. I’m only asking you to do this in moderation: you just try to make the codebase better within the given constraints.
This is learning, and learning the craft is a joy on its own. You will love it.
When we are children, we ask a lot of questions, but as we grow older, somehow we become omniscient. But in order to grow, we need to know how to ask.
I remember when I first started out as a programmer, all we had was MSDN, which read like it was written by ChatGPT– uninspiring, unhelpful and just a parrot of the obvious out there. Worst of all there was almost no example, making the whole MSDN almost useless. There was no StackOverflow that one can get answers almost instantly.
But how times change! Nowadays the MSDN qualities are much better, and even if they aren’t, we still have a lot of other resources. We have tools like StackOverflow, Google Search and also ChatGPT. All it takes is that you ask, and more often than not, the answer is within a Google Search or a question to ChatGPT ( just remember to verify it).
Asking in human language places a premium on you in being able to formulate the question precisely. Asking on the internet is more difficult than it seems because it involves different stages and different skills. You have to be able to break down a question, scope and phrase it correctly, type it out in English with correct vocab and grammar structure, and post it on the appropriate forums. All these are mentally taxing things, and they take practice to get right. People on the forums are not your slaves, so it’s your duty to ensure that your question is well formed and answerable. Maybe this is what turns a lot of programmers off when it comes to actually asking questions on forums. But if you know how to ask and get answers, you can leverage on other’s experience and expertise, which makes you more productive.
When you are receiving feature or bug fixing requests, it’s important that you listen to what has been said, and more importantly, listen for what is not said. Testers or users will describe what they want to see in the software application, but they often give incomplete indications, or worse, they often don’t know what they actually want.
It’s your duty as a developer to figure out the actual implementable feature requests. If you feel that they are saying contradictory things (trust me, it happens more often than you can think of), it simply means that you haven’t synthesized their requirements well enough. At that point, you will need to probe further. You will know it when you reach the end, when you figure out exactly where they are coming from, and you can explain their concern so much better than they do.
Richard Feynman, one of the most colorful physicists in the 20th century, said that you only fully comprehend a problem when you can explain it so simply that a child can understand it. I can’t agree more.
By Write, I don’t just mean writing code; that’s a given. I mean writing good documentation for your fellow engineers to understand. I also don’t mean mechanical XML documentation that your boss forces you to write before he merges your Pull Request; we all know that’s a sham
I mean the ability to write in English and explain technical details. You write to explain the why instead of how. You write to defend why you use this instead of the other techniques in your code commits. You write to explain the motivation of using your piece of code or library, and what’s the limitation.You write to document down future work.
All these require you to write eloquently and concisely in English. Yes, in English only. If you want to accuse me of being a Language Chauvinist, or a supporter of Colonialism, be my guest. I care more about getting the work done and the message across than any political correctness.
Of course, I’m not asking you to go out to a cake shop and just take things. I’m referring to not reinventing the wheel, when you are writing code.
Don’t reimplement your own sort algorithm, .Net has one, use it! You might feel that your hand roll algorithm is more appropriate because it considers the speciality of your situation, and you will be wrong 99.9999% of the time. The algorithm in .Net has undergone robust testing, and is proven to work in a variety of situations, it even receives periodic optimization and bug fixes. You can’t guarantee any of these for your own algorithm.
Good programmers know when to use other people’s code, and how to solicit help if they get stuck ( refer to the above Ask section). We use a lot of third party components, some open source, some bought with a hefty price. The immediate benefit is that we can “zoom out” and focus on the big picture once we can trust the component. Programming is stressful enough, and every line added to the codebase is a burden. So why not do programming by just doing less of it?
I don’t mean reading other people’s code, though that can be beneficial.
I’m talking about general reading. Like reading books, books on history, science, and nonfiction… everything, and especially books that require you to think critically or challenge your prior beliefs. The books should be putting forward different ideas to you, so that even if you don’t engage your critical thinking faculty when reading them, you will still gain some knowledge and fun in the end.
The benefits are twofold, one is that you get to learn new things and expand your horizon. But another more critical benefit is that you learn to be a better programmer. Writing code is more logically constrained than putting forward arguments in words. So in a sense, it is harder to be a lawyer than a programmer because a lawyer doesn’t have a universal truth machine ( such as a computer) to tell them their arguments are wrong. But if you can craft a watertight argument even in words, then it will definitely help your career as a programmer.
Automated tests include unit tests, or integration tests. The names are not important, the important thing is that you should be able to run them at a click and get repeatable results. You must have this kind of test suite.
I can’t emphasize enough the importance of automated tests in the role of modern software development. Being a better programmer is positively correlated to writing good unit tests. Because making your code unit-testable is a way to architect your code. It constrains your design and enforces good design practices like separation of concern, modularity and making the nasty Singleton problem stand out.
A lot of times, one might find the code is not unit testable, but that’s only because the code is not properly thought out, resulting in a jumble of spaghetti that consists of a mixture of different layers of code. How do you test the point and click in the UI code? Of course you can’t! But it’s a mistake to conclude that unit testing is of limited value. Instead you should try to separate different concerns out so that as much code is testable as possible. And as a bonus, you get better structured code.
The benefits of automated tests as a bulwark against regressive bugs are well known. But what is equally important is that automated tests are also a form of documentation.
Don’t understand how a piece of code works? Instead of spawning the entire application, you just have to run a subset of the code in your IDE through and through. Want to explore edge cases? Just write up separate test cases with different initial values and assert the outcome. Reading the tests is definitely easier than reading the whole piece of everything.
Even the problem of memory leak is amenable to the spell of automated tests. You want to check whether instances in the memory are correctly freed. No problem. Just write code that exercises the code path, ensure that the variables go out of the scope and force GC. Now check whether there are relevant instances being held?
Writing automated tests is a “write once, run many times” kind of investment that will reap you benefits in the long run– especially when you are no longer touching the code because the other developers will rely on it to protect them and to serve as documentation for them. If you can always think about how to write automated tests for your code and you succeed, you are already far ahead of the curve compared to your peers.
Know your tools
We are using an MVVM pattern to structure our application because it enforces good code discipline and is amenable to automated tests. But MVVM is a hard concept to grasp, not least because it involves the concept of XAML binding and the code doesn’t always seem to trace out a logical path. So you will need to grok the application and have some abstract thinking; you will need to know where the code is going, and where it’s coming from.
All these will take experience, but you can accelerate your learning by being proficient in Visual Studio, your friendly IDEs and debugging tools. Take time to learn the functions of Visual Studio, learn how and where to set breakpoints, what are parallel stacks, how to “walk up the stack trace”, how to use Live Visual Tree to examine the properties and the binding, and so on, and so on.
Without Visual Studio, a lot of good programmers will feel crippled. Long gone are the days when you can rely on printf debugging statements and still be a productive programmer. Modern software development is a lot more complicated than that.
For programmers, programming is fun to the point of borderline obsessiveness. Once you think about a problem, it will consume you, even your nights and your dreams.
Which is why you should learn to unwind, and walk away from the problem. Upon facing a hard problem, I often solve it by not thinking about it, and just let it simmer in my subconsciousness for a period of time, then out of nowhere, an inspiration will come. Toiling on the desk is not only useless, but is detrimental because the tiredness that sets in will cause you to put in more bugs than you can fix.
That’s why if you have a sleep problem, then I suggest that you fix it first. Nothing is more detrimental to your productivity than having insomnia.
Not everyone is cut out to be a programmer. Everyone is different, which is to say that everyone has different talents and weaknesses.
The problem with modern schooling philosophy is the mindset that “everyone needs to know coding”. The philosophy was dreamt up by well meaning bureaucrats who have absolutely no idea about human’s ability and limits. We can accept that not everyone can finish running marathon, not everyone can play piano, not everyone can draw, some are tall and some are shorts so not everyone can play decent basketball, but then when it comes to programming or other mentally taxing activities like math and logical reasoning, suddenly “you can master it if you try hard enough”.
I would say that programming is 90% nature, 10% nurture. Too bad if it spoils your bubble. But learning to live with truth is more important than indulging in fantasies.
If it happens that you can’t program, so be it! You can always find another niche. Life is too short to waste on a profession that you don’t like and you are not good at. Remember? None of us will be here on earth after 150 years.
So why do you care so much? Just do things that you like, and do things that you are good at.