남성 유저들을 대상으로 이벤트를 진행한다.
이벤트 메시지는 다음과 같다 > '여름 맞이 반바지 90% 할인'
이벤트 메시지가 전송된 유저에게는 할인 쿠폰이 지급 된다.
type eventMessage = {
userId:number,
message:string
}
const getUserIds = (gender:string) =>{
if(gender == 'male'){
return [1,3,5]
}
return [2,4,6]
}
const sendMessages = (dataList:eventMessage[]):[number[], number[]]=>{
const userIds = dataList.map((data)=>{
console.log(`send to ${data.userId}, message: ${data.message}`)
return data.userId
})
return [userIds, [0]]
}
const publishDiscountCoupon = (userIds:number[])=>{
userIds.map((userId)=>{
console.log(`create discount coupon, ${userId}`)
})
}
const mapMessageToUser = (userIds:number[], message:string)=>{
return userIds.map((userId)=>{
return {userId, message}
})
}
export const sendNotification = (gender:string, message:string)=>{
try {
const users = getUserIds(gender);
const dataList = mapMessageToUser(users, message)
const [successUsers, failUsers] = sendMessages(dataList)
publishDiscountCoupon(successUsers)
} catch(error){
console.log(error)
}
}
로직 순서 그대로 작성한 코드이며 딱히 문제되는 부분은 없어 보인다. 아래 시나리오를 적용해보자
모든 유저들을 대상으로 이벤트를 진행한다.
이벤트 메시지는 다음과 같다
-- 홀수 user_id: '모든 상의 10% 할인'
-- 짝수 user_id: '모든 바지 10% 할인'
이벤트 메시지가 전송된 유저에게는 할인 쿠폰이 지급 된다.
이벤트 메시지 전송이 실패된 유저들은 로그만 남긴다.
우선 유저를 추출하는 부분이 바뀌었다. 따라서 getUserIds 의 변화는 불가피 하다.
message 를 계산하는 로직이 생겼다. 그렇기에 message 를 바깥에서 계산해서 주던가 아니면 내부에서 계산을 해야한다.
할인 쿠폰 지급 로직은 동일하므로 재사용이 가능하다.
전송실패시 핸들링이 추가 되었다.
const getAllUserIds = () => {
return [1, 2, 3, 4, 5, 6];
};
const mapMessageToUserByIds = (userIds: number[]) => {
return userIds.map((userId) => {
let message = "상의 10% 할인";
if (userId % 2 !== 0) {
message = "하의 10% 할인";
}
return { userId, message };
});
};
const logError = (userIds: number[]) => {
userIds.map((userId) => {
console.log(`error occur, ${userId}`);
});
};
export const sendNotificationToAll = () => {
try {
const users = getAllUserIds();
const dataList = mapMessageToUserByIds(users);
const [successUsers, failUsers] = sendMessages(dataList);
publishDiscountCoupon(successUsers);
logError(failUsers);
} catch (error) {
console.log(error);
}
};
function sendTMP(
getUserFunc,
mapMessageFunc,
createEventFunc,
eventWhenSuccess,
eventWhenFail){
...
}
interface getUsersType {
(...args: any[]): number[];
}
export const sendTMP = (getUserFunc: getUsersType) => {
return getUserFunc();
};
# test
it("send tmp", () => {
const getUsers = (gender: string) => {
return [1, 2, 3];
};
const res = sendTMP(getUsers("male"));
expect(res).not.toBeNull;
});
it("send tmp", () => {
const getUsers = (gender: string) => () => {
if (gender == "male") {
return [1, 3, 5];
}
return [2, 4, 6];
};
let res = sendTMP(getUsers("male"));
expect(res).toEqual([1, 3, 5]);
res = sendTMP(getUsers("female"));
expect(res).toEqual([2, 4, 6]);
});
type eventMessage = {
userId: number;
message: string;
};
interface mapUserType {
(userIds: number[]): eventMessage[];
}
export const sendTMP = (
getUserFunc: getUsersType,
mapUserFunc: mapUserType
) => {
const userIds = getUserFunc();
const messages = mapUserFunc(userIds);
return messages;
};
# test
it("send tmp", () => {
const getUsers = (gender: string) => () => {
if (gender == "male") {
return [1, 3, 5];
}
return [2, 4, 6];
};
const mapMessage = (userIds: number[]) => {
return userIds.map((userId) => {
return {
userId,
message: "sample message",
};
});
};
const res = sendTMP(getUsers("male"), mapMessage);
console.log(res);
});
const mapGivenMessage = (message: string) => (userIds: number[]) => {
return userIds.map((userId) => {
return {
userId,
message,
};
});
};
const res2 = sendTMP(getUsers("male"), mapGivenMessage("my-message"));
console.log(res2);
type eventResults = {
successUserIds: number[];
failUserIds: number[];
};
interface createEventType {
(eventMessages: eventMessage[]): eventResults;
}
export const sendTMP = (
getUserFunc: getUsersType,
mapUserFunc: mapUserType,
createEventFunc: createEventType
) => {
const userIds = getUserFunc();
const messages = mapUserFunc(userIds);
const results = createEventFunc(messages);
return results;
};
# test
it('...', ()=>{
...
const sendNotification = (data: eventMessage[]) => {
data.map((event) => {
console.log(event);
});
return { successUserIds: [1, 2, 3], failUserIds: [4, 5, 6] };
};
const res = sendTMP(getUsers("male"), mapMessage, sendNotification);
console.log(res)
}
interface handleEventType {
(results: eventResults): void;
}
interface doNothingType {
(...args: any[]): void;
}
export const sendTMP = (
getUserFunc: getUsersType,
mapUserFunc: mapUserType,
createEventFunc: createEventType,
handleEventWhenSuccess: handleEventType | doNothingType,
handleEventWhenFail: handleEventType | doNothingType
) => {
const userIds = getUserFunc();
const messages = mapUserFunc(userIds);
const results = createEventFunc(messages);
handleEventWhenSuccess(results);
handleEventWhenFail(results);
return results;
};
# test
it('...', ()=>{
...
const res = sendTMP(
getUsers("male"),
mapMessage,
sendNotification,
() => "",
() => ""
);
const doSomethingWhenFail = (data: eventResults) => {
data.failUserIds.map((userId) => {
console.log(userId);
});
};
const res2 = sendTMP(
getUsers("male"),
mapGivenMessage("my-message"),
sendNotification,
() => "",
doSomethingWhenFail
);
console.log(res2);
}
export const sendTMP = (
getUserFunc: getUsersType,
mapUserFunc: mapUserType,
createEventFunc: createEventType,
handleEventWhenSuccess: handleEventType | doNothingType,
handleEventWhenFail: handleEventType | doNothingType
) => {
const userIds = getUserFunc();
const messages = mapUserFunc(userIds);
const results = createEventFunc(messages);
handleEventWhenSuccess(results);
handleEventWhenFail(results);
return results;
};
const getUsers = (gender: string) => {
if (gender == "male") {
return [1, 3, 5];
}
return [2, 4, 6];
};
const mapMessage = (userIds: number[]) => {
return userIds.map((userId) => {
return {
userId,
message: "sample message",
};
});
};
const sendNotification = (data: eventMessage[]) => {
data.map((event) => {
console.log(event);
});
return { successUserIds: [1, 2, 3], failUserIds: [4, 5, 6] };
};
const res = pipe("male",
getUsers,
mapMessage,
sendNotification);
console.log(res);
sendNotification(mapMessage(getUsers('male')))
const res = pipe("male", getUsers, mapMessage, sendNotification);
console.log(res);
const sendTemp = flow(getUsers, mapMessage, sendNotification);
console.log(sendTemp("male"));
filter 사용하는 경우에도 작성하는 callback function 에 따라서 다양한 결과를 만들어 낼 수 있다.