Unit of Work ํจํด
Unit of Work(์ดํ UoW)๋ ์๋น์ค ๋ ์ด์ด์ ๋ ํฌ์งํฐ๋ฆฌ ๋ ์ด์ด ์ฌ์ด์ ๋ค์ด๊ฐ๋ ๋๋ค๋ฅธ ๋ ์ด์ด ํจํด์ด๋ค.
์น์๋ฒ์์ ๋ค์๊ณผ ๊ฐ์ ๋ ์ด์ด ๊ตฌ์กฐ์ ๋ํด ์ดํดํ๊ณ ์๋ค๊ณ ๊ฐ์ ํ๋ค.

์์์ฑ (Atomic)
UoW์ ์ฃผ์ ๋ชฉ์ ๊ณผ ์ฉ๋๋ I/O ์์ ์ ๋ํ ์์์ฑ์ ์๋ค.
์ฝ๊ฒ ๋งํ๋ฉด, RDB์์ ๋จ์ผ ํธ๋์ญ์
๋จ์์ ์ฌ๋ฌ๊ฐ์ง ์ฐ์ฐ์ ๋ฌถ์ด์ ์ฌ์ฉํ ๋๊ฐ ๋ง์ ๊ฒ์ด๋ค.
ํนํ ์ผ๋ถ๋ง ์คํจํ๋๋ผ๋ ๊ทธ ์์ ์ฌํญ ์ ์ฒด๋ฅผ rollbackํด์ผ ํ ๊ฒฝ์ฐ ๋ง์ด๋ค.
UoW๋ ๊ทธ๋ฐ ํธ๋์ญ์ ๋จ์์ commit๊ณผ rollback์ ์ฒ๋ฆฌํ๋ ๊ป๋ฐ๊ธฐ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ์ฐ๋ ๊ฒ์ด๋ค.
๊ทธ๋ฆผ์ผ๋ก ํํํ๋ฉด ์ด๋ ๋ค.

์ฌ์ฉ๋ก (Node.js + Sequelize)
Nest.js + Sequelize์์ UoW ํจํด์ ๊ตฌํํด์ ์ ์ฉํ๋ ์์๋ฅผ ๋ณด์ฌ๋ณด๊ฒ ๋ค.
UoW๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋ ์ด์ด๋ฅผ ๊ตฌ์ฑํ ์ ์์ ๊ฒ์ด๋ค.
๋ ํฌ์งํ ๋ฆฌ๊ฐ ์๊ณ , ์๋น์ค๊ฐ ๋ฐ๋ก ๋ ํฌ์งํ ๋ฆฌ๋ฅผ ๊ฐ๋ค์ด๋ค.
ํ์ง๋ง ์ด ์ฝ๋์๋ ์์์ฑ์ ๋ํ ๋ฐ์์ด ๋์ด์์ง ์๋ค.
์ ์๋น์ค์์ ํ๋๋ผ๋ ์๋ํ๋ค๋ฉด ์ด์ฉ๊ฒ ๋๊ฐ?
์ ๊ธฐ์ ๊ทธ๋ฅ ํธ๋์ญ์
์ ์ถ๊ฐํ๋ค๋ฉด, ์ด๋ฐ์์ผ๋ก ํด๋ณผ ์ ์์ ๊ฒ์ด๋ค.
๋ ํฌ์งํ ๋ฆฌ ๋ฉ์๋์์๋ ๋ช
์์ ์ผ๋ก ํธ๋์ญ์
์ ์ ๋ฌ๋ฐ๊ณ ,

์๋น์ค์์๋ ๋ช ์์ ์ผ๋ก ํธ๋์ญ์ ์ ์์ฑํด์ ์ฃผ์ ํ๋ค.
์ด ๋ฐฉ๋ฒ์ ๊ทธ๋ญ์ ๋ญ ์ธ๋งํ์ง๋ง, ๊ทธ๋ฆฌ ์ธ๋ จ๋ ๋ชจ์์๋ ์๋๋ค.
ํธ๋์ญ์
์์ฒด๋ ์ฌ์ค ๋ฐ์ดํฐ์ I/O์ ์ง์ ์ ์ผ๋ก ์ฐ๊ด๋ ๊ธฐ๋ฅ์ธ๋ฐ, ๊ทธ๊ฑธ ์๋น์ค์์ ํ๊ณ ์์ผ๋ ๋ง์ด๋ค.
๋ณด๋ค ๋ฐ๋์งํ ํํ๋ UoW ๋ ์ด์ด๋ฅผ ์ถ๊ฐํด์ ํธ๋์ญ์
์ ๋ํ ์ฒ๋ฆฌ๋ฅผ ์ถ์ํํ๊ณ ๋ถ๋ฆฌํ๋ ๊ฒ์ด๋ค.
์ด๋ฐ ์์ผ๋ก ๋ง๋ค ์ ์๋ค.
์ปค๋ฐ๊ณผ ๋กค๋ฐฑ์ ๋ํ ์ฒ๋ฆฌ๋ฅผ ์ํํ๊ณ , ๋ ํฌ์งํ ๋ฆฌ๋ฅผ ํธ๋์ญ์
๊ธฐ๋ฐ์ผ๋ก ์์ฑํด์ฃผ๋ ์ ํธ์ฑ ๊ฐ์ฒด๊ฐ ๋๋ค.
๊ทธ๋์ ๋ ํฌ์งํ ๋ฆฌ๋ ํธ๋์ญ์ ๊ฐ์ฒด๋ฅผ ์ ๋ฌ๋ฐ์์ผ ํ๊ณ

์๋น์ค๋ ์ด์ UoW๋ฅผ ํตํด ๋ ํฌ์งํ ๋ฆฌ์ ์ก์ธ์คํ๊ฒ ๋๋ค.
์กฐ๊ธ ๋ ๊ฐ๊ฒฐํด์ง๋ฟ๋ง ์๋๋ผ, ๋จ์ํ
์คํธ๋ฅผ ๊ตฌ์ฑํ ๋์๋ UnitOfWork์ Fake Object ๋ฒ์ ์ ๊ตฌํํด์ ๊ต์ฒดํ๋ฉด ๋๋ค๋ ์ฅ์ ์ด ์๋ค.
์๋๋ UoW์ ๋ํ ๋ถ๋ถ์ฝ๋๋ค.
...
export interface IUnitOfWork {
start(): void;
complete(work: () => void): Promise<void>;
getRepository<T>(R: new (transactionManager: any) => T): T;
}
@Injectable()
export class UnitOfWork implements IUnitOfWork {
constructor(
@Inject('SEQUELIZE')
private sequelize: Sequelize,
) {}
private transaction: Transaction | undefined;
async setTransactionManager() {
this.transaction = await this.sequelize.transaction();
}
async start() {
await this.setTransactionManager();
}
getRepository<T>(R: new (transaction: Transaction) => T): T {
if (!this.transaction) {
throw new Error('Unit of work is not started. Call the start() method');
}
return new R(this.transaction);
}
async complete(work: () => void) {
try {
await work();
await this.transaction?.commit();
} catch (error) {
await this.transaction?.rollback();
throw error;
}
}
}
...์ฐธ์กฐ
https://jideowosakin.com/unit-of-work-pattern-in-typescript/