my partner asked if I’d ever written blog posts highlighting skills for new software developers to practice. A challenge considering I’m more than two decades removed from being a new software developer.
To unwind myself to that point and rewind back to my present day would require far more time and effort than a single blog post.
Instead I want to reflect on the skills that have helped me continue as a developer.
I present these in no particular order, but if I had to pick one, it would be Writing.
Write to think, synthesize, and share. When writing code, I’m exploring method signatures, names, and collaborators. Sometimes, I’ll start with the class documentation, writing up the desired responsibility of the class. Other times, I’ll add that at the end. Or, if I’m stuck on an implementation, I’ll start writing about responsibilities and collaborators.
Much like drawing diagrams, I also use documentation to explain something in a different manner. Invariably I find that this change in approach helps me clarify my understanding.
Challenge any code that claims to be self-documenting. Doubly so for people who make that claim. The documentation of “why this exists” can be most valuable as it can provide insight when it’s time to delete that code. Or the stakes of modifying that code.
And please take time to write commit messages. If you are at a loss for what to write go with the following:
- Leave the first line blank (e.g. the subject/title)
- Write one or more paragraphs describing “before this commit”
- Write one or more paragraphs describing “after this commit”
- Go back and write your subject
The purpose of this ritual is to get good at summarization; thinking about the nature of what changed. It also helps others see what you’re seeing and scrutinize the accuracy of your claims. All in service of creating a well understood code-base.
This goes along with writing but is it’s own thing. Where do you put things. For programming there are two major considerations:
- Where do I put this code?
- Where do I put this writing?
In code, I like to think about “In regards to this concept, what is the smallest surface I should expose?” I’ll put something there, in a more visible location, and then build out the details elsewhere. This warrants an example.
Let’s say I am working on a package. I give that package a name, let’s say
CoolThing. I will add public methods to that module. And in an ideal state mark private everything else. This is a principle of narrow interface design; don’t share more than you need to with your collaborators.
With narrow interfaces, you’re helping define how you envision others using your code. And minimizing other folks’s exposure to changes in your code.
Organizing writing is a different creature. Up until adopting Org-Mode 📖 I had an ad hoc note taking process; sometimes paper, sometimes electronic, always filed away in any odd places. But I adjusted and started using a consistent method for all of my note taking.
A fundamental requirement is that I have direct access, via Unix commands, to the notes I took. My note taking can use other tools, but it must store those notes in a way that is insulated from the note taking tool going away. For Emacs 📖, I use Denote 📖. I’ve looked at Logseq 📖 and recommend that as it’s an open-source application that leverages your file system.
Each of my notes have the following properties:
- Date Created
The directory defines the domain (e.g. “blog post”, “glossary”, “index”, etc). Tags are the subjects (e.g. “rpgs”, “emacs”, “programming”). The date created is automated. All of those, along with title and content are searchable, either together or individually.
I recommend reading Karl Voit’s section on Personal Information Management (PIM). Also consider reading Sönke Ahrens’s How to Take Smart Notes; there are specific implementation details, but I’ve focused on the spirit of the book and how I can make things work for me and my approach.
Tasks for Tomorrow
We had one week shutdown and I followed that with a week of vacation. I took 15 minutes to write up notes on what I was working on. I included links to pull requests, slack messages, and Google Docs.
This served two purposes: First, I was pressing to get done with a task on that Friday. Once I wrote up what all I had I realized that I couldn’t possibly deliver a bug-free finished product by end of day. Second, I could set aside that work knowing that I had taken time to prepare my future self to pick resume that work.
And I set it aside. I spent two weeks not thinking about work; not even a moment about the tasks that were waiting for me on my “desk.”
I came back, reviewed what all had developed in my absence, wrote that down in the same place as my prior notes. Then I reviewed my notes and picked right back up.
And this works for the day to day as well.
I love my work and I love ensuring I have energy to do my work. Which means creating space where I’m not at work nor thinking about it. And this habit of writing up the next days stuff, helps me prepare myself. (Also, for those curious, I know for certain that my brain works on things behind the scenes).
Read code. Read poetry. Read fiction. Read non-fiction. Read blogs. Read! And engage with those readings. Write in the margins. Write responses.
Again, the goal is to be adept at encountering many different written forms. To meet the conversation where it’s at. To develop empathy as well as knowledge.
To detangle and learn from other written yarns.
As a developer, you’re going to spend a lot of time reading. More so than writing code and documentation. Get good at it, so that you may get better at writing. Because writing is a primary way that you’ll share your thoughts.
You might record something, but all things in software distill to written symbols.
And read about refactoring. Martin Fowler wrote a great book on it; targeting Java. But there’s also one for Ruby. Understand that refactoring is a key aspect of your work. It’s how you can make sense of code, extend it’s utility, or begin deprecating and removing undesired code.
When I’m stuck, I try to remember to get up and walk through a doorway. A study shows that walking through a door causes forgetting; and when you’re stuck you need to help your brain forget so that it can get unstuck.
So very many authors speak about their walking. I, and they, have found a connection between long walks and deep thinking. I’ve found helpful a long walk; a walk where I set out and only turn around once I start to feel just a bit tired. From that moment forward, that is where the ambulatory magic resides.
I’d love to know what other options, besides walking, that folks have found.
If you have a chance, work with other people. Share your screen or let them share, and then work together to resolve the problems at hand.
Focus on how you’re communicating. If you are typing, try to give context for what you’re doing. If you are not typing, be curious and engaged; ask clarifying questions.
- “Pause! What was the keyboard shortcut you just used?”
- “Wait, could you please the purpose of that variable using a different means? I want to make sure we name and document it well.”
The most powerful question you can ask as a programmer is: “What is the problem you’re wanting to solve?” People are paid to solve problems; software developers and project managers and all other professions solve problems.
By focusing on understanding and clarifying the problem, you can then begin to look to solutions. You may find a tendency to want to have the solutions and/or approaches outlined. But make sure you know the problem. Get that in front of everyone. And from there build out the solutions.
A favorite anecdote of mine is from a friend and coworker. She asks great questions, seeking to understand the problem. In one case, another developer came with a proposed solution for a problem; he wanted to know how long it would take her to implement this solution.
She asked a few questions and for some time to do some research. She came back with a few more questions to better understand the problem. She then proposed a solution, sought validation, and once validated went to work.
The initial proposed solution to the problem was estimated to require about 6 weeks of effort. Clarifying the problem and articulating a new approach and getting acceptance for that approach and implementing that new approach took one day.
Get good at asking what are the functional requirements. What is good enough? What does done look like? What would need to be true for this to work?
I know I got into programming because I love puzzles, so I need to remember to stop and ask questions instead of always proceeding with puzzle solving of general problems.
If you are planning a trip to a region that speaks a different language, you’d do well to learn the basics: saying thank you, directions, times, numbers, and names for key locations (e.g. hospitals, transit stations, and consulates). With those you can probably flounder your way around.
Learning a new software language or paradigm while attempting to solve an ambiguous problem compounds the difficulty of both.
When I want to learn a new language or approach, I pick a well known (to me) domain as my problem. Invariably, I’ll write in new languages various dice rollers and probability calculators for games I play. I understand the problem space quite well and can focus on syntax.
I’m “good” at Ruby and can use that to help me map those language specific skills into resolving a well understood problem.
In order to finish, I need to know what done looks like. Writing up a test plan helps define when you’re done. Ideally that test plan is one that I can exercise automatically.
In That Time When the Only Test and Development Environment Was Production, you can read the assumed test plan we had as we scrambled to fix a broken production state.
But in other setups, I’ll write automated tests and run those. Writing tests often reveals how I might create more composable code. Or to put it another way, leverage dependency injection and defaults for those dependencies as this helps in testing and extensibility.
This approach also helps to create fast unit tests and expose interfaces of interaction. And those dependencies, as parameters, also help create some automated system-level documentation.
Another key consideration, is testing done right is some of the best documentation. It explains how folks anticipate others interacting with the test subjects.
I have a degree in Computer Science, and at the time there was a general advice that classes should be nouns and methods should be verbs. The classic example is I have a
Bird class. I extend that class by creating a
Both of those classes have a
speak method; perhaps aliased to
quack. It seems so very obvious.
But I can’t think of a time I’ve ever implemented a
Bird class in code. I’ve instead dealt with insurance coverage, report cards, electronic theses and dissertations, and other noun like concepts.
However, I’ve also needed to think in terms of generating a report, authorizing access, and routing a letter; creating classes based on those verbs has been truly liberating. And often results in great composition. After all we compose sentences from nouns and verbs. (And paragraphs from sentences. And sections from paragraphs. And chapters from sections).
I’ve been a professional developer since ; and I envision continuing for many more years. I’m not chasing new technology but am instead taking a cautious approach. I’ve seen decades of fads now faded and new paradigms supplanting old approaches; always informing each other but not as well as you’d ever hope. But one truism remains: tech corporations are all angling to tighten and restrict computational freedoms, to extinguish ownership and force licensing and rent. The fundamentals remain: all of software is a mapping problem. Be it mapping functional requirements to technical approaches, ambiguous understandings to task breakdowns, database records to domain objects, or flipping ones and zeroes to map to new computational states.
From the foundation that all is a mapping problem, it follows that I must be cartographer, archaeologist, poet, sociologist, writer, critic, listener, and speaker. And sometimes coder.