@ranimontagna/agent-toolkit 0.1.6 → 0.1.9
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/README.md +83 -10
- package/package.json +1 -1
- package/skills/backend/database/postgres-patterns/LICENSE.ANTIGRAVITY +21 -0
- package/skills/backend/database/postgres-patterns/LICENSE.ECC +21 -0
- package/skills/backend/database/postgres-patterns/NOTICE.md +11 -0
- package/skills/backend/database/postgres-patterns/SKILL.md +180 -0
- package/skills/backend/go/golang-patterns/LICENSE +21 -0
- package/skills/backend/go/golang-patterns/NOTICE.md +10 -0
- package/skills/backend/go/golang-patterns/SKILL.md +674 -0
- package/skills/backend/go/golang-testing/LICENSE +21 -0
- package/skills/backend/go/golang-testing/NOTICE.md +10 -0
- package/skills/backend/go/golang-testing/SKILL.md +329 -0
- package/skills/backend/java/java-coding-standards/LICENSE +21 -0
- package/skills/backend/java/java-coding-standards/NOTICE.md +10 -0
- package/skills/backend/java/java-coding-standards/SKILL.md +383 -0
- package/skills/backend/java/java-junit/LICENSE +21 -0
- package/skills/backend/java/java-junit/NOTICE.md +10 -0
- package/skills/backend/java/java-junit/SKILL.md +64 -0
- package/skills/backend/kotlin/kotlin-patterns/LICENSE +21 -0
- package/skills/backend/kotlin/kotlin-patterns/NOTICE.md +7 -0
- package/skills/backend/kotlin/kotlin-patterns/SKILL.md +711 -0
- package/skills/backend/kotlin/kotlin-testing/LICENSE +21 -0
- package/skills/backend/kotlin/kotlin-testing/NOTICE.md +7 -0
- package/skills/backend/kotlin/kotlin-testing/SKILL.md +824 -0
- package/skills/backend/python/python-patterns/LICENSE +21 -0
- package/skills/backend/python/python-patterns/NOTICE.md +7 -0
- package/skills/backend/python/python-patterns/SKILL.md +424 -0
- package/skills/backend/python/python-testing/LICENSE +21 -0
- package/skills/backend/python/python-testing/NOTICE.md +7 -0
- package/skills/backend/python/python-testing/SKILL.md +494 -0
- package/skills/devops/docker-patterns/LICENSE.ANTIGRAVITY +21 -0
- package/skills/devops/docker-patterns/LICENSE.ECC +21 -0
- package/skills/devops/docker-patterns/NOTICE.md +11 -0
- package/skills/devops/docker-patterns/SKILL.md +397 -0
- package/skills/frontend/accessibility/LICENSE +21 -0
- package/skills/frontend/accessibility/NOTICE.md +10 -0
- package/skills/frontend/accessibility/SKILL.md +145 -0
- package/skills/frontend/design/ui-ux-pro-max/LICENSE +21 -0
- package/skills/frontend/design/ui-ux-pro-max/NOTICE.md +12 -0
- package/skills/frontend/design/ui-ux-pro-max/SKILL.md +672 -0
- package/skills/frontend/design/ui-ux-pro-max/data/_sync_all.py +414 -0
- package/skills/frontend/design/ui-ux-pro-max/data/app-interface.csv +31 -0
- package/skills/frontend/design/ui-ux-pro-max/data/charts.csv +26 -0
- package/skills/frontend/design/ui-ux-pro-max/data/colors.csv +162 -0
- package/skills/frontend/design/ui-ux-pro-max/data/design.csv +1776 -0
- package/skills/frontend/design/ui-ux-pro-max/data/draft.csv +1779 -0
- package/skills/frontend/design/ui-ux-pro-max/data/google-fonts.csv +1924 -0
- package/skills/frontend/design/ui-ux-pro-max/data/icons.csv +106 -0
- package/skills/frontend/design/ui-ux-pro-max/data/landing.csv +35 -0
- package/skills/frontend/design/ui-ux-pro-max/data/products.csv +162 -0
- package/skills/frontend/design/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/angular.csv +51 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/laravel.csv +51 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/threejs.csv +54 -0
- package/skills/frontend/design/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills/frontend/design/ui-ux-pro-max/data/styles.csv +85 -0
- package/skills/frontend/design/ui-ux-pro-max/data/typography.csv +74 -0
- package/skills/frontend/design/ui-ux-pro-max/data/ui-reasoning.csv +162 -0
- package/skills/frontend/design/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills/frontend/design/ui-ux-pro-max/scripts/core.py +262 -0
- package/skills/frontend/design/ui-ux-pro-max/scripts/design_system.py +1148 -0
- package/skills/frontend/design/ui-ux-pro-max/scripts/search.py +114 -0
- package/skills/frontend/react/react-patterns/SKILL.md +4 -4
- package/skills/frontend/react/react-patterns/rules/react/LICENSE +21 -0
- package/skills/frontend/react/react-patterns/rules/react/NOTICE.md +11 -0
- package/skills/frontend/react/react-patterns/rules/react/coding-style.md +109 -0
- package/skills/frontend/react/react-patterns/rules/react/hooks.md +187 -0
- package/skills/frontend/react/react-patterns/rules/react/patterns.md +194 -0
- package/skills/frontend/react/react-patterns/rules/react/security.md +180 -0
- package/skills/frontend/react/react-patterns/rules/react/testing.md +208 -0
- package/skills/frontend/react/react-performance/SKILL.md +2 -2
- package/skills/frontend/react/react-performance/rules/react/LICENSE +21 -0
- package/skills/frontend/react/react-performance/rules/react/NOTICE.md +11 -0
- package/skills/frontend/react/react-performance/rules/react/coding-style.md +109 -0
- package/skills/frontend/react/react-performance/rules/react/hooks.md +187 -0
- package/skills/frontend/react/react-performance/rules/react/patterns.md +194 -0
- package/skills/frontend/react/react-performance/rules/react/security.md +180 -0
- package/skills/frontend/react/react-performance/rules/react/testing.md +208 -0
- package/skills/frontend/react/react-testing/SKILL.md +4 -4
- package/skills/frontend/react/react-testing/rules/react/LICENSE +21 -0
- package/skills/frontend/react/react-testing/rules/react/NOTICE.md +11 -0
- package/skills/frontend/react/react-testing/rules/react/coding-style.md +109 -0
- package/skills/frontend/react/react-testing/rules/react/hooks.md +187 -0
- package/skills/frontend/react/react-testing/rules/react/patterns.md +194 -0
- package/skills/frontend/react/react-testing/rules/react/security.md +180 -0
- package/skills/frontend/react/react-testing/rules/react/testing.md +208 -0
- package/skills/general/code-reviewer/AGENTS.md +292 -0
- package/skills/general/code-reviewer/LICENSE +201 -0
- package/skills/general/code-reviewer/NOTICE.md +10 -0
- package/skills/general/code-reviewer/SKILL.md +132 -0
- package/skills/general/code-reviewer/rules/correctness-error-handling.md +279 -0
- package/skills/general/code-reviewer/rules/maintainability-naming.md +149 -0
- package/skills/general/code-reviewer/rules/maintainability-type-hints.md +93 -0
- package/skills/general/code-reviewer/rules/performance-n-plus-one.md +250 -0
- package/skills/general/code-reviewer/rules/security-sql-injection.md +142 -0
- package/skills/general/code-reviewer/rules/security-xss-prevention.md +225 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Proper Error Handling
|
|
3
|
+
impact: HIGH
|
|
4
|
+
category: correctness
|
|
5
|
+
tags: errors, exceptions, reliability
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Proper Error Handling
|
|
9
|
+
|
|
10
|
+
Always handle errors explicitly. Don't use bare except clauses or ignore errors silently. Provide helpful error messages.
|
|
11
|
+
|
|
12
|
+
## Why This Matters
|
|
13
|
+
|
|
14
|
+
Proper error handling:
|
|
15
|
+
- Prevents silent failures
|
|
16
|
+
- Aids debugging with clear messages
|
|
17
|
+
- Allows graceful degradation
|
|
18
|
+
- Improves user experience
|
|
19
|
+
- Enables error monitoring/alerting
|
|
20
|
+
|
|
21
|
+
## ❌ Incorrect
|
|
22
|
+
|
|
23
|
+
### Bare Except Clause
|
|
24
|
+
```python
|
|
25
|
+
# ❌ Catches everything, including KeyboardInterrupt, SystemExit
|
|
26
|
+
try:
|
|
27
|
+
result = risky_operation()
|
|
28
|
+
except:
|
|
29
|
+
pass # Silent failure, no idea what went wrong
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Generic Exception Without Context
|
|
33
|
+
```python
|
|
34
|
+
# ❌ Too generic, loses error information
|
|
35
|
+
try:
|
|
36
|
+
data = fetch_user(user_id)
|
|
37
|
+
process(data)
|
|
38
|
+
save_result()
|
|
39
|
+
except Exception:
|
|
40
|
+
print("Error occurred") # Which operation failed? Why?
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Ignoring Specific Errors
|
|
44
|
+
```python
|
|
45
|
+
# ❌ Ignoring errors entirely
|
|
46
|
+
try:
|
|
47
|
+
config = json.loads(config_file.read())
|
|
48
|
+
except json.JSONDecodeError:
|
|
49
|
+
pass # App continues with undefined 'config'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## ✅ Correct
|
|
53
|
+
|
|
54
|
+
### Catch Specific Exceptions
|
|
55
|
+
```python
|
|
56
|
+
# ✅ Handle specific errors appropriately
|
|
57
|
+
try:
|
|
58
|
+
config = json.loads(config_file.read())
|
|
59
|
+
except json.JSONDecodeError as e:
|
|
60
|
+
logger.error(f"Invalid JSON in config file: {e}")
|
|
61
|
+
# Provide sensible default
|
|
62
|
+
config = get_default_config()
|
|
63
|
+
except FileNotFoundError:
|
|
64
|
+
logger.warning("Config file not found, using defaults")
|
|
65
|
+
config = get_default_config()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Provide Context in Error Messages
|
|
69
|
+
```python
|
|
70
|
+
# ✅ Clear, actionable error messages
|
|
71
|
+
def get_user(user_id: int) -> User:
|
|
72
|
+
try:
|
|
73
|
+
response = requests.get(f"{API_URL}/users/{user_id}", timeout=5)
|
|
74
|
+
response.raise_for_status()
|
|
75
|
+
return User(**response.json())
|
|
76
|
+
except requests.Timeout:
|
|
77
|
+
raise ValueError(
|
|
78
|
+
f"Timeout fetching user {user_id} from {API_URL}. "
|
|
79
|
+
"Check network connection or increase timeout."
|
|
80
|
+
)
|
|
81
|
+
except requests.HTTPError as e:
|
|
82
|
+
if e.response.status_code == 404:
|
|
83
|
+
raise UserNotFoundError(f"User {user_id} does not exist")
|
|
84
|
+
raise ValueError(f"HTTP error fetching user {user_id}: {e}")
|
|
85
|
+
except json.JSONDecodeError:
|
|
86
|
+
raise ValueError(f"Invalid JSON response for user {user_id}")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Re-raise with Context
|
|
90
|
+
```python
|
|
91
|
+
# ✅ Add context while preserving stack trace
|
|
92
|
+
try:
|
|
93
|
+
process_batch(items)
|
|
94
|
+
except ValidationError as e:
|
|
95
|
+
# Add context and re-raise
|
|
96
|
+
raise ValidationError(
|
|
97
|
+
f"Batch processing failed for {len(items)} items: {e}"
|
|
98
|
+
) from e
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## JavaScript/TypeScript
|
|
102
|
+
|
|
103
|
+
### ❌ Catching Without Specificity
|
|
104
|
+
```javascript
|
|
105
|
+
// ❌ No error handling
|
|
106
|
+
async function fetchUser(id) {
|
|
107
|
+
const response = await fetch(`/api/users/${id}`);
|
|
108
|
+
return response.json(); // What if fetch fails? What if not JSON?
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ❌ Generic catch
|
|
112
|
+
try {
|
|
113
|
+
const user = await fetchUser(id);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.log('Error'); // Which error? From where?
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### ✅ Explicit Error Handling
|
|
120
|
+
```typescript
|
|
121
|
+
// ✅ Proper error handling with types
|
|
122
|
+
class UserNotFoundError extends Error {
|
|
123
|
+
constructor(userId: string) {
|
|
124
|
+
super(`User ${userId} not found`);
|
|
125
|
+
this.name = 'UserNotFoundError';
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function fetchUser(id: string): Promise<User> {
|
|
130
|
+
let response: Response;
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
response = await fetch(`/api/users/${id}`, {
|
|
134
|
+
signal: AbortSignal.timeout(5000)
|
|
135
|
+
});
|
|
136
|
+
} catch (error) {
|
|
137
|
+
if (error instanceof DOMException && error.name === 'TimeoutError') {
|
|
138
|
+
throw new Error(`Timeout fetching user ${id}`);
|
|
139
|
+
}
|
|
140
|
+
throw new Error(`Network error fetching user ${id}: ${error}`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!response.ok) {
|
|
144
|
+
if (response.status === 404) {
|
|
145
|
+
throw new UserNotFoundError(id);
|
|
146
|
+
}
|
|
147
|
+
throw new Error(`HTTP ${response.status} fetching user ${id}`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
return await response.json();
|
|
152
|
+
} catch (error) {
|
|
153
|
+
throw new Error(`Invalid JSON response for user ${id}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Usage
|
|
158
|
+
try {
|
|
159
|
+
const user = await fetchUser(userId);
|
|
160
|
+
displayUser(user);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (error instanceof UserNotFoundError) {
|
|
163
|
+
showNotFoundMessage();
|
|
164
|
+
} else {
|
|
165
|
+
logger.error('Failed to load user:', error);
|
|
166
|
+
showErrorMessage('Unable to load user. Please try again.');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Error Handling Patterns
|
|
172
|
+
|
|
173
|
+
### Result Type (Rust-inspired)
|
|
174
|
+
```typescript
|
|
175
|
+
type Result<T, E = Error> =
|
|
176
|
+
| { ok: true; value: T }
|
|
177
|
+
| { ok: false; error: E };
|
|
178
|
+
|
|
179
|
+
function parseConfig(json: string): Result<Config> {
|
|
180
|
+
try {
|
|
181
|
+
const config = JSON.parse(json);
|
|
182
|
+
return { ok: true, value: config };
|
|
183
|
+
} catch (error) {
|
|
184
|
+
return { ok: false, error: new Error(`Invalid config: ${error}`) };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Usage
|
|
189
|
+
const result = parseConfig(configString);
|
|
190
|
+
if (result.ok) {
|
|
191
|
+
useConfig(result.value);
|
|
192
|
+
} else {
|
|
193
|
+
logger.error(result.error);
|
|
194
|
+
useDefaultConfig();
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Custom Error Classes
|
|
199
|
+
```python
|
|
200
|
+
class DatabaseError(Exception):
|
|
201
|
+
"""Base class for database errors."""
|
|
202
|
+
pass
|
|
203
|
+
|
|
204
|
+
class ConnectionError(DatabaseError):
|
|
205
|
+
"""Database connection failed."""
|
|
206
|
+
pass
|
|
207
|
+
|
|
208
|
+
class QueryError(DatabaseError):
|
|
209
|
+
"""Query execution failed."""
|
|
210
|
+
def __init__(self, query: str, original_error: Exception):
|
|
211
|
+
self.query = query
|
|
212
|
+
self.original_error = original_error
|
|
213
|
+
super().__init__(f"Query failed: {query[:100]}... Error: {original_error}")
|
|
214
|
+
|
|
215
|
+
# Usage
|
|
216
|
+
try:
|
|
217
|
+
db.execute(query)
|
|
218
|
+
except psycopg2.OperationalError as e:
|
|
219
|
+
raise ConnectionError(f"Cannot connect to database: {e}") from e
|
|
220
|
+
except psycopg2.Error as e:
|
|
221
|
+
raise QueryError(query, e) from e
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Logging Errors
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
import logging
|
|
228
|
+
|
|
229
|
+
logger = logging.getLogger(__name__)
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
result = complex_operation()
|
|
233
|
+
except ValueError as e:
|
|
234
|
+
logger.error(
|
|
235
|
+
"Operation failed",
|
|
236
|
+
exc_info=True, # Include stack trace
|
|
237
|
+
extra={
|
|
238
|
+
'user_id': user_id,
|
|
239
|
+
'operation': 'complex_operation',
|
|
240
|
+
'input_data': sanitized_data
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
raise
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Best Practices
|
|
247
|
+
|
|
248
|
+
- [ ] **Catch specific exceptions** (not bare `except` or generic `Exception`)
|
|
249
|
+
- [ ] **Provide context** in error messages (what failed, why, how to fix)
|
|
250
|
+
- [ ] **Log errors** with relevant details
|
|
251
|
+
- [ ] **Don't silently ignore errors**
|
|
252
|
+
- [ ] **Use custom exception classes** for domain errors
|
|
253
|
+
- [ ] **Include stack traces** in logs (but not user-facing messages)
|
|
254
|
+
- [ ] **Handle errors at appropriate level** (don't catch too early)
|
|
255
|
+
- [ ] **Clean up resources** (use context managers/try-finally)
|
|
256
|
+
|
|
257
|
+
## Monitoring & Alerting
|
|
258
|
+
|
|
259
|
+
```python
|
|
260
|
+
# Integration with error tracking
|
|
261
|
+
import sentry_sdk
|
|
262
|
+
|
|
263
|
+
try:
|
|
264
|
+
process_payment(order)
|
|
265
|
+
except PaymentError as e:
|
|
266
|
+
sentry_sdk.capture_exception(e)
|
|
267
|
+
sentry_sdk.set_context("order", {
|
|
268
|
+
"order_id": order.id,
|
|
269
|
+
"amount": order.total,
|
|
270
|
+
"user_id": order.user_id
|
|
271
|
+
})
|
|
272
|
+
raise
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## References
|
|
276
|
+
|
|
277
|
+
- [Python Exception Handling Best Practices](https://docs.python.org/3/tutorial/errors.html)
|
|
278
|
+
- [Error Handling in JavaScript](https://javascript.info/try-catch)
|
|
279
|
+
- [Sentry Error Monitoring](https://sentry.io/)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Meaningful Variable Names
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
category: maintainability
|
|
5
|
+
tags: naming, readability, code-quality
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Use Meaningful Variable Names
|
|
9
|
+
|
|
10
|
+
Choose descriptive, intention-revealing names. Avoid single letters (except loop counters), abbreviations, and generic names.
|
|
11
|
+
|
|
12
|
+
## Why This Matters
|
|
13
|
+
|
|
14
|
+
Code is read 10x more than it's written. Clear names:
|
|
15
|
+
- Make code self-documenting
|
|
16
|
+
- Reduce cognitive load
|
|
17
|
+
- Prevent bugs from misunderstanding
|
|
18
|
+
- Enable easier refactoring
|
|
19
|
+
|
|
20
|
+
## ❌ Incorrect
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
# ❌ Cryptic, meaningless
|
|
24
|
+
def calc(x, y, z):
|
|
25
|
+
tmp = x * y
|
|
26
|
+
res = tmp + z
|
|
27
|
+
return res
|
|
28
|
+
|
|
29
|
+
# ❌ Too generic
|
|
30
|
+
data = fetch_data()
|
|
31
|
+
result = process(data)
|
|
32
|
+
output = format(result)
|
|
33
|
+
|
|
34
|
+
# ❌ Confusing abbreviations
|
|
35
|
+
usr_nm = input()
|
|
36
|
+
acc_bal = get_bal(usr_nm)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## ✅ Correct
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
# ✅ Clear, descriptive
|
|
43
|
+
def calculate_total_price(item_price: float, quantity: int, tax_rate: float) -> float:
|
|
44
|
+
"""Calculate total price including tax."""
|
|
45
|
+
subtotal = item_price * quantity
|
|
46
|
+
total_with_tax = subtotal + (subtotal * tax_rate)
|
|
47
|
+
return total_with_tax
|
|
48
|
+
|
|
49
|
+
# ✅ Intention-revealing
|
|
50
|
+
customer_orders = fetch_customer_orders(customer_id)
|
|
51
|
+
validated_orders = validate_orders(customer_orders)
|
|
52
|
+
order_confirmation_email = format_confirmation_email(validated_orders)
|
|
53
|
+
|
|
54
|
+
# ✅ Full words
|
|
55
|
+
username = input("Enter username: ")
|
|
56
|
+
account_balance = get_account_balance(username)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Naming Conventions by Language
|
|
60
|
+
|
|
61
|
+
### Python (PEP 8)
|
|
62
|
+
```python
|
|
63
|
+
# Variables & functions: snake_case
|
|
64
|
+
user_count = 10
|
|
65
|
+
def calculate_average(): pass
|
|
66
|
+
|
|
67
|
+
# Classes: PascalCase
|
|
68
|
+
class UserAccount: pass
|
|
69
|
+
|
|
70
|
+
# Constants: UPPER_SNAKE_CASE
|
|
71
|
+
MAX_RETRY_ATTEMPTS = 3
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### JavaScript/TypeScript
|
|
75
|
+
```javascript
|
|
76
|
+
// Variables & functions: camelCase
|
|
77
|
+
const userCount = 10;
|
|
78
|
+
function calculateAverage() {}
|
|
79
|
+
|
|
80
|
+
// Classes: PascalCase
|
|
81
|
+
class UserAccount {}
|
|
82
|
+
|
|
83
|
+
// Constants: UPPER_SNAKE_CASE or camelCase
|
|
84
|
+
const MAX_RETRY_ATTEMPTS = 3;
|
|
85
|
+
const maxRetryAttempts = 3; // Also acceptable
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Booleans
|
|
89
|
+
```python
|
|
90
|
+
# Use is_, has_, can_ prefixes
|
|
91
|
+
is_active = True
|
|
92
|
+
has_permission = check_permission()
|
|
93
|
+
can_edit = user.role == "admin"
|
|
94
|
+
|
|
95
|
+
# Not: active, permission, editable
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Context Matters
|
|
99
|
+
|
|
100
|
+
### Loop Variables
|
|
101
|
+
```python
|
|
102
|
+
# ❌ Generic in complex loop
|
|
103
|
+
for i in users:
|
|
104
|
+
for j in i.orders:
|
|
105
|
+
process(j)
|
|
106
|
+
|
|
107
|
+
# ✅ Descriptive
|
|
108
|
+
for user in users:
|
|
109
|
+
for order in user.orders:
|
|
110
|
+
process_order(order)
|
|
111
|
+
|
|
112
|
+
# ✅ Single letter OK for simple index
|
|
113
|
+
for i in range(10):
|
|
114
|
+
print(i)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Scope-Appropriate Names
|
|
118
|
+
```python
|
|
119
|
+
# Short scope: concise OK
|
|
120
|
+
def validate(email):
|
|
121
|
+
# 'email' is clear in this small function
|
|
122
|
+
return '@' in email and '.' in email
|
|
123
|
+
|
|
124
|
+
# Long scope: more descriptive
|
|
125
|
+
class UserAuthenticationService:
|
|
126
|
+
def __init__(self):
|
|
127
|
+
# Longer, clearer for class-level
|
|
128
|
+
self.failed_login_attempts = {}
|
|
129
|
+
self.account_lockout_duration_seconds = 300
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Avoid Ambiguity
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
# ❌ Ambiguous
|
|
136
|
+
def get_data(id):
|
|
137
|
+
return data[id]
|
|
138
|
+
|
|
139
|
+
# What data? What ID?
|
|
140
|
+
|
|
141
|
+
# ✅ Specific
|
|
142
|
+
def get_user_by_id(user_id: int) -> User:
|
|
143
|
+
return users_cache[user_id]
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## References
|
|
147
|
+
|
|
148
|
+
- [PEP 8 - Python Naming Conventions](https://peps.python.org/pep-0008/#naming-conventions)
|
|
149
|
+
- [Clean Code by Robert Martin](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Add Type Hints
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
category: maintainability
|
|
5
|
+
tags: types, python, typescript, type-safety
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Add Type Hints
|
|
9
|
+
|
|
10
|
+
Use type annotations to make code self-documenting and catch errors early.
|
|
11
|
+
|
|
12
|
+
## Why This Matters
|
|
13
|
+
|
|
14
|
+
Type hints provide:
|
|
15
|
+
- **Static analysis** - catch bugs before runtime
|
|
16
|
+
- **Better IDE support** - autocomplete, refactoring
|
|
17
|
+
- **Documentation** - types explain intent
|
|
18
|
+
- **Confidence** - easier refactoring
|
|
19
|
+
|
|
20
|
+
##❌ Incorrect
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
# ❌ No type hints
|
|
24
|
+
def get_user(id):
|
|
25
|
+
return users.get(id)
|
|
26
|
+
|
|
27
|
+
def process_order(order, discount):
|
|
28
|
+
if discount:
|
|
29
|
+
return order['total'] * (1 - discount)
|
|
30
|
+
return order['total']
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## ✅ Correct
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
# ✅ Full type hints
|
|
37
|
+
from typing import Optional, Dict, Any
|
|
38
|
+
|
|
39
|
+
def get_user(id: int) -> Optional[Dict[str, Any]]:
|
|
40
|
+
"""Fetch user by ID.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
id: User ID
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
User dict or None if not found
|
|
47
|
+
"""
|
|
48
|
+
return users.get(id)
|
|
49
|
+
|
|
50
|
+
def process_order(order: Dict[str, Any], discount: Optional[float] = None) -> float:
|
|
51
|
+
"""Calculate order total with optional discount.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
order: Order dictionary with 'total' key
|
|
55
|
+
discount: Discount rate (0.0-1.0), e.g. 0.1 for 10% off
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Final price after discount
|
|
59
|
+
"""
|
|
60
|
+
if discount:
|
|
61
|
+
return order['total'] * (1 - discount)
|
|
62
|
+
return order['total']
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## TypeScript
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// ✅ Explicit types
|
|
69
|
+
interface User {
|
|
70
|
+
id: number;
|
|
71
|
+
name: string;
|
|
72
|
+
email: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getUser(id: number): User | null {
|
|
76
|
+
return users.get(id) ?? null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function processOrder(
|
|
80
|
+
order: { total: number },
|
|
81
|
+
discount?: number
|
|
82
|
+
): number {
|
|
83
|
+
if (discount) {
|
|
84
|
+
return order.total * (1 - discount);
|
|
85
|
+
}
|
|
86
|
+
return order.total;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## References
|
|
91
|
+
|
|
92
|
+
- [Python Type Hints](https://docs.python.org/3/library/typing.html)
|
|
93
|
+
- [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html)
|