Skip to content

Commit

Permalink
chore: add course content
Browse files Browse the repository at this point in the history
  • Loading branch information
gglee89 committed Oct 20, 2023
1 parent 181e4f5 commit 467d2f0
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 6 deletions.
117 changes: 111 additions & 6 deletions ENTERPRISE_ARCHITECTURE_PATTERNS.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,118 @@
> The biggest problem in the development and maintenance of large-scale software is complexity - large systems are hard to understand
- "Out of the Tarpit - Ben Mosely Peter Marks"
- "Out of the Tarpit - Ben Mosely Peter Marks"

> We believe that the major contributor to this complexity in many systems is the handling of state and the burden that this adds when trying to analyse and reason about the system. Other closely related contributors are code volume, and explicit concern with the flow of control through the system.
- "Out of the Tarpit - Ben Mosely Peter Marks"
**State Management**
Lesson 1: Don't use shared mutable state.
- "Out of the Tarpit - Ben Mosely Peter Marks"

- Lesson 1: Don't use shared mutable state.
- Lesson 2: Code Volume
- Lesson 3: Flow

### **State Management**

#### Problem with HIDDEN STATE

![image](https://github.com/gglee89/giwoolee.com/assets/16644017/0c0004b1-8a1e-4103-91b6-8c5a0fd73d1d)

Lesson 2: Code Volume
```js
class Inventory {
ledger = { total: 1200 }
}

class ItemsComponent {
ledger: any
constructor(private inventory: Inventory) {
this.ledger = inventory.ledger;
}
add(x) { this.ledger.total += x; }
}

class WidgetsComponent {
ledger: any
constructor(private inventory: Inventory) {
this.ledger = inventory.ledger;
}
add(x) { this.ledger.total += x; }
}
```

#### Violating the SRP (Single Responsibility Principle)

Essentially we need to test two things within a single test based on how the `reCalculateTotal` function is written. This represents an increase in complexity.

Example of a bad code (hard to test)

```
price;
mode;
widgets: Widget[];
reCalculateTotal(widget: Widget) {
switch (this.mode) {
case 'create':
const newWidget = Object.assign({, widget, { id: uuidv4() }});
this.widgets = [...this.widgets, newWidget]
break;
case 'update':
this.widgets = this.widgets.map(wdgt =>
(widget.id === wdgt.id) ? Object.assign({}, widget) : wdgt);
break;
case 'delete':
this.widgets = this.widgets.filter(wdgt => widget.id !== wdgt.id);
break;
default:
break;
}
this.price = this.widgets.reduce((acc, curr) => acc + curr.price, 0)
}
```

![image](https://github.com/lifebit-ai/web-application/assets/16644017/246a07a2-0436-44c0-a342-42853ad92ad2)

On the surface, you could be tricked into thinking like this is okayish code.

- I've used all the cool, immutable operators,
- using ternary functions
- using Fat arrow functions

Now when we run the code:

```
const testService = new RefactorService();
const testWidget = { id: 100, name: '', price: 100, description: '' };
const testWidgets = [{ id: 100, name: '', price: 200, description: '' }];
testService.widgets = testWidgets;
testService.mode = 'create';
testService.reCalculateTotal(testWidget);
testService.mode = 'update';
testService.reCalculateTotal(testWidget);
testService.mode = 'delete';
testService.reCalculateTotal(testWidget);
```

What are we doing to get as an output of this flow? A: It's really hard to come up with an answer.
The issue is that, using the same parameter, you get different results, potentially every single time.

#### Nested Logic

![image](https://github.com/lifebit-ai/web-application/assets/16644017/5d514df2-95f9-4587-aa60-39e43076e0a0)

Ironically, this is the EASIEST problem to solve. Via, DEPENDENCY INJECTION & the EXTRACT METHOD

- First step (DEPENDENCY INJECTION):
- Instead of using `switch (this.mode)...` we now should use `switch (mode)`
- and the `mode` should be now passed as a parameter of the function as `updateCoursesAndRecalculateCosts(course: Course, mode: string)...`
- Second step (EXTRACT):
- Without breaking the enclosing code
- We get three methods to test (eg.: createCourse, updateCourse, deleteCourse)
- We get three methods we can reuse

![image](https://github.com/lifebit-ai/web-application/assets/16644017/6c3333d3-2866-46a5-9148-6a25c904d496)

Lesson 3: Flow
- With this we're `managing state`, `flow control`, and `code volume`
19 changes: 19 additions & 0 deletions expert-learning-path/enterprice-architecture-patterns-0-class.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class Inventory {
ledger = { total: 1200 }
}

class ItemsComponent {
ledger: any
constructor(private inventory: Inventory) {
this.ledger = inventory.ledger;
}
add(x) { this.ledger.total += x; }
}

class WidgetsComponent {
ledger: any
constructor(private inventory: Inventory) {
this.ledger = inventory.ledger;
}
add(x) { this.ledger.total += x; }
}
23 changes: 23 additions & 0 deletions expert-learning-path/enterprice-architecture-patterns-0.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
price;
mode;
widgets: Widget[];

reCalculateTotal(widget: Widget) {
switch (this.mode) {
case 'create':
const newWidget = Object.assign({, widget, { id: uuidv4() }});
this.widgets = [...this.widgets, newWidget]
break;
case 'update':
this.widgets = this.widgets.map(wdgt =>
(widget.id === wdgt.id) ? Object.assign({}, widget) : wdgt);
break;
case 'delete':
this.widgets = this.widgets.filter(wdgt => widget.id !== wdgt.id);
break;
default:
break;
}

this.price = this.widgets.reduce((acc, curr) => acc + curr.price, 0)
}
27 changes: 27 additions & 0 deletions expert-learning-path/enterprice-architecture-patterns-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
updateCoursesAndRecalculateCost(course: Course, mode: string) {
switch (mode) {
case 'create':
this.courses = this.createCourse(this.courses, course)
break;
case 'update':
this.courses = this.updateCourse(this.courses, course)
break;
case 'delete':
this.courses = this.deleteCourse(this.courses, course);
break;
default:
break;
}

this.price = this.widgets.reduce((acc, curr) => acc + curr.price, 0)
}

createCourse(courses, course) {
return [...courses, Object.assign({}, course, { id: uuidv4() })];
}
updateCourse(courses, course) {
return courses.map(_course => course.id === _course.id ? Object.assign({}, course) : _course)
}
deleteCourse(courses, course) {
return courses.filter(_course => course.id !== _course.id)
}
29 changes: 29 additions & 0 deletions expert-learning-path/enterprice-architecture-patterns-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
onCoursesUpdated(course, mode) {
this.courses = this.updateCourses(this.courses, course, mode);
this.totalCost = this.updateTotalCost(this.courses);
}

updateCourses(courses: Course[], course: Course, mode: string) {
switch (mode) {
case 'create':
return this.createCourse(this.courses, course)
case 'update':
return this.updateCourse(this.courses, course)
case 'delete':
return this.deleteCourse(this.courses, course);
default:
return courses;
}
}

updateTotalCost(courses) { return courses.reduce((acc, curr) => acc + curr.price, 0); }

createCourse(courses, course) {
return [...courses, Object.assign({}, course, { id: uuidv4() })];
}
updateCourse(courses, course) {
return courses.map(_course => course.id === _course.id ? Object.assign({}, course) : _course)
}
deleteCourse(courses, course) {
return courses.filter(_course => course.id !== _course.id)
}

0 comments on commit 467d2f0

Please sign in to comment.