October 18, 2017
12 Things a Professional Computer Programmer Needs to LearnThe last few years has seen an explosion of great learning resources for people interesting in getting into computer programming.
Nothing could be further from the truth, though. Programming languages are just one small aspect of writing software as a professional (albeit a crucial one).
When learners ask me "What else do I need to know how to do?", I'm typically unprepared to answer. Unhelpfully, I might just say "Loads!"
Here, I'm going to attempt to structure some thoughts on this.
2. Learn to use Version Control. Version Control Systems (VCSs) are seatbelts for programmers. If your code has a nasty accident, you want to be able to easily go back to a versin of it that worked. And most professional developers collaborate with other developers on the same source code, so to do it for a living you'll want to know how to use VCSs like Git and Mercurial to effectively manage collaborating without tripping over each other.
3. Learn to work with customers. Typically, when we're learning to code, we tackle our own projects, so - in essence - we are the customer. It gets a bit more complicated when we're creating software for someone else. We need to get a clear understanding of their requirements, and so it's important to learn some simple techniques for exploring and capturing those requirements. Look into use cases and user stories to get you started. Then learn about Specification by Example.
4. Learn to test software. There's more to making sure our code works than running the application and randomly clicking buttons. You'll need to understand how to turn requirement specifications into structured test scripts that really give the code a proper, in-depth workout. How do make sure every requirement is satisfied? How do make sure every line of code is put through its paces? How do we identify combinations of inputs that the code can't handle?
5. Learn to write automated tests. Automated tests are commonly used in Specification by Example to really nail down exactly what the customer wants. They are also crucial to maintaining our code as it grows. Without a decent set of fast-running automated tests, changing code becomes a very risky and expensive business. We're likely to break it and not find out for a long time. Learn how to write automated unit tests for your code, and how to automate other kinds of tests (like system tests that check the whole thing through the user interface or API, and integration tests that check system components work together).
6. Learn to write code that's easy to change. On average, software costs 7-10x as much to maintain over its lifetime as it did to write in the first place. And if there's one thing we've learned from 70 years of writing software, it's that it'll need to change. But, even though we call it "software" - as opposed to "hardware" - because it's easier to change than the design of, say, a printed circuit board, it can still be pretty hard to change code without breaking it. You'll need to learn what kind of things we can do in code tend to make it harder to change and easier to break, and how to avoid doing them. Learn about writing code that's easy to read. Learn about simple design. Learn how to avoid writing "spaghetti code", where the logic gets complicated and tangled. Learn how to shield modules in your code from knowing too much about each other, creating a dense web of dependencies in which even the smallest changes can have catastrophic impact. Learn how to use abstractions to make it easier to swap out different parts of the code when they need to be replaced or extended.
7. Learn to improve the code without breaking it. We call this skill "refactoring", and it's really, really important. Good programmers can write code that works. Great programmers can improve the code - to make it easier to understand and easier to change - in ways that ensure it still works. A function getting too complicated to understand? Refactor it into smaller functions. A module doing too much? Refactor it into multiple modules that do one job. This skill is very closely connected to #5 and #6. You need to know bad code when you see it, and know how to make it better. And you need to be able to re-test the code quickly to make sure you haven't broken anything. Automated Tests + Design Smarts + Refactoring form a Golden Circle for code that works today and can be easily changed tomorrow to meet new customer requirements.
8. Learn to automate donkeywork like building and deploying the software. Good software developers don't manually copy and paste files to production servers, run database scripts, and all of that repetitive stuff, when they want to create test or production builds of their systems and deploy them to a live environment. They program computers to do it. Learn how to automate builds, to do Continuous Integration, and automate your deployments, so that whole delivery process can become as easy and as frictionless as possible.
9. Learn about software architecture. Is your application a mobile app? A website? A Cloud service? Does it need huge amounts of data to be stored? Does it need to be super-secure? Will some features be used by millions of users every day? Will it have a GUI? An API? Is the data really sensitive (e.g., medical records)? We have 7 decades of knowledge - accumulated through trial and error - about how to design software and systems. We have principles for software architecture and the different qualities we might need our software to have: availability, speed, scalability, security, and many more. And there are hundreds of architectural patterns we can learn about that encapsulate much of this knowledge.
10. Learn to manage your time (and yourself). You might enjoy the occasional late night working on your own projects as a beginner, but a professional programmer's in this for lomg haul. So you need to learn to work at a sustainable pace, and to prioritise effectively so that the important stuff gets done. You need to learn what kinds of environments you work best in, and how to change your working environment to maximise your productive time. For example, I tend to work best in the morning, so I like to get an early start. And I rarely spend more than 7-8 hours in a day programming. Learn to manage your time and get the best out of yourself, and to avoid burning out. Work smarter, not harder, and pace yourself. Writing software's a marathon, not a sprint.
11. Learn to collaborate effectively. Typically, writing software is a team sport. Teams that work well together get more done. I've seen teams made up of programmers who are all individually great, but who couldn't work together. They couldn't make decisions, or reach a consensus, and stuff didn't get done because they were too busy arguing and treading on each others' toes. And I've seen teams where everyone was individually technically average, but as a single unit they absolutely shone. Arguably, this is the hardest skill, and the one that takes the longest to master. You may think code's hard. But people are way harder. Much has been written about managing software teams over the decades, but one author I highly recommend is Tom DeMarco (author of "Peopleware"). In practice, this is something you can really only learn from lots and lots of experience. And increasingly important is your ability to work well with diverse teams. The days when computer programming was predominanly a pursuit for western, white, middle class heterosexual men are thankfully changing. If you're one of those people who thinks "girls can't code", or that people from third-world countries are probably not as educated as you, or that people with disabilties probably aren't as smart, then I heartily recommend a different career.
12. Learn to learn. For computer programmers, there's 70 years of learning to catch up on, and a technology landscape that's constantly evolving. This is not a profession where you can let the grass grow under your feet. People with busy lives and limited time have to be good at making the most of their learning opportunities. If you thought you'd learned to learn at college... oh boy, are you in for shock? So many professional programmers I know said they learned more in the first 6 months doing it for a living than they did in 3-4 years of full-time study. But this is one of the reasons I love this job. It never gets boring, and there's always something more to learn. But I've had to work hard to improve how I learn over the years. So will you. Hopefully, the more you learn, the clearer the gaps that need filling will become.
So, there are my twelve things I think you need to learn to be a professional computer programmer. Agree? What would be on your list? You can tweet your thoughts to @jasongorman.
October 13, 2017
Time for the Chief Software Developer?A blog post by Extreme Programming co-creator Kent Beck about ageism in software development has set me thinking again about this whole issue.
As 50 looms on the horizon, I'm becoming only too aware of this predilection employers have for younger - cheaper - developers. "Do you think they might be a little old?" is a question I routinely hear from hiring managers in start-ups in particular.
The net effect of this - aside from throwing great talent and experience on the scrapheap - is we're a profession of perpetual beginners. Young people entering software development are very lucky if they're exposed to industry veterans in any practical way.
So insights about refactoring, say, that date back to the 1980s have to be rediscovered and reinvented year after year. The upshot is that most developers can't refactor code. So most code suffers from a severe lack of maintainability. By the time developers have learned to write better code, our industry dictates that they move away from the code-face. And around we go.
My solution to the "How come you're not a CTO yet?" question that inevitably comes up with someone of my vintage has been to sidestep it. As a developer, I'm getting too old and too expensive for most employers. But as a trainer and coach, 25 years of professional experience is a distinct advantage. So I code every day, and work with other developers on actual software, instead of sitting in meetings or being a PowerPoint jockey.
But sidestepping the job shouldn't be necessary. There should be a viable career path for people who want to stay hands-on. They're both necessary and valuable, especially to technology companies.
I maintain that there should be such a thing as a Chief Software Developer, who sits on the board like a CTO or CIO, but writes code on a day-to-day basis. They would be there to defend the reality of writing software from the uninformed "optimism" of bosses who think it's easy, and who just want everything yesterday, at half the price, and hang the consequences for the business.
I can think of many, many start-ups who could have avoided The Hell of A Thousand Complete Rewrites had such a person had one hand on the wheel. Indeed, I can think of a few very large companies who'd still be trading today if someone with genuine authority had said "No, let's do this right".
I'm a realist, though. I appreciate that history teaches us such authority is rarely given freely. Development teams need to take it. Perhaps one way teams could pave the way would be to identify who in their team would be a Chief Software Developer, and then just start calling them that. After a few years of many teams in many businesses doing it, the drip-drip-drip effect might just make it an officially acknowledged reality.
Who would be your Chief Software Developer?
August 19, 2017
Time For Learning - An Inconvenient TruthI've watched many tweet debates ("twebates"?) recently on the subject of finding time for learning in software development.
In the culture of the code craft movement, the consensus has been that you have to put in the hours. And by that, they tend to mean your own hours, outside of the day job. I've seen many job ads stipulating that candidates would need to show evidence of this extra-curricular commitment: blogs, speaking at conferences, OSS contributions, personal projects and all that.
The counter argument comes chiefly from people advocating greater diversity in software. Single parents, for example, have a lot on their plate that makes popping along to the Extreme Tuesday Club or speaking at a conference in, say, Norway, logistically difficult. Where's the time in their day/week/year to read all three volumes of the Art of Computer Programming?
My perspective on all this, I'm afraid, is cold and sobering. It takes a lot of reading and talking and sharing and experimentation (also known as "trying new stuff") to get good at writing software - and to stay good at it.
That's an inescapable reality. It's an inconvenient truth about software development. Everyone wants those skills, but nobody's willing to pay to develop them. Cui bono? Demonstrably, the employer benefits from more skilled developers. So they should make a contribution to bulding those skills. Simples.
What we're really debating is where does that time come from? Most employers aren't willing to support learning out of their own budgets. They expect developers to arrive fully formed, and that means that anything aside from direct on-the-job experience is down to us to learn in our own time. It's wholly inadequate to the task because we can only learn things that have immediate relevance to what we're doing.
Imagine if doctors had to learn everything that way. "Well, Mr Gorman, I'm afraid you have a burst appendix. This hasn't come up before, so I'm going on a course to learn how to treat it. See you in 2 weeks."
This also excludes people whose backgrounds and situations make finding those extra hours every week very difficult. This is why I believe offering developers "10% time" or "20% time" is really very necessary if we want a more diverse profession. This is another inconvenient truth about software development. Job ads that demand large amounts of extra hours of "elective" work are effectively restricting applications to people with not a lot else going on in their lives.
In practice, the code crafter landscape is still pretty homogenous. When I run public events, we still get about 85% men, and most of those are white. Very occasionally, someone with a disability comes along - and I always try to make sure the event's accessible, and advertise that fact.
But the fact remains that there are a lot of potentially great developers out there who, much as they'd like to, can't get along to a Saturday workshop, and whose employers won't let them take time out for learning during the working week.
Those are the people we in the dev community rarely see. But we shouldn't assume that they're not there because they don't want to learn.
If your job ads say you're committed to increasing diversity, and then demand a large portfolio of extra-curricular activities, you have a cognitive dissonance.
So, my question is this: how do we square this circle? My current belief is that we must adapt the very nature of our jobs so that time for learning and deliberate practice is built into the working week. I believe that this should become the norm, whereas today it's very much the exception.
I come from the school of "if this needs to happen, then let's just do it". We made the mistake, as professionals, of letting other people manage our time. If we're to move forward then that needs to stop. As "prima donna" as this sounds, we should take that time, and not ask for permission.
Because if we ask for permission, we know what the answer will be.
August 11, 2017
Update: Code Craft "Driving Test" FxCop Rules
I've been continuing work on a tool to automatically analyse .NET code submitted for the Code Craft "Driving Test".
Despite tying myself in knots for the first week trying to build a whole code analysis and reporting framework - when will I ever learn?! - I'm making good progress with Plan B this week.
Plan B is to go with the Visual Studio code analysis infrastructure (basically, FxCop). It's been more than a decade since I wrote FxCop rules, and it's been an uphill battle wrapping my head around it again (along with all the changes they've made since 2006).
But I now have 8 code quality rules that are kind of sort of working. Some work well. Some need more thought.
1. Methods can't be longer than 10 LOC
2. Methods can't have > 2 branches
3. Identifiers must be <= 20 characters. (Plan is to exempt test fixture/method names. TO-DO.)
4. Classes can't have > 8 methods (so max class size is 80 LOC)
5. Methods can't use more than one feature of another class. (My very basic interpretation of "Feature Envy". Again, TO-DO to improve that. Again, test code may be exempt.)
6. Boolean parameters are not allowed
7. Methods can't have > 3 parameters
8. Methods can't instantiate project types, unless they are factory or builder methods that return an abstract type. (The beginning of my Dependency Inversion "pincer movement". 2 more rules to come preventing invocation of static project methods, and methods that aren't virtual or abstract. Again, factories and builders will be exempt, as well as test code.)
What's been really fun about the last couple of weeks has been eating my own dog food. As each new rule emerges, I've been applying it frequently to my own code. I'm a great believer in the power of Continuous Inspection, and this has been a timely reminder of just how powerful it can be.
After passing every test, and performing every refactoring, I run a code analysis that will eventually systematically check all my code for 15 or so issues. I fix any problems it raises there and then. I don't commit or push code that fails code analysis.
In Continuous Inspection, this is the equivalent of all my tests being green. Of course, as with functional tests, the resulting code quality may only be as good as the code quality tests. And I'm refining them with more and more examples, and applying them to real code to see what designs they encourage. So far, not so shabby.
And for those inevitable occasions when blindly obeying the design rules would make our code worse, the tool will have a mechanism for opting out of a rule. (Probably a custom attribute that you can apply to classes and fields and methods etc, specifying which rule you're breaking and - most importantly - documenting why. Again, a TO-DO.) In the Driving Test, I'm thinking candidates will get 3 such "hall passes".
If you want to see the work so far, and try it out for yourself, the source code's at https://github.com/jasongorman/CodeCraft.FxCop
And I've made a handful more tickets available for the trial Code Craft "Driving Test" for C# developers on Sept 16th. It's free this time, in exchange for your adventerous and forgiving participation in this business experiment :)
August 9, 2017
Clean Code isn't a Programming Luxury. It's a Business NecessityI'm not going to call out the tweeter, to spare their blushes, but today I saw one of those regular tweets denigrating the business value of "clean code".
This is an all-too-common sentiment I see being expressed at all levels in our industry. Clean Code is a luxury. A nice-to-have. It's just prima donna programmers making their code pretty. Etc etc.
Nothing could be further from the truth. Just from direct personal experience, I've seen several major businesses brought to their knees by their inability to adapt and evolve their software.
There was the financial services company who struggled for nearly a year to produce a stable release of the new features their sales people desperately needed.
There was the mobile software giant who was burning $100 million a year just fixing bugs while the competition was racing ahead.
There was the online recruitment behemoth who rewrote their entire platform multiple times from scratch because the cost of changing it became too great. Every. Single. Time.
I see time and time again businesses being held back by delays to software releases. In an information economy - which is what we now find ourselves in (up to our necks) - the ability to change software and systems is a fundamental factor in a business's ability to compete.
Far from being a luxury, Clean Code - code that's easy to change - is a basic necessity. It is to the Information Age what coal was to the Industrial Age.
No FTSE500 CEO these days can hatch a plan to change their business that doesn't involve someone somewhere changing software. And the lack of responsiveness from IT is routinely cited as a major limiting factor on how their business performs.
Code craft is not about making our code pretty. It's about delivering value today without blocking more value tomorrow. It's that simple.
August 1, 2017
Codemanship Code Craft Driving Test - Trial Run
In my last blog post, I talked about the code quality criteria for our planned "driving test" for code crafters.
If you're interested in taking the test, I'm planning a trial run on Saturday Sept 16th. Initially, it will be just for C# programmers.
Entry is free (this time). You'll need a decent Internet connection, Visual Studio (2013 or later, Community is fine), and a GitHub account. Resharper is highly recommended (you can download a trial version from https://www.jetbrains.com/resharper/download/ - but don't do it now, because it will time out before the trial!) You'll be writing tests with NUnit 2.6.x. You can use whichever .NET mocking framework you desire. No other third-party libraries should be required.
The project we'll set you should take 4-8 hours, and you'll have 24 hours to submit your solution and your screencast link after we begin.
If you've been on Codemanship training courses, the quality criteria should make sense to you, and you'll know what we're looking for in your screencast.
If you haven't, then I recommend twisting the boss's arm and sending them a link to http://www.codemanship.com :)
You can register using the form below.
July 26, 2017
Gold Standard Teams do Continuous Inspection
Working with so many dev teams across a diverse range of industries gives me a great insight into the common features of teams that consistently do great work.
I call these the Gold Standard development teams. And they write gold standard code.
Gold standard code, to me, is code that maybe only 1% of teams are writing. It's more reliable and more maintainable than 99% of the code I see.
Importantly, Gold Standard dev teams don't usually take any longer to deliver working software than their Silver and Bronze Standard peers. Often, they deliver sooner. And it's no coincidence. The practices that lead to gold standard code also tend to make earlier and more frequent delivery easier.
One common feature I see in Gold Standard dev teams is that they do continuous inspection of their code to ensure that it's of a high quality.
Some teams review code quality once in a blue moon. Some review code in every iteration. Some review code with every check in.
Gold Standard dev teams review code quality as often as they test their code, every few minutes. This means they pick up code quality "bugs" almost as soon as they're introduced.
Like functional bugs, code quality bugs are much easier to fix the sooner they're caught. Catching issues immediately enables Gold Standard dev teams to produce very high quality code at little to no extra cost. Often, it saves time.
Continuous testing of software requires a high level of test automation. It's not really possible any other way. Continuous code inspection is no different. Rigorously examining the code for a multitude of problems every few minutes is extremely difficult to do by eye alone. Pre-check-in reviews, and even pair programming, are not enough.
Luckily, there's an ever-growing supply of tools we can use to automate our code inspections. Unsurprisingly, demand for the specialist skillset required is growing rapidly, too.
What kind of questions should we ask in our continuous code inspections? To some extent, that will depend on your specific code quality goals. But there are themes that are common to most code:
1. Complexity - How much "stuff" is there in our code? How many lines of code in this function or module? How many branches? How many operators and operands?
Gold Standard dev teams know the price of increasing code entropy, and fight it vigorously. Is this method getting a bit big? Let's split it into a composed method. Is this class doing too much? Let's split it into multiple classes that each have one distinct job.
2. Duplication - When we duplicate code - and concepts - we end up having to maintain the same logic in multiple places, multiplying the cost of making changes to it.
Gold Standard dev teams monitor the code closely for similarities. Are these two blocks of code kind of the same? Let's turn it into one parameterised method. Are these two classes sort of doing the same thing? Maybe extract the common elements into their own class and have both of them reuse that.
3. Dependencies - If we change a line of code in one place, how much of the rest of the code will break? Unmanaged dependencies - couplings - in our code can amplify the "ripple effect" and multiply the cost of even the smallest changes.
Gold Standard teams are continually aware of, and constantly managing, the dependencies in their code. When a class depends too much on other classes, they reshape the code and redistribute the responsibilities to localise the impact of change.
They also make sure that as many of their dependencies as possible are swappable: that is, one function or class or component can be easily swapped with a different implementation with no impact on the calling code.
4. Readability - Code that's difficult to understand is difficult to change without breaking it.
You may be thinking that it's not possible to automate the checking of code readability, and to some extent that's true. But studies have shown a very strong correlation between the complexity of code and how easy it is to read and understand. For example, code that has a lower Maintainability Index tends to score lower for readability, too.
As well as monitoring code for complexity, Gold Standard dev teams can also monitor the semantic content of their code using an increasingly sophisticated array of Natural Language Processing tools.
Simple applications of well-established readability metrics, like Flesch Reading Ease, can also help draw our attention to difficult code.
And even something as simple as calculating the conceptual correlation between names in our code and words used by our customers to describe the problem domain can help highlight code that may not be "speaking the customer's language".
5. Test assurance - If we made a change that broke the code, how soon would we know? How easy would it be to pinpoint the problem?
This is a crucial factor in the cost of changing code, and one that's usually overlooked in discussions about maintainability. Bugs cost exponentially more to fix the later they're discovered. The goal of automated regression tests is to discover them sooner, which saves us a lot of time.
Gold Standard teams continuously monitor how good their automated tests are at catching regressions. The way they do this is to deliberately introduce errors into their code, and see if any of the tests catch them. This is called mutation testing, and there are tools available for many programming languages that will do it automatically, alerting devs to any gaps in their automated test suites and giving them increased confidence when making changes.
Another key component of test assurance is how often we can run our automated tests. The longer they take to run, the less often we can run them and the longer we have to wait for feedback. Gold Standard teams monitor test execution time and optimise their test suites to run as fast as they need.
And finally, when a test does fail, Gold Standard teams are able to pinpoint the problem and fix it sooner, because their tests typically ask less questions. A Gold Standard automated test suite might cover 100,000 lines of production code with 10-20,000 tests, each having only one reason to fail. LOC/test is a key metric for Gold Standard teams, and they rarely let it go beyond 10 LOC/test.
PS. Shameless plug: If you'd like to learn more about Continuous Inspection, I run a bite-sized training workshop on code craft metrics.
July 18, 2017
Why Don't We Eat Our Own Dog Food?You may already know I'm a big advocate of developers eating our own dog food.
Using the software we create as real end users, in the real world, provides insights that no amount of meetings or documentation can provide.
A quick straw poll I ran on Twitter suggests 2 out of 3 of us haven't actually used the software we're working on for real.
Devs: have you used the software you last worked on a release of as an *end user*?— Codemanship (@codemanship) July 15, 2017
I've been banging this drum for years, for a largely reluctant audience. Managers say "Our users aren't happy with the latest release" and ask me what can be done. And I say "Walk a mile in your customer's shoes". And they say "Thanks for that. But no."
It's such a simple thing to do, and yet somehow so very hard. There's something psychological going on, I reckon. The same reason most hotel chain employees have no idea what it's like to be a customer in their own hotels...
I urge you to try it. Now.
July 16, 2017
Developers & Employers Prefer to Connect Through NetworksI ran Twitter polls on developers' preferences for finding work, and employers' preferences for finding developers.
Devs: how do you prefer to find work?— Codemanship (@codemanship) July 13, 2017
Employers/hiring managers: how do you prefer to find software developers?— Codemanship (@codemanship) July 14, 2017
There's significant alignment. Both devs and employers prefer to connect through their networks - employers apparently more so.
This makes a lot of sense. There's the benefit of "it takes one to know one". And hiring devs who already know your devs may mean a better team fit.
It raises the question of how people who aren't in those networks find opportunities. This has implications for diversity. Hiring entirely through networks could lead to an effectively closed shop.
We should think about how to extend our networks to include people who might not normally be included. For that, we probably need outreach.
Noted also just how little devs and employers think of agencies. This comes as no surprise, when you've been in the industry as long as I have and heard many complaints from both sides.
Handing responsibility for hiring highly skilled workers to someone with no understanding has obvious drawbacks. You may as well ask your greengrocer to do it..
How IT recruitment agencies survive - and thrive - in a market that sees little value in them? It's a mystery for sure. There are just so many better routes now.
I think it boils down to the interpersonal. Sales people in these agencies build relationships with people working in client organisations. It's that simple.
As rational as we like to paint ourselves, we are - in essence - just shaved apes. "Yes, there may be better ways of hiring. But Phil from Computer Bastards Ltd bought me dinner. So they get the job."
That may well change, though. Social media's making it easier for these communities to find each other. As with so many other markets, the Web could end up cutting out the middle man.
July 9, 2017
Why You Should Put Learning Opportunities Front-And-Centre In Dev Recruitment
Devs: what would lure you away from your current job?— Codemanship (@codemanship) July 6, 2017
A little Twitter poll I ran under the Codemanship acccount seems to confirm something that many of us have been saying for years. 41% of those polled said they could be lured from their current job by greater opportunities to learn.
Software development is a career that involves lifelong learning, and lot's of it. That's how we progress. So it doesn't come as a surprise that it was ranked significantly higher than "More money".
It's surprising, then, that learning opportunities don't figure higher in dev recruitment campaigns. I've banged this drum with clients many, many times. Want to attract and retain great developers? Make learning - mentoring, conferences, training, time to read, time to share - a greater part of the job. No, scratch that. Accept that learning is the job, and build your team culture around that inescapable fact.
When you're hiring, don't just look for what they know now. Look for their potential to learn. And their potential to teach (e.g. by example) the stuff they know so others can learn from them. And clear the way for that to happen. A lot.
Sadly, such employers are too few and far between. The unreasonable and unrealistic attitude that developers should arrive knowing everything they need to know, and no learning should go on on company time, is a leading cause of developer attrition.
It's also the reason why you've been searching in vain these last 6 months for a fluent Mandarin and Dutch-speaking full-stack JS/Node/Java/Clojure/Ruby/NoSQL/SQL/Docker/COBOL/Eiffel/Vim/Linux/Windows developer who has an HGV license and is licensed to practice medicine (salary: market rate).
Software developers tend to be highly educated, but the most important thing we learn is how to learn and it's one of the most important skills your money can buy. In return, one of the most valuable perks you can offer them is more opportunities to learn.
As a professional trainer and mentor, I am of course biased. I tell devs what I do, and they say "Wow, you must be really busy!" and I say "You'd think so, wouldn't you?" But the reality is that the majority of employers don't offer their devs any training at all, let alone time to, say, read a book.
The kind of bosses I run training for are unfortunately very much in the minority. Although, interestingly, they seem to have a lot less trouble hiring good developers.