agentme 0.12.0 → 0.13.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.
|
@@ -9,6 +9,7 @@ Propose changes via pull request. All changes must be verified for clarity and n
|
|
|
9
9
|
Foundational standards, principles, and guidelines.
|
|
10
10
|
|
|
11
11
|
- [agentme-edr-002](principles/002-coding-best-practices.md) - **Coding best practices** - Keep files small, tests nearby, and docs synchronized
|
|
12
|
+
- [agentme-edr-023](principles/023-coding-abstraction-practices.md) - **Coding abstraction practices** - Define when abstractions are justified and when they must be inlined
|
|
12
13
|
- [agentme-edr-004](principles/004-unit-test-requirements.md) - **Unit test requirements** - Define minimum unit-test coverage and naming expectations
|
|
13
14
|
- [agentme-edr-007](principles/007-project-quality-standards.md) - **Project quality standards** - Require build, lint, and test verification before completion
|
|
14
15
|
- [agentme-edr-009](principles/009-error-handling.md) - **Error handling** - Standardize explicit errors, logging, and propagation rules
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentme-edr-policy-023-coding-abstraction-practices
|
|
3
|
+
description: Defines when abstractions (functions, classes, wrappers, factories) are justified and when they must be avoided. Tightly related to agentme-edr-policy-002-coding-best-practices.
|
|
4
|
+
apply-to: All software projects
|
|
5
|
+
valid-from: 2026-05-29
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# agentme-edr-policy-023: Coding abstraction practices
|
|
9
|
+
|
|
10
|
+
## Context and Problem Statement
|
|
11
|
+
|
|
12
|
+
Abstractions (helper functions, wrapper classes, factories, indirection layers) can clarify intent and reduce duplication — but when applied without discipline they obscure logic, force unnecessary navigation, and inflate codebases. Teams need clear criteria for when an abstraction earns its place versus when it adds unjustified indirection.
|
|
13
|
+
|
|
14
|
+
What principles should guide the decision to introduce — or reject — an abstraction?
|
|
15
|
+
|
|
16
|
+
## Decision Outcome
|
|
17
|
+
|
|
18
|
+
**Apply a bias toward explicit, functional, input→processing→output code. Introduce abstractions only when they demonstrably add value in logic, intent, reusability or readability.**
|
|
19
|
+
|
|
20
|
+
### Details
|
|
21
|
+
|
|
22
|
+
#### 01-prioritize-functional-programming
|
|
23
|
+
|
|
24
|
+
Prefer functional programming: pure functions with clear input → processing → output flow. Object-oriented patterns (classes, inheritance) are allowed **only** when there is a clear benefit from the additional abstraction they bring — e.g., when complex context management or true inheritance hierarchies are intrinsically part of the best solution for a problem.
|
|
25
|
+
|
|
26
|
+
*Why:* Functional units are simpler to reason about, test, and compose. OO introduces shared mutable state and implicit coupling that must earn its place.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
#### 02-prefer-explicit-calls-over-indirections
|
|
31
|
+
|
|
32
|
+
A sequence of direct calls to libraries and resources makes logic straightforward. Avoid:
|
|
33
|
+
|
|
34
|
+
- Aspect-oriented programming (AOP)
|
|
35
|
+
- Implicit context injection / dependency injection containers
|
|
36
|
+
- Magic decorators that alter control flow invisibly
|
|
37
|
+
|
|
38
|
+
These patterns obfuscate the main program flow and create behavioral indirections that require prior knowledge of state machines living outside the code itself.
|
|
39
|
+
|
|
40
|
+
*When indirection is acceptable:* Framework-mandated patterns (middleware chains, React context, etc.) where the reader already expects the indirection.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
#### 03-trivial-wrappers-are-prohibited
|
|
45
|
+
|
|
46
|
+
A function that merely delegates to another function or API call without adding meaningful logic, domain intent, or readability **must be inlined**. A wrapper is justified only when it:
|
|
47
|
+
|
|
48
|
+
- Encapsulates non-trivial logic (validation, retry, transformation).
|
|
49
|
+
- Communicates a domain concept the underlying expression does not convey.
|
|
50
|
+
- Improves readability of a complex flow by giving a clear name to a cohesive block of work.
|
|
51
|
+
|
|
52
|
+
**Bad — trivial wrapper:**
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
function getUser(id: string) {
|
|
56
|
+
return db.users.findById(id);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Good — adds domain intent:**
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
function isEligibleForTrial(user: User): boolean {
|
|
64
|
+
return !user.hasSubscription && user.createdAt > trialCutoffDate && !user.isBanned;
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
#### 04-object-factories-must-add-value
|
|
71
|
+
|
|
72
|
+
A function that constructs an object (e.g., configuration, options) is only justified if it:
|
|
73
|
+
|
|
74
|
+
- Performs validation or assertion.
|
|
75
|
+
- Computes values dynamically based on inputs.
|
|
76
|
+
- Combines data in a non-linear or conditional way.
|
|
77
|
+
- Is reused by multiple callers.
|
|
78
|
+
|
|
79
|
+
A function that restructures simple static data in an almost 1-to-1 mapping forces the reader to trace indirection for no benefit and must be inlined.
|
|
80
|
+
|
|
81
|
+
**Bad — trivial factory:**
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
function createConfig(port: number, host: string) {
|
|
85
|
+
return { port, host };
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Good — adds validation and defaults:**
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
function createServerConfig(opts: Partial<ServerOpts>): ServerConfig {
|
|
93
|
+
if (opts.port && (opts.port < 1 || opts.port > 65535)) {
|
|
94
|
+
throw new Error(`Invalid port: ${opts.port}`);
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
port: opts.port ?? 3000,
|
|
98
|
+
host: opts.host ?? 'localhost',
|
|
99
|
+
timeout: computeTimeout(opts.environment),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
#### 05-abstractions-for-business-logic-are-encouraged
|
|
107
|
+
|
|
108
|
+
Extracting domain logic into a named function is **encouraged** when it:
|
|
109
|
+
|
|
110
|
+
- Encapsulates a business rule so the reader does not need to parse low-level conditions to understand domain intent.
|
|
111
|
+
- Communicates intent at a glance, making compound conditions or multi-step checks self-describing.
|
|
112
|
+
|
|
113
|
+
**Example:**
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// Good — named function conveys business intent
|
|
117
|
+
if (isAllowed(event)) { ... }
|
|
118
|
+
|
|
119
|
+
// Bad — forces reader to decode domain meaning from raw conditions
|
|
120
|
+
if (event.status === 'active' && event.role !== 'guest' && event.quota > 0) { ... }
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
#### 06-idiomatic-framework-patterns-are-exempt
|
|
126
|
+
|
|
127
|
+
React hooks, higher-order components, middleware chains, and similar patterns established by the framework in use are **not** considered unnecessary abstraction. The reader already expects them, and fighting the framework's idioms creates more confusion than it removes.
|
|
128
|
+
|
|
129
|
+
This exemption does not override other rules — a trivial wrapper inside a hook is still prohibited.
|