1. Start with Why
For any feature, bug, or enhancement – always understand the “why” before the “how.” Ask yourself:
- Why are we doing this?
- What’s the real problem we’re solving?
- Is this the best/right solution?
Blindly writing code without context leads to wasted effort and wrong outcomes. Engineering is problem-solving, not ticket-checking.
2. Fix the Root Cause, Not the Symptom
Surface-level fixes create technical debt. To build resilient systems, dig deeper to find and solve the root problem:
- Bug: A button doesn’t work?
Don’t just fix the button, investigate why the event wasn’t triggered in the first place. - Performance issue: Slow API?
Don’t just slap on caching, analyze query execution plans, payload sizes, or server bottlenecks. - Intermittent errors: Getting occasional failures?
Don’t ignore them, trace logs, monitor dependencies, and uncover the weak link.
Real engineering means solving problems at the source, not patching symptoms.
3. Think Systems, Not Tickets
Completing a ticket ≠ solving a problem. Build systems that prevent recurring issues:
- Are PRs constantly failing due to formatting issues? Add a CI pipeline to enforce linting.
- Manually updating configurations across services? Build a central config service.
Think long-term, even when solving short-term problems.
4. Own It — From Idea to Production
Ownership isn’t about blame, it’s about responsibility. It means pushing past excuses and fully owning both success and failure. When something goes wrong, acknowledge it, learn from it, and fix it.
- Own the problem — understand it thoroughly.
- Own the solution — design it thoughtfully.
- Own the implementation — write clean, scalable code.
- Own the delivery — ensure it’s deployed and monitored.
Success or failure, learn from both.
5. Hustle for Progress, Not Perfection
Speed matters. Get to 80% done fast, ship, gather feedback, and improve.
- Perfect is the enemy of good.
- A working prototype today beats a flawless release 6 months too late.
- Execute with urgency. Iterate relentlessly.
- Iterate, don’t Waterfall
- Agile isn’t just a buzzword.
- V1: Ship fast and gather real-world feedback.
- V2, V3: Improve based on customer insights, not assumptions.
Avoid the “big bang” delivery trap – failing fast is better than failing late.
6. Productivity is a Superpower
Productivity isn’t optional for a software engineer, it’s the core of what we do. That’s likely why the saying goes, a good engineer should be lazy — not to avoid work, but to find the most efficient way to get things done.
Learn shortcuts, master your tools, and optimize your workflow.
- Keyboard shortcuts in IDEs? Mandatory.
- Quick navigation between browser tabs? Yes.
- Automate repetitive tasks? Always.
Spend engineering time like it’s money — because it is.
7. Frugality Drives Creativity
Smart engineers solve problems efficiently – not expensively.
- Use open-source libraries and frameworks when they fit.
- Pay for solutions only when the cost is justified by clear, direct value.
- Avoid tech hype — build what’s necessary, not what’s trendy.
Remember: the best solution is the one that delivers value with the least effort, cost, and risk.
8. Challenge Assumptions
Assumptions are silent bugs waiting to explode. Avoid programming by coincidence, don’t rely on luck or accidental success. Instead, program deliberately, and understand why your code works, not just that it works.
- Did you assume a method returns data? Handle the null case.
- Did you assume a query won’t fail? Add error handling.
- Have you heard Rust or Redis is the next big thing? Evaluate trade-offs before jumping in.
- Did you assume users will follow the “happy path”? Plan for edge cases, bad data, and user mistakes.
Be an engineer, not a follower.
9. Tests Are Mandatory, Not Optional
Code without tests is broken by default. Skipping tests to “save time” only delays the pain. If it’s not tested, it’s not done — it’s just waiting to fail.
- Unit tests ensure individual parts work as intended.
- Integration tests ensure everything works together.
- End-to-end tests protect against regressions.
- Performance and load tests ensure we scale smoothly.
Tests aren’t about “proving it works” — they protect our customers, speed up development, and give us the confidence to iterate fast. If it’s not tested, it’s not done.