Beyond Onboarding
What Your First Year as a Software Engineer Is Really Like
Introduction
Onboarding might last for several days or several weeks as I described in Acquiring and Onboarding Your First Job, but then what?
Onboarding ends. The real challenge begins.
The first year of a software engineering career is not about mastering syntax or algorithms. It’s about learning how software is actually built, maintained, and evolved in the real world.
These are personal observations that may not apply universally and will evolve over time.
The First-Year Learning Curve
It often takes several months to a year before a new developer feels comfortable and productive in a professional codebase.
You are learning the product, the tools, the architecture, the business domain, and the team’s development practices all at the same time. That is a lot to absorb.
Feeling overwhelmed during the first few months is normal. You’re not expected to know everything. Stay curious, keep asking good questions, and focus on steady progress rather than immediate mastery.
The first year isn’t just about surviving the learning curve. It’s about building the foundation for everything that follows.
Continuing Education
Your Computer Science degree is not the end of your education. It is the beginning.
You’ve been studying Computer Science. Your career will be Software Engineering. They are related, but different as I described in You Studied Computer Science. Your Career Will Be Software Engineering.
An academic Computer Science assignment is basically a scoped and well-defined problem to be completed and handed in the following week. You may be part of a small team for larger projects, but for the most part, you tend to be the only person working on your assignment. The main goal is for the code to produce the right answer. You may never look at the code again.
Things will change in your business career. The problems will be broader and less well defined. The customer won’t be able to describe what they want, but they’ll know it when they see it. Or more likely, they tell you that what they see isn’t what they wanted.
You can look for solutions anywhere. The solution, in whatever form it may take, may need to be maintained for years as the customer requests new features and modifications.
You’re not in it alone. You’re part of a team. Solve problems together.
Continuing education is about how concepts come together in real systems.
Here are some broad areas for your continued learning.
Domain
One of the biggest gaps between academic study and professional work is understanding the problem space itself.
Many early-career developers believe their job is to write code. It isn’t. Your job is to solve problems in a domain. Code is just the tool.
As I mentioned in Paradigm Shift, data structures and algorithms aren’t enough. You will need to know how to apply these to create solutions to problems within your customer’s domain, which might cause a new software developer to ask, “What’s the customer’s domain?”
Domain is a major concept in Domain-Driven Design, which I’ll cover in the future (TBD). A domain is the customer’s business context. Netflix’s domain is streaming video content. Linkedin’s domain is allowing users to create a network of professional connections. Amazon’s original domain was selling books, but it’s expanded beyond that.
Knowing how to code is insufficient. Knowing how to code to solve a problem in the customer’s domain is what’s required.
Most software engineers learn their customer’s domain on the job. This takes time. Ask questions beyond the code:
- Who uses this feature?
- What problem does this solve?
- What happens if it fails?
Once you’ve learned the domain for one customer, it will become easier to learn the domain for another customer. It’s similar to how people who learn two natural languages while growing up find it easier to learn additional languages than those who only learned one native language.
My first customer domain was telecommunications. My second customer domain was military applications. I used to joke that there wasn’t much difference between the C++ code I wrote for telecom network elements and military tanks, except that network elements didn’t tend to roam around fields firing shells.
Building Production Software
Understanding the domain is only part of the equation. The other part is understanding how real software systems are built, delivered, and maintained at scale.
Production software is different than programming assignments. Production software is larger. It takes more staff and time to develop. It’s constantly evolving. It must be maintained for months and even years. It has paying customers and actual users who depend upon it.
Ownership and Responsibility
Responsibility means:
- Following through on tasks
- Taking ownership for outcomes
- Noticing problems and addressing them without being asked
Early in your career, this often starts small. Fixing a bug thoroughly instead of patching it. Improving documentation. Following up on issues after deployment.
Over time, responsibility becomes one of the defining traits of a strong engineer.
I used to think of the code I wrote as my code. It wasn’t. I may have designed and implemented the code, but it was part of the project. I needed to design and implement code that anyone on the team should have been able to read, comprehend and modify as needed.
I didn’t own it, but I was responsible for it. Responsibility doesn’t end when the code compiles. It ends when the problem is solved.
Estimation and Uncertainty
Most tasks take longer than you expect, especially when you are unfamiliar with the codebase or domain. When one of my managers asked for my estimates, he told me to double it and then double it again.
Estimates are not commitments. They are best guesses based on incomplete information. Software engineering is the art of making decisions with incomplete information.
There’s a constant tradeoff between accuracy and precision. Here’s an example:
- I can deliver that feature in exactly 34 work days. That’s precise, but it’s probably not accurate. It’s highly doubtful that I’ll deliver in exactly 34 days.
- I can deliver that feature as early as next week or as late as six months from today. That’s probably accurate, but it’s not precise. This estimate gives me a lot of wiggle room.
Estimates are requested to determine staff resource allocation and expected delivery dates. Imprecise and inaccurate estimates make planning more difficult.
Most estimates tend to be along the lines of: I can deliver that feature in 34 days, plus or minus 10 days.
A reasonable estimate is more like a probability range from worst case to best case scenarios. Short term estimates tend to be more accurate than long term estimates.
Over time, your estimates will improve, but they will never be perfect.
Estimates are often missed. A former department head had what I thought was an excellent heuristic when having to report missed estimates:
Inform the client ahead of a missed deadline by the same amount of time expected to miss the deadline.
For example:
- If delivery is expected to be a day late, inform the client a day before the deadline.
- If delivery is expected to be a week late, inform the client a week before the deadline.
Design and Architecture
Design and architecture are skills that develop slowly as you work in real systems and see the consequences of early design choices. Good architecture is often invisible when it works well and painfully obvious when it does not. The concepts below help you reason about those tradeoffs.
- SOLID Design Principles - A set of design principles associated with Object-Oriented (OO) design.
- CUPID Design Principles - Another set of design principles.
- Software Design Patterns and their Foundations - Realizations of those OO design principles.
- Domain-Driven Design (DDD) - A philosophy that design should be based upon the customer’s domain.
- Event Storming - A group activity to understand the domain and sketch out an architecture and design. It’s often used in conjunction with DDD principles.
Development Practices
Development practices are not rules you follow out of obligation. They are habits experienced engineers rely on to keep systems maintainable as they grow. Early in your career, the focus is usually on making things work. These practices help ensure they keep working as the system evolves.
- DRY - Don’t Repeat Yourself. Avoid the practice of copying-and-pasting code. It’s fast at first, but it becomes a maintenance burden later on.
- YAGNI - You Ain’t Gonna Need It. Don’t design or implement code that isn’t needed yet.
- Test-Driven Development/Behavior-Driven Development/Mutation Testing/Etc. - Using automated testing to specify behavior and shape a design.
- Pair Programming - Creating code with a partner. It was initially developed as a practice for two human developers, but some of the ideas might be applicable when working with AI.
- Reading Code - Computer Science focuses upon writing code. Software Engineering spends more time reading and understanding code. This will become more important as AI takes on more code writing responsibilities.
- Code Reviews - Formal code reading to make sure it’s correct, doesn’t have security issues, performance issues, etc. The nature of code reviews will probably change with AI.
Debugging
Production software always has bugs lurking within it. The right set of circumstances may not trigger the bugs for years. Then at the worst possible time, the planets align, and an unknown bug rears its ugly head.
Production errors are rarely isolated or well-defined. Debugging often involves incomplete information, multiple systems, and a fair amount of guesswork. You will find yourself trying to debug behavior in code you did not write, and the original author has long since left the company. Tracking down these bugs is a skill you will develop throughout your career.
Debugging comes in many forms. Here’s one of my favorite finds from the 1980s:
Our builds were flaky. Some developers couldn’t complete full builds, while others had no problems. It wasn’t a major issue, but it slowed down those who couldn’t build consistently.
Then one day I had a thought. We worked on Unix mainframes. Some developers had vt100 terminals. Others had hp terminals. I remembered the vt100 terminal developers having problems, but I couldn’t recall any of the hp terminal developers having problems. It couldn’t be terminal dependent, could it?
I tried a full build on my vt100 terminal. It failed. I set my Unix
TERMvariable toTERM=hpand started another build. It passed. I reset it back toTERM=vt100, and it failed.I strolled over to one of our hp terminal developer’s office and asked her to do a full build. It passed. I asked her to set
TERM=vt100, and it failed. She set it back to hp, and it worked. Aha! It was terminal dependent!We tracked it down to a build script that called
ex. I’ll spare you the technical details other than to say thatexis terminal dependent, and the command didn’t work for a vt100 terminals, but it worked for the hp terminals. Fortunately, it was an easy fix. We only needed to changeextoed.I created a ticket and assigned it to build script team. Their manager refused to accept the ticket. He absolutely refused to accept it even in the face of obvious evidence. At that point, I decided to take matters into my own hands. I claimed the ticket for myself and made the one letter change in the script. The problem disappeared.
Delivery and Operations
Writing code is only the beginning of delivering software. That code must be built, tested, deployed, and observed in environments where real users depend on it. Delivery and operations are the systems and practices that make that possible safely and repeatedly.
- Version Control - Keeping track of all changes.
- CI/CD Pipelines - A process and set of tools that pull a version of the code from version control, build it and test it:
- CI - Continuous Integration: Pulling all recent code changes together regularly, ideally at least daily, to ensure that they still work together when integrated.
- CD - Continuous Delivery: The integrated code should always be in a state where it could be delivered to production at any time.
- CD - Continuous Deployment: The integrated code is automatically deployed to production via the CI/CD pipeline when all tests pass. Unfortunately, we have two meanings for the same CD acronym.
- Observability - Monitoring code in production to observe its behavior and spot any issues that manifest without having to learn of them from your users.
Process and Workflow
Process exists because software is built by groups of people over time. As systems and teams scale, informal coordination stops working. Workflow provides the structure that keeps many moving parts aligned.
- Waterfall Model - A process to specify, design, implement and test code sequentially.
- Agile Software Development - A process to specify, design, implement and test code continuously.
- Issue Tracking Tickets - Keeping track of work in various states of progress, such as: Requested, In Progress and Completed. Tickets tend to cover new feature requests and bug fixes.
Reality of Work
Writing code is a small part of software engineering. Communication, coordination, and organizational alignment often take as much time as implementation.
- Meetings - There will be all sorts of meetings: design, team, department, company, etc. Some will be in person. Some will be remote. Many will feel unnecessary:
- Meetings, Bloody Meetings - Classic John Cleese video from 1976
- How to Make Meetings Less Terrible - Freakonomics podcast from 2019
- If Everyone Hates Meetings, Why Do We Have So Many of Them? - No Stupid Questions podcast from 2021
- Informal/Asynchronous Meetings - These will be communication threads and channels like Email, Slack, Teams, etc.
New Technology
Even after you begin to understand how systems are built today, one reality remains constant: the tools and technologies themselves won’t stand still.
I stated in Software Engineering Problems:
The half-life for technology in the Computer Science field is about three to five years and possibly even shorter with the advent of Generative AI. All technology I learned in college was mostly obsolete a decade or so into my career.
Technology evolves quickly, and engineers must continuously adapt.
Right now, the greatest disruptive technology is Generative AI. Those who learn how to leverage it will have an advantage over those who do not. More on this in an upcoming blog (TBD).
Use LLMs thoughtfully to understand the business and technology but verify anything they produce. They hallucinate/confabulate results.
Use LLMs to summarize documents, understand legacy code, or act as a junior pair programmer. They are useful tools, not authorities.
Trust but verify. Never assume correctness.
Do not put any company proprietary content, documentation or code, in a generic LLM, such as ChatGPT. We don’t know how it might absorb that content and redistribute it. Ask your mentor/manager which LLMs you can safely use. Hopefully, your new employer has a company-approved LLM that you can use safely.
Educational Resources
There is so much more to explore. The internet is filled with educational resources for Software Engineering. Most are free or a reasonable price.
An early draft listed many of these here, but the list became a bit too long to include. I’ll cover these resources in a future post. (TBD).
Managing Your Career
Technical growth is only part of a successful career. The other part is learning how to navigate the profession itself.
You can be a strong engineer and still stall if you don’t actively manage your career.
You’re responsible for your career. Here are some ways to take control of it.
These aren’t technical skills. They’re career skills. And over time, they often matter just as much as your technical ability.
Feedback and Communication
Software Engineering is a social activity. You will get feedback on your work. Code reviews, design discussions, and even casual conversations are all part of how knowledge is shared across a team. Seek and apply feedback early and often. Silence and hesitation slow you down far more than asking a “simple” question.
Expand Your Experience
Don’t get typecast.
Consider new assignments.
I joined my project’s system testing team (QA) for a yearlong rotation when they were short staffed. As I was leaving that rotation, I was offered another yearlong rotation as a business analyst (BA) when the previous BA resigned unexpectedly. Those rotations led to a promotion. I also developed a better understanding of what it meant to be a QA or a BA, but most importantly I learned that I only wanted to be a developer.
Consider new opportunities outside of your current company. You are ultimately responsible for your own career. Remember, You are a Mercenary.
I’ve worked in companies ranging from a few dozen employees to over 100,000, from small teams to true behemoths.
In the largest organizations, I often felt more energy went into internal competition than external competition.
At a startup, much of that overhead disappeared. We were all rowing in the same direction, but in a much smaller, more fragile boat.
Eventually, that boat sank. The behemoth is still lumbering along.
Learn new skills, even if they don’t directly apply to your current job. Pick something that’s interesting to you. It doesn’t matter what it is. You don’t know where it may become useful.
Those new skills are the preparation that allow you to take advantage of opportunity when it strikes. Some may just call it luck, but I prefer this interpretation:
Luck is when preparation meets opportunity — Seneca
Become a Teacher or Mentor
Teaching accelerates mastery.
You’ll learn more by teaching or explaining something. The TV show The Pitt has featured – See one. Do one. Teach one. (SODOTO). It places you in a different frame of mind, much like Rubber Ducking. You may be surprised by how much you actually know and understand when you have to present it. I’ve often felt like I didn’t understand something well, and then it came up in a conversation. I found that I could describe it with more knowledge and confidence that I thought I had.
You may get questions or feedback when teaching or mentoring that makes you think even more about the topic that helps you gain even better understanding. This applies to almost anything, technology, processes, patterns, business domain, etc.
Loyalty
Be rational, not sentimental.
The days of a job for life disappeared decades ago.
Don’t expect loyalty from employers, and don’t assume obligations beyond your own career goals.
Loyalty goes both ways. Don’t hesitate to take a better offer. You might get some resistance to leave and even a guilt trip. I once heard a response when management tries to dissuade you from taking a new offer: It would be financially irresponsible for me to not accept this offer. If it’s a really good offer, there’s not much management can say other than to make a counter offer.
Don’t feel guilty. They will survive. Your employer won’t think twice when they have to let you go.
A better offer might not just mean more money. Consider the entire package:
- Are benefits better?
- Is there a better work-life balance?
- Is it shorter commute?
- Is there a better company culture?
These are personal choices that only you can weigh and consider.
However, when accepting a new position, whether it’s an internal transfer or moving to a new company, try to stay for at least one year before moving on.
Keep Records
Your memory is unreliable. Your records are reliable.
Keep a running list of accomplishments. A previous manager asked me to send him an email every Friday afternoon listing what I had accomplished that week. It was the basis of our weekly one-on-one meetings.
I continued the practice even without managerial prompting. But rather than send an email, I would imagine what I would email to my manager, and I documented it in an electronic file. It made my annual self-assessment much easier, since I had a record of what I had done. I spotted something almost every year that I had either forgotten about, or I had falsely remembered happening in a previous year. If I can’t remember what I had done, I couldn’t expect my manager to have known what I had done.
In addition to weekly summaries, consider documenting whole stories that feature what you’ve done. These stories will be useful for your current job and for interviews for future jobs too.
These records become the foundation for your resume, performance reviews, and future interviews.
Summary
The first year can feel overwhelming. That’s normal. You’re learning more than just code. You’re learning how the profession actually works.
The engineers who succeed long-term aren’t the ones who knew the most on day one. They’re the ones who never stop learning.