"If it stinks, change it." — Kent Beck
An educational repository with 198 code smells organized in 18 categories, each one with:
- 📖 An explanation page: definition, symptoms, causes, consequences, example, solution, recommended refactorings, exceptions, related smells, automatic detection and references.
- 💻 Implementations in 5 languages (generic smells) or in their own language (idiomatic smells):
a
smellyversion (with the smell, marked withSMELL:comments) and arefactoredversion (the fix, withREFACTOR:comments naming the technique applied). - ✅ Tests proving both versions behave the same — or exposing the bug hidden behind the smell.
| # | Category | Smells | Origin |
|---|---|---|---|
| 01 | Bloaters | 5 | Fowler, Mäntylä |
| 02 | Object-Orientation Abusers | 6 | Fowler, Clean Code |
| 03 | Change Preventers | 4 | Fowler, Kerievsky |
| 04 | Dispensables | 7 | Fowler, Clean Code |
| 05 | Couplers | 9 | Fowler 1999/2018, Clean Code |
| 06 | Data Dealers | 6 | Fowler 2018, Jerzyk |
| 07 | Functions & Conditional Logic | 8 | Clean Code, Jerzyk |
| 08 | Error Handling | 5 | Clean Code, Jerzyk |
| 09 | Comments (C1-C5) | 5 | Clean Code |
| 10 | Names (N1-N7) | 10 | Clean Code, Fowler, Jerzyk |
| 11 | General (G1-G36) | 14 | Clean Code, Kerievsky, Jerzyk |
| 12 | Test Smells (T1-T9) | 11 | Clean Code, Meszaros, van Deursen |
| 13 | Environment (E1-E2) | 2 | Clean Code |
| 14 | Python-specific | 20 | PEP 8, Pylint, Little Book of Python Anti-Patterns |
| 15 | C# / .NET-specific | 20 | Microsoft, D. Fowler, M. Seemann |
| 16 | React + TypeScript-specific | 22 | react.dev, typescript-eslint |
| 17 | Go-specific | 22 | Effective Go, Code Review Comments, 100 Go Mistakes |
| 18 | Angular-specific | 22 | angular.dev, RxJS, angular-eslint |
| Total | 198 |
➡️ Full catalog with every smell and link
- Introduction: what a code smell is, history and taxonomies
- Full catalog
- Repository conventions
- Per-language indexes: Python · C# · React + TS · Go · Angular
.
├── catalog.json # Single source of truth (generated from tools/catalog_data.py)
├── docs/
│ ├── INTRODUCTION.md
│ ├── CATALOG.md # Generated
│ ├── CONVENTIONS.md
│ └── smells/<NN-category>/<slug>.md
├── python/code_smells/<category>/<slug>/ smelly.py · refactored.py · test_*.py
├── csharp/src/CodeSmells/<Category>/<Slug>/ Smelly.cs · Refactored.cs
│ └── tests/CodeSmells.Tests/<Category>/ <Slug>Tests.cs (xUnit)
├── react-ts/src/smells/<category>/<slug>/ Smelly.tsx · Refactored.tsx · *.test.tsx (Vitest)
├── go/smells/<category>/<slug>/ smelly/ · refactored/ (with _test.go)
├── angular/src/smells/<category>/<slug>/ smelly.ts · refactored.ts · *.spec.ts (Vitest + TestBed)
└── tools/ # Catalog generation and verification
Requirements: Python 3.11+ with pytest, .NET 8 SDK, Node 22.22+ and Go 1.24.
make all # everything: catalog + the 5 languages
make python # cd python && python3 -m pytest
make csharp # dotnet test CodeSmells.sln (repo root)
make react-ts # cd react-ts && npm ci && npm run check
make go # cd go && go vet ./... && go test ./...
make angular # cd angular && npm ci && npm run checkThe GitHub Actions workflow (.github/workflows/ci.yml) runs the same checks on every push.
Smelly code is bad on purpose, so every linter and analyzer is switched off for smelly files only.
Everything else — refactored code, the production code behind the test smells, and the clean tests — must
pass the same gates locally and in CI:
| Area | Checks |
|---|---|
| Catalog | generated files up to date, every smell has docs + 4 implementations, no broken Markdown links |
| Python | Ruff (lint + format), mypy --strict, pytest with branch coverage |
| C# / .NET | warnings as errors, .NET analyzers latest-recommended, code style enforced in build, NuGet lock files |
| React + TS | TypeScript strict, Vitest + Testing Library with coverage, npm audit |
| Go | gofmt, go vet, go test -race with coverage |
| Angular | strictTemplates + extended diagnostics as errors, Vitest + TestBed with coverage, production build, npm audit |
| Security | CodeQL (C#, Python, Go, JS/TS + workflows), OpenSSF Scorecard, Dependabot, SHA-pinned actions, least-privilege tokens |
Formatting is shared through .editorconfig and line endings through
.gitattributes.
- Add it to
tools/catalog_data.pyand runpython3 tools/build_catalog.py. - Write its page at the
docpath listed incatalog.json. - Implement
smelly+refactored+ tests at everycodepath. python3 tools/check_catalog.py --strictmust finish with no missing items.- Commit using Conventional Commits.
See CONTRIBUTING.md for the full workflow.
- Contributing guide · Code of Conduct · Security policy
- Changelog — generated by release-please from Conventional Commits.
- Licensed under the MIT License.
Fowler & Beck, Refactoring (1999, 2018) · Martin, Clean Code (2008, ch. 17) · Kerievsky, Refactoring to Patterns (2004) · Mäntylä & Lassenius (2006) · Meszaros, xUnit Test Patterns (2007) · Jerzyk & Madeyski, codesmells.org (2023) · Refactoring.Guru · Martin Fowler — CodeSmell · official documentation of each language. See the Introduction.
