Learn the automated tools and workflows that separate hobby projects from production-ready applications: linting, build pipelines, and professional version control practices.
| Quality Level | Code Characteristics | Commit History | Quality Checks | Maintainability |
|---|---|---|---|---|
| Amateur | Only you can read itRandom console.log everywhereIgnored performance |
"wip", "fixed stuff","final final v3" | No automated checks | Low - hard to maintain |
| Professional | Clean, consistentProper error handlingProduction-ready | Clear history documentingproject evolution | Automated lintingPre-submission gates | High - scalable and maintainable |
By the end of this lesson, you will:
Duration: ~40 minutes
Linting is automated code checking for errors, bugs, style issues, and best practice violations.
Why linting matters:
Example:
// Without linting - compiles but has issues
var user = "Alice"
const getData = function() { return data }
console.log("Debug info")
// With linting - clean and consistent
const user = 'Alice';
const getData = () => data;
// No console.log in production code
ESLint is the industry-standard linting tool for JavaScript and TypeScript.
Key features:
--fix flagInstallation:
# Install ESLint
npm install --save-dev eslint
# Initialize configuration
npx eslint --init
For existing projects: Most React/Next.js templates include ESLint by default. Check your package.json for the eslint script.
// ❌ ESLint error: 'score' is defined but never used
const score = 100;
const name = 'Alice';
console.log(name);
// ✅ Fix: Remove or use the variable
const name = 'Alice';
console.log(name);
Why this matters: Unused variables clutter code and may indicate bugs (you meant to use it but forgot).
// ❌ ESLint warning: Unexpected console statement
function processData(data) {
console.log('Processing:', data);
return data.filter(x => x > 0);
}
// ✅ Fix: Use proper logging library or remove
function processData(data) {
// Use logger.info() for production
return data.filter(x => x > 0);
}
Why this matters: console.log is for debugging. Production apps should use proper logging systems.
// ❌ ESLint error: 'userName' is never reassigned. Use 'const' instead
let userName = 'Alice';
console.log(userName);
// ✅ Fix: Use const
const userName = 'Alice';
console.log(userName);
Why this matters: const signals intent - this value won't change. Prevents accidental reassignment.
// ❌ ESLint error: Expected '===' and instead saw '=='
if (score == 100) {
console.log('Perfect!');
}
// ✅ Fix: Use strict equality
if (score === 100) {
console.log('Perfect!');
}
Why this matters: == performs type coercion ('5' == 5 is true), causing unexpected bugs. === is safer.
// ❌ ESLint error: Unexpected var, use let or const instead
var count = 0;
// ✅ Fix: Use let or const
let count = 0;
Why this matters: var has confusing scoping rules. let and const are block-scoped and clearer.
Basic usage:
# Lint all JavaScript files
npx eslint .
# Lint specific file
npx eslint src/game.js
# Auto-fix issues
npx eslint --fix .
Example output:
$ npx eslint src/
/src/game.js
12:7 error 'score' is assigned a value but never used no-unused-vars
23:3 warning Unexpected console statement no-console
45:9 error Expected '===' and instead saw '==' eqeqeq
67:5 error Unexpected var, use let or const instead no-var
✖ 4 problems (3 errors, 1 warning)
2 errors and 0 warnings potentially fixable with the `--fix` option.
Interpretation:
score variableconsole.log() or disable rule== to ===var to let or consteslint --fix to auto-correctStep One: Check for issues
npx eslint .
Step 2: Auto-fix what's possible
npx eslint --fix .
Step 3: Manually fix remaining issues ESLint will show errors it can't auto-fix. Address these one by one.
💡 Tip: Run
eslint --fixmultiple times. Some fixes enable other fixes!
Modern ESLint 9+ (flat config) - eslint.config.js:
import js from '@eslint/js';
export default [
js.configs.recommended,
{
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
browser: true,
node: true,
es2021: true,
},
},
rules: {
'no-console': 'warn', // Warn on console.log
'no-unused-vars': 'error', // Error on unused vars
'prefer-const': 'error', // Error if let should be const
'eqeqeq': 'error', // Require ===
'no-var': 'error', // Ban var keyword
},
},
];
Legacy ESLint 8 (still supported) - .eslintrc.js:
module.exports = {
env: { browser: true, es2021: true, node: true },
extends: ['eslint:recommended'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
rules: {
'no-console': 'warn',
'no-unused-vars': 'error',
'prefer-const': 'error',
},
};
💡 Tip: ESLint 9+ uses flat config format (export default array). For migration guide:
npx @eslint/migrate-config .eslintrc.js
Rule levels:
'off' or 0: Rule disabled'warn' or 1: Show warning (doesn't break build)'error' or 2: Show error (breaks build)1. Lint → Check code quality (ESLint)
2. Type-check → Verify TypeScript types (tsc)
3. Build → Compile for production (Vite/Webpack)
4. Deploy → Push to production
Before submitting your projects, run the full quality pipeline to ensure production readiness:
pnpm lint:fix && pnpm type-check && pnpm build
Command:
pnpm lint:fix
Expected output (success):
> eslint --fix .
✔ All files pass linting
If errors appear: Review and fix them manually. Common issues:
package.jsonCommand:
pnpm type-check
Expected output (success):
> tsc --noEmit
✔ No type errors found
If errors appear: Add missing properties to match TypeScript interfaces.
💡 Tip: TypeScript errors indicate potential runtime bugs. Fix them now to avoid crashes later!
Command:
pnpm build
Expected output (success):
> vite build
✓ 156 modules transformed
✓ built in 2.3s
dist/index.html 1.2 kB
dist/assets/index-a4b3c5d2.js 45.8 kB
If build fails:
Common errors:
Add to package.json:
{
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"type-check": "tsc --noEmit",
"validate": "pnpm lint:fix && pnpm type-check && pnpm build"
}
}
Usage:
# Development mode (hot reload)
pnpm dev
# Full validation before commit
pnpm validate
What happens when you run pnpm validate:
💡 Tip: Always run
pnpm validatebefore pushing code to GitHub. This catches issues early and prevents breaking the build. Make it your pre-submission ritual!
| Quality | Examples | Why? |
|---|---|---|
| Bad | "fixed stuff""update""wip""final final FINAL v3" |
No context for what changedFuture you won't remember detailsEvaluators can't see thought processMakes debugging history impossible |
| Good | "feat: Add difficulty selector with Easy/Medium/Hard options""fix: Prevent double point deduction when using hints""refactor: Simplify word filtering logic for better performance""docs: Add setup instructions to README" |
Concise (less than 50 characters)Descriptive (what changed and why)Action-oriented (imperatives: Add, Fix, Update)Scannable (easy to understand at a glance) |
feat: Add new feature
fix: Fix bug or error
docs: Update documentation
style: Format code (whitespace, semicolons)
refactor: Restructure without changing functionality
test: Add or update tests
chore: Maintenance tasks (dependencies, config)
Examples for AI projects:
feat: Implement AI chat integration with OpenAI API
fix: Resolve crash when user submits empty input
refactor: Extract scoring logic into separate module
docs: Add API documentation and usage examples
test: Add unit tests for form validation
chore: Update dependencies to latest versions
Commit after:
How often? More is better! Aim for 5-10 commits per day of active development.
git add src/knowledge-base.js
git commit -m "feat: Create Smart Farm knowledge base with 50+ Q&A pairs
- Organized by categories: crops, weather, pests, soil
- Added difficulty ratings for beginner/advanced responses
- Implemented JSON structure for easy extension"
Why this works:
💡 Tip: If you can't write a clear commit message, your commit might be doing too much. Break it into smaller, focused commits!
Before committing:
# Review what changed
git status
git diff
# Stage specific files
git add src/components/Game.jsx
git add src/styles/game.css
# Commit with descriptive message
git commit -m "feat: Add game timer with pause functionality"
Amend last commit (if needed):
# Add forgotten file to last commit
git add forgotten-file.js
git commit --amend --no-edit
View commit history:
# See commit log
git log --oneline
# See last 5 commits
git log --oneline -5
# See commits with file changes
git log --stat
pnpm validate - all checks passconsole.log() debug statementsnpm install in new folder).gitignore excludes node_modules/, .envRun this before submission:
# Full pipeline
pnpm validate
# If successful, commit
git add .
git commit -m "chore: Final submission - passed all quality checks"
git push origin main
What this proves:
# Clone to new directory
cd /tmp
git clone https://github.com/yourusername/your-project.git
cd your-project
# Install dependencies
npm install
# Run build pipeline
npm run validate
# Test application
npm run dev
If any step fails: Fix it before submission!
Linting & Code Quality:
no-unused-vars, no-console, prefer-const, eqeqeq, no-vareslint --fix to auto-correct issues.eslintrc.jsBuild Pipeline:
pnpm lint:fix && pnpm type-check && pnpm buildpnpm validate for one-command quality checksProfessional Commit Messages:
feat:, fix:, docs:, refactor:, etc.)Pre-Submission Quality Gates:
.gitignore)Daily workflow:
pnpm validate periodicallyBefore submission:
pnpm validateIn upcoming activities, you'll practice these quality assurance workflows on real projects!
💡 Remember: Professional development isn't just about working code-it's about maintainable, efficient, and scalable systems that stand the test of time.
The Professional Development Mindset:
Before pushing code:
pnpm lint:fix # Clean code ✓
pnpm type-check # Type-safe ✓
pnpm build # Builds successfully ✓
git log --oneline # Professional history ✓
Your submission represents not just what you built, but HOW you built it. Make it count!