|
| 1 | +# Kotlin Guidelines — S3Mock |
| 2 | + |
| 3 | +Canonical reference for Kotlin idioms, naming conventions, and code quality standards used across this project. |
| 4 | + |
| 5 | +## Idioms |
| 6 | + |
| 7 | +### Null Safety |
| 8 | +- Use `?.`, `?:`, and nullable types instead of explicit null checks |
| 9 | +- `x?.foo()` over `if (x != null) { x.foo() }` |
| 10 | +- `x ?: throw ...` or `requireNotNull(x)` over `if (x == null) throw ...` |
| 11 | + |
| 12 | +### Immutability |
| 13 | +- Prefer `val` over `var`, especially for public API properties |
| 14 | + |
| 15 | +### Expression Bodies |
| 16 | +- Use for single-expression functions: `fun foo() = bar()` |
| 17 | + |
| 18 | +### Lambda Parameters |
| 19 | +- Always name `it` in nested or non-trivial lambdas to avoid shadowing |
| 20 | +- `.map { part -> ... }` instead of `.map { it.name }` |
| 21 | + |
| 22 | +### `when` Expressions |
| 23 | +- Prefer `when` over `if-else` chains with 3+ branches |
| 24 | + |
| 25 | +### Scope Functions |
| 26 | +- Use `.let`/`.also` when they improve readability, not gratuitously |
| 27 | +- Use early returns to flatten deeply nested code |
| 28 | +- Extract functions: break up methods longer than ~30 lines |
| 29 | + |
| 30 | +### Collections |
| 31 | +- `list.isEmpty()` / `list.isNotEmpty()` over `list.size == 0` / `list.size > 0` |
| 32 | + |
| 33 | +### String Templates |
| 34 | +- Use `"$value"` over `"" + value` concatenation |
| 35 | + |
| 36 | +### Kotlin Stdlib |
| 37 | +- Prefer Kotlin stdlib / JDK APIs over adding new third-party libraries (no Apache Commons) |
| 38 | + |
| 39 | +## Common Anti-Patterns |
| 40 | + |
| 41 | +| Anti-Pattern | Refactor To | |
| 42 | +|---|---| |
| 43 | +| `if (x != null) { x.foo() }` | `x?.foo()` | |
| 44 | +| `if (x == null) throw ...` | `x ?: throw ...` or `requireNotNull(x)` | |
| 45 | +| `list.size == 0` / `list.size > 0` | `list.isEmpty()` / `list.isNotEmpty()` | |
| 46 | +| `"" + value` | `"$value"` | |
| 47 | +| `Collections.emptyList()` | `emptyList()` | |
| 48 | +| `object.equals(other)` | `object == other` | |
| 49 | +| `!(x is Foo)` / `!(list.contains(x))` | `x !is Foo` / `x !in list` | |
| 50 | +| `for + add` loops | `.map { ... }` | |
| 51 | +| Empty catch blocks | At minimum, log the exception | |
| 52 | +| Magic numbers/strings | Named constants | |
| 53 | + |
| 54 | +## Naming Conventions |
| 55 | + |
| 56 | +- **Booleans**: `is-`/`has-`/`should-`/`can-` prefixes |
| 57 | +- **Collections**: plural nouns |
| 58 | +- **Functions**: verb phrases (`verifyBucketExists`, `resolveVersionId`) |
| 59 | +- **Avoid abbreviations**: `bucketMetadata` not `bktMd` |
| 60 | + |
| 61 | +## Test Naming |
| 62 | + |
| 63 | +- **Backtick names**: Use descriptive sentences — `` fun `should create bucket successfully`() `` |
| 64 | +- **Legacy names**: Refactor `testSomething` camelCase names to backtick style when touching existing tests |
| 65 | +- **Visibility**: Mark test classes as `internal` |
| 66 | + |
| 67 | +## KDoc |
| 68 | + |
| 69 | +- Use `/** */` for public APIs; `//` inline comments for rationale |
| 70 | +- Comments explain **why**, never **what** — remove comments that restate the code |
| 71 | +- Add comments for edge cases, non-obvious S3 semantics, or workarounds |
| 72 | +- Link to AWS API docs or GitHub issues where relevant |
0 commit comments