Introduction
Being assigned to a feature in a programming language you’ve never worked with before can feel intimidating. When AI coding assistants are available, it's tempting to simple accept the generated code and move on.
But doing that raises an important question:
Where do you actually start?
Follow Existing Patterns — But Question Them
When working in an unfamiliar codebase, the most common instinct is to follow existing patterns. Even coding AI assistants will do that for you.
They mainly work most of the time but what if:
- The user story requires a new pattern
- Existing patterns are confusing or undocumented
- The code is written using poor practices
Blindly copying existing code can introduce technical debt or slow you down later. Patterns should guide you, not trap you.
Can AI Coding Assistants Help?
AI coding assistants are incredibly helpful, especially during the familiarization phase. In today’s development environment, syntax is rarely the real blocker.
As long as you understand the fundamentals of programming, AI can help translate ideas into working code.
That said, AI alone is not enough.
Using AI effectively requires that you already understand:
- The goal of the feature
- The responsibilities of each layer
- How your change fits into the system
Building features just to “make them work” with AI won’t help long-term.
Building features with understanding, assisted by AI, significantly boosts productivity.
Also, tokens are limited and costly. Use them intentionally. Choose the right model for the right task, and avoid wasting context on things you could reason through yourself.
A Practical Tip on AI-Generated Code
If you're satifised with AI-generated code, don't immediate accept it.
AI is great at pattern recognition, which means it can generate correct-looking code faster than you can fully understant it.
Instead:
- Type the code yourself rather than auto-accepting it.
- Switch to chat mode and why each part exists.
- Make sure you understand every line.
As developers, we love convenience. But blindly accepting generated code often leads to future inconvience. I've been trapped by this many times. For complex tasks, I prefer chat mode over agent mode. It slows me down and ensures I understand every line of the code.
Always remind youselves to deeply think to save time later. That way, if there's a problem with the generated code, you'll know exactly where to fix it.
Context Matters More Than Syntax
Before writing code, take time to understand the repository at a high level:
- What problem does this service solve?
- How does data flow through the system?
- Where does this feature belong?
For tech leads and senior developers, having an updated onboarding checklist for each large project can be very helpful. Sometimes we forget to focus on these things because they may feel like they don’t add value. However, it improves consistency, speeds up onboarding, and reduces back-and-forth communication.
Some examples:
- Data pipelines: an accessible flowchart is critical—developers shouldn’t need to ask others just to understand the flow
- Frontend repositories: shared configurations (VS Code settings, linters, formatting rules, copilot instructions) reduce friction
- Backend services: clear scaffolding, folder structure, and setup expectations help developers move faster
Define Inputs and Outputs Early
Before building anything, always clarify the inputs and outputs.
Inputs
Ask questions like:
- What are the inputs?
- Are there limitations or constraints?
- What triggers this logic?
- What is required vs optional?
- Should this be optimized for performance, even if it sacrifices readability?
Outputs
Then define:
- What is the expected output?
- Who consumes it?
- What happens when something fails?
Clear input and output definitions prevent rework and misalignment.
Collaborate Early and Often
When you’re new to a repository, following existing patterns is not enough.
- Consult before building
- Sync during implementation
- Use code reviews for validation—not discovery
Implementations often change due to hidden constraints or evolving requirements. Continuous communication ensures the solution stays on track.
Dealing With Bad Existing Code
Sometimes, the existing codebase contains poor practices.
If improvements are low-risk, refactor them. There's still hope. Don't be discouraged by bad code; let it motivate you to write better code moving forward.
If changes are risky, especially when there are no unit test. Avoid copying the bad patterns.
Instead:
- Communicate clearly with your team about the challenges you see.
- Explain why you’re not following certain implementations and suggest alternatives.
- Be consistent in promoting the new pattern, particularly in large teams. Consult with the original developers, and align if they agree with the new approach.
- Review related PRs to prevent conflicting implementations.
By balancing careful refactoring with clear communication, you can improve the codebase without introducing risk or confusion.
Final Thoughts
Working in an unfamiliar language is less about mastering syntax and more about understanding context, intent, and collaboration.
Use existing patterns wisely.
Leverage AI responsibly.
Communicate early and often.
That’s how you build features that last—no matter the language.
