자바스크립트를 사용한 프로젝트를 진행했을 때의 일이다. 이미 개발된 100여 개 정도 되는 API들에 대해 몇 가지 공통적인 전/후 처리 작업을 해줘야 되는 일이 생겼는데, 누락되는 부분 없이 안정성 있게  로직이 추가되어야 했다. 당시 지급으로 처리되어야 할 급한 이슈여서 따로 라이브러리를 찾아보진 않았고 아래와 같이 간단한 AOP 모듈을 만들어 문제를 해결했다. 


var AOP = (function(){
	function crossCut(target, pointCut, policy){
		var reg = new RegExp(pointCut);
		for(var joinPointName in target){
			if(reg.test(joinPointName)){
				policy(joinPointName);
			}
		}
	};
	return {
		injectBefore : function(advice, target, pointCut /* regular expression */){
			function beforePolicy(joinPointName){
				var joinPoint = target[joinPointName];
				target[joinPointName] = function(){
					return advice.call(target, joinPoint, arguments);
				};	
			};
			crossCut(target, pointCut, beforePolicy);
		},
		injectAfter : function(advice, target, pointCut /* regular expression */){
			function afterPolicy(joinPointName){
				var joinPoint = target[joinPointName];
				target[joinPointName] = function(){
					var ret = joinPoint.apply(target, arguments);
					return advice.call(target, arguments, ret);
				};
			};
			crossCut(target, pointCut, afterPolicy);
		}
	};
})();


AOP.injectBefore의 첫 번째 파라미터는 전처리 로직인 advice에 해당하는 함수,  두 번째  파라미터는 전처리가 필요한 target class, 세 번째 파라미터는 해당 클래스에서 전처리가 필요한 함수들의 regular expression 값이다.


function beforeLog(joinPoint, arg){	// 전처리 로직
	console.log("beforeLog [" + arg[0] +"]");
	return joinPoint.apply(this, arg);
};
function afterLog(arg, ret){			// 후처리 로직
	console.log("afterLog [" + ret + "]");
	return ret;
};

function MsgMaker() {};			// 전/후 처리가 필요한 class
MsgMaker.prototype.makeHello = function(name){
	console.log("makeHello");
	return "hello " + name;
};

AOP.injectBefore(beforeLog, MsgMaker.prototype, "^make");	// MsgMaker Class에서 make로 시작하는 모든 함수에 대해 전처리 추가
AOP.injectAfter(afterLog, MsgMaker.prototype, "^make");	// MsgMaker Class에서 make로 시작하는 모든 함수에 대해 후처리 추가

var maker = new MsgMaker();
console.log(maker.makeHello("world"));

//결과
/*
beforeLog [world]
makeHello
afterLog [hello world]
hello world
*/


prototype이 아닌 property로 함수를 추가했다면, 아래와 같이 .prototype을 빼야한다. 

AOP.injectAfter(afterLog, MsgMaker, "^make");


'CleanCode' 카테고리의 다른 글

Error handling - 우아하게 실패하는 방법  (0) 2019.07.20
boolean type parameter의 모호성  (0) 2016.10.15

+ Recent posts