opencode-skills-collection 3.0.49 → 3.0.51
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/bundled-skills/.antigravity-install-manifest.json +27 -1
- package/bundled-skills/ab-test-setup/SKILL.md +14 -0
- package/bundled-skills/apple-notes-search/SKILL.md +122 -0
- package/bundled-skills/astropy/references/coordinates.md +9 -0
- package/bundled-skills/astropy/references/cosmology.md +8 -0
- package/bundled-skills/astropy/references/fits.md +8 -0
- package/bundled-skills/astropy/references/tables.md +8 -0
- package/bundled-skills/astropy/references/time.md +7 -0
- package/bundled-skills/astropy/references/units.md +9 -0
- package/bundled-skills/astropy/references/wcs_and_other_modules.md +9 -0
- package/bundled-skills/browser-extension-builder/SKILL.md +1 -1
- package/bundled-skills/ckw-design/SKILL.md +129 -0
- package/bundled-skills/deterministic-design/SKILL.md +56 -0
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/users/bundles.md +1 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/lint-and-validate/SKILL.md +3 -1
- package/bundled-skills/lookdev/SKILL.md +229 -0
- package/bundled-skills/lookdev-auto/SKILL.md +102 -0
- package/bundled-skills/macos-screen-recorder/SKILL.md +59 -0
- package/bundled-skills/pr-merge-champion/SKILL.md +116 -0
- package/bundled-skills/programmatic-seo/SKILL.md +11 -0
- package/bundled-skills/schema-markup/SKILL.md +11 -0
- package/bundled-skills/screenstudio-alt/SKILL.md +91 -0
- package/bundled-skills/super-code/SKILL.md +209 -0
- package/bundled-skills/super-code/bash/SKILL.md +292 -0
- package/bundled-skills/super-code/c/SKILL.md +263 -0
- package/bundled-skills/super-code/cpp/SKILL.md +271 -0
- package/bundled-skills/super-code/csharp/SKILL.md +276 -0
- package/bundled-skills/super-code/dart/SKILL.md +327 -0
- package/bundled-skills/super-code/elixir/SKILL.md +366 -0
- package/bundled-skills/super-code/go/SKILL.md +234 -0
- package/bundled-skills/super-code/java/SKILL.md +230 -0
- package/bundled-skills/super-code/kotlin/SKILL.md +281 -0
- package/bundled-skills/super-code/php/SKILL.md +316 -0
- package/bundled-skills/super-code/python/SKILL.md +315 -0
- package/bundled-skills/super-code/ruby/SKILL.md +306 -0
- package/bundled-skills/super-code/rust/SKILL.md +289 -0
- package/bundled-skills/super-code/scala/SKILL.md +302 -0
- package/bundled-skills/super-code/swift/SKILL.md +299 -0
- package/bundled-skills/super-code/typescript/SKILL.md +286 -0
- package/bundled-skills/web-media-getter/SKILL.md +119 -0
- package/bundled-skills/youtube-seo-optimizer/SKILL.md +9 -9
- package/package.json +1 -1
- package/skills_index.json +574 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: java
|
|
3
|
+
description: "Language-specific super-code guidelines for java."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-06-16"
|
|
7
|
+
---
|
|
8
|
+
# Java: Idiomatic Efficiency Reference
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
1. [Streams & Collections](#streams)
|
|
12
|
+
2. [Optional](#optional)
|
|
13
|
+
3. [Records & Data Classes](#records)
|
|
14
|
+
4. [Switch Expressions](#switch)
|
|
15
|
+
5. [Concurrency](#concurrency)
|
|
16
|
+
6. [Error Handling](#errors)
|
|
17
|
+
7. [Anti-patterns specific to Java](#antipatterns)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Streams & Collections {#streams}
|
|
22
|
+
|
|
23
|
+
```java
|
|
24
|
+
// ❌ Imperative accumulation
|
|
25
|
+
List<String> result = new ArrayList<>();
|
|
26
|
+
for (Item item : items) {
|
|
27
|
+
if (item.isActive()) result.add(item.getName().toUpperCase());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ✅
|
|
31
|
+
List<String> result = items.stream()
|
|
32
|
+
.filter(Item::isActive)
|
|
33
|
+
.map(item -> item.getName().toUpperCase())
|
|
34
|
+
.toList(); // Java 16+; use .collect(Collectors.toList()) before
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```java
|
|
38
|
+
// ❌ Manual grouping
|
|
39
|
+
Map<String, List<Item>> grouped = new HashMap<>();
|
|
40
|
+
for (Item item : items) {
|
|
41
|
+
grouped.computeIfAbsent(item.getCategory(), k -> new ArrayList<>()).add(item);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ✅
|
|
45
|
+
Map<String, List<Item>> grouped = items.stream()
|
|
46
|
+
.collect(Collectors.groupingBy(Item::getCategory));
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```java
|
|
50
|
+
// ❌ Manual sum
|
|
51
|
+
int total = 0;
|
|
52
|
+
for (Order o : orders) total += o.getAmount();
|
|
53
|
+
|
|
54
|
+
// ✅
|
|
55
|
+
int total = orders.stream().mapToInt(Order::getAmount).sum();
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Prefer method references (`Item::isActive`) over equivalent lambdas (`item -> item.isActive()`).**
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 2. Optional {#optional}
|
|
63
|
+
|
|
64
|
+
```java
|
|
65
|
+
// ❌ Null check chain
|
|
66
|
+
String city = null;
|
|
67
|
+
if (user != null && user.getAddress() != null) {
|
|
68
|
+
city = user.getAddress().getCity();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ✅
|
|
72
|
+
String city = Optional.ofNullable(user)
|
|
73
|
+
.map(User::getAddress)
|
|
74
|
+
.map(Address::getCity)
|
|
75
|
+
.orElse(null);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```java
|
|
79
|
+
// ❌ Optional.get() without isPresent()
|
|
80
|
+
String name = optional.get(); // throws if empty
|
|
81
|
+
|
|
82
|
+
// ✅
|
|
83
|
+
String name = optional.orElse("default");
|
|
84
|
+
// or: optional.orElseThrow(() -> new IllegalStateException("name required"));
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```java
|
|
88
|
+
// ❌ Optional as a field or parameter (anti-pattern)
|
|
89
|
+
class User { private Optional<String> nickname; }
|
|
90
|
+
|
|
91
|
+
// ✅ — Optional is for return types only
|
|
92
|
+
class User { private String nickname; } // nullable field
|
|
93
|
+
public Optional<String> getNickname() { return Optional.ofNullable(nickname); }
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 3. Records & Data Classes {#records}
|
|
99
|
+
|
|
100
|
+
```java
|
|
101
|
+
// ❌ Manual POJO
|
|
102
|
+
class Point {
|
|
103
|
+
private final int x, y;
|
|
104
|
+
public Point(int x, int y) { this.x = x; this.y = y; }
|
|
105
|
+
public int getX() { return x; }
|
|
106
|
+
public int getY() { return y; }
|
|
107
|
+
// + equals, hashCode, toString...
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ✅ (Java 16+)
|
|
111
|
+
record Point(int x, int y) {}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```java
|
|
115
|
+
// ❌ Builder pattern for a 2-field object
|
|
116
|
+
User user = new User.Builder().name("Alice").age(30).build();
|
|
117
|
+
|
|
118
|
+
// ✅ — use record or constructor directly for small objects
|
|
119
|
+
record User(String name, int age) {}
|
|
120
|
+
var user = new User("Alice", 30);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Use `record` for any immutable data carrier. Keep builders only for objects with many optional fields.**
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 4. Switch Expressions {#switch}
|
|
128
|
+
|
|
129
|
+
```java
|
|
130
|
+
// ❌ Switch statement with fall-through and break
|
|
131
|
+
String label;
|
|
132
|
+
switch (status) {
|
|
133
|
+
case ACTIVE: label = "Active"; break;
|
|
134
|
+
case INACTIVE: label = "Inactive"; break;
|
|
135
|
+
default: label = "Unknown";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ✅ (Java 14+)
|
|
139
|
+
String label = switch (status) {
|
|
140
|
+
case ACTIVE -> "Active";
|
|
141
|
+
case INACTIVE -> "Inactive";
|
|
142
|
+
default -> "Unknown";
|
|
143
|
+
};
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
```java
|
|
147
|
+
// ❌ instanceof + cast
|
|
148
|
+
if (shape instanceof Circle) {
|
|
149
|
+
Circle c = (Circle) shape;
|
|
150
|
+
return c.radius() * c.radius() * Math.PI;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ✅ Pattern matching (Java 16+)
|
|
154
|
+
if (shape instanceof Circle c) {
|
|
155
|
+
return c.radius() * c.radius() * Math.PI;
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 5. Concurrency {#concurrency}
|
|
162
|
+
|
|
163
|
+
```java
|
|
164
|
+
// ❌ Raw Thread creation
|
|
165
|
+
Thread t = new Thread(() -> doWork());
|
|
166
|
+
t.start();
|
|
167
|
+
|
|
168
|
+
// ✅
|
|
169
|
+
ExecutorService exec = Executors.newVirtualThreadPerTaskExecutor(); // Java 21
|
|
170
|
+
exec.submit(() -> doWork());
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```java
|
|
174
|
+
// ❌ synchronized on this for fine-grained state
|
|
175
|
+
synchronized(this) { counter++; }
|
|
176
|
+
|
|
177
|
+
// ✅
|
|
178
|
+
AtomicInteger counter = new AtomicInteger();
|
|
179
|
+
counter.incrementAndGet();
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Prefer `CompletableFuture.allOf()` over blocking `.get()` chains for parallel async work.**
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## 6. Error Handling {#errors}
|
|
187
|
+
|
|
188
|
+
```java
|
|
189
|
+
// ❌ Catching Exception to log and swallow
|
|
190
|
+
try {
|
|
191
|
+
risky();
|
|
192
|
+
} catch (Exception e) {
|
|
193
|
+
log.error("error", e);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ✅ — rethrow as unchecked if you can't handle it
|
|
197
|
+
try {
|
|
198
|
+
risky();
|
|
199
|
+
} catch (IOException e) {
|
|
200
|
+
throw new UncheckedIOException(e);
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
```java
|
|
205
|
+
// ❌ Checked exceptions declared on every method
|
|
206
|
+
public void process() throws IOException, SQLException, ParseException { ... }
|
|
207
|
+
|
|
208
|
+
// ✅ — wrap at the boundary; internal methods throw unchecked
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 7. Anti-patterns specific to Java {#antipatterns}
|
|
214
|
+
|
|
215
|
+
| Anti-pattern | Preferred |
|
|
216
|
+
|---|---|
|
|
217
|
+
| `new ArrayList<String>()` (Java 7+) | `new ArrayList<>()` (diamond) |
|
|
218
|
+
| `"string".equals(variable)` (Yoda) | `Objects.equals(variable, "string")` |
|
|
219
|
+
| `for (int i = 0; i < list.size(); i++)` | enhanced for or stream |
|
|
220
|
+
| `StringBuffer` in single-threaded code | `StringBuilder` |
|
|
221
|
+
| `e.printStackTrace()` | `log.error("msg", e)` |
|
|
222
|
+
| `null` return for "not found" | `Optional<T>` return type |
|
|
223
|
+
| Public fields | private + accessor, or `record` |
|
|
224
|
+
| Mutable `static` fields | avoid; use dependency injection |
|
|
225
|
+
| `instanceof` + cast without pattern matching | pattern matching (Java 16+) |
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
## Limitations
|
|
229
|
+
- These are language-specific guidelines and do not cover overall architectural decisions.
|
|
230
|
+
- Over-compression might reduce readability; apply judgement.
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kotlin
|
|
3
|
+
description: "Language-specific super-code guidelines for kotlin."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-06-16"
|
|
7
|
+
---
|
|
8
|
+
# Kotlin + Compose: Idiomatic Efficiency Reference
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
1. [Collections & Data Transformation](#collections)
|
|
12
|
+
2. [Null Safety](#null-safety)
|
|
13
|
+
3. [Functions & Lambdas](#functions)
|
|
14
|
+
4. [Classes & Objects](#classes)
|
|
15
|
+
5. [Coroutines & Flow](#coroutines)
|
|
16
|
+
6. [Compose UI](#compose)
|
|
17
|
+
7. [Anti-patterns specific to Kotlin](#antipatterns)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Collections & Data Transformation {#collections}
|
|
22
|
+
|
|
23
|
+
**Prefer scope functions and stdlib transforms over imperative loops.**
|
|
24
|
+
|
|
25
|
+
```kotlin
|
|
26
|
+
// ❌ Verbose
|
|
27
|
+
val result = mutableListOf<String>()
|
|
28
|
+
for (item in items) {
|
|
29
|
+
if (item.isActive) {
|
|
30
|
+
result.add(item.name.uppercase())
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ✅ Idiomatic
|
|
35
|
+
val result = items.filter { it.isActive }.map { it.name.uppercase() }
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```kotlin
|
|
39
|
+
// ❌ Manual grouping
|
|
40
|
+
val map = mutableMapOf<String, MutableList<Item>>()
|
|
41
|
+
for (item in items) {
|
|
42
|
+
map.getOrPut(item.category) { mutableListOf() }.add(item)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ✅
|
|
46
|
+
val map = items.groupBy { it.category }
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```kotlin
|
|
50
|
+
// ❌ Manual fold
|
|
51
|
+
var total = 0
|
|
52
|
+
for (order in orders) total += order.amount
|
|
53
|
+
|
|
54
|
+
// ✅
|
|
55
|
+
val total = orders.sumOf { it.amount }
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Use `associate`, `associateBy`, `partition`, `flatMap`, `zip` instead of manual equivalents.**
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 2. Null Safety {#null-safety}
|
|
63
|
+
|
|
64
|
+
```kotlin
|
|
65
|
+
// ❌ Unnecessary null check when Elvis suffices
|
|
66
|
+
val name: String
|
|
67
|
+
if (user?.name != null) {
|
|
68
|
+
name = user.name
|
|
69
|
+
} else {
|
|
70
|
+
name = "Guest"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ✅
|
|
74
|
+
val name = user?.name ?: "Guest"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```kotlin
|
|
78
|
+
// ❌ Double null check
|
|
79
|
+
if (response != null && response.body != null) {
|
|
80
|
+
process(response.body!!)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ✅
|
|
84
|
+
response?.body?.let { process(it) }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```kotlin
|
|
88
|
+
// ❌ !! without guard
|
|
89
|
+
val value = nullable!!.doSomething()
|
|
90
|
+
|
|
91
|
+
// ✅ Make the non-null contract explicit at the boundary
|
|
92
|
+
val value = requireNotNull(nullable) { "nullable must be set before calling X" }.doSomething()
|
|
93
|
+
// Or return early:
|
|
94
|
+
val n = nullable ?: return
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 3. Functions & Lambdas {#functions}
|
|
100
|
+
|
|
101
|
+
```kotlin
|
|
102
|
+
// ❌ Single-expression function with unnecessary block body
|
|
103
|
+
fun double(x: Int): Int {
|
|
104
|
+
return x * 2
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ✅
|
|
108
|
+
fun double(x: Int) = x * 2
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
```kotlin
|
|
112
|
+
// ❌ Lambda capturing unused parameter
|
|
113
|
+
items.forEach { item -> doSomething() }
|
|
114
|
+
|
|
115
|
+
// ✅
|
|
116
|
+
items.forEach { doSomething() }
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```kotlin
|
|
120
|
+
// ❌ Redundant with/apply nesting
|
|
121
|
+
val builder = Builder()
|
|
122
|
+
builder.setName("x")
|
|
123
|
+
builder.setAge(1)
|
|
124
|
+
val result = builder.build()
|
|
125
|
+
|
|
126
|
+
// ✅
|
|
127
|
+
val result = Builder().apply {
|
|
128
|
+
setName("x")
|
|
129
|
+
setAge(1)
|
|
130
|
+
}.build()
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Prefer `let`, `run`, `apply`, `also`, `with` over repeated receiver references — but don't nest more than 2 levels deep.**
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 4. Classes & Objects {#classes}
|
|
138
|
+
|
|
139
|
+
```kotlin
|
|
140
|
+
// ❌ Mutable class for immutable data
|
|
141
|
+
class Point {
|
|
142
|
+
var x: Int = 0
|
|
143
|
+
var y: Int = 0
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ✅
|
|
147
|
+
data class Point(val x: Int, val y: Int)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```kotlin
|
|
151
|
+
// ❌ Companion object just to hold a constant
|
|
152
|
+
class Foo {
|
|
153
|
+
companion object {
|
|
154
|
+
val TAG = "Foo"
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ✅ — top-level if only used in this file
|
|
159
|
+
private const val TAG = "Foo"
|
|
160
|
+
class Foo
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
```kotlin
|
|
164
|
+
// ❌ Enum with when that has to be updated in two places
|
|
165
|
+
enum class Status { ACTIVE, INACTIVE }
|
|
166
|
+
fun label(s: Status) = when(s) { Status.ACTIVE -> "Active"; Status.INACTIVE -> "Inactive" }
|
|
167
|
+
|
|
168
|
+
// ✅ — put display logic on the enum itself
|
|
169
|
+
enum class Status(val label: String) { ACTIVE("Active"), INACTIVE("Inactive") }
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Sealed classes/interfaces over enum when variants carry different data.**
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## 5. Coroutines & Flow {#coroutines}
|
|
177
|
+
|
|
178
|
+
```kotlin
|
|
179
|
+
// ❌ Unnecessary async/await pair when result is used immediately
|
|
180
|
+
val result = async { fetchData() }.await()
|
|
181
|
+
|
|
182
|
+
// ✅
|
|
183
|
+
val result = fetchData() // just suspend fun, no async needed
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
```kotlin
|
|
187
|
+
// ❌ Collecting in a loop
|
|
188
|
+
while (true) {
|
|
189
|
+
val value = channel.receive()
|
|
190
|
+
process(value)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ✅
|
|
194
|
+
channel.consumeEach { process(it) }
|
|
195
|
+
// or for Flow:
|
|
196
|
+
flow.collect { process(it) }
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
```kotlin
|
|
200
|
+
// ❌ StateFlow + manual emit boilerplate
|
|
201
|
+
private val _state = MutableStateFlow(initial)
|
|
202
|
+
val state: StateFlow<State> = _state
|
|
203
|
+
// ... in many places: _state.value = newValue
|
|
204
|
+
|
|
205
|
+
// ✅ — use update{} for atomic mutation
|
|
206
|
+
_state.update { it.copy(field = newValue) }
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Don't launch coroutines in constructors or init blocks. Don't use GlobalScope.**
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 6. Compose UI {#compose}
|
|
214
|
+
|
|
215
|
+
```kotlin
|
|
216
|
+
// ❌ Unnecessary remember for derived state that's cheap to compute
|
|
217
|
+
val displayName = remember { user.firstName + " " + user.lastName }
|
|
218
|
+
|
|
219
|
+
// ✅ — only remember if computation is expensive or involves object creation
|
|
220
|
+
val displayName = "${user.firstName} ${user.lastName}"
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
```kotlin
|
|
224
|
+
// ❌ Passing entire state object when composable only needs one field
|
|
225
|
+
@Composable
|
|
226
|
+
fun UserBadge(user: User) { Text(user.name) }
|
|
227
|
+
|
|
228
|
+
// ✅ — pass only what's needed (stability + minimal recomposition)
|
|
229
|
+
@Composable
|
|
230
|
+
fun UserBadge(name: String) { Text(name) }
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```kotlin
|
|
234
|
+
// ❌ Inline click handler lambda (creates new instance each recomposition)
|
|
235
|
+
Button(onClick = { viewModel.onSave() }) { ... }
|
|
236
|
+
|
|
237
|
+
// ✅
|
|
238
|
+
val onSave = remember { { viewModel.onSave() } }
|
|
239
|
+
Button(onClick = onSave) { ... }
|
|
240
|
+
// Or pass it down as a parameter already
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
```kotlin
|
|
244
|
+
// ❌ Nested Column/Row just to group children
|
|
245
|
+
Column {
|
|
246
|
+
Column {
|
|
247
|
+
Text("a")
|
|
248
|
+
Text("b")
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ✅
|
|
253
|
+
Column {
|
|
254
|
+
Text("a")
|
|
255
|
+
Text("b")
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Use `LazyColumn`/`LazyRow` for lists of unknown or large size. Never put a `LazyColumn` inside a `Column` with unbounded height.**
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## 7. Anti-patterns specific to Kotlin {#antipatterns}
|
|
264
|
+
|
|
265
|
+
| Anti-pattern | Preferred |
|
|
266
|
+
|---|---|
|
|
267
|
+
| `if (x == true)` | `if (x)` |
|
|
268
|
+
| `if (x == null) return else x!!` | `val x = x ?: return` |
|
|
269
|
+
| `listOf().toMutableList()` for a known-size list | `mutableListOf()` |
|
|
270
|
+
| `when` with a single branch and else | `if/else` |
|
|
271
|
+
| `.toString()` on a string | remove it |
|
|
272
|
+
| Explicit `Unit` return type on functions | omit (inferred) |
|
|
273
|
+
| `object : Runnable { override fun run() { ... } }` | `Runnable { ... }` (SAM) |
|
|
274
|
+
| `@JvmStatic` in pure Kotlin code | only needed for Java interop |
|
|
275
|
+
| Wrapping every function in try/catch to log | handle at the boundary, not inside |
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
## Limitations
|
|
280
|
+
- These are language-specific guidelines and do not cover overall architectural decisions.
|
|
281
|
+
- Over-compression might reduce readability; apply judgement.
|