# 코드리뷰 (2022.10.04)
# Vue.js
# 다른 객체에게 일을 시킬 때 판단요소도 위임하자
- 다른 객체에게 무엇인가 요구하면서 묻는 행위 금지
- 일을 시켰으면 업무 처리 방식에 대해서는 관심을 두지 말자
# as is
onBatchMenu(index) {
if (selectedCount == 1) {
switch (index) {
case 0:
updateRewardState.show(selectedCount, state);
break;
case 1:
updateRewardExpectedAt.show(selectedCount, rewardExpectedAt);
break;
case 2:
updateRewardPoint.show(selectedCount, point);
break;
}
return
}
switch (index) {
case 0:
updateRewardState.show(selectedCount);
break;
case 1:
updateRewardExpectedAt.show(selectedCount);
break;
case 2:
updateRewardPoint.show(selectedCount);
break;
}
},
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
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
# to be
onBatchMenu(index) {
switch (index) {
case 0:
updateRewardState.show(selectedCount, state);
break;
case 1:
updateRewardExpectedAt.show(selectedCount, rewardExpectedAt);
break;
case 2:
updateRewardPoint.show(selectedCount, point);
break;
}
},
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 숫자 대신 의미있는 이름으로 변경
async upload2(path, blob, name) {
...
},
data() {
return {
columnManager1: new QuasarColumnManager(columns1),
columnManager2: new QuasarColumnManager(columns2),
columns1: columns1,
columns2: columns2,
rows1: this.userDetail.pointHistory,
rows2: [],
}
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 코드(codes.js)로 분리해서 관리
data() {
return {
influencerGrades: [
{ label: "Celeb", value: 0 },
{ label: "Macro", value: 1 },
{ label: "Micro", value: 2 },
{ label: "Reviewer", value: 3 },
],
steps: [
{ label: "섭외", value: 0 },
{ label: "진행", value: 1 },
{ label: "게재", value: 2 },
{ label: "완료", value: 3 },
],
states: [
{ label: '지원완료', value: 0 },
{ label: '초대 중', value: 1 },
{ label: '거절', value: 2 },
{ label: '미게재', value: 3 },
{ label: '확인중', value: 4 },
{ label: '확인 요청', value: 5 },
{ label: '미승인', value: 6 },
{ label: '진행취소', value: 7 },
{ label: '완료', value: 7 },
],
}
},
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
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
- codes.js를 통해서 캡슐화하고 중복 사용 방어
- 서버로부터 새로운 코드가 자동으로 갱신되도록
# 코드 단순화
# as is
methods: {
getColumnHeader(col) {
return this.columnManager.getHeader(col);
},
getColumn(col) {
return this.columnManager.getColumn(col);
},
getCode(col) {
return this.columnManager.getCode(col);
},
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# to be
methods: {
... this.columnManager,
}
1
2
3
2
3
# 템플릿 영역에서 자주 사용하는 외부 메소드를 VueBase에 추가
methods: {
toLink(text) {
return strg.toLink(text);
},
}
1
2
3
4
5
2
3
4
5
- VueBase 추가 또는 spread operator(...)를 사용해서 methods에 추가한다. (columnManager 동일)
# 객체 속성이 너무 많을 때 초기화 가이드
# as is
state: () => ({
...
params: {
title: null,
email: null,
brand: null,
category: null,
platform: null,
status: null,
createdFrom: null,
createdTo: null,
applicationDeadlineFrom: null,
applicationDeadlineTo: null,
},
}),
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# to be
state: () => ({
...
params: { },
}),
1
2
3
4
2
3
4
- undefinded가 문제되지 않는 경우에 굳이 null 값을 갖는 속성을 초기화할 필요가 없다.
# 코드 일관성 이슈
# as is
if (campaignQuestion.isRequire) {
campaignQuestion.isRequire = 1;
} else campaignQuestion.isRequire = 0;
1
2
3
2
3
# to be
if (campaignQuestion.isRequire) {
campaignQuestion.isRequire = 1;
} else {
campaignQuestion.isRequire = 0;
}
1
2
3
4
5
2
3
4
5
# Flutter
# 상속 상태에서 초기화 및 종료처리 순서
# as is
void initState() {
defaultTextStyle = TextStyle(color: ...);
super.initState();
}
void dispose() {
super.dispose();
controller.dispose();
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# to be
void initState() {
super.initState();
defaultTextStyle = TextStyle(color: ...);
}
void dispose() {
controller.dispose();
super.dispose();
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- 상속 받아서 사용하는 리소스가 준비가 되지 않은 상태에서 초기화가 이루어지면서 에러가 발생할 가능성이 있다.
- 종료처리의 경우도 같은 오류가 발생할 가능성이 있다.
- 당장은 문제가 없더라도 안전한 습관을 길들이는 것이 좋다.
# null check issue #1
# as is
String? brandName;
if (_campaign.brand != null &&
_campaign.brand?.brand_name.isNotEmpty) {
brandName = _campaign.brand?.brand_name as String;
} else {
brandName = "";
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# to be
String brandName = _campaign.brand?.brand_name ?? "";
1
# null check issue #2
# as is
{
...
itemCount: point == null ? 0 : point!.length,
...
}
1
2
3
4
5
2
3
4
5
# to be
{
...
itemCount: point?.length ?? 0,
...
}
1
2
3
4
5
2
3
4
5
# 복잡한 분기문을 단순하게
# as is
Future<void> changeEmail(String? inputEmail) async {
this.inputEmail = inputEmail;
if (inputEmail!.isNotEmpty) {
bool isValidEmail = isEmail(inputEmail!);
if (inputEmail == loginUser!.email) {
validEmail = isValidEmail;
return;
}
if (isValidEmail) {
busy();
final checkResult = await checkEmail(inputEmail);
validEmail = checkResult.result;
emailMessage = checkResult.message;
showEmailMessage = true;
}
} else {
validEmail = false;
emailMessage = "";
showEmailMessage = false;
}
success();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# to be
Future<void> changeEmail(String inputEmail) async {
this.inputEmail = inputEmail;
validEmail = false;
emailMessage = "";
showEmailMessage = false;
if (inputEmail.isEmpty) return;
bool isValidEmail = isEmail(inputEmail);
if (isValidEmail == false) return;
validEmail = (inputEmail == loginUser?.email);
if (validEmail) return;
busy();
try {
final checkResult = await checkEmail(inputEmail);
validEmail = checkResult.result;
emailMessage = checkResult.message;
showEmailMessage = true;
} finally {
success();
}
}
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 외부의 영향을 최소화하기 외 기타
# as is
Future<void> saveUrl() async {
if (this.inputPostingUrl!.isEmpty) {
CommonUtils.toast("URL을 입력해 주세요.");
return;
}
this.busy();
if (this.inputPostingUrl != null) {
final result = await _campaignService.saveUrlToApplyCampaign(...);
if (result) {
await this.fetchApplyData(this.campaignApply!.campaign!.id);
CommonUtils.toast("정상적으로 등록 되었습니다.");
} else {
CommonUtils.toast("URL 등록시 에러가 발생했습니다. 다시 시도해 주세요.");
}
}
this.idle();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# to be #1
Future<void> saveUrl() async {
if (inputPostingUrl?.isEmpty ?? true) {
CommonUtils.toast("URL을 입력해 주세요.");
return;
}
busy();
try {
final result = await _campaignService.saveUrlToApplyCampaign(...);
if (result) {
fetchApplyData(campaignApply!.campaign!.id);
CommonUtils.toast("정상적으로 등록 되었습니다.");
} else {
CommonUtils.toast("URL 등록시 에러가 발생했습니다. 다시 시도해 주세요.");
}
} finally {
idle();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 2: 반복되는 null check issue
# to be #2
Future<void> saveUrl(int? campaignId, String? url) async {
if (campaignId == null) return;
if (url == null) return;
if (url.isEmpty) {
CommonUtils.toast("URL을 입력해 주세요.");
return;
}
busy();
try {
final result = await _campaignService.saveUrlToApplyCampaign(url);
if (result) {
fetchApplyData(campaignId);
CommonUtils.toast("정상적으로 등록 되었습니다.");
} else {
CommonUtils.toast(result.errorMsg);
}
} finally {
idle();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 2-3: 지역 변수의 경우 null check 이후에는 ! 또는 ? 기호를 사용하지 않아도 된다.
- 17: 에러 메시지가 발생하는 원인을 클라이언트에서는 알 수 없으므로 서버에서 메시지를 보내주는 것으로 변경한다.