@yaawn/workflow 0.0.0-stage → 0.3.1

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.
Files changed (101) hide show
  1. package/README.md +172 -2
  2. package/agents/instructions/output-styles/yaawn-eli5.instructions.md +45 -0
  3. package/agents/instructions/yaawn-accessibility.css.instructions.md +58 -0
  4. package/agents/instructions/yaawn-accessibility.html.instructions.md +90 -0
  5. package/agents/instructions/yaawn-accessibility.javascript.instructions.md +50 -0
  6. package/agents/instructions/yaawn-clean-code.typescript.instructions.md +74 -0
  7. package/agents/instructions/yaawn-function-coupling.typescript.instructions.md +100 -0
  8. package/agents/instructions/yaawn-html-css-js.html.instructions.md +32 -0
  9. package/agents/instructions/yaawn-open-source-first.instructions.md +38 -0
  10. package/agents/instructions/yaawn-personas.instructions.md +18 -0
  11. package/agents/instructions/yaawn-semantic-html.html.instructions.md +40 -0
  12. package/agents/instructions/yaawn-vanilla-css.css.instructions.md +50 -0
  13. package/agents/output-styles/yaawn-eli5.instructions.md +45 -0
  14. package/agents/personas/yaawn-developer.md +16 -0
  15. package/agents/personas/yaawn-product-owner.md +18 -0
  16. package/agents/personas/yaawn-reviewer.md +16 -0
  17. package/agents/skills/yaawn-clean-code/SKILL.md +61 -0
  18. package/agents/skills/yaawn-clean-code/references/classes.md +114 -0
  19. package/agents/skills/yaawn-clean-code/references/comments.md +164 -0
  20. package/agents/skills/yaawn-clean-code/references/error-handling.md +151 -0
  21. package/agents/skills/yaawn-clean-code/references/formatting.md +146 -0
  22. package/agents/skills/yaawn-clean-code/references/functions.md +261 -0
  23. package/agents/skills/yaawn-clean-code/references/meaningful-names.md +234 -0
  24. package/agents/skills/yaawn-clean-code/references/objects-and-data-structures.md +130 -0
  25. package/agents/skills/yaawn-clean-code/references/principles.md +76 -0
  26. package/agents/skills/yaawn-clean-code/references/simple-design-and-code-smells.md +130 -0
  27. package/agents/skills/yaawn-clean-code/references/unit-tests.md +114 -0
  28. package/agents/skills/yaawn-create-plan/SKILL.md +228 -0
  29. package/agents/skills/yaawn-grill-bug-report/SKILL.md +31 -0
  30. package/agents/skills/yaawn-grill-bug-report/references/bug-report-checklist.md +27 -0
  31. package/agents/skills/yaawn-grill-design/SKILL.md +68 -0
  32. package/agents/skills/yaawn-grill-design/references/design-checklist.md +36 -0
  33. package/agents/skills/yaawn-grill-other/SKILL.md +31 -0
  34. package/agents/skills/yaawn-grill-other/references/other-checklist.md +19 -0
  35. package/agents/skills/yaawn-grill-refactor/SKILL.md +31 -0
  36. package/agents/skills/yaawn-grill-refactor/references/refactor-checklist.md +26 -0
  37. package/agents/skills/yaawn-grill-spike/SKILL.md +31 -0
  38. package/agents/skills/yaawn-grill-spike/references/spike-checklist.md +25 -0
  39. package/agents/skills/yaawn-grill-story/SKILL.md +34 -0
  40. package/agents/skills/yaawn-grill-story/references/concept-challenge.md +67 -0
  41. package/agents/skills/yaawn-grill-story/references/story-checklist.md +43 -0
  42. package/agents/skills/yaawn-implement-plan/SKILL.md +196 -0
  43. package/agents/skills/yaawn-implement-plan/assets/fix-prompt.md +66 -0
  44. package/agents/skills/yaawn-implement-plan/assets/review-prompt.md +89 -0
  45. package/agents/skills/yaawn-implement-plan/assets/session-prompt.md +80 -0
  46. package/agents/skills/yaawn-implement-plan/scripts/agent.ts +218 -0
  47. package/agents/skills/yaawn-implement-plan/scripts/caffeinate.ts +56 -0
  48. package/agents/skills/yaawn-implement-plan/scripts/groups.ts +233 -0
  49. package/agents/skills/yaawn-implement-plan/scripts/overnight.ts +772 -0
  50. package/agents/skills/yaawn-implement-plan/scripts/parallel.ts +1176 -0
  51. package/agents/skills/yaawn-implement-plan/scripts/processes.ts +53 -0
  52. package/agents/skills/yaawn-implement-plan/scripts/stages.ts +65 -0
  53. package/agents/skills/yaawn-implement-plan/scripts/targets.ts +381 -0
  54. package/agents/skills/yaawn-implement-plan/scripts/worktrees.ts +431 -0
  55. package/agents/skills/yaawn-owasp-security/SKILL.md +106 -0
  56. package/agents/skills/yaawn-owasp-security/references/a01-broken-access-control.md +58 -0
  57. package/agents/skills/yaawn-owasp-security/references/a02-security-misconfiguration.md +56 -0
  58. package/agents/skills/yaawn-owasp-security/references/a03-software-supply-chain-failures.md +56 -0
  59. package/agents/skills/yaawn-owasp-security/references/a04-cryptographic-failures.md +67 -0
  60. package/agents/skills/yaawn-owasp-security/references/a05-injection.md +53 -0
  61. package/agents/skills/yaawn-owasp-security/references/a06-insecure-design.md +48 -0
  62. package/agents/skills/yaawn-owasp-security/references/a07-authentication-failures.md +68 -0
  63. package/agents/skills/yaawn-owasp-security/references/a08-software-data-integrity-failures.md +45 -0
  64. package/agents/skills/yaawn-owasp-security/references/a09-security-logging-alerting-failures.md +59 -0
  65. package/agents/skills/yaawn-owasp-security/references/a10-mishandling-exceptional-conditions.md +63 -0
  66. package/agents/skills/yaawn-prepare-plan/SKILL.md +110 -0
  67. package/agents/skills/yaawn-save-plan/SKILL.md +65 -0
  68. package/agents/skills/yaawn-save-plan/scripts/plan-body.ts +331 -0
  69. package/agents/skills/yaawn-save-plan/scripts/save-plan.ts +443 -0
  70. package/agents/skills/yaawn-split-story/SKILL.md +189 -0
  71. package/agents/skills/yaawn-split-story/references/spider.md +64 -0
  72. package/agents/skills/yaawn-split-story/scripts/create-issue.ts +162 -0
  73. package/agents/skills/yaawn-verify-executed-plan/SKILL.md +154 -0
  74. package/agents/skills/yaawn-verify-executed-plan/scripts/overnight.ts +362 -0
  75. package/agents/skills/yaawn-verify-executed-plan/scripts/pull-request.ts +131 -0
  76. package/agents/skills/yaawn-write-bug-report/SKILL.md +87 -0
  77. package/agents/skills/yaawn-write-other/SKILL.md +90 -0
  78. package/agents/skills/yaawn-write-refactor/SKILL.md +94 -0
  79. package/agents/skills/yaawn-write-spike/SKILL.md +94 -0
  80. package/agents/skills/yaawn-write-user-story/SKILL.md +187 -0
  81. package/agents/skills/yaawn-write-user-story/references/acceptance-criteria.md +186 -0
  82. package/agents/skills/yaawn-write-user-story/references/five-types-of-value.md +82 -0
  83. package/agents/skills/yaawn-write-user-story/references/user-story-fundamentals.md +75 -0
  84. package/agents/yaawn-glossary.md +146 -0
  85. package/agents/yaawn-grilling.md +75 -0
  86. package/agents/yaawn-worktrees.md +69 -0
  87. package/config/install-tasks.json +35 -0
  88. package/config/settings.json +23 -0
  89. package/config/wizard.json +128 -0
  90. package/github/ISSUE_TEMPLATE/yaawn-bug-report.md +59 -0
  91. package/github/ISSUE_TEMPLATE/yaawn-other.md +38 -0
  92. package/github/ISSUE_TEMPLATE/yaawn-refactor.md +38 -0
  93. package/github/ISSUE_TEMPLATE/yaawn-spike.md +16 -0
  94. package/github/ISSUE_TEMPLATE/yaawn-story.md +56 -0
  95. package/package.json +33 -4
  96. package/scripts/install.js +73 -0
  97. package/yaawn/gitignore +1 -0
  98. package/yaawn/yaawn-definition-of-done.md +5 -0
  99. package/yaawn/yaawn-project-glossary.md +7 -0
  100. package/yaawn/yaawn-user-roles.md +3 -0
  101. package/yaawn/yaawn-verification-commands.md +7 -0
@@ -0,0 +1,151 @@
1
+ # Error Handling
2
+
3
+ Error handling is important, but if it obscures logic, it's wrong.
4
+
5
+ > Source: Robert C. Martin, _Clean Code_ — Chapter 7: Error Handling
6
+
7
+ ## Rules
8
+
9
+ ### Use exceptions rather than return codes
10
+
11
+ Returning error codes leads to deeply nested structures and forces callers to handle errors immediately.
12
+
13
+ ```typescript
14
+ // Bad — error codes force nested handling
15
+ function login(dto: AuthDto): ResponseCode {
16
+ if (!dto.email || !dto.password) return ResponseCode.BadRequest;
17
+ const user = userRepository.get(dto);
18
+ if (!user) return ResponseCode.UserNotFound;
19
+ if (!matchPassword(user.password, dto.password)) return ResponseCode.WrongPassword;
20
+ setUserSession(user);
21
+ return ResponseCode.Success;
22
+ }
23
+
24
+ // Good — exceptions separate the happy path from error handling
25
+ function login(dto: AuthDto): void {
26
+ if (!dto.email || !dto.password) {
27
+ throw new BadRequestError('Email and password are required');
28
+ }
29
+ const user = userRepository.get(dto);
30
+ if (!user) {
31
+ throw new UserNotFoundError('Invalid username or password');
32
+ }
33
+ if (!matchPassword(user.password, dto.password)) {
34
+ throw new AuthError('Invalid username or password');
35
+ }
36
+ setUserSession(user);
37
+ }
38
+ ```
39
+
40
+ ### Extract try/catch bodies
41
+
42
+ If `try` exists in a function, it should be the first keyword. Extract the body into a separate function. Nothing should follow the catch/finally block.
43
+
44
+ ```typescript
45
+ // Bad
46
+ function performLogin(dto: AuthDto): void {
47
+ try {
48
+ login(dto);
49
+ } catch (error) {
50
+ logger.error(error);
51
+ }
52
+ redirect(); // should be inside the try block
53
+ }
54
+
55
+ // Good
56
+ function performLogin(dto: AuthDto): void {
57
+ try {
58
+ login(dto);
59
+ redirect();
60
+ } catch (error) {
61
+ logger.error(error);
62
+ }
63
+ }
64
+ ```
65
+
66
+ ### Provide context with exceptions
67
+
68
+ Each exception should provide enough context to determine the source and location of the error. Include the root cause when wrapping errors.
69
+
70
+ ```typescript
71
+ // Bad — loses the original stack trace
72
+ catch (error) {
73
+ throw new AuthError('Cannot get user');
74
+ }
75
+
76
+ // Good — preserves the cause chain
77
+ catch (error) {
78
+ throw new AuthError('Cannot get user', { cause: error });
79
+ }
80
+ ```
81
+
82
+ ### Define exception classes by the caller's needs
83
+
84
+ Wrap third-party API errors into a single common exception type. This minimizes dependencies, makes it easier to switch libraries, and simplifies mocking in tests.
85
+
86
+ ```typescript
87
+ // Bad — caller must handle every specific error
88
+ try {
89
+ port.open();
90
+ } catch (error) {
91
+ if (error instanceof DeviceResponseError) {
92
+ /* ... */
93
+ }
94
+ if (error instanceof UnlockedError) {
95
+ /* ... */
96
+ }
97
+ if (error instanceof GMXError) {
98
+ /* ... */
99
+ }
100
+ }
101
+
102
+ // Good — wrapper normalizes the error surface
103
+ class PortDeviceFailure extends Error {
104
+ constructor(message: string, options?: ErrorOptions) {
105
+ super(message, options);
106
+ }
107
+ }
108
+
109
+ // Inside the port module
110
+ try {
111
+ // low-level operations
112
+ } catch (error) {
113
+ throw new PortDeviceFailure('Device communication failed', { cause: error });
114
+ }
115
+ ```
116
+
117
+ ### Don't return null
118
+
119
+ Returning `null` leads to null-check cascades. Prefer throwing an exception or returning a special-case object (empty array, empty object, `Optional`/`Result` types).
120
+
121
+ ```typescript
122
+ // Bad
123
+ function getEmployees(): Employee[] | null {
124
+ return null;
125
+ }
126
+
127
+ const employees = getEmployees();
128
+ if (employees !== null) {
129
+ for (const e of employees) {
130
+ /* ... */
131
+ }
132
+ }
133
+
134
+ // Good
135
+ function getEmployees(): Employee[] {
136
+ return [];
137
+ }
138
+
139
+ const employees = getEmployees();
140
+ for (const e of employees) {
141
+ /* ... */
142
+ }
143
+ ```
144
+
145
+ ### Don't pass null
146
+
147
+ Passing `null` into methods is worse than returning it. Forbid passing `null` by default. Use TypeScript's `strictNullChecks` to enforce this at compile time.
148
+
149
+ ### Fail fast
150
+
151
+ Detect problems as early as possible. Validate inputs at system boundaries. When something is wrong, fail immediately with a clear error rather than propagating corrupted state.
@@ -0,0 +1,146 @@
1
+ # Formatting
2
+
3
+ Code formatting is important. It is about **communication**, and communication is the professional developer's first order of business.
4
+
5
+ > Source: Robert C. Martin, _Clean Code_ — Chapter 5: Formatting
6
+
7
+ ## Rules
8
+
9
+ ### Vertical openness between concepts
10
+
11
+ Use blank lines to separate distinct concepts: imports, property blocks, methods. Each blank line is a visual cue identifying a new concept.
12
+
13
+ ```typescript
14
+ import { Injectable } from '@angular/core';
15
+ import { HttpClient } from '@angular/common/http';
16
+
17
+ @Injectable({ providedIn: 'root' })
18
+ export class UserService {
19
+ readonly apiUrl = '/api/users';
20
+ readonly defaultPageSize = 20;
21
+
22
+ constructor(private http: HttpClient) {}
23
+
24
+ getUsers(): Observable<User[]> {
25
+ // ...
26
+ }
27
+
28
+ getUser(id: string): Observable<User> {
29
+ // ...
30
+ }
31
+ }
32
+ ```
33
+
34
+ ### Use vertical density for tightly related concepts
35
+
36
+ Lines of code that are tightly related should appear vertically dense — don't separate them with blank lines or useless comments.
37
+
38
+ ```typescript
39
+ // Bad — comments break the association
40
+ /** The class name of the reporter listener */
41
+ private className: string;
42
+
43
+ /** The properties of the reporter listener */
44
+ private properties: Property[] = [];
45
+
46
+ // Good — tightly related, no visual noise
47
+ private className: string;
48
+ private properties: Property[] = [];
49
+ ```
50
+
51
+ ### Place dependent functions vertically close
52
+
53
+ If one function calls another, they should be vertically close. The **caller should appear above the callee** (stepdown rule).
54
+
55
+ ```typescript
56
+ // Good — createUser calls validateUser and sendNotification, which follow it
57
+ createUser(dto: UserDto): void {
58
+ this.validateUser(dto);
59
+ this.userRepository.save(dto);
60
+ this.sendNotification(dto);
61
+ }
62
+
63
+ private validateUser(dto: UserDto): void { /* ... */ }
64
+
65
+ private sendNotification(dto: UserDto): void { /* ... */ }
66
+ ```
67
+
68
+ ### Declare variables close to their usage
69
+
70
+ Don't declare all variables at the top of a function. Declare them where they are first used.
71
+
72
+ ```typescript
73
+ // Bad — response declared too early
74
+ function userStatistics(users: User[]): UserStatisticResponse {
75
+ const response = new UserStatisticResponse();
76
+ const admins: User[] = [];
77
+ const guests: User[] = [];
78
+ // ... loop ...
79
+ response.admins = admins;
80
+ response.guests = guests;
81
+ return response;
82
+ }
83
+
84
+ // Good — response declared where first needed
85
+ function userStatistics(users: User[]): UserStatisticResponse {
86
+ const admins: User[] = [];
87
+ const guests: User[] = [];
88
+
89
+ for (const user of users) {
90
+ if (isAdmin(user)) admins.push(user);
91
+ else guests.push(user);
92
+ }
93
+
94
+ const response = new UserStatisticResponse();
95
+ response.admins = admins;
96
+ response.guests = guests;
97
+ return response;
98
+ }
99
+ ```
100
+
101
+ ### Use horizontal whitespace to show association
102
+
103
+ - **No** space between function name and opening parenthesis (they are closely related)
104
+ - **Yes** space around assignment operators (left and right sides are distinct)
105
+ - **Yes** space after commas in argument lists (arguments are separate entities)
106
+
107
+ ### Avoid horizontal alignment
108
+
109
+ Don't align variable names or types into columns — it draws the eye to the wrong thing and is hard to maintain.
110
+
111
+ ```typescript
112
+ // Bad
113
+ private socket: Socket;
114
+ private input: InputStream;
115
+ private output: OutputStream;
116
+
117
+ // Good
118
+ private socket: Socket;
119
+ private input: InputStream;
120
+ private output: OutputStream;
121
+ ```
122
+
123
+ ### Don't break indentation
124
+
125
+ Never collapse short functions or if statements onto one line. Use proper block formatting.
126
+
127
+ ```typescript
128
+ // Bad
129
+ constructor(parent: ParentWidget) { super(parent); }
130
+ render(): string { return ''; }
131
+
132
+ // Good
133
+ constructor(parent: ParentWidget) {
134
+ super(parent);
135
+ }
136
+
137
+ render(): string {
138
+ return '';
139
+ }
140
+ ```
141
+
142
+ ### Follow team rules
143
+
144
+ Individual style preferences give way to team conventions. The codebase should look like it was written by one person, not a committee of disagreeing individuals.
145
+
146
+ > **Project convention:** This codebase enforces formatting via `.editorconfig` and ESLint. Follow the established conventions.
@@ -0,0 +1,261 @@
1
+ # Functions
2
+
3
+ Functions should be small and do one thing.
4
+
5
+ > Source: Robert C. Martin, _Clean Code_ — Chapter 3: Functions
6
+
7
+ ## Rules
8
+
9
+ ### Small
10
+
11
+ The first rule of functions is that they should be small. The second rule is that they should be smaller than that. Aim for **15 lines or fewer**. If a function grows beyond that, start asking questions.
12
+
13
+ ### Do one thing
14
+
15
+ A function should do one thing, do it well, and do it only. If you can extract another function from it with a name that is **not merely a restatement** of its implementation, it's doing more than one thing.
16
+
17
+ ### One level of abstraction per function (SLAP)
18
+
19
+ Statements within a function should all be at the same level of abstraction. Don't mix high-level orchestration with low-level details.
20
+
21
+ ```typescript
22
+ // Bad — mixed abstraction levels
23
+ function getUserReportDtos(): UserReportDto[] {
24
+ const users = CsvUtils.read('user.csv', User);
25
+ const dtos: UserReportDto[] = [];
26
+ if (users && users.length > 0) {
27
+ for (const user of users) {
28
+ const dto: UserReportDto = { name: user.name, email: user.email };
29
+ dtos.push(dto);
30
+ }
31
+ }
32
+ return dtos;
33
+ }
34
+
35
+ // Good — each function is at one level of abstraction
36
+ function getUserReportDtos(): UserReportDto[] {
37
+ const users = readUsersFromCsvFile('user.csv');
38
+ return mapToUserReportDtos(users);
39
+ }
40
+
41
+ function readUsersFromCsvFile(fileName: string): User[] {
42
+ return CsvUtils.read(fileName, User);
43
+ }
44
+
45
+ function mapToUserReportDtos(users: User[]): UserReportDto[] {
46
+ if (!isValid(users)) {
47
+ return [];
48
+ }
49
+ return users.map(mapToUserReportDto);
50
+ }
51
+ ```
52
+
53
+ ### The stepdown rule
54
+
55
+ Read code from top to bottom. Every function should be followed by those at the next level of abstraction.
56
+
57
+ ### Avoid nested structures
58
+
59
+ Use early returns (guard clauses) instead of deeply nested if statements.
60
+
61
+ ```typescript
62
+ // Bad
63
+ function isUserValid(userDto: UserDto): boolean {
64
+ if (userDto) {
65
+ if (userDto.password) {
66
+ if (userDto.email) {
67
+ return !userService.isEmailExists(userDto.email);
68
+ }
69
+ }
70
+ }
71
+ return false;
72
+ }
73
+
74
+ // Good
75
+ function isUserValid(userDto: UserDto): boolean {
76
+ if (!userDto) return false;
77
+ if (!userDto.password) return false;
78
+ if (!userDto.email) return false;
79
+ return !userService.isEmailExists(userDto.email);
80
+ }
81
+ ```
82
+
83
+ ### Avoid negative conditionals
84
+
85
+ Negatives are harder to understand than positives.
86
+
87
+ ```typescript
88
+ // Bad
89
+ if (!isNotEmpty(users)) {
90
+ }
91
+
92
+ // Good
93
+ if (isEmpty(users)) {
94
+ }
95
+ ```
96
+
97
+ ### Replace switch statements with polymorphism
98
+
99
+ Switch statements violate SRP and OCP — they grow with every new type. Use polymorphism instead.
100
+
101
+ ```typescript
102
+ // Bad
103
+ function perform(vehicle: Vehicle): void {
104
+ switch (vehicle.type) {
105
+ case 'bicycle':
106
+ vehicle.ride();
107
+ break;
108
+ case 'car':
109
+ vehicle.drive();
110
+ break;
111
+ case 'airplane':
112
+ vehicle.fly();
113
+ break;
114
+ }
115
+ }
116
+
117
+ // Good — each type knows how to perform
118
+ interface VehicleAction {
119
+ perform(): void;
120
+ }
121
+
122
+ class Bicycle implements VehicleAction {
123
+ perform(): void {
124
+ this.ride();
125
+ }
126
+ }
127
+ ```
128
+
129
+ ### Use descriptive names
130
+
131
+ A long descriptive name is better than a short enigmatic name. A long descriptive name is better than a long descriptive comment.
132
+
133
+ ```typescript
134
+ // Bad
135
+ function createPrd(): void {} // Create a product
136
+
137
+ // Good
138
+ function createProduct(): void {}
139
+ ```
140
+
141
+ Be consistent: use the same verbs across the codebase (`get` vs `fetch`, `set` vs `update`, `add` vs `append`).
142
+
143
+ ### Prefer fewer arguments
144
+
145
+ Zero arguments (niladic) is ideal. One (monadic) and two (dyadic) are fine. Three (triadic) should be avoided. More than three requires strong justification.
146
+
147
+ When a function needs many arguments, wrap them in an object.
148
+
149
+ ```typescript
150
+ // Bad
151
+ function createUser(username: string, password: string, gender: Gender, roleId: number): void {}
152
+
153
+ // Good
154
+ function createUser(userDto: CreateUserDto): void {}
155
+ ```
156
+
157
+ ### Avoid flag arguments
158
+
159
+ A boolean argument declares the function does more than one thing. Split into two functions.
160
+
161
+ ```typescript
162
+ // Bad
163
+ function execute(isTestSuite: boolean): void {
164
+ if (isTestSuite) {
165
+ /* suite logic */
166
+ } else {
167
+ /* single test logic */
168
+ }
169
+ }
170
+
171
+ // Good
172
+ function executeTestSuite(): void {}
173
+ function executeSingleTest(): void {}
174
+ ```
175
+
176
+ ### Have no side effects
177
+
178
+ A function promises to do one thing — don't do hidden things.
179
+
180
+ ```typescript
181
+ // Bad — "get" function secretly updates the database
182
+ function getUserByEmail(email: string): User {
183
+ const user = userRepository.getUserByEmail(email);
184
+ user.lastAccess = new Date();
185
+ userRepository.update(user);
186
+ return user;
187
+ }
188
+ ```
189
+
190
+ ### Avoid output arguments
191
+
192
+ Don't mutate arguments passed to a function. If a function must change state, have it change the state of its owning object.
193
+
194
+ ```typescript
195
+ // Bad
196
+ function appendFooter(report: StringBuffer): void;
197
+
198
+ // Good
199
+ report.appendFooter();
200
+ ```
201
+
202
+ ### Separate command from query
203
+
204
+ Functions should either **do something** or **answer something**, but not both.
205
+
206
+ ```typescript
207
+ // Bad
208
+ function set(attribute: string, value: string): boolean;
209
+ if (set('username', 'gpcoder')) {
210
+ }
211
+
212
+ // Good
213
+ if (attributeExists('username')) {
214
+ setAttribute('username', 'gpcoder');
215
+ }
216
+ ```
217
+
218
+ ### Prefer exceptions to returning error codes
219
+
220
+ Error codes lead to deeply nested structures and violate command-query separation.
221
+
222
+ ```typescript
223
+ // Bad
224
+ function login(dto: AuthDto): ResponseCode {
225
+ if (!dto.email || !dto.password) return ResponseCode.BadRequest;
226
+ // ...
227
+ return ResponseCode.Success;
228
+ }
229
+
230
+ // Good
231
+ function login(dto: AuthDto): void {
232
+ if (!dto.email || !dto.password) {
233
+ throw new BadRequestError('Email and password are required');
234
+ }
235
+ // ...
236
+ }
237
+ ```
238
+
239
+ ### Extract try/catch bodies
240
+
241
+ If `try` exists in a function, it should be the first word. Extract the body into its own function.
242
+
243
+ ```typescript
244
+ // Good
245
+ function performLogin(dto: AuthDto): void {
246
+ try {
247
+ login(dto);
248
+ redirect();
249
+ } catch (error) {
250
+ logger.error(error);
251
+ }
252
+ }
253
+ ```
254
+
255
+ ### DRY — Don't Repeat Yourself
256
+
257
+ Duplication is the root of all evil in software. Every piece of knowledge must have a single, unambiguous representation.
258
+
259
+ ### Write, test, and refine
260
+
261
+ > "When I write functions, they come out long and complicated. But I also have unit tests that cover every one of those clumsy lines of code. So then I massage and refine that code, splitting out functions, changing names, eliminating duplication." — Robert C. Martin