최근 기능 개선 프로젝트를 진행하면서 리팩토링한 코드가 있는데, 리팩토링 전/후 내용을 정리해 본다. 수정한 코드는 마이플랫폼 코드이다. 마이플랫폼 코드는 겉모습은 자바 스크립트와 유사한데, 객체로 묶는 단위가 없고 함수 위주로 코드를 작성한다. 마이플랫폼에 대해 몰라도 이 글에서 사용하는 코드를 읽는 데 문제는 없을 것이다.
내용 설명
수정할 코드는 서버쪽 인증과 관련되어 있는데, 서버 기능 변경을 위해 클라이언트 코드인 마이플랫폼 코드도 변경하게 되었다. 마이플랫폼 코드에서 인증은 크게 두 가지 방식으로 진행한다.
- 포탈에서 로그인한 뒤 마이플랫폼 구동 시 : 인증 키를 넘겨서 인증 처리
- 마이플랫폼 바로 구동 시 : 로그인 폼에서 아이디/암호를 입력받아 인증 처리
기존 코드를 그림으로 정리해봤다. 설명을 위해 실제 코드에서 사용한 이름을 약간 바꿨다. 패키지는 파일 한 개를, 이름에 괄호가 포함된 것은 함수를, 괄호가 없는 것은 변수를 의미한다. 예를 들어, login.js 파일에는 Login() 함수, Login2() 함수, Success() 함수가 있고, isLoginPage라는 변수가 있다. 의존은 특정 함수에서 다른 함수를 호출함을 의미한다. 아래 그림의 경우 Login2() 함수에서 LoginEnable() 함수를 호출한다.
그림만 봐도 뭔가 복잡해 보이는데, 실행 흐름을 보면 순환 의존이 더 명확해진다.
Login.xml은 독립된 어플리케이션을 실행할 때 사용하는 화면이다. 실행 흐름은 대략 다음과 같다.
- Login.xml: OnLoadCompleted() 실행
- Login.xml->OnLoadCompleted() : login.js->Login2(true) 실행
- login.js->Login2() : 파라미터로 전달받은 true를 isLoginPage에 할당
- login.js->Login2() :
- 인증에 성공하면, 인증 처리 후 Success(아이디) 실행
- 인증에 실패했는데
- isLoginPage가 true면 Login.xml->LoginEnable() 실행 후 리턴. 로그인 폼이 보여짐
- login.js->Success()
- isLoginPage가 true면, Login.xml->initSession() 실행. 이후 프로그램 실행 처리
SDI.xml은 단일 화면을 실행할 때 사용한다. 실행 흐름은 다음과 같다.
- SDI.xml: OnLoadCompleted() 실행
- SDI.xml->OnLoadCompleted() : login.js->Login2(false) 실행
- login.js->Login2() : 파라미터로 전달받은 false를 isLoginPage에 할당
- login.js->Login2() :
- 인증에 성공하면, 인증 처리 후 Success(아이디) 실행
- 인증에 실패했는데
- isLoginPage가 false면 SDI.xml->LoginCheck(false)실행.
- login.js->Success()
- isLoginPage가 false면, Login.xml->LoginCheck(true) 실행. 이후 프로그램 실행 처리
login.js의 Login2() 함수와 Success() 함수는 로그인 성공이나 실패시 사용할 함수를 선택할 때 isLoginPage 변수를 사용한다. 이 변수가 true면, FrameLoing.xml의 함수를 호출하고, false면 SDI.xml의 함수를 호출한다. isLoginPage 변수를 알맞게 설정하기 위해 Login2() 함수를 호출할 때, FrameLogin.xml에서는 true를 전달하고 SDI.xml에서는 false를 전달한다.
문제점을 보자.
- FrameLogin.xml에서 login.js의 Login2() 함수를 호출할 때 true를 전달하는데, FrameLogin.xml 코드를 처음보면 이 true가 무엇을 의미하는지 알 수 없다. 이는 SDI.xml도 마찬가지다.
- 인증 성공이나 실패시 어떤 함수를 실행할지 여부는 FrameLogin.xml에서 결졍해야 하는데, 이 결정을 login.js에서 하고 있다. 즉, login.js는 인증만 처리하는 것이 아니라 화면의 실행흐름까지 관리한다.이러면서 순환의존이 발생하고, 어떤 화면에서 인증 요청을 했는지 알기 위해 isLoginPage 변수를 사용하고 있다.
여기서 isLoingPage가 true일 때 사용한 코드를 FrameLogin.xml로 옮겼다.
// FrameLogin.xml 코드
function OnLoadCompleted() {
Login2(true);
if (인증성공) initSession();
else LoginEnable();
}
비슷하게 isLoginPage가 false일 때 사용한 코드를 SDI.xml로 옮겼다.
// SDI.xml 코드
function OnLoadCompleted() {
Login2(false);
if (인증성공) LoginCheck(true);
else LoginCheck(false);
}
코드를 옮긴 후 login.js 코드는 다음과 같이 단순해졌다. Success() 함수는 더 이상 필요없으므로 지웠다.
// login.js
var isLoginPage;
function Login2(flag) {
isLoginPage = flag;
// 인증처리
}
isLoginPage 변수도 필요 없으므로 이 변수를 지우고, FrameLogin.xml과 SDI.xml에서 Login2() 함수를 호출할 때 전달한 true/false 인자도 삭제했다.
// login.js
function Login2() {
// 인증 처리
}
// FrameLogin.xml 코드
function OnLoadCompleted() {
Login2();
if (인증성공) initSession();
else LoginEnable();
}
// SDI.xml 코드
function OnLoadCompleted() {
Login2(false);
if (인증성공) LoginCheck(true);
else LoginCheck(false);
}
변경 후 구조
변경 후 구조는 다음과 같다.
구조를 변경하기 전과 비교해 다음이 나아졌다.
- 순환 의존을 일부 제거했다. login.js->Login() 함수에서 여전히 FrameLogin.xml->initSession()을 호출하기 때문에, 순환 의존이 남아 있지만, 전체 구조가 간결해졌다.
- 실행 흐름이 보다 명확해졌다. FrameLogin.xml과 SDI.xml 코드만 봐도 인증 성공/실패시 어떤 코드를 실행하는지 알 수 있다. 변경 전에는 코드를 쫓아가서 login.js->Login2()나 login.js->Success() 코드를 봐야 전체 실행 흐름을 알 수 있었다.
- login.js의 역할이 보다 명확해졌다. 이전 구조에서 login.js는 인증 처리뿐만 아니라 각 화면별로 실행 흐름을 제어했다. 실행 흐름 제어 부분을 알맞은 곳으로 옮겨서 login.js는 인증 자체에 집중하게 되었다. 이 과정에서 Success() 함수나 isLoginPage같은 변수도 날렸다.
의존 순환을 더 제거해야 하지만, 코드 구조가 전체적으로 명확해졌다.