inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

[워밍업 클럽 스터디 2기 - BE] 1주차 발자국

김민성
0

해당 내용을 바탕으로 작성된 블로그 입니다.

추상

우리가 클린 코드를 추구하는 이유

가독성 - Readability

글이 잘 읽힌다 = 이해가 잘 된다. = 유지보수 하기 수월해진다. = 우리의 시간과 자원이 절약된다.

 

클린코드를 관통하는 아주 중요한 주제

바로 추상(抽象)

 

추상과 구체

도메인 영역에서 핵심만 남기는 행위가 추상, 이를 보고 유추할 수 있는게 구체

중요한 정보는 가려내어 남기고, 덜 중요한 정보는 생략하여 버린다

 

추상화의 가장 대표적인 행위 : 이름 짓기

 

이름 짓기

이름을 짓는다는 행위는, 추상적 사고를 기반으로 한다.

 

이름 짓기 팁

단수와 복수를 구분하기

끝에 '(e)s'를 붙여 어떤 데이터(변수, 클래스 등)가 단수인지, 복수인지를 나타내는 것만으로도 읽는 이에게 중요한 정보를 같이 전달할 수 있다.

이름 줄이지 않기

줄임말이라는 것은 가독성을 제물로 바쳐 효율성을 얻는 것으로, 대부분 잃는 것에 비해 얻는 것이 적다.

은어/방언 사용하지 않기

비슷한 상황에서 자주 사용하는 단어, 개념 습득하기

→ ex. pool, candidate, threshold 등

 

이름을 지으면서 코드를 읽을 수 있게 됐다.

 

메서드와 추상화

국어/영어 독해할 때 잘 쓰여진 글이라면 한 문단의 주제는 반드시 하나다.

메서드의 이름으로 구체를 추상화 하는 것이다.

잘 쓰여진 코드라면 한 메서드의 주제는 반드시 하나다.

 

메서드 선언부

* 메서드 시그니처 : 메서드명 + 파라미터 (메서드 오버로드)

메서드명

파라미터

반환타입

[지뢰찾기 - 메서드 추출](https://github.com/iamminseongKim/readable-code/commit/66523910ce932a0e103f22bc3ecf2d93f418e116#diff-9f9444b48fc52a78913dc852f9b4c9a5cc42aa4e5525c09fe92c5d24b6e41182)

 

추상화 레벨

하나의 세계 안에서는, 추상화 레벨이 동등해야 한다.

public static void main(String[] args) {

	showGameStartComments();
	initializeGame();
	showBoard();

	if (gameStatus == 1) {  
	    System.out.println("지뢰를 모두 찾았습니다. GAME CLEAR!");  
	    break;  
	}

	...

	checkIfGameIsOver();
}

자 이 코드에서 메서드를 쭉쭉 호출하다가 갑자기 gameStatus == 1 이런 코드가 나와 멈칫하게 된다.

이러한 점이 레벨이 안맞다는 점이다.

그럼

public static void main(String[] args) {
	showGameStartComments();
	initializeGame();
	showBoard();

	if (doesUserWinTheGame()) {  
	    System.out.println("지뢰를 모두 찾았습니다. GAME CLEAR!");  
	    break;  
	}
	...
	checkIfGameIsOver();
}

private boolean doesUserWinTheGame() {
	return gameStatus == 1;
}

다음과 같이 레벨을 맞춰주자.

 

매직 넘버, 매직 스트링

 

매직 넘버, 매직 스트링?

[추상화 레벨 & 매직 넘버, 매직 스트링](https://github.com/iamminseongKim/readable-code/commit/ccdb4d9894b82c6f340acfb7543414423669a296)

상수를 뽑아내므로써 가독성, 유지보수성이 증가한걸 느낌.

 

논리, 사고의 흐름

뇌 메모리 적게 쓰기

인지적 경제성

뇌 메모리 적게 쓰기.. 읽는 사람이 뇌를 적게 쓰기 위해 만들 때 잘 쓰자..

 

Early return

if (a > 3) {
	doSomething1();
} else if (a <= 3 && b > 1) {
	doSomething2();
} else {
	doSomething3();
}

이 if문을 쭉쭉 내려가면서 생각해보면

마지막 else를 생각할 때 쯤이면 모든 if 조건을 다 인지하고 있어야 그 예외를 생각하고 doSomething3()이 실행되겠구나 생각할 것이다.

이걸 해결하기 위해서 사용하면 좋은 것이 Early return이다.


extracted();

void extracted() {
	if(a > 3) {
		doSomething1();
		return;
	}
	
	if(a<=3 && b>1) {
		doSomething2();
		return;
	}
	
	doSomething3();
}

 

Early return으로 else의 사용을 지양, else를 쓰지 않아도 되면 쓰지 않도록 노력하자.

[Early return 코드](https://github.com/iamminseongKim/readable-code/commit/31dc6569a71028141c665e2f341eb7d05cb0896f)

사고의 depth 줄이기

중첩 분기문, 중첩 반복문

중첩 for문을 지양하고 바깥이 어떻게 도는지 알 필요 없게 만들자.

 

주의

[예제 코드 - 중첩 for문 (Stream 사용)](https://github.com/iamminseongKim/readable-code/commit/37eaf9ebc8f5c4774cf295d5e3be3dfb82b1c9bb)

 

사용할 변수는 가깝게 선언하기

int i = 10;

// 저 ~~아래 한 20줄 

int j = i + 30;

이런 식으로 사용하지 말자.

// 저 아래 20줄 

int i = 10;
int j = i + 30;

가깝게 선언하자.

[예제 코드 - scanner 수정(상수로 또 뺌)](https://github.com/iamminseongKim/readable-code/commit/bd15a345918cf602506cb8182a4aa5b90a826877)

 

공백 라인을 대하는 자세

공백 라인도 의미를 가진다

부정어를 대하는 자세

[예제 코드 - isLandMineCell()에 부정연산자 제거한 과정](https://github.com/iamminseongKim/readable-code/commit/1070112c4dfd0d230f1edbda6ad0a2d8f612509c)

 

해피 케이스와 예외 처리

Null을 대하는 자세

Optional에 관하여

Optional을 해소하는 방법

[해피 케이스와 예외처리 - 예제](https://github.com/iamminseongKim/readable-code/commit/cb02070c415ed2f2c70cf417cca0701015fe2f18)

 



객체 지향 패러다임

정해진 순서 차례대로 진행하는 프로그래밍 절차 지향

객체라는걸 만들어서 상호 작용을 하도록 개발하는 객체지향

사이드 이펙트가 없는 a를 넣으면 항상 같은 리턴을 주는 순수 함수

이런 함수를 기반으로 개발하는 함수형 프로그래밍

 

추상의 관점으로 바라보는 객체 지향

객체 : Object, 추상화된 (데이터 + 코드)

협력과 책임

객체간의 협력 + 객체가 담당하는 책임

캡추상다

관심사의 분리

Seperation Of Concern

높은 응집도, 낮은 결합도

a라는 관점을 모아서 관리 -> 유지보수성 증가

그리고 이렇게 모인 관심사들 끼리는 결합도가 낮게 개발.

a를 수정했는데 b에 영향이 없게 개발.

 

객체 설계하기 1

오브젝트도 데이터나 로직은 숨기고, 이를 공개적인 메서드를 통해서만 외부에서 소통할 수 있도록 추상화 해야 한다.

객체가 제공하는 것

새로운 객체를 만들 때 주의할 점

 

 

도메인 지식은 만드는 것이 아니라 발견하는 것

[Board 객체화](https://github.com/iamminseongKim/readable-code/commit/2c04b02413a879e3135a1fd905abb445a4d9dcd9)

[Board - Sign Cell 넣기](https://github.com/iamminseongKim/readable-code/commit/7a593983ce867b9233172344189b781c6bf207c1)

[cell을 도메인 지식을 통해 리팩토링](https://github.com/iamminseongKim/readable-code/commit/295a3d84a208216fc630e52dee08cbfb1385abfc)

 

SOLID

 

 

객체 지향 적용하기

상속과 조합

[객체지향 적용하기 - 상속과 조합 - 셀을 상속에서 조합으로 바꾸기](https://github.com/iamminseongKim/readable-code/commit/86a49db553a752eca745a0d462125ee0d0b4ad70)

Value Object

만원 지폐가 일렬번호(인스턴스)가 다르다고 가치가 다른 즉 다른 만원인가?

 

VO vs Entity

 

class UserAccount {
	private String userId; // 식별자
	private String 이름;
	private String 생년월일;
	private Address 집주소;
}

이건 Entity

class Address {
	private String 시도;
	private String 시군구;
	private String 도로명;
	private String 건물번호;
}

이건 VO 이다.

 

[Value Object - Cell의 상태를 value object로 만들기.](https://github.com/iamminseongKim/readable-code/commit/b667b43de3dfa2fa78fc6a4baf24af570acf69d6)

 

미션

미션 1 추상과 구체 예시

내가 생각한 추상은 모두가 이해할 수 있도록 말을 요약이라 생각해서

내가 좋아하는 야구에서 이 예시를 찾아봤다.

야구를 좀 본사람은 4-6-3 병살 저 6자만 봐도 어떤 일이 일어났는지 바로 이해할 것이다.

그래서 나는 이걸로 미션을 제출했다.

 

미션 2 코드 리팩토링

주문관련 코드를 리팩토링 하는 미션이였다.

코드를 보면 if-else로 많이 감싸져 있어서 그걸 제일 먼저 Early return을 이용해서 바꿔줬고,

그 다음엔 return false보다는 예외로 값이 잘못된 것을 알려줬다.

마지막으로 if문 안에 추상화 레벨을 맞추기 위해 메서드를 추출했다.

 

아쉬운 점은 예외를 커스텀 예외로 만드는 걸 안했고, if문 검증 로직을 굳이 service단이 아니라 order객체 내에서

했어도 좋았을 것 같다는 생각을 했다.

 

느낀점

자바를 2년이상 써오면서 원래 알았던 개념도 있고, 처음 봤던 개념도 있었다.

그런데 이번 내용들을 학습하면서 항상 클린코드 클린코드 해야지 생각만 하던걸

이젠 직접 어떻게 작성 해야하는지, 어떤 점을 고려해야 하는지 좀 감을 잡을 수 있었던 것 같다.

 

솔직히 공부를 많이 안했던 것 같아서 좀 부끄럽지만 이번 계기로 클린코드와 테스트 코드에 자신감을 가질 수 있도록 노력하겠다.

 

 

백엔드 워밍업클럽

답변 0