@booklib/skills 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/animation-at-work/SKILL.md +246 -0
- package/animation-at-work/assets/example_asset.txt +1 -0
- package/animation-at-work/references/api_reference.md +369 -0
- package/animation-at-work/references/review-checklist.md +79 -0
- package/animation-at-work/scripts/example.py +1 -0
- package/bin/skills.js +85 -0
- package/clean-code-reviewer/SKILL.md +292 -0
- package/clean-code-reviewer/evals/evals.json +67 -0
- package/data-intensive-patterns/SKILL.md +204 -0
- package/data-intensive-patterns/assets/example_asset.txt +1 -0
- package/data-intensive-patterns/references/api_reference.md +34 -0
- package/data-intensive-patterns/references/patterns-catalog.md +551 -0
- package/data-intensive-patterns/references/review-checklist.md +193 -0
- package/data-intensive-patterns/scripts/example.py +1 -0
- package/data-pipelines/SKILL.md +252 -0
- package/data-pipelines/assets/example_asset.txt +1 -0
- package/data-pipelines/references/api_reference.md +301 -0
- package/data-pipelines/references/review-checklist.md +181 -0
- package/data-pipelines/scripts/example.py +1 -0
- package/design-patterns/SKILL.md +245 -0
- package/design-patterns/assets/example_asset.txt +1 -0
- package/design-patterns/references/api_reference.md +1 -0
- package/design-patterns/references/patterns-catalog.md +726 -0
- package/design-patterns/references/review-checklist.md +173 -0
- package/design-patterns/scripts/example.py +1 -0
- package/domain-driven-design/SKILL.md +221 -0
- package/domain-driven-design/assets/example_asset.txt +1 -0
- package/domain-driven-design/references/api_reference.md +1 -0
- package/domain-driven-design/references/patterns-catalog.md +545 -0
- package/domain-driven-design/references/review-checklist.md +158 -0
- package/domain-driven-design/scripts/example.py +1 -0
- package/effective-java/SKILL.md +195 -0
- package/effective-java/assets/example_asset.txt +1 -0
- package/effective-java/references/api_reference.md +1 -0
- package/effective-java/references/items-catalog.md +955 -0
- package/effective-java/references/review-checklist.md +216 -0
- package/effective-java/scripts/example.py +1 -0
- package/effective-kotlin/SKILL.md +225 -0
- package/effective-kotlin/assets/example_asset.txt +1 -0
- package/effective-kotlin/references/api_reference.md +1 -0
- package/effective-kotlin/references/practices-catalog.md +1228 -0
- package/effective-kotlin/references/review-checklist.md +126 -0
- package/effective-kotlin/scripts/example.py +1 -0
- package/kotlin-in-action/SKILL.md +251 -0
- package/kotlin-in-action/assets/example_asset.txt +1 -0
- package/kotlin-in-action/references/api_reference.md +1 -0
- package/kotlin-in-action/references/practices-catalog.md +436 -0
- package/kotlin-in-action/references/review-checklist.md +204 -0
- package/kotlin-in-action/scripts/example.py +1 -0
- package/lean-startup/SKILL.md +250 -0
- package/lean-startup/assets/example_asset.txt +1 -0
- package/lean-startup/references/api_reference.md +319 -0
- package/lean-startup/references/review-checklist.md +137 -0
- package/lean-startup/scripts/example.py +1 -0
- package/microservices-patterns/SKILL.md +179 -0
- package/microservices-patterns/references/patterns-catalog.md +391 -0
- package/microservices-patterns/references/review-checklist.md +169 -0
- package/package.json +17 -0
- package/refactoring-ui/SKILL.md +236 -0
- package/refactoring-ui/assets/example_asset.txt +1 -0
- package/refactoring-ui/references/api_reference.md +355 -0
- package/refactoring-ui/references/review-checklist.md +114 -0
- package/refactoring-ui/scripts/example.py +1 -0
- package/storytelling-with-data/SKILL.md +238 -0
- package/storytelling-with-data/assets/example_asset.txt +1 -0
- package/storytelling-with-data/references/api_reference.md +379 -0
- package/storytelling-with-data/references/review-checklist.md +111 -0
- package/storytelling-with-data/scripts/example.py +1 -0
- package/system-design-interview/SKILL.md +213 -0
- package/system-design-interview/assets/example_asset.txt +1 -0
- package/system-design-interview/references/api_reference.md +582 -0
- package/system-design-interview/references/review-checklist.md +201 -0
- package/system-design-interview/scripts/example.py +1 -0
- package/using-asyncio-python/SKILL.md +242 -0
- package/using-asyncio-python/assets/example_asset.txt +1 -0
- package/using-asyncio-python/references/api_reference.md +267 -0
- package/using-asyncio-python/references/review-checklist.md +149 -0
- package/using-asyncio-python/scripts/example.py +1 -0
- package/web-scraping-python/SKILL.md +259 -0
- package/web-scraping-python/assets/example_asset.txt +1 -0
- package/web-scraping-python/references/api_reference.md +393 -0
- package/web-scraping-python/references/review-checklist.md +163 -0
- package/web-scraping-python/scripts/example.py +1 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
# Kotlin In Action — Practices Catalog
|
|
2
|
+
|
|
3
|
+
Comprehensive catalog of practices from *Kotlin In Action* (2nd Edition) by Roman Elizarov,
|
|
4
|
+
Svetlana Isakova, Sebastian Aigner, and Dmitry Jemerov, organized by chapter.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Part 1: Introducing Kotlin
|
|
9
|
+
|
|
10
|
+
### Chapter 1 — Kotlin: What and Why
|
|
11
|
+
|
|
12
|
+
**1.1 — Statically typed with type inference**
|
|
13
|
+
Kotlin is statically typed but uses extensive type inference to reduce boilerplate. Declare types explicitly only when they add clarity (public APIs, complex expressions).
|
|
14
|
+
|
|
15
|
+
**1.2 — Multi-paradigm: functional + object-oriented**
|
|
16
|
+
Kotlin supports both functional and OOP styles. Use functional style (immutable data, pure functions, higher-order functions) for data transformations; OOP for domain modeling and encapsulation.
|
|
17
|
+
|
|
18
|
+
**1.3 — Interoperable with Java**
|
|
19
|
+
Kotlin compiles to JVM bytecode and has seamless Java interop. Call Java from Kotlin and vice versa. Be aware of platform types at boundaries.
|
|
20
|
+
|
|
21
|
+
**1.4 — Safe by design**
|
|
22
|
+
Kotlin's type system eliminates null pointer exceptions at compile time. Non-null types are the default; nullable types require explicit `?` annotation.
|
|
23
|
+
|
|
24
|
+
**1.5 — Concise and expressive**
|
|
25
|
+
Kotlin reduces boilerplate through data classes, type inference, default arguments, extension functions, and string templates. Prefer concise idioms over verbose patterns.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
### Chapter 2 — Kotlin Basics
|
|
30
|
+
|
|
31
|
+
**2.1 — Functions with expression bodies**
|
|
32
|
+
For simple functions, use expression-body syntax (`= expression`) instead of block bodies with explicit return. This improves readability for one-expression functions.
|
|
33
|
+
|
|
34
|
+
**2.2 — Variables: val vs var**
|
|
35
|
+
Use `val` (immutable) by default. Use `var` (mutable) only when the value truly needs to change. This communicates intent and prevents accidental mutation.
|
|
36
|
+
|
|
37
|
+
**2.3 — String templates**
|
|
38
|
+
Use string templates (`"Hello, $name"` or `"Result: ${expr}"`) instead of string concatenation. They're more readable and efficient.
|
|
39
|
+
|
|
40
|
+
**2.4 — Classes with properties**
|
|
41
|
+
Kotlin classes declare properties directly in the class header or body. The compiler generates getters/setters automatically. Use custom accessors only when needed.
|
|
42
|
+
|
|
43
|
+
**2.5 — Enum classes with properties and methods**
|
|
44
|
+
Enum classes can have properties, methods, and implement interfaces. Use them for fixed sets of constants with associated behavior.
|
|
45
|
+
|
|
46
|
+
**2.6 — when expression**
|
|
47
|
+
Use `when` as a more powerful replacement for switch. It works with any type, supports pattern matching with smart casts, and can be used as an expression returning a value.
|
|
48
|
+
|
|
49
|
+
**2.7 — Smart casts**
|
|
50
|
+
After an `is` check, the compiler automatically casts the variable to the checked type. Combine with `when` for elegant type-based dispatching.
|
|
51
|
+
|
|
52
|
+
**2.8 — Ranges and progressions**
|
|
53
|
+
Use `..` operator, `downTo`, `step`, and `in` for ranges. Ranges work with any Comparable type. Use `until` for half-open ranges.
|
|
54
|
+
|
|
55
|
+
**2.9 — Exceptions as expressions**
|
|
56
|
+
`try` is an expression in Kotlin and returns a value. Kotlin has no checked exceptions. Use exceptions for programming errors, not for expected conditions.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
### Chapter 3 — Defining and Calling Functions
|
|
61
|
+
|
|
62
|
+
**3.1 — Named arguments**
|
|
63
|
+
Use named arguments for clarity, especially with boolean parameters, multiple parameters of the same type, or when skipping default values. Named arguments serve as self-documentation.
|
|
64
|
+
|
|
65
|
+
**3.2 — Default parameter values**
|
|
66
|
+
Use default parameter values instead of method overloading. This reduces the number of functions while maintaining flexibility.
|
|
67
|
+
|
|
68
|
+
**3.3 — Top-level functions and properties**
|
|
69
|
+
Use top-level functions instead of Java-style utility classes with static methods. Top-level properties are useful for constants (`const val`).
|
|
70
|
+
|
|
71
|
+
**3.4 — Extension functions**
|
|
72
|
+
Add functions to existing classes without modifying them. Extensions are resolved statically (not virtual). Use them to enrich third-party APIs with domain-specific operations.
|
|
73
|
+
|
|
74
|
+
**3.5 — Extension properties**
|
|
75
|
+
Like extension functions but accessed as properties. Use for computed values that feel natural as properties of the extended type.
|
|
76
|
+
|
|
77
|
+
**3.6 — Varargs and spread operator**
|
|
78
|
+
Use `vararg` for functions accepting variable numbers of arguments. Use the spread operator (`*`) to pass arrays to vararg parameters.
|
|
79
|
+
|
|
80
|
+
**3.7 — Infix functions**
|
|
81
|
+
Mark single-parameter member/extension functions with `infix` for natural DSL-like syntax (e.g., `1 to "one"`, `route matches "/api"`).
|
|
82
|
+
|
|
83
|
+
**3.8 — Destructuring declarations**
|
|
84
|
+
Use destructuring to unpack data classes, maps, and other structures into individual variables. Works with `componentN()` operator functions.
|
|
85
|
+
|
|
86
|
+
**3.9 — Triple-quoted strings**
|
|
87
|
+
Use triple-quoted strings (`"""..."""`) for multi-line strings, regex patterns, and strings containing special characters. Use `trimMargin()` or `trimIndent()` for clean formatting.
|
|
88
|
+
|
|
89
|
+
**3.10 — Local functions**
|
|
90
|
+
Define functions inside other functions to encapsulate helper logic and reduce duplication. Local functions have access to the enclosing function's variables.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### Chapter 4 — Classes, Objects, and Interfaces
|
|
95
|
+
|
|
96
|
+
**4.1 — Interfaces with default implementations**
|
|
97
|
+
Kotlin interfaces can have default method implementations and properties (without backing fields). Use interfaces with defaults for mix-in behavior.
|
|
98
|
+
|
|
99
|
+
**4.2 — Final by default (open/abstract)**
|
|
100
|
+
Classes and methods are `final` by default. Mark as `open` only when designed for inheritance. Use `abstract` for classes that must be subclassed.
|
|
101
|
+
|
|
102
|
+
**4.3 — Visibility modifiers**
|
|
103
|
+
Kotlin has four visibility levels: `public` (default), `internal` (module), `protected` (subclass), `private` (class/file). Use the most restrictive visibility that works.
|
|
104
|
+
|
|
105
|
+
**4.4 — Inner vs nested classes**
|
|
106
|
+
Nested classes (default) don't hold a reference to the outer class. Use `inner` only when access to the outer instance is needed. Prefer nested to avoid memory leaks.
|
|
107
|
+
|
|
108
|
+
**4.5 — Sealed classes and interfaces**
|
|
109
|
+
Use `sealed` for restricted class hierarchies. The compiler enforces exhaustive `when` expressions. Subclasses must be defined in the same package (same file for sealed classes pre-1.5).
|
|
110
|
+
|
|
111
|
+
**4.6 — Primary constructors and init blocks**
|
|
112
|
+
Use the primary constructor for essential properties. Use `init` blocks for validation logic. Secondary constructors should delegate to the primary.
|
|
113
|
+
|
|
114
|
+
**4.7 — Data classes**
|
|
115
|
+
Use the `data` modifier for classes that primarily hold data. Automatically generates `equals()`, `hashCode()`, `toString()`, `copy()`, and `componentN()` functions. Use `val` properties.
|
|
116
|
+
|
|
117
|
+
**4.8 — Class delegation with by**
|
|
118
|
+
Use the `by` keyword to delegate interface implementation to a composed object. This replaces inheritance-based code reuse with composition.
|
|
119
|
+
|
|
120
|
+
**4.9 — Object declarations (singletons)**
|
|
121
|
+
Use `object` declarations for singletons. They're thread-safe and lazily initialized. Use for stateless utility objects, service locators, or named constants.
|
|
122
|
+
|
|
123
|
+
**4.10 — Companion objects**
|
|
124
|
+
Use `companion object` for factory methods and constants associated with a class. Companion objects can implement interfaces and have extension functions.
|
|
125
|
+
|
|
126
|
+
**4.11 — Object expressions (anonymous objects)**
|
|
127
|
+
Use object expressions to create anonymous implementations of interfaces or abstract classes. Unlike Java anonymous classes, they can access and modify local variables.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Part 2: Embracing Kotlin
|
|
132
|
+
|
|
133
|
+
### Chapter 5 — Programming with Lambdas
|
|
134
|
+
|
|
135
|
+
**5.1 — Lambda syntax and conventions**
|
|
136
|
+
Lambda expressions use `{ params -> body }` syntax. When a lambda is the last argument, move it outside parentheses. For single-parameter lambdas, use `it`.
|
|
137
|
+
|
|
138
|
+
**5.2 — Member references**
|
|
139
|
+
Use `::functionName` to pass existing functions as lambdas. Works with top-level functions, member functions, constructors, and extension functions. Prefer references when they're clearer than lambdas.
|
|
140
|
+
|
|
141
|
+
**5.3 — Functional collection APIs**
|
|
142
|
+
Use `filter`, `map`, `all`, `any`, `count`, `find`, `groupBy`, `flatMap`, `flatten`, `fold`, `reduce`, `associate`, `zip`, `windowed`, `chunked` instead of manual loops. Chain operations for declarative data processing.
|
|
143
|
+
|
|
144
|
+
**5.4 — Lazy collection operations with Sequences**
|
|
145
|
+
For collections with 2+ chained operations on large data, use `.asSequence()` to avoid creating intermediate collections. Sequences process elements lazily, one at a time.
|
|
146
|
+
|
|
147
|
+
**5.5 — SAM conversion**
|
|
148
|
+
When calling Java methods expecting single-abstract-method interfaces, pass a lambda directly. Kotlin automatically converts the lambda to the SAM interface. For Kotlin interfaces, use `fun interface`.
|
|
149
|
+
|
|
150
|
+
**5.6 — Lambdas with receivers (with, apply, also)**
|
|
151
|
+
- `with(obj) { ... }` — Group multiple calls on the same object; returns lambda result
|
|
152
|
+
- `apply { ... }` — Configure an object; returns the receiver
|
|
153
|
+
- `also { ... }` — Perform side effects; returns the receiver
|
|
154
|
+
- `let { ... }` — Transform a value or null-check; returns lambda result
|
|
155
|
+
- `run { ... }` — Scoped computation; returns lambda result
|
|
156
|
+
- `buildString { ... }` — Build strings with StringBuilder receiver
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
### Chapter 6 — Working with Collections and Sequences
|
|
161
|
+
|
|
162
|
+
**6.1 — Extended collection functional APIs**
|
|
163
|
+
Beyond basic filter/map, use: `associate` for building maps, `groupBy` for categorization, `partition` for splitting by predicate, `zip` for pairing collections, `windowed` and `chunked` for sliding windows.
|
|
164
|
+
|
|
165
|
+
**6.2 — Sequence operations in depth**
|
|
166
|
+
Sequences have intermediate operations (lazy, return Sequence) and terminal operations (eager, trigger computation). Order matters: put `filter` before `map` to reduce processed elements. Use `generateSequence` for infinite sequences.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### Chapter 7 — Working with Nullable Values
|
|
171
|
+
|
|
172
|
+
**7.1 — Nullable types**
|
|
173
|
+
Append `?` to make a type nullable: `String?`. The compiler enforces null safety: you cannot call methods on nullable types without null checks.
|
|
174
|
+
|
|
175
|
+
**7.2 — Safe call operator (?.) **
|
|
176
|
+
Use `?.` to call methods on nullable values. Returns null if the receiver is null. Chain safe calls for deep navigation: `person?.address?.city`.
|
|
177
|
+
|
|
178
|
+
**7.3 — Elvis operator (?:)**
|
|
179
|
+
Use `?:` to provide a default value when an expression is null. Combine with `return` or `throw` for early exits: `val name = input ?: return`.
|
|
180
|
+
|
|
181
|
+
**7.4 — Safe cast (as?)**
|
|
182
|
+
Use `as?` for safe type casts that return null instead of throwing ClassCastException. Combine with Elvis for safe cast with fallback.
|
|
183
|
+
|
|
184
|
+
**7.5 — Not-null assertion (!!)**
|
|
185
|
+
Avoid `!!` whenever possible. It converts null to NPE. Use only when you can prove non-nullness but the compiler cannot. Document why it's safe.
|
|
186
|
+
|
|
187
|
+
**7.6 — let for null checks**
|
|
188
|
+
Use `?.let { ... }` to execute a block only when a value is non-null. The value is available as `it` (non-null) inside the block.
|
|
189
|
+
|
|
190
|
+
**7.7 — lateinit properties**
|
|
191
|
+
Use `lateinit var` for properties that are initialized after construction (e.g., dependency injection, test setup). Accessing before initialization throws. Cannot be used with primitive types.
|
|
192
|
+
|
|
193
|
+
**7.8 — Extensions on nullable types**
|
|
194
|
+
Extension functions can be defined on nullable types (e.g., `String?.isNullOrBlank()`). Inside the extension, `this` can be null. Use for utility functions that should handle null gracefully.
|
|
195
|
+
|
|
196
|
+
**7.9 — Platform types**
|
|
197
|
+
Types from Java without nullability annotations are platform types (`Type!`). They can be treated as nullable or non-null. Always add explicit nullability at Java/Kotlin boundaries to prevent runtime NPEs.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
### Chapter 8 — Basic Types, Collections, and Arrays
|
|
202
|
+
|
|
203
|
+
**8.1 — Primitive types**
|
|
204
|
+
Kotlin maps basic types (Int, Long, Double, etc.) to Java primitives when possible. Nullable types (Int?) map to boxed types (Integer). Avoid nullable numeric types in performance-critical code.
|
|
205
|
+
|
|
206
|
+
**8.2 — Number conversions**
|
|
207
|
+
Kotlin does not auto-widen numbers. Use explicit conversion functions: `toInt()`, `toLong()`, `toDouble()`, etc. This prevents silent precision loss.
|
|
208
|
+
|
|
209
|
+
**8.3 — Any, Unit, and Nothing**
|
|
210
|
+
- `Any` — Root of the Kotlin type hierarchy (equivalent to Object)
|
|
211
|
+
- `Unit` — Equivalent to void but is an actual type with a single value; use as generic type parameter
|
|
212
|
+
- `Nothing` — No value; used for functions that never return (throw, infinite loop); is a subtype of every type
|
|
213
|
+
|
|
214
|
+
**8.4 — Read-only vs mutable collections**
|
|
215
|
+
Kotlin distinguishes `Collection` (read-only) from `MutableCollection`. Use read-only collections by default. Expose mutable collections only when mutation is part of the API contract.
|
|
216
|
+
|
|
217
|
+
**8.5 — Arrays and primitive arrays**
|
|
218
|
+
Use `IntArray`, `LongArray`, `DoubleArray`, etc. for primitive arrays (no boxing). Use `Array<T>` for reference type arrays. Use `intArrayOf()`, `arrayOf()` factory functions. Prefer collections over arrays in most cases.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
### Chapter 9 — Operator Overloading and Other Conventions
|
|
223
|
+
|
|
224
|
+
**9.1 — Arithmetic operator overloading**
|
|
225
|
+
Define `plus`, `minus`, `times`, `div`, `rem` as operator functions. Operator meaning must match the conventional mathematical semantics. Can be defined as member or extension functions.
|
|
226
|
+
|
|
227
|
+
**9.2 — Compound assignment operators**
|
|
228
|
+
`plusAssign`, `minusAssign`, etc. are called for `+=`, `-=`. For mutable collections, these modify in place. For immutable collections, they create new instances.
|
|
229
|
+
|
|
230
|
+
**9.3 — Unary operators**
|
|
231
|
+
`unaryMinus`, `unaryPlus`, `not`, `inc`, `dec` for unary operations. Use for domain types where these operations have clear mathematical meaning.
|
|
232
|
+
|
|
233
|
+
**9.4 — Comparison operators**
|
|
234
|
+
Implement `Comparable<T>` to enable `<`, `>`, `<=`, `>=` comparisons. Use `compareValuesBy` for multi-field comparison. `==` calls `equals`, `===` checks reference identity.
|
|
235
|
+
|
|
236
|
+
**9.5 — Collection conventions (get, set, in, rangeTo)**
|
|
237
|
+
Define `get` operator for index access (`obj[key]`), `set` for mutation (`obj[key] = value`), `contains` for `in` checks, `rangeTo` for `..` operator.
|
|
238
|
+
|
|
239
|
+
**9.6 — Destructuring declarations**
|
|
240
|
+
Data classes automatically generate `component1()` through `componentN()`. Define `componentN` operators on other classes for destructuring. Works in for loops, lambda parameters, and variable declarations.
|
|
241
|
+
|
|
242
|
+
**9.7 — Delegated properties**
|
|
243
|
+
Use `by lazy { }` for lazy initialization (thread-safe by default). Use `Delegates.observable` for change notification. Use `by map` for storing properties in maps. Create custom delegates with `ReadOnlyProperty`/`ReadWriteProperty`.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
### Chapter 10 — Higher-Order Functions: Lambdas as Parameters and Return Values
|
|
248
|
+
|
|
249
|
+
**10.1 — Function types**
|
|
250
|
+
Kotlin has first-class function types: `(Int, String) -> Boolean`. Use them as parameter types, return types, and variable types. Nullable function types: `((Int) -> Unit)?`.
|
|
251
|
+
|
|
252
|
+
**10.2 — Calling functions passed as arguments**
|
|
253
|
+
Higher-order functions accept function types as parameters. Use them for strategy pattern, callbacks, and customizable algorithms.
|
|
254
|
+
|
|
255
|
+
**10.3 — Default values for function type parameters**
|
|
256
|
+
Provide default implementations for function type parameters. This makes higher-order functions flexible without requiring callers to always pass a lambda.
|
|
257
|
+
|
|
258
|
+
**10.4 — Returning functions**
|
|
259
|
+
Functions can return other functions. Use for factory patterns, partial application, and creating specialized behavior at runtime.
|
|
260
|
+
|
|
261
|
+
**10.5 — Inline functions**
|
|
262
|
+
Mark higher-order functions as `inline` to eliminate lambda allocation overhead. The compiler inlines both the function body and the lambda at call sites. Use for frequently-called utility functions.
|
|
263
|
+
|
|
264
|
+
**10.6 — noinline and crossinline**
|
|
265
|
+
Use `noinline` for lambda parameters that should not be inlined (e.g., stored in a variable). Use `crossinline` for lambdas passed to other contexts where non-local returns are not allowed.
|
|
266
|
+
|
|
267
|
+
**10.7 — Non-local returns**
|
|
268
|
+
In inline functions, `return` inside a lambda returns from the enclosing function (non-local return). Use labeled returns (`return@functionName`) for local returns from lambdas.
|
|
269
|
+
|
|
270
|
+
**10.8 — Anonymous functions**
|
|
271
|
+
Use anonymous functions (`fun(x: Int): Int { ... }`) when you need local returns without labels. Anonymous functions use `return` to return from themselves, not the enclosing function.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
### Chapter 11 — Generics
|
|
276
|
+
|
|
277
|
+
**11.1 — Type parameters and constraints**
|
|
278
|
+
Use generic type parameters for reusable algorithms. Apply upper bounds with `:` to constrain type parameters: `fun <T : Comparable<T>> sort(list: List<T>)`.
|
|
279
|
+
|
|
280
|
+
**11.2 — Non-null type parameters**
|
|
281
|
+
By default, `<T>` allows nullable types. Use `<T : Any>` to ensure non-null type parameters when null values would be invalid.
|
|
282
|
+
|
|
283
|
+
**11.3 — Type erasure**
|
|
284
|
+
Generic type information is erased at runtime on JVM. You cannot check `is List<String>` at runtime. Use star projection `is List<*>` for runtime type checks.
|
|
285
|
+
|
|
286
|
+
**11.4 — Reified type parameters**
|
|
287
|
+
Use `inline fun <reified T>` to preserve type information at runtime. Enables `is T` checks and `T::class` access. Only works with inline functions.
|
|
288
|
+
|
|
289
|
+
**11.5 — Covariance (out)**
|
|
290
|
+
Use `out` for type parameters that are only produced (returned). A `Producer<out T>` allows `Producer<Cat>` to be used where `Producer<Animal>` is expected. Read-only collections are covariant.
|
|
291
|
+
|
|
292
|
+
**11.6 — Contravariance (in)**
|
|
293
|
+
Use `in` for type parameters that are only consumed (accepted as arguments). A `Consumer<in T>` allows `Consumer<Animal>` to be used where `Consumer<Cat>` is expected.
|
|
294
|
+
|
|
295
|
+
**11.7 — Declaration-site vs use-site variance**
|
|
296
|
+
Declare variance at the class level (declaration-site) when it applies everywhere. Use use-site variance (type projection) when variance applies only at specific usage points.
|
|
297
|
+
|
|
298
|
+
**11.8 — Star projection (*)**
|
|
299
|
+
Use `*` when you don't care about or don't know the type argument. `List<*>` is like `List<out Any?>` — you can read Any? but can't write. Use for runtime type checks.
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Part 3: Expanding Kotlin
|
|
304
|
+
|
|
305
|
+
### Chapter 12 — Annotations and Reflection
|
|
306
|
+
|
|
307
|
+
**12.1 — Applying annotations**
|
|
308
|
+
Annotations are applied with `@AnnotationName`. Can target classes, functions, properties, parameters, and expressions. Use annotation arguments for configuration.
|
|
309
|
+
|
|
310
|
+
**12.2 — Annotation targets**
|
|
311
|
+
Use site targets to specify where an annotation applies: `@get:Rule`, `@field:Inject`, `@file:JvmName`. Important for Java interop and annotation processing.
|
|
312
|
+
|
|
313
|
+
**12.3 — Meta-annotations**
|
|
314
|
+
Annotations on annotations control retention, targets, and repetition. `@Target` specifies allowed elements, `@Retention` controls availability at runtime.
|
|
315
|
+
|
|
316
|
+
**12.4 — Classes as annotation parameters**
|
|
317
|
+
Use `KClass` parameters in annotations to reference types: `@DeserializeInterface(CompanyImpl::class)`. Access with `::class` syntax.
|
|
318
|
+
|
|
319
|
+
**12.5 — Kotlin Reflection API**
|
|
320
|
+
Use `KClass` (via `::class` or `javaClass.kotlin`) for runtime class inspection. `KCallable`, `KFunction`, `KProperty` for accessing members. Use for serialization, dependency injection, and framework construction.
|
|
321
|
+
|
|
322
|
+
**12.6 — Member access with reflection**
|
|
323
|
+
Use `KProperty1<T, R>` for property references, `KFunction` for function references. Access `call()` for invocation, `get()` for property access. Handle visibility with `isAccessible = true`.
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
### Chapter 13 — DSL Construction
|
|
328
|
+
|
|
329
|
+
**13.1 — From APIs to DSLs**
|
|
330
|
+
DSLs provide more readable, domain-specific syntax than plain API calls. Kotlin's lambdas with receivers enable clean DSL construction. Compare chained method calls vs nested DSL blocks.
|
|
331
|
+
|
|
332
|
+
**13.2 — Lambdas with receivers in DSLs**
|
|
333
|
+
The receiver type in `T.() -> Unit` makes `this` refer to the receiver inside the lambda. This enables calling methods on the receiver without explicit qualification, creating a natural DSL syntax.
|
|
334
|
+
|
|
335
|
+
**13.3 — @DslMarker for scope control**
|
|
336
|
+
Use `@DslMarker` meta-annotation to prevent access to outer receivers from inner DSL blocks. This prevents bugs from accidentally calling methods on wrong receiver scopes.
|
|
337
|
+
|
|
338
|
+
**13.4 — invoke convention in DSLs**
|
|
339
|
+
Define `operator fun invoke()` to make objects callable like functions. Useful for DSL entry points and configurable function objects.
|
|
340
|
+
|
|
341
|
+
**13.5 — Type-safe builders**
|
|
342
|
+
Build hierarchical structures (HTML, XML, UI layouts) using nested lambdas with receivers. Each builder function creates a child node and adds it to the parent. Combine with extension functions for clean DSL APIs.
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## Part 4: Kotlin for Concurrency
|
|
347
|
+
|
|
348
|
+
### Chapter 14 — Structured Concurrency with Coroutines
|
|
349
|
+
|
|
350
|
+
**14.1 — Coroutines as lightweight threads**
|
|
351
|
+
Coroutines are lightweight, suspendable computations. Thousands can run concurrently without thread overhead. Use `suspend` functions for asynchronous operations.
|
|
352
|
+
|
|
353
|
+
**14.2 — Coroutine builders**
|
|
354
|
+
- `launch { }` — Fire-and-forget coroutine, returns Job
|
|
355
|
+
- `async { }` — Coroutine with a result, returns Deferred<T>; use `await()` to get result
|
|
356
|
+
- `runBlocking { }` — Bridges regular and coroutine world; blocks the current thread. Use only in main() or tests.
|
|
357
|
+
|
|
358
|
+
**14.3 — Structured concurrency principles**
|
|
359
|
+
Every coroutine must have a scope (CoroutineScope). Child coroutines are tied to their parent's lifecycle. When a parent is cancelled, all children are cancelled. When a child fails, the parent and siblings are cancelled.
|
|
360
|
+
|
|
361
|
+
**14.4 — CoroutineScope and context**
|
|
362
|
+
CoroutineScope defines the lifecycle for coroutines. CoroutineContext holds Job, Dispatcher, and other elements. Use `coroutineScope { }` for scoped concurrent operations within suspend functions.
|
|
363
|
+
|
|
364
|
+
**14.5 — Dispatchers**
|
|
365
|
+
- `Dispatchers.Default` — CPU-intensive work (shared thread pool)
|
|
366
|
+
- `Dispatchers.IO` — Blocking I/O operations (expandable thread pool)
|
|
367
|
+
- `Dispatchers.Main` — UI thread (Android/Swing)
|
|
368
|
+
- `Dispatchers.Unconfined` — Starts in caller thread; resumes in whatever thread. Use with care.
|
|
369
|
+
Use `withContext(dispatcher)` to switch dispatchers within a coroutine.
|
|
370
|
+
|
|
371
|
+
**14.6 — Exception handling**
|
|
372
|
+
Uncaught exceptions in `launch` propagate to the parent and cancel siblings. Use `CoroutineExceptionHandler` for top-level error handling. `async` stores exceptions and rethrows on `await()`. Use `supervisorScope` to prevent child failure from cancelling siblings.
|
|
373
|
+
|
|
374
|
+
**14.7 — Cancellation and timeouts**
|
|
375
|
+
Cancellation is cooperative: coroutines must check `isActive` or call suspending functions that check for cancellation. Use `withTimeout(ms)` or `withTimeoutOrNull(ms)` for time-limited operations. Use `ensureActive()` in computation-heavy loops.
|
|
376
|
+
|
|
377
|
+
**14.8 — Sequential vs concurrent execution**
|
|
378
|
+
By default, suspend function calls are sequential. Use `async { }` to run operations concurrently. Use `coroutineScope { }` + `async { }` for structured concurrent decomposition.
|
|
379
|
+
|
|
380
|
+
**14.9 — Shared mutable state**
|
|
381
|
+
Coroutines can share mutable state unsafely. Solutions: use thread-safe data structures (`AtomicInteger`, `ConcurrentHashMap`), confine state to a single thread with `newSingleThreadContext`, use `Mutex` for mutual exclusion, or use actors (channel-based).
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
### Chapter 15 — Flows
|
|
386
|
+
|
|
387
|
+
**15.1 — Cold streams with Flow**
|
|
388
|
+
Flow represents an asynchronous stream of values computed lazily. Unlike sequences, flows support suspension. Flow is cold: the producer code runs only when collected.
|
|
389
|
+
|
|
390
|
+
**15.2 — Flow builders**
|
|
391
|
+
- `flow { emit(value) }` — General-purpose flow builder with suspend block
|
|
392
|
+
- `flowOf(1, 2, 3)` — Flow from fixed values
|
|
393
|
+
- `.asFlow()` — Convert collections, sequences, or ranges to flows
|
|
394
|
+
|
|
395
|
+
**15.3 — Flow operators**
|
|
396
|
+
Intermediate operators (return Flow, lazy):
|
|
397
|
+
- `map { }` — Transform each element
|
|
398
|
+
- `filter { }` — Keep elements matching predicate
|
|
399
|
+
- `transform { }` — General transformation; can emit multiple values
|
|
400
|
+
- `take(n)` — Limit to first n elements
|
|
401
|
+
- `drop(n)` — Skip first n elements
|
|
402
|
+
|
|
403
|
+
**15.4 — Terminal operators**
|
|
404
|
+
Terminal operators (trigger collection, suspend):
|
|
405
|
+
- `collect { }` — Process each emitted value
|
|
406
|
+
- `toList()` / `toSet()` — Collect into a collection
|
|
407
|
+
- `first()` / `single()` — Get first/only element
|
|
408
|
+
- `reduce { }` / `fold { }` — Accumulate values
|
|
409
|
+
|
|
410
|
+
**15.5 — Flow context and flowOn**
|
|
411
|
+
Flow preserves context: the collector's coroutine context is used by default. Use `flowOn(dispatcher)` to change the upstream execution context. Never use `withContext` inside a flow builder.
|
|
412
|
+
|
|
413
|
+
**15.6 — Buffering and conflation**
|
|
414
|
+
- `buffer()` — Run collector and emitter concurrently with a buffer
|
|
415
|
+
- `conflate()` — Drop intermediate values when collector is slow
|
|
416
|
+
- `collectLatest { }` — Cancel previous collection when new value arrives
|
|
417
|
+
|
|
418
|
+
**15.7 — Combining flows**
|
|
419
|
+
- `zip(otherFlow) { a, b -> }` — Pair elements from two flows
|
|
420
|
+
- `combine(otherFlow) { a, b -> }` — Combine latest values from two flows
|
|
421
|
+
|
|
422
|
+
**15.8 — Flattening flows**
|
|
423
|
+
- `flatMapConcat { }` — Sequentially process inner flows
|
|
424
|
+
- `flatMapMerge { }` — Concurrently process inner flows
|
|
425
|
+
- `flatMapLatest { }` — Cancel previous inner flow on new emission
|
|
426
|
+
|
|
427
|
+
**15.9 — Exception handling in flows**
|
|
428
|
+
Use `catch { }` operator to handle upstream exceptions declaratively. Use `try/catch` around terminal operators for downstream exceptions. The `catch` operator can emit fallback values.
|
|
429
|
+
|
|
430
|
+
**15.10 — Flow completion**
|
|
431
|
+
Use `onCompletion { cause -> }` to perform actions when flow completes (normally or with exception). Works as a declarative alternative to try/finally.
|
|
432
|
+
|
|
433
|
+
**15.11 — StateFlow and SharedFlow**
|
|
434
|
+
- `StateFlow<T>` — Hot flow holding a single updatable value; always has a current value; replays latest to new collectors. Use for state management.
|
|
435
|
+
- `SharedFlow<T>` — Hot flow for broadcasting events to multiple collectors; configurable replay; use for events that shouldn't be missed.
|
|
436
|
+
- Convert cold Flow to SharedFlow with `shareIn(scope, started, replay)` or StateFlow with `stateIn(scope, started, initialValue)`.
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Kotlin In Action — Code Review Checklist
|
|
2
|
+
|
|
3
|
+
Systematic checklist for reviewing Kotlin code against the 15 chapters
|
|
4
|
+
from *Kotlin In Action* (2nd Edition) by Elizarov, Isakova, Aigner, and Jemerov.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. Basics & Functions (Chapters 2–3)
|
|
9
|
+
|
|
10
|
+
### Functions
|
|
11
|
+
- [ ] **Ch 2 — Expression-body functions** — Are simple one-expression functions using `= expr` syntax instead of block bodies with explicit return?
|
|
12
|
+
- [ ] **Ch 2 — val vs var** — Is `val` used by default? Is `var` used only when mutation is genuinely needed?
|
|
13
|
+
- [ ] **Ch 2 — String templates** — Are string templates used instead of string concatenation? Are complex expressions wrapped in `${}`?
|
|
14
|
+
- [ ] **Ch 2 — when expressions** — Are chains of if/else replaced with `when` where appropriate? Is `when` used as an expression to return values?
|
|
15
|
+
- [ ] **Ch 2 — Smart casts** — Are smart casts leveraged after `is` checks instead of explicit casts?
|
|
16
|
+
- [ ] **Ch 2 — Ranges** — Are `..`, `until`, `downTo`, `step` used instead of manual loop bounds?
|
|
17
|
+
- [ ] **Ch 2 — try as expression** — Is `try` used as an expression where appropriate to assign results of error-handling logic?
|
|
18
|
+
|
|
19
|
+
### Defining and Calling Functions
|
|
20
|
+
- [ ] **Ch 3 — Named arguments** — Are boolean parameters named? Are same-typed adjacent parameters named? Are arguments named when skipping defaults?
|
|
21
|
+
- [ ] **Ch 3 — Default parameter values** — Are default values used instead of function overloads? Are Java-style telescoping constructors replaced?
|
|
22
|
+
- [ ] **Ch 3 — Top-level functions** — Are utility functions defined at top level instead of in Java-style static utility classes?
|
|
23
|
+
- [ ] **Ch 3 — Extension functions** — Are extensions used to enrich existing types? Are they preferred over utility classes? Are they used appropriately (not for core class behavior)?
|
|
24
|
+
- [ ] **Ch 3 — Infix functions** — Are single-parameter functions marked `infix` when it improves readability in DSL contexts?
|
|
25
|
+
- [ ] **Ch 3 — Destructuring** — Are data class results destructured where it improves clarity? Are `_` used for unused components?
|
|
26
|
+
- [ ] **Ch 3 — Local functions** — Are repeated validation/helper patterns extracted into local functions instead of duplicated?
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 2. Classes, Objects, and Interfaces (Chapter 4)
|
|
31
|
+
|
|
32
|
+
### Inheritance Model
|
|
33
|
+
- [ ] **Ch 4 — Final by default** — Are classes kept final unless explicitly designed for inheritance? Is `open` used intentionally?
|
|
34
|
+
- [ ] **Ch 4 — Interface defaults** — Are interface default implementations used for shared behavior across unrelated types?
|
|
35
|
+
- [ ] **Ch 4 — Sealed classes** — Are type hierarchies with fixed variants modeled as sealed classes/interfaces? Do `when` expressions benefit from exhaustiveness?
|
|
36
|
+
- [ ] **Ch 4 — Abstract classes** — Is `abstract` used only for classes that define a template with some implementations?
|
|
37
|
+
|
|
38
|
+
### Data and Delegation
|
|
39
|
+
- [ ] **Ch 4 — Data classes** — Are data-holding classes using the `data` modifier? Are all properties in the primary constructor `val`? Is `copy()` used instead of mutation?
|
|
40
|
+
- [ ] **Ch 4 — Class delegation (by)** — Is the `by` keyword used instead of inheritance for delegating interface implementation? Is composition preferred over inheritance for code reuse?
|
|
41
|
+
|
|
42
|
+
### Visibility and Objects
|
|
43
|
+
- [ ] **Ch 4 — Visibility modifiers** — Is the most restrictive visibility used? Is `internal` used for module-private APIs? Are implementation details `private`?
|
|
44
|
+
- [ ] **Ch 4 — Nested vs inner classes** — Are nested classes preferred over `inner` to avoid holding outer references? Is `inner` used only when outer access is needed?
|
|
45
|
+
- [ ] **Ch 4 — Companion objects** — Are companion objects used for factory methods instead of constructors? Do they implement interfaces where useful?
|
|
46
|
+
- [ ] **Ch 4 — Object declarations** — Are singletons implemented with `object` instead of Java-style patterns? Are they used for stateless services and constants?
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 3. Lambdas & Collections (Chapters 5–6)
|
|
51
|
+
|
|
52
|
+
### Lambda Expressions
|
|
53
|
+
- [ ] **Ch 5 — Lambda syntax** — Are lambdas moved outside parentheses when they're the last argument? Is `it` used for single-parameter lambdas? Are multi-line lambdas readable?
|
|
54
|
+
- [ ] **Ch 5 — Member references** — Are `::functionName` references used instead of wrapper lambdas (e.g., `list.map(::transform)` vs `list.map { transform(it) }`)?
|
|
55
|
+
- [ ] **Ch 5 — SAM conversion** — When calling Java APIs expecting SAM interfaces, are lambdas passed directly? For Kotlin, are `fun interface` used for single-method interfaces?
|
|
56
|
+
|
|
57
|
+
### Collection Processing
|
|
58
|
+
- [ ] **Ch 5 — Functional APIs** — Are `filter`, `map`, `flatMap`, `groupBy`, `associate`, `fold`, `reduce` used instead of manual loops?
|
|
59
|
+
- [ ] **Ch 5-6 — Sequence for large collections** — For 2+ chained operations on large collections, is `.asSequence()` used? Are intermediate collections avoided?
|
|
60
|
+
- [ ] **Ch 6 — Specialized operations** — Is `any {}` used instead of `filter {}.isNotEmpty()`? Is `firstOrNull {}` used instead of `filter {}.firstOrNull()`? Is `count {}` used instead of `filter {}.size`?
|
|
61
|
+
|
|
62
|
+
### Scope Functions
|
|
63
|
+
- [ ] **Ch 5 — apply for configuration** — Is `apply { }` used for object initialization/configuration blocks?
|
|
64
|
+
- [ ] **Ch 5 — let for null-safe transforms** — Is `?.let { }` used for null-safe transformations instead of if-not-null blocks?
|
|
65
|
+
- [ ] **Ch 5 — also for side effects** — Is `also { }` used for logging/debugging side effects that shouldn't affect the chain?
|
|
66
|
+
- [ ] **Ch 5 — with for grouped calls** — Is `with(obj) { }` used when making multiple calls on the same object?
|
|
67
|
+
- [ ] **Ch 5 — Scope function overuse** — Are scope functions NOT nested excessively? Is readability maintained?
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 4. Null Safety & Types (Chapters 7–8)
|
|
72
|
+
|
|
73
|
+
### Null Handling
|
|
74
|
+
- [ ] **Ch 7 — Safe calls (?.)** — Are safe calls used for nullable navigation instead of explicit null checks? Are they chained for deep access?
|
|
75
|
+
- [ ] **Ch 7 — Elvis (?:)** — Is Elvis used for default values? Is it combined with `return` or `throw` for early exits?
|
|
76
|
+
- [ ] **Ch 7 — No !! (not-null assertion)** — Is `!!` absent or justified with a comment? Are safe alternatives (safe call, Elvis, let, lateinit) used instead?
|
|
77
|
+
- [ ] **Ch 7 — let for null checks** — Is `?.let { }` used appropriately for null-safe blocks? Is it NOT overused where a simple `if` is clearer?
|
|
78
|
+
- [ ] **Ch 7 — lateinit** — Is `lateinit` used for properties initialized after construction (DI, tests)? Is it NOT used where a nullable type or lazy init is more appropriate?
|
|
79
|
+
- [ ] **Ch 7 — Platform types** — At Java/Kotlin boundaries, are types explicitly annotated? Do platform types (`Type!`) NOT leak into Kotlin APIs?
|
|
80
|
+
- [ ] **Ch 7 — Nullable type design** — Are nullable types used only when absence is a meaningful part of the domain? Are non-null types the default?
|
|
81
|
+
|
|
82
|
+
### Type System
|
|
83
|
+
- [ ] **Ch 8 — Primitive types** — In hot paths, are nullable numeric types avoided to prevent boxing? Are `IntArray`/`LongArray`/`DoubleArray` used instead of `Array<Int>`/`List<Int>`?
|
|
84
|
+
- [ ] **Ch 8 — Number conversions** — Are explicit conversion functions used instead of relying on implicit widening? No silent precision loss?
|
|
85
|
+
- [ ] **Ch 8 — Unit type** — Is `Unit` used correctly as a return type for functions with side effects? Is it used as a generic type argument where needed?
|
|
86
|
+
- [ ] **Ch 8 — Nothing type** — Is `Nothing` used for functions that never return? Are throw expressions and infinite loops typed as Nothing?
|
|
87
|
+
- [ ] **Ch 8 — Read-only collections** — Are read-only collection types (List, Set, Map) used by default? Are mutable collections exposed only when mutation is part of the contract?
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 5. Conventions & Delegation (Chapter 9)
|
|
92
|
+
|
|
93
|
+
- [ ] **Ch 9 — Operator overloading** — Do operator overloads match conventional mathematical/collection semantics? Are operators used only when their meaning is unambiguous in the domain?
|
|
94
|
+
- [ ] **Ch 9 — Comparison via Comparable** — Is `Comparable<T>` implemented for natural ordering? Is `compareValuesBy` used for multi-field comparison?
|
|
95
|
+
- [ ] **Ch 9 — Destructuring** — Are data class results destructured for clarity? Are `componentN` operators defined for non-data classes that benefit from destructuring?
|
|
96
|
+
- [ ] **Ch 9 — by lazy** — Is `by lazy` used for expensive initializations that may not be needed? Is the thread safety mode appropriate (SYNCHRONIZED, PUBLICATION, NONE)?
|
|
97
|
+
- [ ] **Ch 9 — Delegates.observable** — Are change-notification patterns using `Delegates.observable` or `Delegates.vetoable` instead of manual setter logic?
|
|
98
|
+
- [ ] **Ch 9 — Map-backed properties** — For dynamic property storage (e.g., JSON deserialization), are map-delegated properties used?
|
|
99
|
+
- [ ] **Ch 9 — Custom delegates** — For repeated property patterns, are custom property delegates created with `ReadOnlyProperty`/`ReadWriteProperty`?
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 6. Higher-Order Functions & Inline (Chapter 10)
|
|
104
|
+
|
|
105
|
+
- [ ] **Ch 10 — Function types** — Are function types used for callbacks, strategies, and customizable behavior instead of single-method interfaces (in Kotlin code)?
|
|
106
|
+
- [ ] **Ch 10 — Default function parameters** — Do higher-order functions provide sensible default lambdas where appropriate?
|
|
107
|
+
- [ ] **Ch 10 — Inline functions** — Are frequently-called higher-order functions marked `inline`? Is inline NOT used for large function bodies?
|
|
108
|
+
- [ ] **Ch 10 — noinline** — Are lambda parameters that are stored (not immediately invoked) marked `noinline`?
|
|
109
|
+
- [ ] **Ch 10 — crossinline** — Are lambda parameters passed to other execution contexts marked `crossinline`?
|
|
110
|
+
- [ ] **Ch 10 — Non-local returns** — Are non-local returns from inline lambdas used intentionally? Are labeled returns (`return@label`) used when only local return is intended?
|
|
111
|
+
- [ ] **Ch 10 — Anonymous functions** — Are anonymous functions used instead of labeled returns when local returns are frequent?
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 7. Generics (Chapter 11)
|
|
116
|
+
|
|
117
|
+
- [ ] **Ch 11 — Type parameter constraints** — Are upper bounds applied to restrict type parameters? Is `<T : Any>` used when non-null is required?
|
|
118
|
+
- [ ] **Ch 11 — Reified type parameters** — Are inline functions with `reified T` used when runtime type information is needed instead of `Class<T>` parameters?
|
|
119
|
+
- [ ] **Ch 11 — Covariance (out)** — Are type parameters that are only produced marked `out`? Are read-only interfaces covariant?
|
|
120
|
+
- [ ] **Ch 11 — Contravariance (in)** — Are type parameters that are only consumed marked `in`?
|
|
121
|
+
- [ ] **Ch 11 — Star projection** — Is `*` used for runtime type checks and when the specific type argument doesn't matter?
|
|
122
|
+
- [ ] **Ch 11 — Type erasure awareness** — Is code aware that generic type information is erased at runtime? No runtime `is List<String>` checks?
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 8. Annotations & Reflection (Chapter 12)
|
|
127
|
+
|
|
128
|
+
- [ ] **Ch 12 — Annotation targets** — Are annotation site targets (`@get:`, `@field:`, `@file:`) used correctly for Java interop?
|
|
129
|
+
- [ ] **Ch 12 — Meta-annotations** — Are custom annotations properly annotated with `@Target` and `@Retention`?
|
|
130
|
+
- [ ] **Ch 12 — Reflection usage** — Is reflection used sparingly and only where compile-time alternatives are insufficient? Is the Kotlin reflection API (`KClass`, `KProperty`) used instead of Java reflection?
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 9. DSL Construction (Chapter 13)
|
|
135
|
+
|
|
136
|
+
- [ ] **Ch 13 — Lambdas with receivers** — Are DSL builder functions using receiver lambdas (`T.() -> Unit`) for natural syntax?
|
|
137
|
+
- [ ] **Ch 13 — @DslMarker** — Is `@DslMarker` used to prevent outer receiver access from inner DSL blocks?
|
|
138
|
+
- [ ] **Ch 13 — invoke convention** — Is the `invoke` operator used appropriately for callable objects in DSL contexts?
|
|
139
|
+
- [ ] **Ch 13 — Type-safe builders** — Are hierarchical structures built with type-safe builder patterns? Is the builder pattern correct and not leaking mutable state?
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 10. Coroutines (Chapter 14)
|
|
144
|
+
|
|
145
|
+
### Structure
|
|
146
|
+
- [ ] **Ch 14 — Structured concurrency** — Are all coroutines launched within a proper CoroutineScope? Is GlobalScope avoided? Do parent-child relationships hold?
|
|
147
|
+
- [ ] **Ch 14 — Coroutine builders** — Is `launch` used for fire-and-forget, `async` for results, `runBlocking` only in main/tests?
|
|
148
|
+
- [ ] **Ch 14 — coroutineScope** — Is `coroutineScope { }` used in suspend functions to create structured scopes for parallel decomposition?
|
|
149
|
+
|
|
150
|
+
### Dispatchers
|
|
151
|
+
- [ ] **Ch 14 — Dispatcher selection** — Is `Dispatchers.Default` used for CPU work, `Dispatchers.IO` for blocking I/O, `Dispatchers.Main` for UI? Is `withContext` used to switch?
|
|
152
|
+
- [ ] **Ch 14 — No blocking in Default** — Are blocking operations NOT running on `Dispatchers.Default`? Are they wrapped in `withContext(Dispatchers.IO)`?
|
|
153
|
+
|
|
154
|
+
### Error Handling & Cancellation
|
|
155
|
+
- [ ] **Ch 14 — Exception handling** — Are exceptions handled properly? Is `CoroutineExceptionHandler` used at top level? Is `supervisorScope` used when child failures should be independent?
|
|
156
|
+
- [ ] **Ch 14 — Cancellation cooperation** — Do long-running coroutines check `isActive` or call `ensureActive()`? Are cancellation exceptions not swallowed?
|
|
157
|
+
- [ ] **Ch 14 — Timeouts** — Is `withTimeout` or `withTimeoutOrNull` used for time-limited operations?
|
|
158
|
+
|
|
159
|
+
### Shared State
|
|
160
|
+
- [ ] **Ch 14 — Thread safety** — Is shared mutable state protected? Are `Mutex`, atomic types, or single-thread confinement used? No unprotected shared vars across coroutines?
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 11. Flows (Chapter 15)
|
|
165
|
+
|
|
166
|
+
### Flow Basics
|
|
167
|
+
- [ ] **Ch 15 — Flow builders** — Are `flow {}`, `flowOf()`, or `.asFlow()` used appropriately? Is `flow {}` used for suspend-based emission?
|
|
168
|
+
- [ ] **Ch 15 — Flow context** — Is `flowOn` used to change upstream context instead of `withContext` inside flow builders?
|
|
169
|
+
- [ ] **Ch 15 — Cold vs hot** — Are cold Flows used for on-demand data? Are StateFlow/SharedFlow used for state and events?
|
|
170
|
+
|
|
171
|
+
### Operators
|
|
172
|
+
- [ ] **Ch 15 — Intermediate operators** — Are `map`, `filter`, `transform`, `take`, `drop` used instead of manual collection loops?
|
|
173
|
+
- [ ] **Ch 15 — Terminal operators** — Is `collect` used for side effects, `toList`/`toSet` for materialization, `first`/`reduce`/`fold` for aggregation?
|
|
174
|
+
- [ ] **Ch 15 — Buffering** — Is `buffer()` used when collector is slower than emitter? Is `conflate()` used when only latest value matters?
|
|
175
|
+
|
|
176
|
+
### Error Handling & Completion
|
|
177
|
+
- [ ] **Ch 15 — catch operator** — Is `catch { }` used for upstream exception handling? Are downstream exceptions handled with try/catch around terminal operators?
|
|
178
|
+
- [ ] **Ch 15 — onCompletion** — Is `onCompletion { }` used for cleanup and finalization logic?
|
|
179
|
+
|
|
180
|
+
### Hot Flows
|
|
181
|
+
- [ ] **Ch 15 — StateFlow** — Is `StateFlow` used for observable state with a current value? Is `value` property used for synchronous access?
|
|
182
|
+
- [ ] **Ch 15 — SharedFlow** — Is `SharedFlow` used for broadcasting events? Is replay configured appropriately?
|
|
183
|
+
- [ ] **Ch 15 — shareIn/stateIn** — Are cold flows converted to hot flows with proper `SharingStarted` strategy (Eagerly, Lazily, WhileSubscribed)?
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Quick Review Workflow
|
|
188
|
+
|
|
189
|
+
1. **Basics pass** — Scan for Java-style code: utility classes, getter/setter methods, missing named args, string concatenation, manual loops
|
|
190
|
+
2. **Class design pass** — Check for proper sealed hierarchies, data classes, delegation, visibility, final by default
|
|
191
|
+
3. **Null safety pass** — Hunt for `!!`, unchecked platform types, nullable types where non-null works, missing safe calls
|
|
192
|
+
4. **Collection pass** — Check for Sequence usage on large pipelines, proper functional APIs, scope function clarity
|
|
193
|
+
5. **Concurrency pass** — Verify structured concurrency, proper dispatchers, cancellation cooperation, shared state protection
|
|
194
|
+
6. **Flow pass** — Check for correct Flow usage, hot vs cold, buffering, exception handling, context preservation
|
|
195
|
+
7. **Prioritize findings** — Rank by severity: concurrency bugs > null safety > class design > idioms > style
|
|
196
|
+
|
|
197
|
+
## Severity Levels
|
|
198
|
+
|
|
199
|
+
| Severity | Description | Example |
|
|
200
|
+
|----------|-------------|---------|
|
|
201
|
+
| **Critical** | Concurrency bugs, null safety violations, resource leaks | Unprotected shared state in coroutines, `!!` on user input, GlobalScope usage in production, missing cancellation cooperation |
|
|
202
|
+
| **High** | Incorrect Kotlin usage, missed type safety, structural issues | Platform types leaking, eager collection processing on large data, blocking on Default dispatcher, missing structured concurrency |
|
|
203
|
+
| **Medium** | Non-idiomatic code, missed Kotlin features, readability issues | Java-style utility classes, manual loops instead of functional APIs, inheritance instead of delegation, missing named arguments |
|
|
204
|
+
| **Low** | Polish, minor optimizations, style improvements | Missing destructuring, sequence opportunity, infix function opportunity, scope function preference |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|