Skip to content

Instantly share code, notes, and snippets.

@phillippelevidad
Created November 4, 2023 00:27
Show Gist options
  • Save phillippelevidad/b1df7c17bf4278c4495ee6e084770bf5 to your computer and use it in GitHub Desktop.
Save phillippelevidad/b1df7c17bf4278c4495ee6e084770bf5 to your computer and use it in GitHub Desktop.
Product class, getters/setters, validation, business rules
/*
In the realm of OOP, it's preferable for business logic to be in close proximity to the data it pertains to.
This not only aligns with the 'S' in the SOLID principles—emphasizing, that Single Responsibility is about segregating unrelated
duties but also about consolidating related ones.
The method outlined below leverages getters and setters to intercept data handling, thereby preventing the model from accepting
any invalid values. This ensures that an invalid product could never exist within the system.
It should be noted that the validations demonstrated here are simplistic and meant for illustrative purposes.
Such rudimentary checks would typically reside outside the domain class, shifted towards the outer layers of the architecture,
a concept explored in this insightful video by Derek Comartin from CodeOpinion.com: https://www.youtube.com/watch?v=FbYcIqVmGRk
However, if the validations extend beyond mere format checks to become significant for business operations, they ought to be
embedded within the Model in an OOP-centric approach. For further exploration on where to place business logic within an
application, this additional video can be quite enlightening: https://www.youtube.com/watch?v=PrJIMTZsbDw
*/
class Product {
#id;
#name;
#price;
constructor({ id, name, price }) {
this.id = id;
this.name = name;
this.price = price;
}
get id() {
return this.#id;
}
set id(value) {
if (value.length < 2 || value.length > 20)
throw new DomainError("Invalid id");
this.#id = value;
}
get name() {
return this.#name;
}
set name(value) {
if (!/^[a-zA-Z]+$/.test(value)) throw new DomainError("Invalid name");
this.#name = value;
}
get price() {
return this.#price;
}
set price(value) {
if (value <= 0) throw new DomainError("Invalid price");
this.#price = value;
}
valueOf() {
return {
id: this.id,
name: this.name,
price: this.price,
};
}
toJSON() {
return this.valueOf();
}
}
class DomainError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
}
}
function createValid() {
return new Product({
id: "000001",
name: "Computer",
price: 100,
});
}
function createInvalid() {
return new Product({
id: "",
name: "123",
price: 0,
});
}
const assert = require("assert");
assert.doesNotThrow(() => createValid());
assert.throws(() => createInvalid(), DomainError);
assert.equal(
JSON.stringify(createValid()),
'{"id":"000001","name":"Computer","price":100}'
);
assert.deepStrictEqual(createValid().valueOf(), {
id: "000001",
name: "Computer",
price: 100,
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment