Get the guide to build your first AI agent directly in your inbox with a newsletter signup:
During some seasons, I’ve felt lost at work. I was working more hours, but I had the feeling that I was making less progress.
And I’m not talking about specific metrics like lines of code, PRs, or such objective measurements. I’m talking about a subjective feeling.
The problem was that urgent work was becoming more frequent; there was no time to do some important changes and refactors because a short-term fix already does 80% of it, even if it’s painful to maintain.
If you don’t even have time to do important things in the codebase, you don’t have time for other important conversations with your manager or self-reflection like career growth.
But it doesn’t have to be like this. Everything may be on fire, but if you only maintain these 10 habits, I promise that your workday will feel much better.
You’ll feel like:
👉 If this sounds interesting, subscribe now. 22,000+ engineers are already becoming more productive. Paid subscribers have access to premium resources
What are good habits for software engineers?
A good habit for a software engineer is a repeatable behavior that protects your attention, your work, and your growth. Besides being good, the more you do it, the easier it becomes to do it the next day.
Remember that we’re not doing this to be more productive, to earn a higher salary, or get promoted. All of these are benefits of the habits, but our main goal is the benefit of being in control.
The order of these protocols below is not about importance, but the order in which I usually do them, morning to evening.
1. Define the one thing that must move today
If you work at a big company, during your night there’s someone already working and creating artifacts that you have to review: Code, emails, Slack messages... You name it
It can be tempting to start the day clearing those artifacts to have a clean inbox, but you may never catch up. That’s a bad habit of aiming to clear the inbox: You’ll waste the best hours of your workday on it, and every time you’ll have the itch to come back to it to clear new items that arrive.kk.
I really mean that the first hours of work are the most important ones. It’s the time when you are fresh, you can do a meaningful block of work, and you can think clearly about the big picture before diving into the details.
That’s why I propose you start your day by defining the one thing that you must do today. That one thing that will make you feel happy with your work today, the thing that moves the needle, the thing that, no matter how bad your day turns out later, you’ll feel accomplished.
Of course, it’s not only about defining it but about making it happen. That’s why whenever some urgent work arrives, if you haven’t finished the main thing, I’d consider whether the urgent work can wait for one hour or two.
Remember to keep it achievable. Don’t plan big goals that you can’t achieve that day; that would be setting yourself up for failure.
2. Protect one uninterrupted deep-work block
So now that we have defined the direction, let’s make it happen.
There are two enemies when doing deep work:
Distractions: You are working but stop to check something. It starts internally
Interruptions: Someone (or some notification) arrives. The root cause is something external.
So we have to set ourselves up for success:
Remove all notifications, put on your headphones, or grab your laptop and go to some place where your team can’t access you. This will reduce the chances of interruptions.
Also, keep your workspace clean and have a notepad (physical or digital) nearby. Whenever a new thought arrives and you are tempted to check something online, write it down to do it after your uninterrupted deep work blocks.
This is easier said than done, but let’s assume that you are working without distractions and interruptions now. But still, you may feel like you’re not making progress if you don’t set a concrete goal for that block.
As I wrote, you have to plan something achievable. When planning, include a concrete output for the work block. For us software engineers, it can be something like raising the PR with the code changes or finishing providing feedback on a document.
This concrete output will help you “check the box”, and that’s a damn great feeling.
Of course, don’t remove all notifications if you’re on-call and always keep yourself accessible in case of an emergency. This is just to reduce the random chats just because you are there, and only for a fraction of your workday where you’ll achieve most of the work.
3. Understand before changing
Now that we code with AI, it’s easy to become over-reliant on it.
With that, I mean that we shouldn’t delegate all our judgment to it. If every question that I need answered needs to go through AI, I’ll always remain unfamiliar with the codebase.
That’s why the next protocol is to always build an understanding before starting to work on the codebase.
This doesn’t have to be a deep understanding like the people who built that codebase. It’s mostly about having answers to some questions like entry point, dependencies, state, side effects, output.
You don’t have to read the code line by line to have that understanding. Tests can help you understand the code, as can documentation, checking the logs, or checking recent changes.
You can use AI to help you explore all of this, but make sure to end with an outcome of having an answer to these questions. Bonus points if you actually open the code instead of only relying on an AI explanation
4. Make the smallest change that solves the problem
Our human brain has trouble reasoning about big and complex changes. It will end up understanding them, but only after dedicating time and effort.
But you don’t want 5 alignment meetings and 7 documents to solve a problem that can be solved with just a PR that everyone understands.
The problem isn’t only at code-review time, but also during your implementation, during testing, when deploying it, and when reverting in case of issues.
There’s a reason we created interfaces and abstractions: We want to hide complexity away by agreeing on a contract, and both the provider and the consumer have to honor it.
This can conflict with the Boy Scout rule of “seeing something and doing something”. That’s why I suggest always aiming to leave things better and to avoid making things worse with your code.
But break down all the improvements into smaller pieces that are easy to reason about. It’s better for everyone.
Lastly, if you see something that you don’t have to fix, record it in a ticket that is easy to implement. Tickets that only name the problem are harder to prioritize if they are tech debt. But if you indicate clearly what’s the problem and the solution (or multiple alternative solutions), it will be easier to take it in parallel to other work and do it.
5. Close the feedback loop quickly
There’s a distance between a hypothesis and the feedback that proves it or steers your next hypotheses. Your goal as a software engineer is to shorten that distance.
We all make assumptions, but it’s important to tell ourselves the truth and be clear that it’s a hypothesis. Many people end up believing things are true just because they held that assumption too long in their heads.
There’s always a shorter way to get the feedback. Compile the code, run the test, or hit the endpoint like if you were the user. Don’t try to solve a bug you can’t reproduce.
Once you have some feedback, it will be easier to keep testing your new hypotheses, getting closer to the solution.
6. Verify your assumptions with evidence
There are always degrees of evidence. For example, if I query our logs and see 50k failures, then it’s more important than the evidence of a failure that is only happening in another developer’s environment, but nobody else reproduces, and no log/metric indicates something is wrong.
Actually, this happened to me recently. I was testing with a development build of a mobile app and a functionality that involves my team’s service didn’t work. I could have considered this a huge deal, but instead I went and tried the same with another app, checked our logs...
Of course this is a bug in the not-yet-released version, but now I’ve got more information regarding who to reach and what the severity is. Otherwise, I would have created unnecessary noise if I claimed: “that the entire feature is down”.
This may seem like a simple example, but you’d be surprised by how many of these we have every day. The truth is always there; we just have to look for it.
7. Test the failure path, not only the happy path
I remember learning the idea that when coding, before AI, 50% of the time goes to making it work and 50% of the time to make it right.
I thought at first this was about making the code readable, refactor it, making it optimal... But it’s also about making it always work, not only on the happy path.
There are always things that go wrong, and any interface has to design both the happy path and the error paths. Dependencies fail, messages arrive twice, and input params arrive wrong.
Go one by one through all of the components to make sure you handle the error scenarios. You don’t have to reproduce everything outside of unit testing; you just have to ensure that you identify all the failure paths and handle them.
It’s always a fine balance between testing too much and leaving things open for failure.
8. Read code every day
We are the ones deciding what code is right and wrong when AI writes it.
I won’t claim that I write code by hand to keep myself sharp because I don’t. But I do read a lot of code from different people, and I try to keep revisiting the good practices of software engineering.
This helps both with reviewing code and with designing a harness for AI to write good code. It will improve your future prompts, and most importantly, improve your future decisions.
9. Ship something
A failure mode now with AI is that you can have 10 agent sessions in parallel but finalize none.
It’s easy to ask AI to review the code once again to find improvements and prevent comments in the code review (especially when the company pays for the tokens). But in the end, the impact of having the code locally and not having the code is the same: zero.
We must remain practical and make sure that we are delivering at a good speed and throughput for our role and level.
There’s always a way to trick the metric by skipping tests or verifications, and I don’t mean to ship things like that. The point is to benchmark yourself and ensure you always make progress.
10. End the day by making tomorrow cheaper
Cycling back to the beginning, we are starting our day planning. The best way to plan is to know at a glance what you did yesterday and remember your thoughts of what was left unfinished.
That’s why, for our last protocol, at the end of the day, we’ll leave a shutdown note for our tomorrow’s self.
Just something simple like:
Finished: …
Remaining: …
Tomorrow’s priority: …
Waiting on / risk: …
This helps you bring a meaningful update to your daily standup with your work done, your plan for the day, and risks or blockers. It helps with planning the work tomorrow, as you see what’s still in progress and what should be a priority.
And most importantly, it lets you finish the day with a clear idea of the work you did, so your sense of satisfaction is higher. And you won’t ruminate about work because you trust these protocols and you’ve set your tomorrow’s self up for success.
Conclusion
These protocols are things that take less than 5 or 10 minutes.
And that’s the whole point. I have tried powerful (and complex) productivity systems that seemed like the ultimate tool to achieve a lot. But the friction to use those tools ends up with me going through my day without them, and creating that feeling of being lost.
These protocols are adaptable: You get the idea and why it works, and you can plug them into your work. You don’t have to measure a binary “success” or “failure” to apply them all. Just leave yourself a reminder to start applying some tomorrow, and little by little, add the others.
At least try them, and then you decide if they work for you or if some of your existing habits are good enough that you don’t need these.
Now, equipped with these protocols, you’ll make deliberate progress, and you’ll be aware of it.
If you found value in this post:
❤️ Click the heart to help others find it.
✉️ Subscribe to get the next one in your inbox.
💬 Leave a comment with your biggest takeaway
♻️ Share it with your peers
Today’s article will allow you to move faster through the phases of our system to become productive engineers and get promoted faster
I’m building this system below for paid subscribers. Thanks for your continued support!













These are good 10 pointers.
But I see 10 pointers are too heavy as well.
I agree to start the day with plan and have some dedicated time to make the change.
Essential point 3, 4, 5 need to be merge into one single pointers.
Once you decided to must make a change, observe and understand the change, chunk it out and take the smallest piece to solve the problem, code and solve that smallest piece with the testing ie close the feedback.