@sun-asterisk/sunlint 1.3.40 → 1.3.42
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/core/rule-selection-service.js +11 -0
- package/package.json +1 -1
- package/skill-assets/sunlint-code-quality/rules/dart/D001-recommended-lints.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D002-dispose-resources.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D003-prefer-widget-classes.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D004-avoid-shrinkwrap.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D005-widget-nesting.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D006-large-callbacks.md +54 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D007-lifecycle-order.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D008-long-functions.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D009-function-parameters.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D010-cyclomatic-complexity.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D011-named-parameters.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D012-named-booleans.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D013-single-public-class.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D014-safe-collection-access.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D015-copywith-consistency.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D016-project-tests.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D017-review-dependencies.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D018-no-commented-code.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D019-single-child-wrappers.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D020-if-else-limit.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D021-negated-booleans.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D022-setstate-usage.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D023-unnecessary-overrides.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D024-avoid-unnecessary-statefulwidget.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/dart/D025-nested-ternaries.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/go/C006-verb-noun-functions.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/go/C013-no-dead-code.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/go/C014-dependency-injection.md +85 -0
- package/skill-assets/sunlint-code-quality/rules/go/C017-no-constructor-logic.md +67 -0
- package/skill-assets/sunlint-code-quality/rules/go/C018-generic-errors.md +63 -0
- package/skill-assets/sunlint-code-quality/rules/go/C019-error-log-level.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/go/C020-no-unused-imports.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/go/C022-no-unused-variables.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/go/C023-no-duplicate-names.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/go/C024-centralize-constants.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/go/C029-catch-log-root-cause.md +56 -0
- package/skill-assets/sunlint-code-quality/rules/go/C030-custom-error-classes.md +69 -0
- package/skill-assets/sunlint-code-quality/rules/go/C033-separate-data-access.md +68 -0
- package/skill-assets/sunlint-code-quality/rules/go/C035-error-context-logging.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/go/C041-no-hardcoded-secrets.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/go/C042-boolean-naming.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/go/C052-controller-parsing.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/go/C060-superclass-logic.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/go/C067-no-hardcoded-config.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/go/S003-open-redirect.md +80 -0
- package/skill-assets/sunlint-code-quality/rules/go/S004-no-log-credentials.md +66 -0
- package/skill-assets/sunlint-code-quality/rules/go/S005-server-authorization.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/go/S006-default-credentials.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/go/S007-output-encoding.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/go/S009-approved-crypto.md +63 -0
- package/skill-assets/sunlint-code-quality/rules/go/S010-csprng.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S011-encrypted-client-hello.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/go/S012-secrets-management.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/go/S013-tls-connections.md +61 -0
- package/skill-assets/sunlint-code-quality/rules/go/S016-no-sensitive-query-string.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/go/S017-parameterized-queries.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/go/S019-email-input-sanitization.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/go/S020-eval-code-execution.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/go/S022-context-escaping.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/go/S023-dynamic-js-encoding.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/go/S025-server-validation.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/go/S026-tls-encryption.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/go/S027-mtls-validation.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/go/S028-upload-limits.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/go/S029-csrf-protection.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S030-directory-browsing.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S031-secure-cookie-flag.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/go/S032-httponly-cookie.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/go/S033-samesite-cookie.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/go/S034-host-prefix-cookie.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/go/S035-app-hostnames.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/go/S036-internal-file-paths.md +56 -0
- package/skill-assets/sunlint-code-quality/rules/go/S037-anti-cache-headers.md +43 -0
- package/skill-assets/sunlint-code-quality/rules/go/S039-tls-certificate-validation.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/go/S041-logout-invalidation.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/go/S042-long-lived-sessions.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/go/S044-critical-changes-reauth.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S045-brute-force-protection.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/go/S047-oauth-csrf-protection.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/go/S048-oauth-redirect-validation.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/go/S049-auth-code-expiry.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/go/S050-token-entropy.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S051-password-length.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/go/S052-otp-entropy.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/go/S053-generic-error-messages.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/go/S054-no-default-admin.md +43 -0
- package/skill-assets/sunlint-code-quality/rules/go/S055-content-type-validation.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/go/S056-log-injection.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/go/S057-synchronized-time.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/go/S058-ssrf-protection.md +70 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB001-use-snake-case.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB002-use-camel-case.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB003-use-screaming-snake-case.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB004-predicate-methods.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB005-dangerous-methods.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB006-indentation.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB007-line-length.md +25 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB008-rescue-exception.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB009-save-bang.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB010-avoid-n-plus-one.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB011-use-find-each.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB012-sql-injection.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB013-prefer-has-many-through.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB014-dependent-associations.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB015-modern-validations.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB016-thin-controllers.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB017-avoid-fat-models.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB018-service-objects.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB019-avoid-metaprogramming.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB020-use-pluck.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB021-use-size.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB022-order-by-timestamps.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB023-where-missing.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB024-method-length.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB025-parameter-limits.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB026-avoid-deep-nesting.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB027-guard-clauses.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB028-class-length.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB029-meaningful-names.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB030-dry-principle.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB031-mvc-architecture.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB032-use-concerns.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB033-moderate-callbacks.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB034-use-decorators.md +33 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB035-comprehensive-tests.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB036-frozen-string-literal.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB037-it-parameter.md +25 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB038-modern-enum-syntax.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB039-solid-adapters.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB040-rails-authentication.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB041-async-query-loading.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB042-hotwire-turbo.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB043-use-propshaft.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB044-structured-logging.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/ruby/RB045-prism-parser.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW001-block-based-kvo.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW002-class-delegate-protocol.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW003-compiler-protocol-init.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW004-contains-over-filter-count.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW005-convenience-type.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW006-discarded-notification-center-observer.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW007-discouraged-direct-init.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW008-discouraged-optional-boolean.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW009-empty-count.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW010-empty-string.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW011-explicit-init.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW012-fatal-error-message.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW013-for-where.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW014-force-cast.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW015-force-try.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW016-force-unwrapping.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW017-function-parameter-count.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW018-large-tuple.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW019-legacy-constructor.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW020-nesting.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW021-no-extension-access-modifier.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW022-overridden-super-call.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW023-override-in-extension.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW024-private-over-fileprivate.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW025-private-unit-test.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW026-prohibited-super-call.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW027-sorted-first-last.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW028-syntactic-sugar.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW029-unused-closure-parameter.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW030-unused-enumerated.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW031-unused-optional-binding.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW032-valid-ibinspectable.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW033-vertical-parameter-alignment.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW034-void-return.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/swift/SW035-weak-delegate.md +28 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pubspec dependencies should be reviewed regularly
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Ensure dependencies are kept up-to-date for security and stability
|
|
5
|
+
tags: maintenance, security, dependencies
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Pubspec dependencies should be reviewed regularly
|
|
9
|
+
|
|
10
|
+
Dependencies in `pubspec.yaml` should be reviewed and updated regularly (at least every 4 months). Outdated dependencies may contain security vulnerabilities or miss critical performance improvements.
|
|
11
|
+
|
|
12
|
+
**Incorrect (old lock file):**
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
# pubspec.lock last modified: 6 months ago
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Correct (regularly updated):**
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
# run 'flutter pub upgrade' and review dependencies regularly
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Tools:** Custom analyzer (D017)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Remove Commented-Out Code
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Keep codebase clean by removing commented-out code
|
|
5
|
+
tags: cleanliness, readability, maintenance
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Remove Commented-Out Code
|
|
9
|
+
|
|
10
|
+
Commented-out code should be removed instead of being left in the source files. Dead code comments create clutter and confusion. If you need to reference old code, rely on version control (Git).
|
|
11
|
+
|
|
12
|
+
**Incorrect (abandoned code):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
void calculate() {
|
|
16
|
+
final result = 10 + 5;
|
|
17
|
+
// print("Debug result: $result");
|
|
18
|
+
// if (result > 10) {
|
|
19
|
+
// doSomething();
|
|
20
|
+
// }
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Correct (clean file):**
|
|
26
|
+
|
|
27
|
+
```dart
|
|
28
|
+
void calculate() {
|
|
29
|
+
final result = 10 + 5;
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Tools:** Custom analyzer (D018)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Single Child in Multi-Child Widget
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Use appropriate widget types for the number of children
|
|
5
|
+
tags: performance, efficiency, best-practices
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Single Child in Multi-Child Widget
|
|
9
|
+
|
|
10
|
+
Multi-child widgets like `Column`, `Row`, `Stack`, `ListView`, or `GridView` are inefficient when used with only a single child. Use single-child optimized widgets like `SizedBox`, `Padding`, `Center`, or `Container` instead.
|
|
11
|
+
|
|
12
|
+
**Incorrect (inefficient Column):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
Column(
|
|
16
|
+
children: [
|
|
17
|
+
Text("Only one child here"),
|
|
18
|
+
],
|
|
19
|
+
)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (efficient wrapper):**
|
|
23
|
+
|
|
24
|
+
```dart
|
|
25
|
+
Padding(
|
|
26
|
+
padding: const EdgeInsets.all(8.0),
|
|
27
|
+
child: Text("Only one child here"),
|
|
28
|
+
)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Tools:** Custom analyzer (D019)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Limit If/Else Branches
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Reduce complexity by limiting the number of if/else branches
|
|
5
|
+
tags: readability, complexity, clean-code
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Limit If/Else Branches
|
|
9
|
+
|
|
10
|
+
Complex if/else chains with more than 3 branches reduce code readability and increase cyclomatic complexity. When facing multiple branches, consider using `switch` statements, lookup tables (Maps), or the Strategy pattern.
|
|
11
|
+
|
|
12
|
+
**Incorrect (long if/else chain):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
if (type == 'A') {
|
|
16
|
+
doA();
|
|
17
|
+
} else if (type == 'B') {
|
|
18
|
+
doB();
|
|
19
|
+
} else if (type == 'C') {
|
|
20
|
+
doC();
|
|
21
|
+
} else if (type == 'D') {
|
|
22
|
+
doD();
|
|
23
|
+
} else {
|
|
24
|
+
doDefault();
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Correct (using switch or Map):**
|
|
29
|
+
|
|
30
|
+
```dart
|
|
31
|
+
// Option 1: Switch (better readability)
|
|
32
|
+
switch (type) {
|
|
33
|
+
case 'A': doA(); break;
|
|
34
|
+
case 'B': doB(); break;
|
|
35
|
+
case 'C': doC(); break;
|
|
36
|
+
case 'D': doD(); break;
|
|
37
|
+
default: doDefault();
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Tools:** Custom analyzer (D020)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Negated Boolean Checks
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Improve code readability by avoiding inverted or negated boolean conditions
|
|
5
|
+
tags: readability, logic, clean-code
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Negated Boolean Checks
|
|
9
|
+
|
|
10
|
+
Negated boolean checks (using `!`) make code harder to read and understand. Replace negative conditions with positive ones wherever possible, and avoid double negations like `!!`.
|
|
11
|
+
|
|
12
|
+
**Incorrect (fragmented logic):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
if (!isNotAuthorized) { ... }
|
|
16
|
+
if (!(a == b)) { ... }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (clear logic):**
|
|
20
|
+
|
|
21
|
+
```dart
|
|
22
|
+
if (isAuthorized) { ... }
|
|
23
|
+
if (a != b) { ... }
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Tools:** Custom analyzer (D021)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use setState Correctly
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Ensure setState is used correctly in StatefulWidget to avoid performance issues and bugs
|
|
5
|
+
tags: performance, best-practices, lifecycle, state-management
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use setState Correctly
|
|
9
|
+
|
|
10
|
+
Common `setState` anti-patterns include: calling `setState` inside `build()`, nesting `setState` calls, making multiple `setState` calls in the same method, or using async callbacks inside `setState`. These lead to performance issues, unnecessary rebuilds, or hard-to-track UI bugs.
|
|
11
|
+
|
|
12
|
+
**Incorrect (async inside setState):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
setState(() async {
|
|
16
|
+
await fetchData(); // WRONG: setState should be synchronous
|
|
17
|
+
_data = "new data";
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Correct (sync update after async):**
|
|
22
|
+
|
|
23
|
+
```dart
|
|
24
|
+
// Fetch data first
|
|
25
|
+
final newData = await fetchData();
|
|
26
|
+
|
|
27
|
+
// Update state synchronously
|
|
28
|
+
if (mounted) {
|
|
29
|
+
setState(() {
|
|
30
|
+
_data = newData;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Tools:** Custom analyzer (D022)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Unnecessary Method Overrides
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Remove methods that only call super with the same parameters as they add no value
|
|
5
|
+
tags: readability, clean-code, refactoring
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Unnecessary Method Overrides
|
|
9
|
+
|
|
10
|
+
Methods that override a parent method but only call `super.methodName()` with the same parameters are unnecessary and should be removed. These empty overrides add no functionality and create unnecessary code clutter. Common examples include lifecycle methods like `initState()`, `dispose()`, or `didUpdateWidget()` that only call their super implementation.
|
|
11
|
+
|
|
12
|
+
**Incorrect (super call only):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
@override
|
|
16
|
+
void initState() {
|
|
17
|
+
super.initState();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@override
|
|
21
|
+
void dispose() {
|
|
22
|
+
super.dispose();
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Correct (remove if no logic):**
|
|
27
|
+
|
|
28
|
+
```dart
|
|
29
|
+
// Just remove the method override entirely if it only calls super
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Tools:** Custom analyzer (D023)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Unnecessary StatefulWidget
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Use StatelessWidget when no state management is needed to improve performance
|
|
5
|
+
tags: performance, flutter, widgets, best-practices
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Unnecessary StatefulWidget
|
|
9
|
+
|
|
10
|
+
StatefulWidget should only be used when the widget needs to maintain mutable state that changes over time. If a widget extends StatefulWidget but its State class has no mutable fields, never calls setState(), and doesn't use lifecycle methods beyond build(), it should be converted to StatelessWidget. StatelessWidget is more efficient as it doesn't maintain state and has less overhead.
|
|
11
|
+
|
|
12
|
+
**Incorrect (StatefulWidget with no state):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
class MyTitle extends StatefulWidget {
|
|
16
|
+
final String text;
|
|
17
|
+
const MyTitle({super.key, required this.text});
|
|
18
|
+
|
|
19
|
+
@override
|
|
20
|
+
State<MyTitle> createState() => _MyTitleState();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class _MyTitleState extends State<MyTitle> {
|
|
24
|
+
@override
|
|
25
|
+
Widget build(BuildContext context) {
|
|
26
|
+
return Text(widget.text);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Correct (StatelessWidget):**
|
|
32
|
+
|
|
33
|
+
```dart
|
|
34
|
+
class MyTitle extends StatelessWidget {
|
|
35
|
+
final String text;
|
|
36
|
+
const MyTitle({super.key, required this.text});
|
|
37
|
+
|
|
38
|
+
@override
|
|
39
|
+
Widget build(BuildContext context) {
|
|
40
|
+
return Text(text);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Tools:** Custom analyzer (D024)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Nested Conditional Expressions
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Improve code readability by avoiding nested ternary operators
|
|
5
|
+
tags: readability, maintainability, clean-code
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Avoid Nested Conditional Expressions
|
|
9
|
+
|
|
10
|
+
Nested conditional expressions (ternary operators like `a ? b : c ? d : e`) reduce code readability significantly. When logic is complex, use if-else statements or extract the logic into a well-named variable or function.
|
|
11
|
+
|
|
12
|
+
**Incorrect (hard to follow):**
|
|
13
|
+
|
|
14
|
+
```dart
|
|
15
|
+
final color = isAdmin ? Colors.red : isLogged ? Colors.green : Colors.grey;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Correct (descriptive logic):**
|
|
19
|
+
|
|
20
|
+
```dart
|
|
21
|
+
// Option 1: if-else
|
|
22
|
+
Color userColor;
|
|
23
|
+
if (isAdmin) {
|
|
24
|
+
userColor = Colors.red;
|
|
25
|
+
} else if (isLogged) {
|
|
26
|
+
userColor = Colors.green;
|
|
27
|
+
} else {
|
|
28
|
+
userColor = Colors.grey;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Option 2: Extracted getter
|
|
32
|
+
Color get userColor => _calculateUserColor();
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Tools:** Custom analyzer (D025)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Function Names Verb-Noun
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: makes code self-documenting
|
|
5
|
+
tags: naming, functions, readability, conventions, quality
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Function Names Verb-Noun
|
|
9
|
+
|
|
10
|
+
Functions do things. Action verbs make purpose clear.
|
|
11
|
+
|
|
12
|
+
**Incorrect (vague names):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
func user() { } // Noun only
|
|
16
|
+
func userData() { } // Noun only
|
|
17
|
+
func doSomething() { } // Vague
|
|
18
|
+
func handleStuff() { } // Vague
|
|
19
|
+
func manager() { } // Noun only
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (action verbs):**
|
|
23
|
+
|
|
24
|
+
```go
|
|
25
|
+
func GetUser() { }
|
|
26
|
+
func CreateUserAccount() { }
|
|
27
|
+
func ValidateEmailFormat() { }
|
|
28
|
+
func CalculateTotalPrice() { }
|
|
29
|
+
func SendConfirmationEmail() { }
|
|
30
|
+
func ConvertCurrencyToUSD() { }
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Verb categories:**
|
|
34
|
+
|
|
35
|
+
| Category | Verbs |
|
|
36
|
+
|----------|-------|
|
|
37
|
+
| Retrieval | `Get`, `Fetch`, `Find`, `Load`, `Query` |
|
|
38
|
+
| Creation | `Create`, `Build`, `Make`, `Generate` |
|
|
39
|
+
| Modification | `Set`, `Update`, `Modify`, `Change` |
|
|
40
|
+
| Deletion | `Delete`, `Remove`, `Destroy`, `Clear` |
|
|
41
|
+
| Validation | `Validate`, `Verify`, `Check`, `Ensure` |
|
|
42
|
+
| Computation | `Calculate`, `Compute`, `Parse`, `Format` |
|
|
43
|
+
| Boolean | `Is`, `Has`, `Can`, `Should`, `Will` |
|
|
44
|
+
|
|
45
|
+
**Tools:** PR review, GolangCI-Lint
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Do Not Use Dead Code
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: reduces codebase noise and maintenance burden
|
|
5
|
+
tags: dead-code, cleanup, maintenance, quality
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Do Not Use Dead Code
|
|
9
|
+
|
|
10
|
+
Dead code confuses readers and increases cognitive load. Git history preserves deleted code.
|
|
11
|
+
|
|
12
|
+
**Incorrect (keeping dead code):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
func ProcessOrder(order *Order) float64 {
|
|
16
|
+
// Old implementation - keeping for reference
|
|
17
|
+
// total := 0.0
|
|
18
|
+
// for _, item := range order.Items {
|
|
19
|
+
// total += item.Price * float64(item.Quantity)
|
|
20
|
+
// }
|
|
21
|
+
// return total
|
|
22
|
+
|
|
23
|
+
total := calculateTotal(order)
|
|
24
|
+
return total
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Unused function - someone might need it later
|
|
28
|
+
func legacyCalculation() { }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Correct (clean code):**
|
|
32
|
+
|
|
33
|
+
```go
|
|
34
|
+
func ProcessOrder(order *Order) float64 {
|
|
35
|
+
return calculateTotal(order)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Delete unused functions - git history preserves them
|
|
39
|
+
// Delete commented code - git history preserves it
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Types of dead code:**
|
|
43
|
+
- Commented-out code
|
|
44
|
+
- Unused functions/structs/methods
|
|
45
|
+
- Unreachable code
|
|
46
|
+
- Unused variables (Go compiler will error on these locally, but they may exist in long-lived branches)
|
|
47
|
+
|
|
48
|
+
**Tools:** gofmt, govet, staticcheck, GolangCI-Lint
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Dependency Injection
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: enables testability and loose coupling
|
|
5
|
+
tags: dependency-injection, testing, coupling, architecture, quality
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Dependency Injection
|
|
9
|
+
|
|
10
|
+
Direct instantiation creates tight coupling, making testing difficult and changes risky. DI enables mockability, replaceability, and testability.
|
|
11
|
+
|
|
12
|
+
**Incorrect (hardcoded dependencies):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
type OrderService struct {
|
|
16
|
+
db *PostgresDatabase
|
|
17
|
+
mailer *SendGridMailer
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
func NewOrderService() *OrderService {
|
|
21
|
+
return &OrderService{
|
|
22
|
+
db: NewPostgresDatabase(), // Hardcoded dependency
|
|
23
|
+
mailer: NewSendGridMailer(), // Hardcoded dependency
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
func (s *OrderService) CreateOrder(data OrderData) error {
|
|
28
|
+
order, err := s.db.Insert("orders", data)
|
|
29
|
+
if err != nil {
|
|
30
|
+
return err
|
|
31
|
+
}
|
|
32
|
+
return s.mailer.Send(data.Email, "Order created")
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Correct (injected dependencies via interfaces):**
|
|
37
|
+
|
|
38
|
+
```go
|
|
39
|
+
type Database interface {
|
|
40
|
+
Insert(table string, data any) (any, error)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type Mailer interface {
|
|
44
|
+
Send(to string, message string) error
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type OrderService struct {
|
|
48
|
+
db Database
|
|
49
|
+
mailer Mailer
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func NewOrderService(db Database, mailer Mailer) *OrderService {
|
|
53
|
+
return &OrderService{
|
|
54
|
+
db: db,
|
|
55
|
+
mailer: mailer,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
func (s *OrderService) CreateOrder(data OrderData) error {
|
|
60
|
+
order, err := s.db.Insert("orders", data)
|
|
61
|
+
if err != nil {
|
|
62
|
+
return err
|
|
63
|
+
}
|
|
64
|
+
return s.mailer.Send(data.Email, "Order created")
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Usage
|
|
68
|
+
service := NewOrderService(
|
|
69
|
+
NewPostgresDatabase(connString),
|
|
70
|
+
NewSendGridMailer(apiKey),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
// Testing
|
|
74
|
+
mockDb := new(MockDatabase)
|
|
75
|
+
mockMailer := new(MockMailer)
|
|
76
|
+
testService := NewOrderService(mockDb, mockMailer)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Benefits:**
|
|
80
|
+
- Easy mocking for unit tests
|
|
81
|
+
- Swappable implementations
|
|
82
|
+
- Clear dependencies visible in constructor/factory
|
|
83
|
+
- Supports interface-based design (accept interfaces, return structs)
|
|
84
|
+
|
|
85
|
+
**Tools:** GolangCI-Lint, Manual review
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: No Business Logic In Factory Functions
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: ensures predictable object initialization
|
|
5
|
+
tags: factory, initialization, side-effects, patterns, quality
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## No Business Logic In Factory Functions
|
|
9
|
+
|
|
10
|
+
Factory functions (e.g., `NewService`) should only initialize state. Side effects in factory functions are unexpected and make testing difficult.
|
|
11
|
+
|
|
12
|
+
**Incorrect (logic in factory function):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
type UserService struct {
|
|
16
|
+
config Config
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
func NewUserService(configPath string) (*UserService, error) {
|
|
20
|
+
// BAD: Reading files in factory function
|
|
21
|
+
rawConfig, err := os.ReadFile(configPath)
|
|
22
|
+
if err != nil {
|
|
23
|
+
return nil, err
|
|
24
|
+
}
|
|
25
|
+
var config Config
|
|
26
|
+
json.Unmarshal(rawConfig, &config)
|
|
27
|
+
|
|
28
|
+
// BAD: Network calls/API initialization here
|
|
29
|
+
resp, _ := http.Get("https://api.example.com/init")
|
|
30
|
+
|
|
31
|
+
// BAD: Logging/side effects
|
|
32
|
+
log.Println("UserService initialized")
|
|
33
|
+
|
|
34
|
+
return &UserService{config: config}, nil
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Correct (clear separation):**
|
|
39
|
+
|
|
40
|
+
```go
|
|
41
|
+
type UserService struct {
|
|
42
|
+
config Config
|
|
43
|
+
httpClient *http.Client
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
func NewUserService(config Config, httpClient *http.Client) *UserService {
|
|
47
|
+
// Only assignment - no side effects
|
|
48
|
+
return &UserService{
|
|
49
|
+
config: config,
|
|
50
|
+
httpClient: httpClient,
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Service initialization in main or a dedicated bootstrapper
|
|
55
|
+
func InitializeApp() {
|
|
56
|
+
rawConfig, _ := os.ReadFile("./config.json")
|
|
57
|
+
var config Config
|
|
58
|
+
json.Unmarshal(rawConfig, &config)
|
|
59
|
+
|
|
60
|
+
httpClient := &http.Client{Timeout: 10 * time.Second}
|
|
61
|
+
|
|
62
|
+
service := NewUserService(config, httpClient)
|
|
63
|
+
log.Println("UserService ready")
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Tools:** PR review, Manual review
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Do Not Return Generic Errors
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: enables proper error handling and monitoring
|
|
5
|
+
tags: error-handling, custom-errors, debugging, quality
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Do Not Return Generic Errors
|
|
9
|
+
|
|
10
|
+
Generic errors (like `errors.New("error")`) lack context needed for debugging. They make it impossible to distinguish between error types for proper handling.
|
|
11
|
+
|
|
12
|
+
**Incorrect (generic errors):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
if user == nil {
|
|
16
|
+
return errors.New("error")
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if !isValid {
|
|
20
|
+
return fmt.Errorf("invalid")
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Correct (specific custom errors or sentinel errors):**
|
|
25
|
+
|
|
26
|
+
```go
|
|
27
|
+
// Sentinel errors for simple checks
|
|
28
|
+
var ErrUserNotFound = errors.New("user not found")
|
|
29
|
+
|
|
30
|
+
func (s *Service) GetUser(id string) (*User, error) {
|
|
31
|
+
if user == nil {
|
|
32
|
+
return nil, fmt.Errorf("%w: user with ID %s not found", ErrUserNotFound, id)
|
|
33
|
+
}
|
|
34
|
+
return user, nil
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Custom error types for complex context
|
|
38
|
+
type ValidationError struct {
|
|
39
|
+
Field string
|
|
40
|
+
Message string
|
|
41
|
+
Value any
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
func (e *ValidationError) Error() string {
|
|
45
|
+
return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if !isValid {
|
|
49
|
+
return &ValidationError{
|
|
50
|
+
Field: "email",
|
|
51
|
+
Message: "invalid format",
|
|
52
|
+
Value: email,
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Custom errors should include:
|
|
58
|
+
- Descriptive message with context (use `%w` for wrapping)
|
|
59
|
+
- Error codes or types for programmatic handling (using `errors.Is` or `errors.As`)
|
|
60
|
+
- Relevant data for debugging
|
|
61
|
+
- Appropriate mapping to status codes in the transport layer (e.g., HTTP 404)
|
|
62
|
+
|
|
63
|
+
**Tools:** GolangCI-Lint (errname, goerr113), Manual review
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Do Not Use Error Log For Non-critical
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: prevents alert fatigue and log noise
|
|
5
|
+
tags: logging, log-levels, error, observability, quality
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Do Not Use Error Log For Non-critical
|
|
9
|
+
|
|
10
|
+
Incorrect log levels cause alert fatigue and hide real issues. When everything is an "error", nothing is.
|
|
11
|
+
|
|
12
|
+
**Incorrect (overusing error level):**
|
|
13
|
+
|
|
14
|
+
```go
|
|
15
|
+
// NOT an error - expected business case
|
|
16
|
+
slog.Error("User entered wrong password")
|
|
17
|
+
|
|
18
|
+
// NOT an error - validation failure
|
|
19
|
+
slog.Error("Email format invalid")
|
|
20
|
+
|
|
21
|
+
// NOT an error - temporary network issue
|
|
22
|
+
slog.Error("Retry attempt 2 of 5")
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Correct (appropriate log levels using slog):**
|
|
26
|
+
|
|
27
|
+
```go
|
|
28
|
+
// WARN - recoverable, may need attention
|
|
29
|
+
slog.Warn("Payment retry attempt", "attempt", 2, "max_attempts", 5)
|
|
30
|
+
|
|
31
|
+
// INFO - normal business events
|
|
32
|
+
slog.Info("Login failed - invalid password", "user_id", userID, "attempts", 3)
|
|
33
|
+
|
|
34
|
+
// DEBUG - detailed troubleshooting
|
|
35
|
+
slog.Debug("Validation failed", "field", "email", "value", maskedEmail)
|
|
36
|
+
|
|
37
|
+
// ERROR - only for actual system failures
|
|
38
|
+
slog.Error("Database connection lost", "host", dbHost, "error", err)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Log Level Guide:**
|
|
42
|
+
|
|
43
|
+
| Level | Use For |
|
|
44
|
+
|-------|---------|
|
|
45
|
+
| ERROR | System failures, crashes, unrecoverable |
|
|
46
|
+
| WARN | Potential issues, degraded performance |
|
|
47
|
+
| INFO | Business events, state changes |
|
|
48
|
+
| DEBUG | Detailed troubleshooting |
|
|
49
|
+
|
|
50
|
+
**Tools:** Log linter, Custom rule, `slog` (standard library)
|