From 6ac70ac455df034fa039d7973a72489fe339b085 Mon Sep 17 00:00:00 2001
From: Behnamrhp74 <behnam.rahimpoor@beatstream.com>
Date: Tue, 11 Mar 2025 22:44:02 +0300
Subject: [PATCH 1/4] doc: Add base failure document

---
 catalog/docs/failure-error-handling.md | 140 +++++++++++++++++++++++++
 1 file changed, 140 insertions(+)
 create mode 100644 catalog/docs/failure-error-handling.md

diff --git a/catalog/docs/failure-error-handling.md b/catalog/docs/failure-error-handling.md
new file mode 100644
index 0000000..8c43c20
--- /dev/null
+++ b/catalog/docs/failure-error-handling.md
@@ -0,0 +1,140 @@
+# Error handling with failure
+
+## What is failure
+In each application and in each logic, there can be failure on the process and based on their complexity it can be few or many possilbe scenarios for these failures.
+
+In software development we always trying to have more controll on this failure to:
+- Avoid possible bugs  
+- Help user to understand about the state of the application with proper messages
+- Controll on the processes for some side effects
+- Monitor the behavior of the application
+
+So having a specific way of error handling for these failure to achieve all these requirements in our app, helps us to build more robust, trustable, and maintainable application.
+
+Many frameworks provides their own ways to handle these failures which thet can name it as exceptions, failures or any other things, but for sure we shouldn't always depend our logics and apps to the behavior of the frameworks and besides there are many frameworks which doesn't provide error handling tools, so we should always have a specific and reliable way to handle our errors in all layers of the application.
+
+## Failure handling with base failure
+To have granular controll on the failure and have specific type for all errors we can use the inheritance and abstraction power of oop.
+So we can define an abstract calsss as our base failure, which is our specific type of our failures in the application.
+
+```ts
+export default abstract class BaseFailure<META_DATA> {
+
+  metadata: META_DATA | undefined;
+
+  constructor(metadata?: META_DATA) {
+    this.metadata = metadata ?? undefined;
+  }
+}
+
+```
+As you see it's just a simple abstract class which gets some metadata about details of error in any shape. But wait it's just starting of the story, we can have many ideas with this failure.
+
+## How to write a simple failure
+So for creating a simple failure we can just define our failure in any domain for any scenaio which we need like this:
+```ts
+export default class CreateUserFailure extends BaseFailure<{ userId: string }> {
+  constructor(metadata?: { userId: string }) {
+    super(metadata);
+  }
+}
+```
+
+So in our logics for creating user we can return specific tyep of failure for creating user.
+
+## Combination with Functional programming
+Functional programming is a deep topic which we cannot cover it here for more details and learn about it you can watch these course or many courses and related books which exists on the web. But for this article we care about one of the most useful functors in functional programming and how failure can fit perfectly with failure. And this functor is either funtor. 
+Either provides a data which is two parts, it's right answer and left answer. right answer is the type of the answer which we expect from either and left answer is exactly what we need as unexpected result.
+You're gussing right this base failure will be our left answers for either functor.
+```ts
+Either<
+  BaseFailure<unknown>,
+  ResponseType
+>
+```
+So as we always have specific type for handling unexpected resulsts, so we can define a new type for either in our app.
+```ts
+export type ApiEither<ResponseType> = Either<
+  BaseFailure<unknown>,
+  ResponseType
+>;
+```
+So any othe either which for calling api we can use this either type for them.
+And also for async process we use TaskEither which is the same as either functor but for asynchronous process.
+```ts
+type ApiTask<ResponseType> = TaskEither<BaseFailure<unknown>, ResponseType>;
+```
+
+For example to get customers repository to handle all calling for customer api we can use this type for them.
+```ts
+export default interface CustomerRepo {
+  fetchList(query: string): ApiTask<Customer[]>;
+}
+```
+And in the repo we can have this pipe to get customer data:
+```ts
+pipe(
+      tryCatch(
+        async () => {
+          ...// calling api and returning result
+        },
+        (l) => failureOr(l, new NetworkFailure(l as Error)),
+      ),
+      map(this.customersDto.bind(this)),
+    ) as ApiTask<Customer[]>;
+```
+Pipe is just a pipe of process and operations which we make on the data to shape the whole process.
+
+As you see in try catch which is constructor of a ApiEither we defined our right response from first callback and our failure as the second callback argument.
+And failureOr is just a helper to get a error and turn to some specific failure __which is NetworkFailure in this example__ 
+So in the process of fetching customer we know the unexpected result, always will be a speicfic type. 
+```ts
+export function failureOr(
+  reason: unknown,
+  failure: BaseFailure<any>,
+): BaseFailure<any> {
+  if (reason instanceof BaseFailure) {
+    return reason;
+  }
+  return failure;
+}
+```
+So in any layer we can get the failure do some logics on left response based on its metadata and turn the failure shape to any other failure shape and use it for different purposes.
+
+## Usecases of this idea
+
+### Monitoring for failures
+There are many situations that when some important process had some problems we wanna have controll on it, to know when and why these things happened and store it in one of the monitoting tools. 
+
+For example on getting CreateUserFailure in repository layer, we can send a log with specific time and use parameters data to any logging or monitoring tools.
+
+### Monitoring on bugs with dev failures
+There are many situations specifally in frontend appications which some unexpected behavior happens from the development mistakes and bugs for example by getting some bugs or data changes in apis, it's possible to face with unexpected behaviors  and we wanna show some specific message or redirect user to error page with descent message. On top of in frontend applications they cannot get the log in this situation as it's happened in the user's system, so they can send the metadata as a log to one api if they face with dev failures.
+
+To acheive this we can simply define another abstract failure like this:
+
+```ts
+export default abstract class BaseDevFailure<
+  META_DATA,
+> extends BaseFailure<META_DATA> {}
+```
+As you see it's just another failure which is extend from base failure.
+So for example in some part of application which should send some arguments into domain layer and as these arguments are dynamic and possible to send unexpected data we can define one dev failure for this situation like this:
+```ts
+export default class ArgumentsFailure<
+  META_DATA,
+> extends BaseDevFailure<META_DATA> {
+  constructor(metadata?: META_DATA) {
+    super(metadata);
+  }
+}
+```
+So we can consider this scenario in our logics and facing with this failure we can make a log request to our log api even from frontend applications, so on facing with this situation they can show a descent message to user to contact to support team at the same time they store the bug log to have full controll on these situations.
+
+### Manage translations and error messages with failure
+With this idea we can move one step beyound error handling and even handle translation and showing related messages in frontend applications in an automatic way.
+
+For each process and scenario we should define specific failure and also at the same time for each one of them we should show specific message in specific language based on selected language by the user. 
+
+So we can use this idea and automate these process together.
+

From 1f6431eec6d25ede4016510e6e4e27ec75365051 Mon Sep 17 00:00:00 2001
From: Behnamrhp74 <behnam.rahimpoor@beatstream.com>
Date: Tue, 11 Mar 2025 23:51:27 +0300
Subject: [PATCH 2/4] doc: Add translation description for failure doc

---
 catalog/docs/failure-error-handling.md | 75 ++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/catalog/docs/failure-error-handling.md b/catalog/docs/failure-error-handling.md
index 8c43c20..093a18a 100644
--- a/catalog/docs/failure-error-handling.md
+++ b/catalog/docs/failure-error-handling.md
@@ -138,3 +138,78 @@ For each process and scenario we should define specific failure and also at the
 
 So we can use this idea and automate these process together.
 
+To achieve this requirement we can pass a unique  string key from constructor based on the failure scenario.
+So our base failure will turn like this:
+```ts
+export default abstract class BaseFailure<META_DATA> {
+  private readonly BASE_FAILURE_MESSAGE = "failure";
+
+  /**
+   * Use this message as key lang for failure messages
+   */
+  message = this.BASE_FAILURE_MESSAGE;
+
+  metadata: META_DATA | undefined;
+
+  constructor(key: string, metadata?: META_DATA) {
+    this.message = makeFailureMessage(this.message, key);
+    this.metadata = metadata ?? undefined;
+  }
+}
+
+/**
+ * Gets Message key and it'll add it to the failure message key hierarchy
+ */
+export function makeFailureMessage(message: string, key: string) {
+  if (!key) return message;
+  return `${message}.${key}`;
+}
+
+```
+As you see we have a message property, which has 
+`BASE_FAILURE_MESSAGE` which is the base key for all failure messages. Also it gets key from constructor and with makeFailureMessage function concat the new key with the message and shape new message for each failre.
+
+Also each failure can get their own key from their constructors.
+So at the end of the day we can have a chained message key that we can use it as a message key.
+
+For example for a failure like `UserAlreadyExistsFailure` we can have a parent failure for all user domain failures like this:
+
+```ts
+export default class UserFailure extends BaseFailure {
+  constructor(key: string) {
+    super(makeFailureMessage("user", key));
+  }
+}
+```
+and now we can make our failure:
+```ts
+export default class UserAlreadyExistsFailure extends UserFailure {
+  constructor() {
+    super("alreadyExists");
+  }
+}
+```
+so the result of message for `UserAlreadyExistsFailure`, will be `failure.user.alreadyExists`.
+
+At the same time in other place in our project we're using langkey object to specify translation key and this object, like failure follows domain and folder structure to specify lang key.
+
+```ts
+const langKey = {
+  // ...
+    failure: {
+      user: {
+        alreadyExists: "failure.user.alreadyExists",
+      }
+  }
+}
+```
+So we can use our failure message key to get lang key and by passing it to translation method we can get translated failure message and make a automated process to show error message based on failure that we get.
+
+```ts
+const usecaseResponse = await getUsersUsecase() as Promise<Either<BaseFailure, User[]>>
+
+if (!isLeft(usecaseResponse)) return;
+  if (!(usecaseResponse instanceOf BaseFailure)) return;
+
+const translatedFailureMessage = t(usecaseResponse.left.message)
+```
\ No newline at end of file

From da8bbc5c9e95d895b4c5d6707b8bd08d6ed815d1 Mon Sep 17 00:00:00 2001
From: Behnamrhp74 <behnam.rahimpoor@beatstream.com>
Date: Thu, 13 Mar 2025 23:01:52 +0300
Subject: [PATCH 3/4] doc: Add class diagram and image for failure

---
 .../failure-class-diagram.puml                | 53 +++++++++++++++++++
 .../failure-class-diagram.svg                 |  1 +
 .../failure-error-handling.md                 |  4 +-
 3 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 catalog/docs/failure-error-handling/failure-class-diagram.puml
 create mode 100644 catalog/docs/failure-error-handling/failure-class-diagram.svg
 rename catalog/docs/{ => failure-error-handling}/failure-error-handling.md (98%)

diff --git a/catalog/docs/failure-error-handling/failure-class-diagram.puml b/catalog/docs/failure-error-handling/failure-class-diagram.puml
new file mode 100644
index 0000000..708ff76
--- /dev/null
+++ b/catalog/docs/failure-error-handling/failure-class-diagram.puml
@@ -0,0 +1,53 @@
+@startuml Failure Class Diagram
+abstract BaseFailure {
+ - String BASE_FAILURE_MESSAGE = "failure"
+ + String message = this.BASE_FAILURE_MESSAGE
+ 
+ constructor(key: string)
+}
+
+class UserFailure {
+	constructor(key: string)
+}
+
+note left 
+	Extends parent message key by sending 
+  `user` keyword as a domain to parent.
+  So in `UserFailure` our `message` 
+  	property will be `failure.user`.
+end note
+
+UserFailure --|> BaseFailure
+
+ 
+class UserModificationFailure {
+	constructor(key: string)
+}
+note right 
+	Extends parent message key by sending 
+  `modification` keyword to parent.
+  So in `UserModificationFailure` our `message` 
+  	property will be `failure.user.modification`
+end note
+UserModificationFailure --|> UserFailure
+
+class UserModificationAlreadyExistsFailure {
+	constructor()
+}
+note left 
+	Extends parent message key by sending 
+  `alreadyExists` keyword to parent.
+  So in `UserModificationAlreadyExistsFailure`
+  	our `message` 	property will be 
+    `failure.user.modification.AlreadyExists`
+end note
+
+class DeviceFailure {
+	constructor()
+}
+
+DeviceFailure --|> BaseFailure
+UserModificationAlreadyExistsFailure --|> UserModificationFailure
+
+
+@enduml
\ No newline at end of file
diff --git a/catalog/docs/failure-error-handling/failure-class-diagram.svg b/catalog/docs/failure-error-handling/failure-class-diagram.svg
new file mode 100644
index 0000000..7eab9a2
--- /dev/null
+++ b/catalog/docs/failure-error-handling/failure-class-diagram.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="us-ascii" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="516px" preserveAspectRatio="none" style="width:956px;height:516px;background:#FFFFFF;" version="1.1" viewBox="0 0 956 516" width="956px" zoomAndPan="magnify"><defs/><g><!--class BaseFailure--><g id="elem_BaseFailure"><rect codeLine="1" fill="#F1F1F1" height="96.8906" id="BaseFailure" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="358" x="403" y="412.73"/><ellipse cx="537.75" cy="428.73" fill="#A9DCDF" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M537.8594,424.0738 L536.7031,429.1519 L539.0313,429.1519 L537.8594,424.0738 Z M536.375,421.8394 L539.3594,421.8394 L542.7188,434.23 L540.2656,434.23 L539.5,431.1675 L536.2188,431.1675 L535.4688,434.23 L533.0313,434.23 L536.375,421.8394 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="80" x="558.25" y="433.5767">BaseFailure</text><line style="stroke:#181818;stroke-width:0.5;" x1="404" x2="760" y1="444.73" y2="444.73"/><rect fill="none" height="6" style="stroke:#C82930;stroke-width:1.0;" width="6" x="411" y="455.3784"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="290" x="423" y="461.7251">String BASE_FAILURE_MESSAGE = "failure"</text><ellipse cx="414" cy="474.6753" fill="none" rx="3" ry="3" style="stroke:#038048;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="332" x="423" y="478.022">String message = this.BASE_FAILURE_MESSAGE</text><line style="stroke:#181818;stroke-width:0.5;" x1="404" x2="760" y1="485.3238" y2="485.3238"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="162" x="409" y="502.3189">constructor(key: string)</text></g><!--class UserFailure--><g id="elem_UserFailure"><rect codeLine="8" fill="#F1F1F1" height="64.2969" id="UserFailure" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="174" x="403" y="285.32"/><ellipse cx="447.25" cy="301.32" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M450.2188,306.9606 Q449.6406,307.2575 449,307.3981 Q448.3594,307.5544 447.6563,307.5544 Q445.1563,307.5544 443.8281,305.9138 Q442.5156,304.2575 442.5156,301.1325 Q442.5156,298.0075 443.8281,296.3513 Q445.1563,294.695 447.6563,294.695 Q448.3594,294.695 449,294.8513 Q449.6563,295.0075 450.2188,295.3044 L450.2188,298.0231 Q449.5938,297.445 449,297.1794 Q448.4063,296.8981 447.7813,296.8981 Q446.4375,296.8981 445.75,297.9763 Q445.0625,299.0388 445.0625,301.1325 Q445.0625,303.2263 445.75,304.3044 Q446.4375,305.3669 447.7813,305.3669 Q448.4063,305.3669 449,305.1013 Q449.5938,304.82 450.2188,304.2419 L450.2188,306.9606 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="77" x="467.75" y="306.1667">UserFailure</text><line style="stroke:#181818;stroke-width:0.5;" x1="404" x2="576" y1="317.32" y2="317.32"/><line style="stroke:#181818;stroke-width:0.5;" x1="404" x2="576" y1="325.32" y2="325.32"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="162" x="409" y="342.3151">constructor(key: string)</text></g><g id="elem_GMN4"><path d="M84,282.2 L84,352.7313 A0,0 0 0 0 84,352.7313 L368,352.7313 A0,0 0 0 0 368,352.7313 L368,321.46 L402.54,317.46 L368,313.46 L368,292.2 L358,282.2 L84,282.2 A0,0 0 0 0 84,282.2 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M358,282.2 L358,292.2 L368,292.2 L358,282.2 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="259" x="90" y="299.2669">Extends parent message key by sending</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="248" x="94" y="314.3997">`user` keyword as a domain to parent.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="224" x="94" y="329.5325">So in `UserFailure` our `message`</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="4" x="90" y="344.6653">&#160;</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="189" x="122" y="344.6653">property will be `failure.user`.</text></g><!--class UserModificationFailure--><g id="elem_UserModificationFailure"><rect codeLine="22" fill="#F1F1F1" height="64.2969" id="UserModificationFailure" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="191" x="394.5" y="154.78"/><ellipse cx="409.5" cy="170.78" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M412.4688,176.4206 Q411.8906,176.7175 411.25,176.8581 Q410.6094,177.0144 409.9063,177.0144 Q407.4063,177.0144 406.0781,175.3738 Q404.7656,173.7175 404.7656,170.5925 Q404.7656,167.4675 406.0781,165.8113 Q407.4063,164.155 409.9063,164.155 Q410.6094,164.155 411.25,164.3113 Q411.9063,164.4675 412.4688,164.7644 L412.4688,167.4831 Q411.8438,166.905 411.25,166.6394 Q410.6563,166.3581 410.0313,166.3581 Q408.6875,166.3581 408,167.4363 Q407.3125,168.4988 407.3125,170.5925 Q407.3125,172.6863 408,173.7644 Q408.6875,174.8269 410.0313,174.8269 Q410.6563,174.8269 411.25,174.5613 Q411.8438,174.28 412.4688,173.7019 L412.4688,176.4206 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="159" x="423.5" y="175.6267">UserModificationFailure</text><line style="stroke:#181818;stroke-width:0.5;" x1="395.5" x2="584.5" y1="186.78" y2="186.78"/><line style="stroke:#181818;stroke-width:0.5;" x1="395.5" x2="584.5" y1="194.78" y2="194.78"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="162" x="400.5" y="211.7751">constructor(key: string)</text></g><g id="elem_GMN9"><path d="M620.5,151.67 L620.5,182.93 L585.93,186.93 L620.5,190.93 L620.5,222.2013 A0,0 0 0 0 620.5,222.2013 L949.5,222.2013 A0,0 0 0 0 949.5,222.2013 L949.5,161.67 L939.5,151.67 L620.5,151.67 A0,0 0 0 0 620.5,151.67 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M939.5,151.67 L939.5,161.67 L949.5,161.67 L939.5,151.67 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="259" x="626.5" y="168.7369">Extends parent message key by sending</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="215" x="630.5" y="183.8697">`modification` keyword to parent.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="300" x="630.5" y="199.0025">So in `UserModificationFailure` our `message`</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="4" x="626.5" y="214.1353">&#160;</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="267" x="658.5" y="214.1353">property will be `failure.user.modification`</text></g><!--class UserModificationAlreadyExistsFailure--><g id="elem_UserModificationAlreadyExistsFailure"><rect codeLine="33" fill="#F1F1F1" height="64.2969" id="UserModificationAlreadyExistsFailure" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="281" x="349.5" y="16.69"/><ellipse cx="364.5" cy="32.69" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M367.4688,38.3306 Q366.8906,38.6275 366.25,38.7681 Q365.6094,38.9244 364.9063,38.9244 Q362.4063,38.9244 361.0781,37.2838 Q359.7656,35.6275 359.7656,32.5025 Q359.7656,29.3775 361.0781,27.7212 Q362.4063,26.065 364.9063,26.065 Q365.6094,26.065 366.25,26.2212 Q366.9063,26.3775 367.4688,26.6744 L367.4688,29.3931 Q366.8438,28.815 366.25,28.5494 Q365.6563,28.2681 365.0313,28.2681 Q363.6875,28.2681 363,29.3462 Q362.3125,30.4087 362.3125,32.5025 Q362.3125,34.5963 363,35.6744 Q363.6875,36.7369 365.0313,36.7369 Q365.6563,36.7369 366.25,36.4713 Q366.8438,36.19 367.4688,35.6119 L367.4688,38.3306 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="249" x="378.5" y="37.5367">UserModificationAlreadyExistsFailure</text><line style="stroke:#181818;stroke-width:0.5;" x1="350.5" x2="629.5" y1="48.69" y2="48.69"/><line style="stroke:#181818;stroke-width:0.5;" x1="350.5" x2="629.5" y1="56.69" y2="56.69"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="90" x="355.5" y="73.6851">constructor()</text></g><g id="elem_GMN14"><path d="M6,6 L6,91.6641 A0,0 0 0 0 6,91.6641 L314,91.6641 A0,0 0 0 0 314,91.6641 L314,52.83 L349.01,48.83 L314,44.83 L314,16 L304,6 L6,6 A0,0 0 0 0 6,6 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M304,6 L304,16 L314,16 L304,6 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="259" x="12" y="23.0669">Extends parent message key by sending</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="221" x="16" y="38.1997">`alreadyExists` keyword to parent.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="283" x="16" y="53.3325">So in `UserModificationAlreadyExistsFailure`</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="4" x="12" y="68.4653">&#160;</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="98" x="44" y="68.4653">our `message`</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="96" x="172" y="68.4653">property will be</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="256" x="24" y="83.5981">`failure.user.modification.AlreadyExists`</text></g><!--class DeviceFailure--><g id="elem_DeviceFailure"><rect codeLine="44" fill="#F1F1F1" height="64.2969" id="DeviceFailure" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="124" x="612" y="285.32"/><ellipse cx="627" cy="301.32" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M629.9688,306.9606 Q629.3906,307.2575 628.75,307.3981 Q628.1094,307.5544 627.4063,307.5544 Q624.9063,307.5544 623.5781,305.9138 Q622.2656,304.2575 622.2656,301.1325 Q622.2656,298.0075 623.5781,296.3513 Q624.9063,294.695 627.4063,294.695 Q628.1094,294.695 628.75,294.8513 Q629.4063,295.0075 629.9688,295.3044 L629.9688,298.0231 Q629.3438,297.445 628.75,297.1794 Q628.1563,296.8981 627.5313,296.8981 Q626.1875,296.8981 625.5,297.9763 Q624.8125,299.0388 624.8125,301.1325 Q624.8125,303.2263 625.5,304.3044 Q626.1875,305.3669 627.5313,305.3669 Q628.1563,305.3669 628.75,305.1013 Q629.3438,304.82 629.9688,304.2419 L629.9688,306.9606 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="92" x="641" y="306.1667">DeviceFailure</text><line style="stroke:#181818;stroke-width:0.5;" x1="613" x2="735" y1="317.32" y2="317.32"/><line style="stroke:#181818;stroke-width:0.5;" x1="613" x2="735" y1="325.32" y2="325.32"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="90" x="618" y="342.3151">constructor()</text></g><!--link UserFailure to BaseFailure--><g id="link_UserFailure_BaseFailure"><path codeLine="19" d="M510.42,349.91 C522.33,368.26 527.782,376.6868 541.162,397.2768 " fill="none" id="UserFailure-to-BaseFailure" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="550.97,412.37,546.1931,394.0075,536.131,400.5462,550.97,412.37" style="stroke:#181818;stroke-width:1.0;"/></g><!--link UserModificationFailure to UserFailure--><g id="link_UserModificationFailure_UserFailure"><path codeLine="31" d="M490,219.37 C490,239.29 490,246.96 490,266.9 " fill="none" id="UserModificationFailure-to-UserFailure" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="490,284.9,496,266.9,484,266.9,490,284.9" style="stroke:#181818;stroke-width:1.0;"/></g><!--link DeviceFailure to BaseFailure--><g id="link_DeviceFailure_BaseFailure"><path codeLine="48" d="M653.58,349.91 C641.67,368.26 636.218,376.6868 622.838,397.2768 " fill="none" id="DeviceFailure-to-BaseFailure" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="613.03,412.37,627.869,400.5462,617.8069,394.0075,613.03,412.37" style="stroke:#181818;stroke-width:1.0;"/></g><!--link UserModificationAlreadyExistsFailure to UserModificationFailure--><g id="link_UserModificationAlreadyExistsFailure_UserModificationFailure"><path codeLine="49" d="M490,81.4 C490,103.39 490,114.59 490,136.54 " fill="none" id="UserModificationAlreadyExistsFailure-to-UserModificationFailure" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="490,154.54,496,136.54,484,136.54,490,154.54" style="stroke:#181818;stroke-width:1.0;"/></g><!--SRC=[bTBTRe8m60RWOx-hUEFHbaKkOCcMO8RBadaouh6jKBKHgMdBb6oxznN6128OEQNVpzkdy9MncaSMKsx4ZCiaqm9VX0b2gsMwmTGFW-NCVtjVV0JBUH26_ck09upNVxLZmiD_wLuOmpV2dTgjD5vN9u4GgTJjp2AhzDrEv8ymPViz_H152JS62oDqdMLqhI5LLY0HQmiQ1IShqjZWmBL8xJcEQy4gXt5dHKe2MEOMiEBWg7GCRi0HgpsNAQogsZrN5oguJwmHXq5b6gmQpOfXeuDM1w5jZgDC4gm4M6NZbMiySejHv2HgNcmo-NvkgfEpgQy_Lx5SouXRgTBRA4e9BJVROHJxngAQf8-X8zPm4g-ri-RfktSfrQ2Z7YS_qOB7UN2InfeUjBFKu7-6DwSFa-eAnWgdjjmbcwl15JklDRWXMG6zY4yPYIiIrAwu-2Ll4Zu_JyVR_G80]--></g></svg>
\ No newline at end of file
diff --git a/catalog/docs/failure-error-handling.md b/catalog/docs/failure-error-handling/failure-error-handling.md
similarity index 98%
rename from catalog/docs/failure-error-handling.md
rename to catalog/docs/failure-error-handling/failure-error-handling.md
index 093a18a..e8a96b9 100644
--- a/catalog/docs/failure-error-handling.md
+++ b/catalog/docs/failure-error-handling/failure-error-handling.md
@@ -212,4 +212,6 @@ if (!isLeft(usecaseResponse)) return;
   if (!(usecaseResponse instanceOf BaseFailure)) return;
 
 const translatedFailureMessage = t(usecaseResponse.left.message)
-```
\ No newline at end of file
+```
+This is the final version, class diagram for our failur architecture:
+![Failure class diagram](./failure-class-diagram.svg)

From 4291fa832aedddaf081b1d66a577fe68513f4ee8 Mon Sep 17 00:00:00 2001
From: Behnamrhp74 <behnam.rahimpoor@beatstream.com>
Date: Fri, 14 Mar 2025 00:07:13 +0300
Subject: [PATCH 4/4] doc: finalize failure document

---
 .../failure-error-handling.md                 | 117 +++++++++++-------
 1 file changed, 73 insertions(+), 44 deletions(-)

diff --git a/catalog/docs/failure-error-handling/failure-error-handling.md b/catalog/docs/failure-error-handling/failure-error-handling.md
index e8a96b9..56ac874 100644
--- a/catalog/docs/failure-error-handling/failure-error-handling.md
+++ b/catalog/docs/failure-error-handling/failure-error-handling.md
@@ -1,21 +1,22 @@
 # Error handling with failure
 
 ## What is failure
-In each application and in each logic, there can be failure on the process and based on their complexity it can be few or many possilbe scenarios for these failures.
+In each application and in each logic, there can be failures in the process, and based on their complexity, there can be a few or many possible scenarios for these failures.
 
-In software development we always trying to have more controll on this failure to:
-- Avoid possible bugs  
-- Help user to understand about the state of the application with proper messages
-- Controll on the processes for some side effects
-- Monitor the behavior of the application
+In software development, we always try to have more control over these failures to:
 
-So having a specific way of error handling for these failure to achieve all these requirements in our app, helps us to build more robust, trustable, and maintainable application.
+Avoid possible bugs
+Help users understand the state of the application with proper messages
+Control processes for side effects
+Monitor the behavior of the application
+So, having a specific way of handling errors to achieve all these requirements in our app helps us build a more robust, reliable, and maintainable application.
 
-Many frameworks provides their own ways to handle these failures which thet can name it as exceptions, failures or any other things, but for sure we shouldn't always depend our logics and apps to the behavior of the frameworks and besides there are many frameworks which doesn't provide error handling tools, so we should always have a specific and reliable way to handle our errors in all layers of the application.
+Many frameworks provide their own ways to handle these failures, which they may call exceptions, failures, or other terms. But we shouldn't always depend on the behavior of frameworks for our logic and apps. Besides, many frameworks do not provide error handling tools, so we need to design a reliable architecture for the error handling in our application.
 
 ## Failure handling with base failure
-To have granular controll on the failure and have specific type for all errors we can use the inheritance and abstraction power of oop.
-So we can define an abstract calsss as our base failure, which is our specific type of our failures in the application.
+To have granular control over failures and define a specific type for all errors, we can use the power of inheritance and abstraction in OOP.
+
+We can define an abstract class as our base failure, which serves as the specific type for all failures in the application.
 
 ```ts
 export default abstract class BaseFailure<META_DATA> {
@@ -28,10 +29,11 @@ export default abstract class BaseFailure<META_DATA> {
 }
 
 ```
-As you see it's just a simple abstract class which gets some metadata about details of error in any shape. But wait it's just starting of the story, we can have many ideas with this failure.
+As you can see, it's just a simple abstract class that takes some metadata about the error details in any form. But wait, this is just the beginning of the story, we can explore many ideas with this failure.
 
 ## How to write a simple failure
-So for creating a simple failure we can just define our failure in any domain for any scenaio which we need like this:
+So, to create a simple failure, we can define our failure in any domain for any scenario we need, like this:
+
 ```ts
 export default class CreateUserFailure extends BaseFailure<{ userId: string }> {
   constructor(metadata?: { userId: string }) {
@@ -40,38 +42,53 @@ export default class CreateUserFailure extends BaseFailure<{ userId: string }> {
 }
 ```
 
-So in our logics for creating user we can return specific tyep of failure for creating user.
+So in our logics for creating user we can return specific type of failure for creating user.
 
 ## Combination with Functional programming
-Functional programming is a deep topic which we cannot cover it here for more details and learn about it you can watch these course or many courses and related books which exists on the web. But for this article we care about one of the most useful functors in functional programming and how failure can fit perfectly with failure. And this functor is either funtor. 
-Either provides a data which is two parts, it's right answer and left answer. right answer is the type of the answer which we expect from either and left answer is exactly what we need as unexpected result.
-You're gussing right this base failure will be our left answers for either functor.
+Functional programming is a deep topic that we cannot fully cover here. For more details, you can check out various courses and books available online.
+
+However, for this article, we focus on one of the most useful functors in functional programming and how failure fits perfectly with it. This concept is the Either type.
+
+Either is an algebraic data type (ADT) that represents computations that can return either a success or a failure. It consists of two possible values:
+
+- Right(value): Represents a successful result.
+- Left(error): Represents a failure or unexpected result.
+
+You're guessing right, our base failure will serve as the Left value in Either, allowing us to handle errors in a structured and functional way.
+
 ```ts
 Either<
   BaseFailure<unknown>,
   ResponseType
 >
 ```
-So as we always have specific type for handling unexpected resulsts, so we can define a new type for either in our app.
+So as we always have specific type for handling unexpected results, so we can define a new type for either in our app.
 ```ts
 export type ApiEither<ResponseType> = Either<
   BaseFailure<unknown>,
   ResponseType
 >;
 ```
-So any othe either which for calling api we can use this either type for them.
-And also for async process we use TaskEither which is the same as either functor but for asynchronous process.
+So, for any API calls, we can use the Either type to handle both success and failure cases.
+
+Additionally, for asynchronous processes, we use TaskEither, which works similarly to Either but is designed for handling asynchronous operations.
+
+
 ```ts
 type ApiTask<ResponseType> = TaskEither<BaseFailure<unknown>, ResponseType>;
 ```
 
-For example to get customers repository to handle all calling for customer api we can use this type for them.
+For example, when creating a customer repository to handle all API calls for customers, we can use this type to manage success and failure cases.
+
 ```ts
 export default interface CustomerRepo {
   fetchList(query: string): ApiTask<Customer[]>;
 }
 ```
 And in the repo we can have this pipe to get customer data:
+
+> Note: In functional programming, a pipe is a composition of functions where the output of one function is passed as the input to the next, allowing for a clean, readable flow of data transformations.
+
 ```ts
 pipe(
       tryCatch(
@@ -83,11 +100,11 @@ pipe(
       map(this.customersDto.bind(this)),
     ) as ApiTask<Customer[]>;
 ```
-Pipe is just a pipe of process and operations which we make on the data to shape the whole process.
+As you can see, in the try-catch block, which is the constructor of ApiEither, we define the right response in the first callback and the failure in the second callback argument.
 
-As you see in try catch which is constructor of a ApiEither we defined our right response from first callback and our failure as the second callback argument.
-And failureOr is just a helper to get a error and turn to some specific failure __which is NetworkFailure in this example__ 
-So in the process of fetching customer we know the unexpected result, always will be a speicfic type. 
+failureOr is just a helper function that takes an error and converts it into a specific failure type, NetworkFailure in this example.
+
+This ensures that during the process of fetching customer data, we always know the unexpected result will be of a specific type.
 ```ts
 export function failureOr(
   reason: unknown,
@@ -99,27 +116,30 @@ export function failureOr(
   return failure;
 }
 ```
+So in the process of fetching customer we know the unexpected result, always will be a speicfic type. 
 So in any layer we can get the failure do some logics on left response based on its metadata and turn the failure shape to any other failure shape and use it for different purposes.
 
 ## Usecases of this idea
 
-### Monitoring for failures
-There are many situations that when some important process had some problems we wanna have controll on it, to know when and why these things happened and store it in one of the monitoting tools. 
+There are many situations where, if an important process encounters problems, we want to have control over it. We need to know when and why these issues happened and store that information in one of the monitoring tools.
 
-For example on getting CreateUserFailure in repository layer, we can send a log with specific time and use parameters data to any logging or monitoring tools.
+For example, when a CreateUserFailure occurs in the repository layer, we can send a log with the specific time and relevant parameter data to any logging or monitoring tool.
 
 ### Monitoring on bugs with dev failures
-There are many situations specifally in frontend appications which some unexpected behavior happens from the development mistakes and bugs for example by getting some bugs or data changes in apis, it's possible to face with unexpected behaviors  and we wanna show some specific message or redirect user to error page with descent message. On top of in frontend applications they cannot get the log in this situation as it's happened in the user's system, so they can send the metadata as a log to one api if they face with dev failures.
+There are many situations, especially in frontend applications, where unexpected behavior occurs due to development mistakes or bugs. For example, when bugs or data changes in APIs happen, it's possible to face unexpected behaviors. In such cases, we want to show a specific message or redirect the user to an error page with a clear message.
 
-To acheive this we can simply define another abstract failure like this:
+Additionally, in frontend applications, logs may not be directly available in these situations, as the issue occurs on the user's system. To handle this, we can send metadata as a log to an API when encountering development failures.
+
+To achieve this, we can simply define another abstract failure like this:
 
 ```ts
 export default abstract class BaseDevFailure<
   META_DATA,
 > extends BaseFailure<META_DATA> {}
 ```
-As you see it's just another failure which is extend from base failure.
-So for example in some part of application which should send some arguments into domain layer and as these arguments are dynamic and possible to send unexpected data we can define one dev failure for this situation like this:
+As you can see, it’s just another failure that extends from the base failure.
+
+For example, in some parts of the application, when sending dynamic arguments into the domain layer, there's a possibility of sending unexpected data. In such situations, we can define a specific development failure like this:
 ```ts
 export default class ArgumentsFailure<
   META_DATA,
@@ -132,14 +152,13 @@ export default class ArgumentsFailure<
 So we can consider this scenario in our logics and facing with this failure we can make a log request to our log api even from frontend applications, so on facing with this situation they can show a descent message to user to contact to support team at the same time they store the bug log to have full controll on these situations.
 
 ### Manage translations and error messages with failure
-With this idea we can move one step beyound error handling and even handle translation and showing related messages in frontend applications in an automatic way.
+With this approach, we can go a step further than just error handling and even manage translations and display related messages in frontend applications automatically.
 
-For each process and scenario we should define specific failure and also at the same time for each one of them we should show specific message in specific language based on selected language by the user. 
+For each process and scenario, we should define a specific failure. At the same time, for each failure, we should display a corresponding message in the selected language based on the user's preference.
 
-So we can use this idea and automate these process together.
+We can use this idea to automate both the error handling and message translation process.
 
-To achieve this requirement we can pass a unique  string key from constructor based on the failure scenario.
-So our base failure will turn like this:
+To achieve this, we can pass a unique string key from the constructor based on the failure scenario. Our base failure will look like this:
 ```ts
 export default abstract class BaseFailure<META_DATA> {
   private readonly BASE_FAILURE_MESSAGE = "failure";
@@ -166,13 +185,15 @@ export function makeFailureMessage(message: string, key: string) {
 }
 
 ```
-As you see we have a message property, which has 
-`BASE_FAILURE_MESSAGE` which is the base key for all failure messages. Also it gets key from constructor and with makeFailureMessage function concat the new key with the message and shape new message for each failre.
+As you can see, we have a message property, which contains `BASE_FAILURE_MESSAGE`, the base key for all failure messages. It also accepts a key from the constructor, and with the makeFailureMessage function, it concatenates the new key with the message, shaping a unique message for each failure.
+
+Each failure can have its own key passed from its constructor.
+
+In the end, we can have a chained message key that we can use as the message key for each failure.
+
+For example, for a failure like `UserAlreadyExistsFailure`, we can have a parent failure for all user domain failures, like this:
 
-Also each failure can get their own key from their constructors.
-So at the end of the day we can have a chained message key that we can use it as a message key.
 
-For example for a failure like `UserAlreadyExistsFailure` we can have a parent failure for all user domain failures like this:
 
 ```ts
 export default class UserFailure extends BaseFailure {
@@ -181,7 +202,7 @@ export default class UserFailure extends BaseFailure {
   }
 }
 ```
-and now we can make our failure:
+and now we can define our failure:
 ```ts
 export default class UserAlreadyExistsFailure extends UserFailure {
   constructor() {
@@ -191,7 +212,7 @@ export default class UserAlreadyExistsFailure extends UserFailure {
 ```
 so the result of message for `UserAlreadyExistsFailure`, will be `failure.user.alreadyExists`.
 
-At the same time in other place in our project we're using langkey object to specify translation key and this object, like failure follows domain and folder structure to specify lang key.
+At the same time, in another part of our project, we're using a langKey object to specify the translation key. This object, like the failure structure, follows the domain and folder structure to specify the language key.
 
 ```ts
 const langKey = {
@@ -203,7 +224,7 @@ const langKey = {
   }
 }
 ```
-So we can use our failure message key to get lang key and by passing it to translation method we can get translated failure message and make a automated process to show error message based on failure that we get.
+So, we can use our failure message key to retrieve the language key. By passing it to the translation method, we can get the translated failure message and automate the process of displaying the error message based on the failure we encounter.
 
 ```ts
 const usecaseResponse = await getUsersUsecase() as Promise<Either<BaseFailure, User[]>>
@@ -215,3 +236,11 @@ const translatedFailureMessage = t(usecaseResponse.left.message)
 ```
 This is the final version, class diagram for our failur architecture:
 ![Failure class diagram](./failure-class-diagram.svg)
+
+## Conclusion
+In this article, we've explored how to handle failures effectively in software applications by combining error handling with functional programming concepts like the Either type. 
+
+Furthermore, by integrating these failure handling mechanisms with automated processes for translating and displaying error messages, we create a more seamless experience for users, no matter the scenario. This approach not only improves the user experience by offering clear and context-specific messages, but it also provides valuable insights through monitoring and logging, enabling teams to quickly address issues.
+
+Ultimately, this architecture supports building more robust, maintainable, and user-friendly applications, which I have used in many of my own projects, especially in frontend ones.
+