์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋์์ Unit of Work ํจํด์ ์ฌ์ฉํ์ฌ ๊ฐ๋ ฅํ ํธ๋์ญ์ ๊ด๋ฆฌ๋ฅผ ๊ตฌํํ๊ณ , ์ฌ๋ฌ ์์ ์ ๊ฑธ์ณ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ๊ณผ ์ผ๊ด์ฑ์ ๋ณด์ฅํ๋ ๋ฐฉ๋ฒ์ ์์๋ด ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋ Unit of Work: ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ์ํ ํธ๋์ญ์ ๊ด๋ฆฌ
ํ๋ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ๋ฐ์์, ํนํ ๋ชจ๋์ ํ์ฉํ๊ณ ๋ฐ์ดํฐ ์์ค์ ์ํธ ์์ฉํ๋ ๋ณต์กํ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ์ ์งํ๋ ๊ฒ์ ๊ฐ์ฅ ์ค์ํฉ๋๋ค. Unit of Work ํจํด์ ํธ๋์ญ์ ์ ๊ด๋ฆฌํ๋ ๊ฐ๋ ฅํ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ์ฌ, ์ผ๋ จ์ ์์ ๋ค์ด ๋จ์ผ ์์์ ๋จ์๋ก ์ฒ๋ฆฌ๋๋๋ก ๋ณด์ฅํฉ๋๋ค. ์ด๋ ๋ชจ๋ ์์ ์ด ์ฑ๊ณตํ๊ฑฐ๋(์ปค๋ฐ), ๋ง์ฝ ์ด๋ค ์์ ์ด๋ผ๋ ์คํจํ๋ฉด ๋ชจ๋ ๋ณ๊ฒฝ ์ฌํญ์ด ๋กค๋ฐฑ๋์ด ์ผ๊ด์ฑ ์๋ ๋ฐ์ดํฐ ์ํ๋ฅผ ๋ฐฉ์งํ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ์ด ๊ธ์์๋ ์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋์ ๋งฅ๋ฝ์์ Unit of Work ํจํด์ ์ด์ , ๊ตฌํ ์ ๋ต ๋ฐ ์ค์ ์์ ๋ฅผ ํ๊ตฌํฉ๋๋ค.
Unit of Work ํจํด ์ดํดํ๊ธฐ
Unit of Work ํจํด์ ๋ณธ์ง์ ์ผ๋ก ๋น์ฆ๋์ค ํธ๋์ญ์ ๋ด์์ ๊ฐ์ฒด์ ๋ํ ๋ชจ๋ ๋ณ๊ฒฝ ์ฌํญ์ ์ถ์ ํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ด๋ฌํ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฐ์ดํฐ ์ ์ฅ์(๋ฐ์ดํฐ๋ฒ ์ด์ค, API, ๋ก์ปฌ ์คํ ๋ฆฌ์ง ๋ฑ)์ ๋จ์ผ ์์์ ์์ ์ผ๋ก ์์ํํ๋ ๊ฒ์ ์กฐ์จํฉ๋๋ค. ๋ ์ํ ๊ณ์ข ๊ฐ์ ์๊ธ์ ์ด์ฒดํ๋ ์ํฉ์ ์์ํด ๋ณด์ธ์. ํ ๊ณ์ข์์ ์ธ์ถํ๊ณ ๋ค๋ฅธ ๊ณ์ข์ ์ ๊ธํด์ผ ํฉ๋๋ค. ๋ ์์ ์ค ํ๋๋ผ๋ ์คํจํ๋ฉด, ๋์ด ์ฌ๋ผ์ง๊ฑฐ๋ ์ค๋ณต๋๋ ๊ฒ์ ๋ง๊ธฐ ์ํด ์ ์ฒด ํธ๋์ญ์ ์ด ๋กค๋ฐฑ๋์ด์ผ ํฉ๋๋ค. Unit of Work๋ ์ด๊ฒ์ด ์์ ์ ์ผ๋ก ์ผ์ด๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
ํต์ฌ ๊ฐ๋
- ํธ๋์ญ์ (Transaction): ๋จ์ผ ๋ ผ๋ฆฌ์ ์์ ๋จ์๋ก ์ทจ๊ธ๋๋ ์ผ๋ จ์ ์ฐ์ฐ. '์ ๋ถ ์๋๋ฉด ์ ๋ฌด(all or nothing)' ์์น์ ๋๋ค.
- ์ปค๋ฐ(Commit): Unit of Work๊ฐ ์ถ์ ํ ๋ชจ๋ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฐ์ดํฐ ์ ์ฅ์์ ์์ํํ๋ ๊ฒ์ ๋๋ค.
- ๋กค๋ฐฑ(Rollback): Unit of Work๊ฐ ์ถ์ ํ ๋ชจ๋ ๋ณ๊ฒฝ ์ฌํญ์ ํธ๋์ญ์ ์์ ์ ์ ์ํ๋ก ๋๋๋ฆฌ๋ ๊ฒ์ ๋๋ค.
- ๋ฆฌํฌ์งํ ๋ฆฌ(Repository) (์ ํ ์ฌํญ): ์๋ฐํ ๋งํด Unit of Work์ ์ผ๋ถ๋ ์๋์ง๋ง, ๋ฆฌํฌ์งํ ๋ฆฌ๋ ์ข ์ข ํจ๊ป ์๋ํฉ๋๋ค. ๋ฆฌํฌ์งํ ๋ฆฌ๋ ๋ฐ์ดํฐ ์ ๊ทผ ๊ณ์ธต์ ์ถ์ํํ์ฌ Unit of Work๊ฐ ์ ์ฒด ํธ๋์ญ์ ๊ด๋ฆฌ์ ์ง์คํ ์ ์๋๋ก ํฉ๋๋ค.
Unit of Work ์ฌ์ฉ์ ์ด์
- ๋ฐ์ดํฐ ์ผ๊ด์ฑ: ์ค๋ฅ๋ ์์ธ ์ํฉ์์๋ ๋ฐ์ดํฐ๊ฐ ์ผ๊ด์ฑ ์๊ฒ ์ ์ง๋จ์ ๋ณด์ฅํฉ๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ด๋ ํธ๋ฆฝ ๊ฐ์: ์ฌ๋ฌ ์์ ์ ๋จ์ผ ํธ๋์ญ์ ์ผ๋ก ๋ฌถ์ด ์ฌ๋ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ค๋ฒํค๋๋ฅผ ์ค์ด๊ณ ์ฑ๋ฅ์ ํฅ์์ํต๋๋ค.
- ๋จ์ํ๋ ์ค๋ฅ ์ฒ๋ฆฌ: ๊ด๋ จ๋ ์์ ์ ๋ํ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ์ค์ ์ง์คํํ์ฌ ์คํจ ๊ด๋ฆฌ ๋ฐ ๋กค๋ฐฑ ์ ๋ต ๊ตฌํ์ ์ฉ์ดํ๊ฒ ํฉ๋๋ค.
- ํฅ์๋ ํ ์คํธ ์ฉ์ด์ฑ: ํธ๋์ญ์ ๋ก์ง ํ ์คํธ๋ฅผ ์ํ ๋ช ํํ ๊ฒฝ๊ณ๋ฅผ ์ ๊ณตํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋์์ ์ฝ๊ฒ ๋ชจ์(mock)ํ๊ณ ๊ฒ์ฆํ ์ ์์ต๋๋ค.
- ๋์ปคํ๋ง(Decoupling): ๋น์ฆ๋์ค ๋ก์ง์ ๋ฐ์ดํฐ ์ ๊ทผ ๋ฌธ์ ์ ๋ถ๋ฆฌํ์ฌ ๋ ๊น๋ํ ์ฝ๋์ ๋ ๋์ ์ ์ง๋ณด์์ฑ์ ์ด์งํฉ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋์์ Unit of Work ๊ตฌํํ๊ธฐ
๋ค์์ ์๋ฐ์คํฌ๋ฆฝํธ ๋ชจ๋์์ Unit of Work ํจํด์ ๊ตฌํํ๋ ์ค์ ์์ ์ ๋๋ค. ๊ฐ์์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ์ฉ์ ํ๋กํ์ ๊ด๋ฆฌํ๋ ๋จ์ํ๋ ์๋๋ฆฌ์ค์ ์ด์ ์ ๋ง์ถ ๊ฒ์ ๋๋ค.
์์ ์๋๋ฆฌ์ค: ์ฌ์ฉ์ ํ๋กํ ๊ด๋ฆฌ
์ฌ์ฉ์ ํ๋กํ ๊ด๋ฆฌ๋ฅผ ๋ด๋นํ๋ ๋ชจ๋์ด ์๋ค๊ณ ์์ํด ๋ณด์ธ์. ์ด ๋ชจ๋์ ์ฌ์ฉ์์ ํ๋กํ์ ์ ๋ฐ์ดํธํ ๋ ๋ค์๊ณผ ๊ฐ์ ์ฌ๋ฌ ์์ ์ ์ํํด์ผ ํฉ๋๋ค.
- ์ฌ์ฉ์์ ๊ธฐ๋ณธ ์ ๋ณด(์ด๋ฆ, ์ด๋ฉ์ผ ๋ฑ) ์ ๋ฐ์ดํธ.
- ์ฌ์ฉ์์ ํ๊ฒฝ ์ค์ ์ ๋ฐ์ดํธ.
- ํ๋กํ ์ ๋ฐ์ดํธ ํ๋ ๋ก๊น .
์ฐ๋ฆฌ๋ ์ด ๋ชจ๋ ์์ ์ด ์์์ ์ผ๋ก ์ํ๋๊ธฐ๋ฅผ ์ํฉ๋๋ค. ๋ง์ฝ ์ด ์ค ํ๋๋ผ๋ ์คํจํ๋ฉด ๋ชจ๋ ๋ณ๊ฒฝ ์ฌํญ์ ๋กค๋ฐฑํ๊ณ ์ถ์ต๋๋ค.
์ฝ๋ ์์
๊ฐ๋จํ ๋ฐ์ดํฐ ์ ๊ทผ ๊ณ์ธต์ ์ ์ํด ๋ณด๊ฒ ์ต๋๋ค. ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ผ๋ฐ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ API์ ์ํธ ์์ฉํด์ผ ํฉ๋๋ค. ๋จ์ํ๋ฅผ ์ํด ์ธ๋ฉ๋ชจ๋ฆฌ ์คํ ๋ฆฌ์ง๋ฅผ ์ฌ์ฉํ๊ฒ ์ต๋๋ค:
// userProfileModule.js
const users = {}; // ์ธ๋ฉ๋ชจ๋ฆฌ ์คํ ๋ฆฌ์ง (์ค์ ํ๊ฒฝ์์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๋์ผ๋ก ๋์ฒด)
const log = []; // ์ธ๋ฉ๋ชจ๋ฆฌ ๋ก๊ทธ (์ ์ ํ ๋ก๊น
๋ฉ์ปค๋์ฆ์ผ๋ก ๋์ฒด)
class UserRepository {
constructor(unitOfWork) {
this.unitOfWork = unitOfWork;
}
async getUser(id) {
// ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ ์๋ฎฌ๋ ์ด์
return users[id] || null;
}
async updateUser(user) {
// ๋ฐ์ดํฐ๋ฒ ์ด์ค ์
๋ฐ์ดํธ ์๋ฎฌ๋ ์ด์
users[user.id] = user;
this.unitOfWork.registerDirty(user);
}
}
class LogRepository {
constructor(unitOfWork) {
this.unitOfWork = unitOfWork;
}
async logActivity(message) {
log.push(message);
this.unitOfWork.registerNew(message);
}
}
class UnitOfWork {
constructor() {
this.dirty = [];
this.new = [];
}
registerDirty(obj) {
this.dirty.push(obj);
}
registerNew(obj) {
this.new.push(obj);
}
async commit() {
try {
// ๋ฐ์ดํฐ๋ฒ ์ด์ค ํธ๋์ญ์
์์ ์๋ฎฌ๋ ์ด์
console.log("ํธ๋์ญ์
์์ ์ค...");
// dirty ๊ฐ์ฒด์ ๋ณ๊ฒฝ ์ฌํญ ์์ํ
for (const obj of this.dirty) {
console.log(`๊ฐ์ฒด ์
๋ฐ์ดํธ ์ค: ${JSON.stringify(obj)}`);
// ์ค์ ๊ตฌํ์์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์
๋ฐ์ดํธ๊ฐ ํฌํจ๋ฉ๋๋ค
}
// new ๊ฐ์ฒด ์์ํ
for (const obj of this.new) {
console.log(`๊ฐ์ฒด ์์ฑ ์ค: ${JSON.stringify(obj)}`);
// ์ค์ ๊ตฌํ์์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฝ์
์ด ํฌํจ๋ฉ๋๋ค
}
// ๋ฐ์ดํฐ๋ฒ ์ด์ค ํธ๋์ญ์
์ปค๋ฐ ์๋ฎฌ๋ ์ด์
console.log("ํธ๋์ญ์
์ปค๋ฐ ์ค...");
this.dirty = [];
this.new = [];
return true; // ์ฑ๊ณต ํ์
} catch (error) {
console.error("์ปค๋ฐ ์ค ์ค๋ฅ ๋ฐ์:", error);
await this.rollback(); // ์ค๋ฅ ๋ฐ์ ์ ๋กค๋ฐฑ
return false; // ์คํจ ํ์
}
}
async rollback() {
console.log("ํธ๋์ญ์
๋กค๋ฐฑ ์ค...");
// ์ค์ ๊ตฌํ์์๋ ์ถ์ ๋ ๊ฐ์ฒด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก
// ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ณ๊ฒฝ ์ฌํญ์ ๋๋๋ฆฝ๋๋ค.
this.dirty = [];
this.new = [];
}
}
export { UnitOfWork, UserRepository, LogRepository };
์ด์ ์ด ํด๋์ค๋ค์ ์ฌ์ฉํด ๋ด ์๋ค:
// main.js
import { UnitOfWork, UserRepository, LogRepository } from './userProfileModule.js';
async function updateUserProfile(userId, newName, newEmail) {
const unitOfWork = new UnitOfWork();
const userRepository = new UserRepository(unitOfWork);
const logRepository = new LogRepository(unitOfWork);
try {
const user = await userRepository.getUser(userId);
if (!user) {
throw new Error(`ID๊ฐ ${userId}์ธ ์ฌ์ฉ์๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.`);
}
// ์ฌ์ฉ์ ์ ๋ณด ์
๋ฐ์ดํธ
user.name = newName;
user.email = newEmail;
await userRepository.updateUser(user);
// ํ๋ ๊ธฐ๋ก
await logRepository.logActivity(`์ฌ์ฉ์ ${userId} ํ๋กํ์ด ์
๋ฐ์ดํธ๋์์ต๋๋ค.`);
// ํธ๋์ญ์
์ปค๋ฐ
const success = await unitOfWork.commit();
if (success) {
console.log("์ฌ์ฉ์ ํ๋กํ์ด ์ฑ๊ณต์ ์ผ๋ก ์
๋ฐ์ดํธ๋์์ต๋๋ค.");
} else {
console.log("์ฌ์ฉ์ ํ๋กํ ์
๋ฐ์ดํธ๊ฐ ์คํจํ์ต๋๋ค (๋กค๋ฐฑ๋จ).");
}
} catch (error) {
console.error("์ฌ์ฉ์ ํ๋กํ ์
๋ฐ์ดํธ ์ค ์ค๋ฅ ๋ฐ์:", error);
await unitOfWork.rollback(); // ๋ชจ๋ ์ค๋ฅ์ ๋ํด ๋กค๋ฐฑ ๋ณด์ฅ
console.log("์ฌ์ฉ์ ํ๋กํ ์
๋ฐ์ดํธ๊ฐ ์คํจํ์ต๋๋ค (๋กค๋ฐฑ๋จ).");
}
}
// ์ฌ์ฉ ์์
async function main() {
// ๋จผ์ ์ฌ์ฉ์ ์์ฑ
const unitOfWorkInit = new UnitOfWork();
const userRepositoryInit = new UserRepository(unitOfWorkInit);
const logRepositoryInit = new LogRepository(unitOfWorkInit);
const newUser = {id: 'user123', name: 'Initial User', email: 'initial@example.com'};
userRepositoryInit.updateUser(newUser);
await logRepositoryInit.logActivity(`์ฌ์ฉ์ ${newUser.id}๊ฐ ์์ฑ๋์์ต๋๋ค`);
await unitOfWorkInit.commit();
await updateUserProfile('user123', 'Updated Name', 'updated@example.com');
}
main();
์ค๋ช
- UnitOfWork ํด๋์ค: ์ด ํด๋์ค๋ ๊ฐ์ฒด์ ๋ณ๊ฒฝ ์ฌํญ์ ์ถ์ ํ๋ ์ญํ ์ ํฉ๋๋ค. `registerDirty`(์์ ๋ ๊ธฐ์กด ๊ฐ์ฒด์ฉ)์ `registerNew`(์๋ก ์์ฑ๋ ๊ฐ์ฒด์ฉ) ๋ฉ์๋๋ฅผ ๊ฐ์ง๋๋ค.
- ๋ฆฌํฌ์งํ ๋ฆฌ: `UserRepository`์ `LogRepository` ํด๋์ค๋ ๋ฐ์ดํฐ ์ ๊ทผ ๊ณ์ธต์ ์ถ์ํํฉ๋๋ค. ์ด๋ค์ `UnitOfWork`๋ฅผ ์ฌ์ฉํ์ฌ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฑ๋กํฉ๋๋ค.
- commit ๋ฉ์๋: `commit` ๋ฉ์๋๋ ๋ฑ๋ก๋ ๊ฐ์ฒด๋ค์ ์ํํ๋ฉฐ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฐ์ดํฐ ์ ์ฅ์์ ์์ํํฉ๋๋ค. ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๋ฐ์ดํธ, API ํธ์ถ ๋๋ ๋ค๋ฅธ ์์์ฑ ๋ฉ์ปค๋์ฆ์ด ํฌํจ๋ฉ๋๋ค. ๋ํ ์ค๋ฅ ์ฒ๋ฆฌ ๋ฐ ๋กค๋ฐฑ ๋ก์ง๋ ํฌํจํฉ๋๋ค.
- rollback ๋ฉ์๋: `rollback` ๋ฉ์๋๋ ํธ๋์ญ์ ์ค์ ๋ฐ์ํ ๋ชจ๋ ๋ณ๊ฒฝ ์ฌํญ์ ๋๋๋ฆฝ๋๋ค. ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๋ฐ์ดํธ๋ ๋ค๋ฅธ ์์์ฑ ์์ ์ ์ทจ์ํ๋ ์์ ์ด ํฌํจ๋ฉ๋๋ค.
- updateUserProfile ํจ์: ์ด ํจ์๋ Unit of Work๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ํ๋กํ ์ ๋ฐ์ดํธ์ ๊ด๋ จ๋ ์ผ๋ จ์ ์์ ์ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
๋น๋๊ธฐ ๊ณ ๋ ค ์ฌํญ
์๋ฐ์คํฌ๋ฆฝํธ์์ ๋๋ถ๋ถ์ ๋ฐ์ดํฐ ์ ๊ทผ ์์ ์ ๋น๋๊ธฐ์ ์ ๋๋ค(์: ํ๋ก๋ฏธ์ค์ ํจ๊ป `async/await` ์ฌ์ฉ). ์ ์ ํ ํธ๋์ญ์ ๊ด๋ฆฌ๋ฅผ ๋ณด์ฅํ๊ธฐ ์ํด Unit of Work ๋ด์์ ๋น๋๊ธฐ ์์ ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
๋์ ๊ณผ์ ์ ํด๊ฒฐ์ฑ
- ๊ฒฝ์ ์กฐ๊ฑด(Race Conditions): ๋ฐ์ดํฐ ์์์ ์ด๋ํ ์ ์๋ ๊ฒฝ์ ์กฐ๊ฑด์ ๋ฐฉ์งํ๊ธฐ ์ํด ๋น๋๊ธฐ ์์ ์ด ์ ์ ํ ๋๊ธฐํ๋๋๋ก ํด์ผ ํฉ๋๋ค. `async/await`๋ฅผ ์ผ๊ด๋๊ฒ ์ฌ์ฉํ์ฌ ์์ ์ด ์ฌ๋ฐ๋ฅธ ์์๋ก ์คํ๋๋๋ก ๋ณด์ฅํ์ธ์.
- ์ค๋ฅ ์ ํ: ๋น๋๊ธฐ ์์ ์์ ๋ฐ์ํ ์ค๋ฅ๊ฐ `commit` ๋๋ `rollback` ๋ฉ์๋๋ก ์ ๋๋ก ํฌ์ฐฉ๋๊ณ ์ ํ๋๋๋ก ํด์ผ ํฉ๋๋ค. `try/catch` ๋ธ๋ก๊ณผ `Promise.all`์ ์ฌ์ฉํ์ฌ ์ฌ๋ฌ ๋น๋๊ธฐ ์์ ์์ ๋ฐ์ํ๋ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ์ธ์.
๊ณ ๊ธ ์ฃผ์
ORM๊ณผ์ ํตํฉ
Sequelize, Mongoose ๋๋ TypeORM๊ณผ ๊ฐ์ ๊ฐ์ฒด-๊ด๊ณํ ๋งคํผ(ORM)๋ ์ข ์ข ์์ฒด ๋ด์ฅ ํธ๋์ญ์ ๊ด๋ฆฌ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ORM์ ์ฌ์ฉํ ๋, Unit of Work ๊ตฌํ ๋ด์์ ํด๋น ํธ๋์ญ์ ๊ธฐ๋ฅ์ ํ์ฉํ ์ ์์ต๋๋ค. ์ด๋ ์ผ๋ฐ์ ์ผ๋ก ORM์ API๋ฅผ ์ฌ์ฉํ์ฌ ํธ๋์ญ์ ์ ์์ํ ๋ค์, ํธ๋์ญ์ ๋ด์์ ORM์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ์ ๊ทผ ์์ ์ ์ํํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค.
๋ถ์ฐ ํธ๋์ญ์
๊ฒฝ์ฐ์ ๋ฐ๋ผ ์ฌ๋ฌ ๋ฐ์ดํฐ ์์ค๋ ์๋น์ค์ ๊ฑธ์ณ ํธ๋์ญ์ ์ ๊ด๋ฆฌํด์ผ ํ ์๋ ์์ต๋๋ค. ์ด๋ฅผ ๋ถ์ฐ ํธ๋์ญ์ ์ด๋ผ๊ณ ํฉ๋๋ค. ๋ถ์ฐ ํธ๋์ญ์ ์ ๊ตฌํํ๋ ๊ฒ์ ๋ณต์กํ ์ ์์ผ๋ฉฐ ์ข ์ข 2๋จ๊ณ ์ปค๋ฐ(2PC)์ด๋ ์ฌ๊ฐ(Saga) ํจํด๊ณผ ๊ฐ์ ํน์ ๊ธฐ์ ์ด ํ์ํฉ๋๋ค.
์ต์ข ์ผ๊ด์ฑ(Eventual Consistency)
๊ณ ๋๋ก ๋ถ์ฐ๋ ์์คํ ์์๋ ๊ฐ๋ ฅํ ์ผ๊ด์ฑ(๋ชจ๋ ๋ ธ๋๊ฐ ๋์์ ๋์ผํ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ ๊ฒ)์ ๋ฌ์ฑํ๋ ๊ฒ์ด ์ด๋ ต๊ณ ๋น์ฉ์ด ๋ง์ด ๋ค ์ ์์ต๋๋ค. ๋์์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ๋ฐ์ดํฐ๊ฐ ์ผ์์ ์ผ๋ก๋ ์ผ์นํ์ง ์์ ์ ์์ง๋ง ๊ฒฐ๊ตญ ์ผ๊ด๋ ์ํ๋ก ์๋ ด๋๋ ์ต์ข ์ผ๊ด์ฑ์ ์์ฉํ๋ ๊ฒ์ ๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ์ข ์ข ๋ฉ์์ง ํ์ ๋ฉฑ๋ฑ์ฑ(idempotent) ์์ ๊ณผ ๊ฐ์ ๊ธฐ์ ์ ์ฌ์ฉํฉ๋๋ค.
๊ธ๋ก๋ฒ ๊ณ ๋ ค ์ฌํญ
๊ธ๋ก๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ Unit of Work ํจํด์ ์ค๊ณํ๊ณ ๊ตฌํํ ๋ ๋ค์์ ๊ณ ๋ คํ์ธ์:
- ์๊ฐ๋: ํ์์คํฌํ ๋ฐ ๋ ์ง ๊ด๋ จ ์์ ์ด ์ฌ๋ฌ ์๊ฐ๋์์ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌ๋๋๋ก ํด์ผ ํฉ๋๋ค. ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋๋ UTC(ํ์ ์ธ๊ณ์)๋ฅผ ํ์ค ์๊ฐ๋๋ก ์ฌ์ฉํ์ธ์.
- ํตํ: ๊ธ์ต ๊ฑฐ๋๋ฅผ ๋ค๋ฃฐ ๋๋ ์ผ๊ด๋ ํตํ๋ฅผ ์ฌ์ฉํ๊ณ ํตํ ๋ณํ์ ์ ์ ํ๊ฒ ์ฒ๋ฆฌํ์ธ์.
- ํ์งํ(Localization): ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฌ๋ฌ ์ธ์ด๋ฅผ ์ง์ํ๋ ๊ฒฝ์ฐ, ์ค๋ฅ ๋ฉ์์ง์ ๋ก๊ทธ ๋ฉ์์ง๊ฐ ์ ์ ํ๊ฒ ํ์งํ๋๋๋ก ํ์ธ์.
- ๋ฐ์ดํฐ ํ๋ผ์ด๋ฒ์: ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ๋ GDPR(์ผ๋ฐ ๋ฐ์ดํฐ ๋ณดํธ ๊ท์ ) ๋ฐ CCPA(์บ๋ฆฌํฌ๋์ ์๋น์ ๊ฐ์ธ์ ๋ณด ๋ณดํธ๋ฒ)์ ๊ฐ์ ๋ฐ์ดํฐ ๊ฐ์ธ์ ๋ณด ๋ณดํธ ๊ท์ ์ ์ค์ํ์ธ์.
์์ : ํตํ ๋ณํ ์ฒ๋ฆฌ
์ฌ๋ฌ ๊ตญ๊ฐ์์ ์ด์๋๋ ์ ์์๊ฑฐ๋ ํ๋ซํผ์ ์์ํด ๋ณด์ธ์. Unit of Work๋ ์ฃผ๋ฌธ์ ์ฒ๋ฆฌํ ๋ ํตํ ๋ณํ์ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.
async function processOrder(orderData) {
const unitOfWork = new UnitOfWork();
// ... ๋ค๋ฅธ ๋ฆฌํฌ์งํ ๋ฆฌ๋ค
try {
// ... ๋ค๋ฅธ ์ฃผ๋ฌธ ์ฒ๋ฆฌ ๋ก์ง
// ๊ฐ๊ฒฉ์ USD(๊ธฐ๋ณธ ํตํ)๋ก ๋ณํ
const usdPrice = await currencyConverter.convertToUSD(orderData.price, orderData.currency);
orderData.usdPrice = usdPrice;
// ์ฃผ๋ฌธ ์์ธ ์ ๋ณด ์ ์ฅ (๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ณ unitOfWork์ ๋ฑ๋ก)
// ...
await unitOfWork.commit();
} catch (error) {
await unitOfWork.rollback();
throw error;
}
}
๋ชจ๋ฒ ์ฌ๋ก
- Unit of Work ๋ฒ์๋ ์งง๊ฒ ์ ์ง: ์ฅ๊ธฐ ์คํ ํธ๋์ญ์ ์ ์ฑ๋ฅ ๋ฌธ์ ์ ๊ฒฝํฉ์ ์ ๋ฐํ ์ ์์ต๋๋ค. ๊ฐ Unit of Work์ ๋ฒ์๋ฅผ ๊ฐ๋ฅํ ํ ์งง๊ฒ ์ ์งํ์ธ์.
- ๋ฆฌํฌ์งํ ๋ฆฌ ์ฌ์ฉ: ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ์ ๊ทผ ๋ก์ง์ ์ถ์ํํ์ฌ ๋ ๊น๋ํ ์ฝ๋์ ๋ ๋์ ํ ์คํธ ์ฉ์ด์ฑ์ ์ด์งํ์ธ์.
- ์ ์คํ ์ค๋ฅ ์ฒ๋ฆฌ: ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ๊ฐ๋ ฅํ ์ค๋ฅ ์ฒ๋ฆฌ ๋ฐ ๋กค๋ฐฑ ์ ๋ต์ ๊ตฌํํ์ธ์.
- ์ฒ ์ ํ ํ ์คํธ: ๋จ์ ํ ์คํธ์ ํตํฉ ํ ์คํธ๋ฅผ ์์ฑํ์ฌ Unit of Work ๊ตฌํ์ ๋์์ ๊ฒ์ฆํ์ธ์.
- ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง: Unit of Work ๊ตฌํ์ ์ฑ๋ฅ์ ๋ชจ๋ํฐ๋งํ์ฌ ๋ณ๋ชฉ ํ์์ ์๋ณํ๊ณ ํด๊ฒฐํ์ธ์.
- ๋ฉฑ๋ฑ์ฑ ๊ณ ๋ ค: ์ธ๋ถ ์์คํ ์ด๋ ๋น๋๊ธฐ ์์ ์ ๋ค๋ฃฐ ๋, ์์ ์ ๋ฉฑ๋ฑ์ฑ ์๊ฒ ๋ง๋๋ ๊ฒ์ ๊ณ ๋ คํ์ธ์. ๋ฉฑ๋ฑ์ฑ ์์ ์ ์ด๊ธฐ ์ ์ฉ ์ดํ ๊ฒฐ๊ณผ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ์ฌ๋ฌ ๋ฒ ์ ์ฉํ ์ ์์ต๋๋ค. ์ด๋ ์ฅ์ ๊ฐ ๋ฐ์ํ ์ ์๋ ๋ถ์ฐ ์์คํ ์์ ํนํ ์ ์ฉํฉ๋๋ค.
๊ฒฐ๋ก
Unit of Work ํจํด์ ์๋ฐ์คํฌ๋ฆฝํธ ์ ํ๋ฆฌ์ผ์ด์ ์์ ํธ๋์ญ์ ์ ๊ด๋ฆฌํ๊ณ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ๋ ๋ฐ ์ ์ฉํ ๋๊ตฌ์ ๋๋ค. ์ผ๋ จ์ ์์ ์ ๋จ์ผ ์์์ ๋จ์๋ก ์ฒ๋ฆฌํจ์ผ๋ก์จ ์ผ๊ด์ฑ ์๋ ๋ฐ์ดํฐ ์ํ๋ฅผ ๋ฐฉ์งํ๊ณ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ๋จ์ํํ ์ ์์ต๋๋ค. Unit of Work ํจํด์ ๊ตฌํํ ๋๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ํน์ ์๊ตฌ ์ฌํญ์ ๊ณ ๋ คํ๊ณ ์ ์ ํ ๊ตฌํ ์ ๋ต์ ์ ํํ์ธ์. ๋น๋๊ธฐ ์์ ์ ์ ์คํ๊ฒ ์ฒ๋ฆฌํ๊ณ , ํ์ํ ๊ฒฝ์ฐ ๊ธฐ์กด ORM๊ณผ ํตํฉํ๋ฉฐ, ์๊ฐ๋ ๋ฐ ํตํ ๋ณํ๊ณผ ๊ฐ์ ๊ธ๋ก๋ฒ ๊ณ ๋ ค ์ฌํญ์ ํด๊ฒฐํด์ผ ํฉ๋๋ค. ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๊ณ ๊ตฌํ์ ์ฒ ์ ํ ํ ์คํธํจ์ผ๋ก์จ ์ค๋ฅ๋ ์์ธ ์ํฉ์์๋ ๋ฐ์ดํฐ ์ผ๊ด์ฑ์ ์ ์งํ๋ ๊ฐ๋ ฅํ๊ณ ์ ๋ขฐํ ์ ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. Unit of Work์ ๊ฐ์ ์ ์ ์๋ ํจํด์ ์ฌ์ฉํ๋ฉด ์ฝ๋๋ฒ ์ด์ค์ ์ ์ง๋ณด์์ฑ๊ณผ ํ ์คํธ ์ฉ์ด์ฑ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค.
์ด๋ฌํ ์ ๊ทผ ๋ฐฉ์์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์ฒ๋ฆฌ์ ๋ํ ๋ช ํํ ๊ตฌ์กฐ๋ฅผ ์ค์ ํ๊ณ ์ฝ๋๋ฒ ์ด์ค ์ ๋ฐ์ ๊ฑธ์ณ ์ผ๊ด์ฑ์ ์ด์งํ๋ฏ๋ก, ๋๊ท๋ชจ ํ์ด๋ ํ๋ก์ ํธ์์ ์์ ํ ๋ ๋์ฑ ์ค์ํด์ง๋๋ค.