Write better code, ship with confidence. Git workflows, TDD, clean code, security, and the habits that separate senior engineers from juniors.
Your branching strategy defines how your team collaborates, how often you ship, and how stable your main branch stays. Choose based on your release frequency and team size.
| Strategy | How It Works | Best For | Used By |
|---|---|---|---|
| Git Flow | main + develop + feature/* + release/* + hotfix/*. Merges go develop → release → main | Versioned releases, mobile apps with app store review | Large enterprise, teams with scheduled releases |
| GitHub Flow | main + feature branches. PR → review → merge to main → deploy | Web apps with continuous delivery | GitHub, Netlify, most SaaS companies |
| Trunk-Based | Everyone commits to main (or very short-lived branches). Feature flags hide unfinished work | High-velocity teams, CI/CD at scale | Google, Facebook, Netflix |
# GitHub Flow — simple and effective for most teams # 1. Create a feature branch from main git checkout main git pull origin main git checkout -b feature/add-expense-categories # 2. Make commits with clear messages git commit -m "feat: add category dropdown to expense form" git commit -m "test: add unit tests for category validation" git commit -m "fix: prevent empty category submission" # 3. Push and open PR git push origin feature/add-expense-categories # Open PR → get 2 reviews → merge → auto-deploy # Conventional Commits format # feat: new feature | fix: bug fix | docs: docs only # refactor: code change | test: add tests | chore: build/deps
Write the test before you write the code. TDD forces you to think about the interface and expected behavior before implementation — resulting in simpler, more testable code.
// Step 1: RED — Write failing test first describe('BudgetCalculator', () => { it('warns when spending exceeds 80% of budget', () => { const calc = new BudgetCalculator({ limit: 1000 }); calc.addExpense(850); expect(calc.isNearLimit()).toBe(true); }); }); // → Test fails: BudgetCalculator is not defined ❌ // Step 2: GREEN — Write minimum code to pass class BudgetCalculator { constructor({ limit }) { this.limit = limit; this.spent = 0; } addExpense(amount) { this.spent += amount; } isNearLimit() { return (this.spent / this.limit) >= 0.8; } } // → Test passes ✅ // Step 3: REFACTOR — Improve without breaking tests class BudgetCalculator { constructor({ limit, warningThreshold = 0.8 }) { this.limit = limit; this.warningThreshold = warningThreshold; this.spent = 0; } addExpense(amount) { if (amount <= 0) throw new Error('Amount must be positive'); this.spent += amount; } get spentPercentage() { return this.spent / this.limit; } isNearLimit() { return this.spentPercentage >= this.warningThreshold; } } // → Still passes ✅ — now cleaner and more configurable
Code is read 10× more than it's written. Clean code is not about aesthetics — it's about reducing the cognitive load for every engineer who touches it after you.
function calc(d, r) { let x = 0; for (let i = 0; i < d.length; i++) { if (d[i].t === 1) { x += d[i].a * r; } } return x; }
function calculateTaxableIncome( expenses, taxRate ) { return expenses .filter(e => e.type === EXPENSE_TYPE.BUSINESS) .reduce((total, e) => total + (e.amount * taxRate), 0 ); }
| Principle | Rule | Metric |
|---|---|---|
| Function size | Functions should do ONE thing | Max 20 lines |
| Function args | Fewer arguments = easier to test | Max 3 params (use objects for more) |
| Naming | Names should reveal intent | getUserById not getU or fetch |
| Comments | Comment WHY, not WHAT (code explains what) | Remove all "noise" comments |
| Nesting | Deep nesting = complexity. Use early returns | Max 3 levels deep |
| DRY | Don't Repeat Yourself — extract duplication | If copy-pasted: extract function/module |
The Open Web Application Security Project publishes the most critical web vulnerabilities. Every developer must understand these — security is not just the security team's job.
Users can access resources they shouldn't. Example: User A accesses /api/invoices/456 which belongs to User B by changing the ID.
// ❌ Vulnerable: trusts client-provided ID app.get('/api/expenses/:id', async (req, res) => { const expense = await findById(req.params.id); // any user can access any expense! res.json(expense); }); // ✅ Secure: always filter by authenticated user app.get('/api/expenses/:id', async (req, res) => { const expense = await findByIdAndUser(req.params.id, req.user.id); if (!expense) return res.status(404).json({ error: 'Not found' }); res.json(expense); });
Malicious SQL injected into queries. Classic example: ' OR '1'='1 in a login form bypasses authentication.
// ❌ Vulnerable: string concatenation const query = `SELECT * FROM users WHERE email = '${email}'`; // Input: admin'-- → SELECT * FROM users WHERE email = 'admin'--' // ✅ Secure: parameterized queries const query = 'SELECT * FROM users WHERE email = $1'; const result = await db.query(query, [email]); // input sanitized automatically
Weak passwords, no rate limiting on login, session tokens in URLs, no MFA for privileged accounts.
// ✅ Secure authentication checklist: // 1. Hash passwords with bcrypt (cost factor 12+) const hash = await bcrypt.hash(password, 12); // 2. Rate limit login attempts (max 5 per 15 min per IP) app.use('/api/auth/login', rateLimit({ windowMs: 15 * 60000, max: 5 })); // 3. Use httpOnly + secure + sameSite cookies for sessions res.cookie('session', token, { httpOnly: true, secure: true, sameSite: 'strict' });
npm audit, pip-audit, or Dependabot on every project. Unpatched dependencies are the #1 cause of breaches.