How to Ban a Class or Method in Code (And Why You Should)
Prevent dangerous APIs with automated checks to improve code quality.
1The Problem of Dangerous APIs Spreading
Every growing codebase accumulates dangerous APIs that are prone to misuse or violate architectural boundaries. Teams initially rely on PR reviews or wiki pages to prevent these issues. However, human vigilance fades over time, and forbidden patterns spread across pull requests. For example, using GlobalScope or spyk() threatens code reliability. The solution is to automate these bans through static checks.
2What Does Banning an API Mean?
Banning an API involves setting up automated static checks or compiler rules that trigger build errors or linter failures when forbidden classes, functions, or imports appear in the source code. Instead of catching bad patterns during manual code review or after a production outage, developers receive immediate feedback in their IDE. For instance, methods like Thread.sleep(), which cause flaky tests, can be blocked this way.
3Benefits of Banning APIs
Code reviews don't scale; as teams grow, forbidden imports or anti-patterns slip through. Banning APIs shifts enforcement from human review to deterministic build checks. It also prevents the use of methods like GlobalScope (causing memory leaks) or runBlocking (blocking threads). Architectural boundaries can be enforced by banning cross-layer imports, ensuring domain modules remain framework-independent.
43 APIs You Should Ban
1. MockK's spyk(): Partial mocks execute real code, leading to fragile tests. Use pure mocks or fakes instead. 2. GlobalScope and runBlocking: They bypass structured concurrency, causing memory leaks and UI freezes. 3. Thread.sleep(): Often used as a hack for async test race conditions but results in slow, flaky tests. Use coroutine testing utilities like runTest instead.
5Enforcing Bans with Static Analysis (Detekt)
Linters like Detekt can block forbidden methods and imports. For example, detekt.yml can define rules to ban Thread.sleep() or spyk(), with explanations suggesting alternatives. This approach prevents new dangerous patterns from entering the codebase and provides instant IDE feedback. It’s particularly effective for maintaining consistent coding standards across large teams.
6Architecture Tests for Bans (Konture)
Tools like Konture enforce architectural rules using standard Kotlin unit tests. For example, you can write tests to block spyk() in test code or GlobalScope imports in production code. These tests run in CI pipelines, automatically flagging banned API usage. Konture allows customization of which parts of the codebase are inspected, making it flexible for different project needs.
7Compiler-Level Bans (@Deprecated ERROR)
For internal APIs, Kotlin’s @Deprecated annotation with ERROR level can enforce bans at compile time. For example, marking a legacy BaseActivity class as deprecated with ERROR level forces migration to ComposeActivity. The ReplaceWith parameter suggests alternatives, guiding developers toward best practices. This method is ideal for phasing out deprecated components.
8Conclusion: Code Reviews Aren’t API Policing
Manual code reviews are inefficient for preventing dangerous API usage. Instead, use linters like Detekt, architecture tests like Konture, or compiler-level bans. These automations keep the codebase clean and deterministic, encouraging developers to adopt best practices. By eliminating technical debt early, teams can focus on building robust, maintainable software.
Original article: ProAndroidDev - Medium — Kodda Sınıf veya Metot Yasaklamanın Yolları ve Önemi