일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 골랑 고퍼
- go
- go middleware
- gin logger
- go panic
- 고루틴 채널
- go 맥 air
- gin middleware
- go 패닉
- go디자인패턴
- clean architecture middleware
- go 대기그룹
- 신입개발자
- go 맥 air 환경변수
- gopath 환경변수
- golang gopher
- air 환경변수
- 좀비고루틴
- go 맥
- go 마스코트
- gin recovery
- go recover
- go 환경변수
- go clean architecture
- go 캐릭터
- go channel
- go air
- go air 환경변수
- git
- 개발자
- Today
- Total
뽀미의 개발노트
클래스 상속, 오버라이딩, private과 protected 등 개념 활용 예제 본문
코드를 짜던 도중 맞닥뜨린 문제... 되게 어렵게 느껴졌는데 해결하고 나니 너무 쉽게 느껴진다. 이렇게 쉬운 것도 머리 끙끙 싸매고 해결해야 한다는 것이 조금 부끄럽지만 앞으로 같은 실수를 하지 않기 위해 기록으로 남기겠다! 나중에 내가 보려고 남기는 기록이므로 회사 제품을 모르는 누군가를 위해 쉽게 풀어 쓰는게 아니라 오로지 나!! 나를 위해서 써야겠다. 근데 너무 회사 관련된 걸 자세하게 쓰면 고소당할 수도 있으므로 모든 변수명과 함수명은 가명(?)을 사용했다.
QA쪽에서 넘어온 이슈는 "마스터모드, 노트마스터모드가 닫히지 않는다"였다. 모드에는 크게 기본모드들(기본모드, 노트모드)과 마스터모드들(마스터모드, 노트마스터모드)가 있다. 마스터모드 또는 노트마스터모드에서 닫기를 누르면 기본모드들로 가야하는데 마스터 모드 닫으면 노트마스터모드로, 그리고 노트마스터모드 닫으면 마스터모드로 가는 현상이 무한 반복 되는 것이 문제였다!!!
문제 원인 분석
this.changeModeProcess(context, ModeContainer.getPreviousMode());
// 닫기 누르면 '모드 바꾸는 함수'에 '이전모드'를 인자로 줌
관련 코드를 보니, 모드 닫기를 누르면 '이전'모드로 돌아가도록 되어 있었다.
@boundMethod
private changeModeProcess(context: DocumentContext, newMode: ModeEnum): boolean {
const modeContainer = context.getModeContainer() as PointModeContainer;
modeContainer.setMode(newMode); // 새로운 모드를 셋해준다
return true;
}
changModeProcess라는 함수는 새로운 모드를 셋팅해주는 함수였다! 그래서 setMode 함수를 보니
class PointModeContainer extends ModeContainer {
@boundMethod
public setMode(newMode: ModeEnum): void {
const currentMode = this.getMode(); // 모드 바꾸기 전, 현재 모드 기억하기
const isNormalBasedMode =
checkModeType(currentMode) === ModeTypeEnum.NORMAL_TYPE;
if (isNormalBasedMode === true) {
this.setPreviousMode(currentMode); // 현재모드가 기본타입이면 이전모드에 저장
}
super.setMode(newMode); // 새로운 모드 세팅!
}
}
export default PointModeContainer;
이는 ModeContainer의 상속을 받는 PointModeContainer 클래스였고, 부모의 함수 setMode를 자식 클래스에서 오버라이딩 하고 있었다. 아직 새로운 모드를 세팅해주기 전, 현재 모드를 기억하고 그 현재 모드가 기본 모드라면 이전모드에 그 모드를 저장한다. 그 후에 새로운 모드 세팅해줌!!
그니깐 정리해보자면, previousMode 즉 이전모드에는 기본모드만 기억되야하고 마스터모드는 기억되면 안된다!! 근데 여기까지만 보면 로직에 문제가 없다. 왜냐면 지금 문제 상황은 마스터모드와 노트마스터모드를 이전모드로 기억해서 문제임!! 기본모드만 이전모드로 기억해야되는 것이 맞음!!! 그럼 왜 동작이 이상한 걸까? 저 setMode는 자식클래스에서 새롭게 오버라이딩한 함수이고, 결국 super.setMode로 부모 클래스의 함수를 호출하고 있다. 혹시 저기가 문제인 걸까 해서 부모클래스로 가보았다!!!
class ModeContainer {
@observable
private mode: ModeEnum;
private previousMode: ModeEnum;
@boundMethod
public getMode(): ModeEnum {
return this.mode;
}
@boundMethod
public setMode(mode: ModeEnum): void {
this.previousMode = this.mode;
this.mode = mode;
}
@boundMethod
public getPreviousMode(): ModeEnum {
return this.previousMode;
}
@boundMethod
public setPreviousMode(previousMode: ModeEnum): void {
this.previousMode = previousMode;
}
}
export default ModeContainer;
봤더니 부모클래스의 setMode 함수가 조금 수상한 것을 볼 수 있었다.. 엥? setMode에서는 새로운 모드만 정해주는 것이 아니라 이전모드도 셋해주고 있다.....?? 그렇다면 자식클래스의 setMode에서 '기본모드일 때만 이전모드로 기억한다'는 결국 의미가 없는 코드가 된다!! 왜냐면 어차피 super.setMode(newMode)로 부모 클래스의 함수를 호출하는 순간 기본모드고 뭐고 상관없이 그냥 현재 모드를 이전모드로 강제로 셋해버리기 때문!!! 그리고 부모 클래스에서 변수를 바꾸면 어차피 자식 클래스도 그 변수를 쓴다!!
이런 로직상의 문제가 있어서 결국 마스터모드도 이전모드로 기억해버리고, 결국 모드 닫기를 누르면 기본모드로 가야되는데 '이전모드'로 노트마스터모드가 기억되어 있으면 그리로 가고, 또한 노트마스터 모드 닫기를 눌렀는데 '이전모드'로 마스터모드가 기억되어 있으면 그리고 가고 이렇게 무한반복 되는 현상이 발생했던 것!!!
사실 여기까지 분석하는 것도 힘들었다.. 왜냐면 회사에서 나는 좟밥이고 기존 코드는 하늘같은 선배님들이 짜신 코드이기 때문에 감히 로직상 오류가 있을 거라고 쉽게 추측해내기가 힘들다ㅜ 암튼 이런 오류가 있다는 것을 발견. 그럼 이제부터 이걸 어떻게 해결하느냐가 관건인데 여기서 또 나의 삽질이 시작되었다.
문제 해결하기
해결법 1)
this.changeModeProcess(context, ModeEnum.NORMAL_MODE);
내가 생각해낸 해결책 첫번째는 모드 닫기를 눌렀을 때 '이전 모드로 돌아가는 것'이 아닌 그냥 '기본 모드로 돌아가는 것'으로 하드코딩 해버리는 것이었다! 그럼 동작 자체는 제대로 되는 듯 보였으나 근데 사실 타입이 기본 타입인건 기본모드만 있는게 아니라 노트모드, 여러슬라이드모드 등 다양한 것이 있었기 때문에 저렇게 하드코딩할 수 없었다. 이전모드로 돌아가도록 해야하는 건 맞기 때문에 이 해결책은 불가능하다.
해결법 2)
class ModeContainer {
@boundMethod
public setMode(mode: ModeEnum): void {
this.mode = mode;
}
@boundMethod
public setPreviousMode(previousMode: ModeEnum): void {
this.previousMode = previousMode;
}
}
export default ModeContainer;
setMode 함수에서 예상 외로 previousMode와 mode 둘다 셋해버리는게 문제였기 때문에 (setPreviousMode 함수가 따로 있음에도 불구하고) setMode를 그냥 mode만 셋해주는 함수로 바꿔버리는 것!! 꽤 그럴듯한 해결책이었으나 이미 다른 굉장히 많은 곳에서 이 setMode 함수를 사용하고 있었고 내가 다 따라다니면서 수정해주기가 좀 힘들었기 때문에 이 해결책은 기각...
해결법 3)
class PointModeContainer extends ModeContainer {
@boundMethod
public setMode(newMode: ModeEnum): void {
const currentMode = this.getMode();
const isNormalBasedMode =
checkModeType(currentMode) === ModeTypeEnum.NORMAL_TYPE;
super.setMode(newMode); // 새로운 모드 세팅 후
if (isNormalBasedMode === true) {
this.setPreviousMode(currentMode); // 현재모드가 기본타입이면 이전모드에 저장
}
}
}
export default PointModeContainer;
두번째 해결책은 별 생각없이 함 해봤다가 바로 이건 아니라는 걸 깨달았다. 부모클래스에서 setMode에서는 이전모드와 모드를 모두 설정해주고, setPreviousMode에서는 이전모드만 셋해주고 있다. 그래서 setMode와 setPreviousMode의 순서를 바꾸면 되지 않을까? 라고 생각했다. 근데 순서를 바꾸기 전과 마찬가지로 이건 무의미한 코드이다.
왜냐면 1) 마스터 모드일 경우 -> setMode에서 이미 이전모드로 기억되버림. 밑에 조건식에 안 걸려서 setPreviousMode를 따로 타지 않지만 상관없음. 왜냐면 어차피 이미 이전모드로 기억되버렸으니까.
2) 기본 모드일 경우 -> setMode에서 이미 이전모드로 기억됨. 밑에 조건식에 걸려서 setPreviousMode를 타면 그냥 똑같은 짓 두번 하는 거임. 이미 이전모드로 기억해놓고 또 기억하겠다고 하는 것임.
암튼 순서를 바꿔도 로직오류는 여전했다. 그니깐 지금 부모 클래스의 setMode에서 어차피 mode와 previousMode 두개를 한꺼번에 다루고 있는데 자식 클래스에서 마치 두개가 따로 다뤄지는 것처럼 로직을 짠 것이 문제이다!! 어떻게 하면 자식 클래스에서 두개를 따로 셋해줄 수 있을까??
해결책 4)
class PointModeContainer extends ModeContainer {
@boundMethod
public setMode(newMode: ModeEnum): void {
const currentMode = this.getMode(); // 모드 바꾸기 전, 현재 모드 기억하기
const isNormalBasedMode =
checkModeType(currentMode) === ModeTypeEnum.NORMAL_TYPE;
if (isNormalBasedMode === true) {
this.setPreviousMode(currentMode); // 현재모드가 기본타입이면 이전모드에 저장
}
this.mode = newMode // 부모클래스의 변수 직접 바꾸기!!
}
}
export default PointModeContainer;
내가 하고싶은 건 결국 previousMode 냅두고 mode만 바꾸는 것이다!! 그럼 굳이 super.setMode(newMode)를 안 쓰면 되지 않을까? 왜냐면 그 함수가 두 변수를 모두 셋해줘서 문제인 거니까. 그래서 나는 그 함수 대신 this.mode = newMode를 넣어서 부모클래스의 변수 mode에 직접 newMode를 저장하면 되는 것 아닐지 생각해냈다!! 근데 이렇게 하면 에러가 난다. 왜냐면 부모클래스에서 mode가 private이었기 때문!! private을 쓰면 현재 클래스에서만 그 변수에 접근할 수 있으니까 에러가 나는 것이다!!
class ModeContainer {
@observable
protected mode: ModeEnum;
@boundMethod
public setMode(mode: ModeEnum): void {
this.previousMode = this.mode;
this.mode = mode;
}
}
export default ModeContainer;
그럼 부모 클래스의 mode를 자식까지도 접근 가능하게 protected로 바꿔주면 되는거 아냐? -> 그래서 이렇게 고쳤다!!! 오오오ㅗ!!! 이렇게 고치니 동작도 제대로 되고 로직에도 오류가 없었다. 그러나 한가지 문제는 이건 내가 혼자 만드는 프로젝트가 아니라 회사 프로젝트이기 때문에 클래스의 중요한 변수를 내가 맘대로 private -> protected 로 바꿀 수가 없다는 것이 문제...!! 그래서 팀쟝님께 여쭤보았다. 팀장님께서는 이 클래스 ModeContainer가 우리 팀만 쓰는 함수인지 아님 전 모듈 공통으로 쓰는 함수인지 먼저 여쭤보셨다! 우리만 쓰는건 PointModeContainer이고 저거는 워드랑 셀팀도 쓰기 때문에 공통이었다.. 그럼 만약 바꾼다고 해도 공통팀한테 허락받고 바꿔야 하고, 웬만하면 바꾸면 안되는 것이었다!ㅜㅜ 그래서 팀장님께서 다른 방법을 제안하셨다.
해결책 5)
@boundMethod
public setMode(newMode: ModeEnum): void {
const currentMode = this.getMode();
const previousMode = this.getPreviousMode(); // 1) 일단 이전모드 기억
super.setMode(newMode); // 2) 새로운 모드로 셋해주기
if (isMasterBasedMode(currentMode)) {
this.setPreviousMode( // 3) 조건 참이면 아까 기억한 이전모드 셋해주기
isMasterBasedMode(previousMode) === false
? previousMode
: ModeEnum.NORMAL_MODE
);
}
}
function isMasterBasedMode(mode: ModeEnum): boolean {
return (
mode === ModeEnum.MASTER_MODE || mode === ModeEnum.NOTES_MASTER_MODE
);
}
지금 문제점은 1) setMode에서 두 변수를 모두 다루고 있다. 2) 근데 나는 mode만 바꾸고 싶다 -> 이게 문제인 것! 그럼 부모 클래스의 변수를 protected로 바꾸지 않고 최대한 현재 있는 함수를 이용해서 내가 원하는 대로 mode와 previousMode를 설정해보자!! 그러면 함수를 세번 써서 1) 현재 상태에서 '이전모드'를 일단 기억해놓고, 2) setMode로 이전모드와 모드 둘다 바꿔버리고, 3) 조건 걸어서 내가 아까 기억해뒀던 이전모드를 다시 setPrviousMode로 셋해버리는 것이다!! 이렇게 하면 현재 있는 함수를 이용해서도 두 변수를 따로 셋해줄 수 있다!!!
하 아니 이거 분명히 배웠던 건데 왜 생각을 못 했지?? 이거 그 변수 스와핑이랑 비슷한 거잖아!! 이전모드랑 현재모드에 저장해둔거 계속 바꾸는 거잖아!! 이전모드에 A 있고 현재모드에 B 있을 때, 내가 만약 B에서 C 로 바꾸고 싶다면 -> 1) 일단 A를 다른곳에 저장 2) 현재모드에 C 이전모드에 B 저장 3) 조건 따져서 이전모드에 A 저장하거나 아님 냅두기 이거잖아!!!! 으앙ㅇ아아아아 배운것도 활용못해 으엉엉 이거 그거자나
https://youtube.com/shorts/-60uOEQKDc8?si=8ycyviPrKzT1FJIh
(유튜브 참고 : 코딩독학 codok)
이거랑 비슷한 거잖아!! 물론 이건 변수 자리 바꾸기고 나는 상황이 조금 다르지만 어쨌든.. 암튼 앞으로 비슷한 상황이 온다면 꼭 이번에 배운 것을 잘 활용하도록 하자..!
암튼 결론적으로 되게 쉬운 해결책이었는데 그래도 내가 이렇게 쉬운 것도 몰랐구나 하는 교훈을 얻은 좋은 이슈였다!! 클래스.. 잘 배웠는데 막상 적용하려니 어렵구만
'Trouble_Shooting' 카테고리의 다른 글
React 프로젝트 시작하는 법 (0) | 2024.03.24 |
---|---|
eXERD에서 리버스 엔지니어링으로 mysql 가져오기 오류 해결 (0) | 2023.06.29 |
화상채팅방 오류 해결하기 (아직 못함) (0) | 2023.06.27 |
웹사이트 내용 엑셀 파일로 다운받기 (0) | 2023.06.26 |
Selenium으로 웹크롤링 겨우 해냄 (0) | 2023.06.23 |