클린코드 3장 (함수), 4장 (주석)

JAVA/클린코드|2020. 6. 20. 23:04

 

함수


- 함수를 만드는 기본 규칙은 작게 만드는 것!

 

- 함수 내부에 if 문 등의 1단이나 2단 그 이상의 중첩 구조가 발생되면 안된다.

 

- 함수의 활동은 한가지 그 이상을 하지마라.

 

- switch문에 다음과 같이 한가지 작업만 해야한다는 SRP 이론과 코드의 변경이 있으면 안된다는 OCP 규칙을 위반한다. 이를 해결하기 위해서는 다형성을 이용해서 해결해야 한다.

// 문제 코드
public int calEmployeePay(Employee e) {
	switch (e.type) {
		case SALARIED:
			return calculateSalariedPay();
		case HOURLY:
			return calculateHourlyPay();
		case .....
	}
}

// 변경 내용
public interface Employee {
	int calPay();
}


public SalaryEmployee implements Employee {
		
		@Override
		public int calPay() {
				...
		}
}

public int calEmployeePay(Employee e) {
	return e.calPay();
}

- 함수 이름이 길어지더라도 서술적으로 한방에 이해가 가능한 이름이 오히려 더 깔끔하고 좋은 코드다.

  ex) includeSetupAndTeardownPages..

 

- 함수의 인수는 기본적으로 3개 까지가 사실 마지노선이라고 생각하고 그 이상은 절대 오지 않도록 해라. 인수가 있으면 함수 자체를 이해하는데 더 어려움을 겪게 된다.

 

- 인수가 늘어난다면 별도의 인수 객체를 만들어서 묶어서 보내는 게 더 낫다.

  ex) int x, int y ⇒ Point point

 

- 함수의 이름과 인자가 한꺼번에 이해가 가능한 이름에 가장 좋다.

  ex) write(name), assertExpectedEqualsActual(expected, actual)

 

- 함수의 이름과 다른 행위를 함수안에 실행 시키지 마라 ex) checkPassword() 함수내에서 사용자 세션을 초기화 한다거나 하는 행위는 자칫하면 엄청 큰 버그를 일으킬 가능성이 크다.

 

- 에러 코드를 사용하는 것보다는 try catch를 이용해서 에러 코드를 분리하는 것이 좋고, try catch블록은 모든 영역이 아닌 별도 함수내에서 처리하도록 하는 것이 좋다.

 

- 중복된 코드를 계속 양산하지 마라.

- 모든 함수와 함수 내 모든 블록에 입구와 출구는 하나만 존재해야 한다.

 

 

 

 

주석


- 잘 작성된 주석은 이해가 되지만 경솔하고 근거없는 주석은 코드를 더 이해하기 어렵게 만든다.

 

- 주석은 코드로 의도를 표현하지 못해서 실패를 만회하기 위해 적은 코드이다. 그러므로 주석을 달고 있다면 코드를 잘 못 작성한 건 아니지 잘 생각해봐라.

 

- 주석은 언제나 코드를 따라가지 못하기 때문에 언젠가 주석은 코드와 분리되어 고아가 되어버리는 순간이 오기 때문에 조심해야 한다.

 

- 저작권 등의 정보를 알리거나 외부 라이브러리 등의 사용이나 내부 규약으로 인해 어쩔수 없이 사용하는 인자 등의 부분에 대해서 명료한 설명을 위한 주석 또는 결과 값에 대한 결과에 대한 주석 정도는 괜찮다.

 

- 누군가의 공을 달거나 HTML 주석을 위해 사용하거나 근처 코드가 아닌 다른 코드에 대한 주석 등을 다는 이런 코드들은 코드 개선에 시간을 들이는 게 더 낫고 클래스 파일에 바이트나 낭비하지 말아라.

 

 

 

결론

함수

함수는 당연히 나도 의미가 있도록 사용하기 위해서 네이밍에 많은 고민을 하고 있고 같이 일하시는 분들이 잘 이해할 수 있도록 간결하게 만들려고 노력은 하고 있다. 근데 사실 프로젝트가 커지고 하다보면 쉽지 많은 않다. 흑

 

주석

주석은 15년도에 일을 시작했을 때만해도 선배들이나 주변 개발 컨벤션에서 보면 항상 주석을 달라고 되어 있었고 오픈소스로 나와있는 라이브러리들에도 자세한 설명이 기재되어 있었다. 그래서 따라하는 습관을 들였는데 주석이 말한 그대로 코드를 따라가기 어려웠고 어느순간부터는 주석이 도움이 되는게 아니라 오히려 방해가 된다는 생각을 나 또한 들게 되어 지금은 주석대신 코드를 더 명확하게 짜기 위해서 노력하고 있다.

 

 

댓글()

자바 성능 튜닝 이야기 책 리뷰

Book Review|2020. 6. 12. 21:46
자바 성능 튜닝 이야기
국내도서
저자 : 이상민
출판 : 인사이트 2013.10.26
상세보기

요새 개발을 하면서 Java GC 튜닝이나 옵션 설정을 효율적으로 하지 못하는거 같아서 책 제목만 보고 자바 튜닝에 대해 공부해보고자 구매하였다.

 

흠... 근데 앞에 있는 대부분의 자료구조 선택 기준이나 String과 같은 자료형 주의사항등에 대한 이야기 대부분들이 대학교 2학년 때 봤었던 남궁성님의 자바의 정석이나 Effective java 책에 비해 많이 부족하고 블로그 글을 읽는다는 느낌을 많이 받았다.

 

 

GC에 대한 내용도 2011년도에 나온 네이버 D2에 글이 더 자세하게 기록되어 있는 거 같다. https://d2.naver.com/helloworld/1329

 

책 구매 후 이렇게 단 기간에 넘기면서 2시간만에 다 본건 처음이었다.

다음 읽을 책은 자바 최적화 인데 이건 조금 더 좋은 내용이 있었으면 좋겠다!!

댓글()

모던 자바 인 액션 내용 정리

JAVA/고급 자바|2020. 4. 12. 16:46

 

포킹 

자바 8에서 추가된 스트림 api에서 데이터를 필터링, 추출, 그룹화 등의 기능을 진행할 수 있다. 이러한 동작들을 병렬화 할 수 있어 여러 cpu에서 작업을 분산해서 처리할 수 있다. 이런 작업을 포킹 단계라고 한다.

 

 

함수형 인터페이스

- 하나의 추상메서드를 가지고 있는 함수형 인터페이스지만 상속을 받은 인터페이스는 추상메서드를 하나만 가지고 있다고 하여도 함수형 인터페이스가 아니다.

- 디폴트 메소드가 아무리 많아도 추상 메소드가 하나이면 함수형 인터페이스이다.

- @FunctionalInterfeace 애노테이션을 붙이면 함수형 인터페이스가 아닌 경우 컴파일 에러를 발생 시킬 수 있다.

 

 

람다에서 지역변수를 final로 제약하는 이유 

람다에서 지역변수가 final로 사용되는지 궁금한데 이는 인터페이스 변수는 힙에 저장되고 지역변수는 스택에 저장되는 이유가 대표적이다. 람다에서 지역변수에 바로 접근할 수 있다는 가정하에 람다가 스레드에서 실행된다면 변수가 할당한 스레드가 사라져서 변수 할당이 해제되었는데도 람다를 실행하는 스레드에서는 해당 변수에 접근하려 할 수 있다. 그렇기 때문에 람다 내부에서 사용하는 값은 복사본으로써 그 값은 변경되면 안된다는 제약이 존재한다. (그래서  무조건 final로 제약하는 것)

 

 

predicate에는 여러 and, or, negete등이 사용이 가능하다.

and와 or로 predicate를 연결 할 수 있고 negete로 반대의 값을 가져올수도 있다.

 

List<String> dish = Arrays.asList("banana", "pizza", "chicken");

Predicate<String> isBanana = new Predicate<String>() {
	@Override
	public boolean test(String s) {
    	return s.equals("banana");
	}
};

Predicate<String> isChicken = new Predicate<String>() {
	@Override
	public boolean test(String s) {
    	return s.equals("chicken");
	}
};

Predicate<String> isNotPizza = new Predicate<String>() {
	@Override
	public boolean test(String s) {
    	return !s.equals("pizza");
	}
};

// predicate or
System.out.println(dish.stream().filter(isBanana.or(isChicken)).collect(Collectors.joining(", ")));

// predicate and
System.out.println(dish.stream().filter(isBanana.and(isChicken)).collect(Collectors.joining(", ")));

// predicate negate
System.out.println(dish.stream().filter(isBanana.negate()).collect(Collectors.joining(", ")));

 

 

Map의 문제 FlatMap으로 해결

- 문제상황

["hello", "world"] 두개의 단어에서 알파벳 중복된 걸 빼고 하나의 알파벳 배열로 합쳐 보자. 구하고자 하는 결과물은 다음과 같다. ["H", "e", "l", "o", "W", "r", "d"]

 

- Map으로 진행

List<String> str = Arrays.asList("hello", "world");

str.stream()
    .map(data -> data.split(""))
    .distinct()
    .collect(Collectors.toList());

이렇게 하면 각 문자열에서 문자로 쪼개고 거기서 distinct작업을 한뒤 합쳐서 성공적으로 하나의 list안에 중복된 문자가 없을 것 같지만 실제로는 ["hello"], ["world"]가 노출 된다. 

 

왜냐하면 실제로 동작하는은 다음과 같이 진행되기 때문이다.

hello → ["h","e","l","l","o"] (split하면 문자열 배열로 반환) 
world → ["w", "o", "r", "l", "d"] (split하면 문자열 배열로 반환) 

최종
→ distinct 대상이 string[] 결국 두개가 합쳐져 Stream<String[]>이 된다.

그럼 이를 해결 하기 위해서 map에서 생성된 배열이 dinstinct로 넘어갈 때 각 값을 다른 스트림으로 만든 다음 모든 스트림을 하나의 스트림으로 연결해야 하는데 이를 flatMap으로 해결이 가능하다.

 

List<String> str = Arrays.asList("hello", "world");
        System.out.println(str.stream()
            .map(data -> data.split(""))
            .flatMap(Arrays::stream)
            .distinct()
            .collect(Collectors.toList()));

map으로 반환된 Stream<String[]>에서 각 String[]을 Stream으로 변형한 후 하나의 stream으로 합쳐서 distinct를 진행하면 정상적인 결과가 도출된다.

 

flatmap은 각 요소를 별도의 스트림으로 만든 후 다시 합쳐준다. 또한 flatMap은 스트림을 받아 다른 스트림으로 변경해주는 역할을 한다.

예를 들어 (1, 2, 3) 배열과 (4, 5) 배열이 있을 때 이 두개를 합쳐서 (1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3,5) 이렇게 묶고 싶으면 다음과 같이 flatMap을 사용하여 두개를 합칠 수 있다.

List<Integer> data1 = Arrays.asList(1, 2, 3);
List<Integer> data2 = Arrays.asList(4, 5);
data1.stream()
	.flatMap(
		data -> data2.stream().map(j -> new int[] {data, j})
	)
	.collect(Collectors.toList());

만약 map(data → data.2stream().map(j → new int[] {data, })로 사용했으면 결국 최종적으로 Stream<Stream<int[]>>가 만들어지는 아쉬운 결과가 나올 수 있다.

 

 

findFirst와 findAny 차이

findFirst와 findAny는 같은 결과를 가져오지만 병렬 스트림에서는 findFirst로 첫 번째 요소를 가져오는게 어렵기 때문에 그런 경우에는 findAny를 사용한다.

 

 

parallel stream과 fork/join

parallel을 사용하여 fork/join 병렬을 진행 할 수 있다. 병렬 스트림은 기본적으로 ForkJoinPool을 사용하는데 이는 프로세스 수 즉 Runtime.getRuntime().availableProcessor()가 반환하는 값에 상응하는 스레드를 갖는다. 이 fork/join의 스레드 수는 조절이 가능하다.

 

 

Optional Serialize

Optional의 경우에 serialize를 구현하지 않았기 때문에 이는 직렬화 될 수 없다.

 

 

옳지 못한 상속 차단

코드 양이 많고 동작이 변경 되기를 원치 않는 클래스의 경우 final로 선언 또는 private 생성자를 지정한다. 이렇게 되어 있는 클래스의 기능을 이용하기 위해서는 델리게이션 즉 멤버 변수로 이용해서 클래스에서 필요한 메서드를 직접 호출하는 메서드를 작성하는 것이 좋다.

 

 

다중 상속 상황에서 동일한 이름의 메소드 우선순위

1. 클래스가 무조건 이긴다.

2. 서브 인터페이스가 이긴다. 예를 들어 B 클래스가 A 클래스를 상속받는다면 B 클래스가 무조건 A 클래스를 이긴다.

3. 이래도 불명확한 경우에는 여러 인터페이스를 상속받은 클래스에서 명시적으로 받고자 하는 곳을 지정할 수 있다.

 

 

CompletableFuture와 리액티브 프로그래밍 컨셉

값이 있을 때는 onNext, 도중에 에러가 발생했을 때는 onError, 값을 다 소진했거나 에러가 발생해서 더 이상 처리할 데이터가 없을 때 onComplete 등 각각의 콜백이 호출 된다. 이런 이벤트는 보통 순서의 개의치 않는다.

 

CompletableFuture 클래스의 join는 Future 인터페이스의 get 메소드와 동일한 의미로써 작업이 끝날 때 까지 기다린다. 다만 join은 어떠한 예외도 발생시키지 않는다는 차이점이 존재한다.

 

publisher는 subscriber가 자신을 구독하는 경우 최초로 onSubscribe를 호출하여 SubScription 객체를 전달한다. 이 Subscription 인터페이스는 publisher에게 이벤트 요청을 알리는 request 메소드가 있고 더 이상 받지 않겠다고 하는 cancel이 존대한다. 

 

publisher는 반드시 Subscription의 request 메소드에 정의된 개수 이하의 요소만 Subscriber에게 전달 할 수 있다. 해당 요청을 받은 publisher는 subscriber에게 onNext를 통해 여러번에 통해 데이터를 전달 할 수 있고 전달된 값에 따라 onComplete, onError를 통해 publisher에게 데이터 전달 성공 유무를 전달 할 수 있다. 이 대화는 publisher가 subscriber에게 전달한 subscription을 통해서 이루어진다.

 

 

 

 

 

책 전체가 조금 재미없게 구성되어 있다. 그래도 정리할 수 있어 좋았다.

댓글()

더글라스 케네디, 데드 하트 후기

Book Review|2019. 4. 29. 01:23
데드 하트
국내도서
저자 : 더글라스 케네디(Douglas Kennedy) / 조동섭역
출판 : 밝은세상 2017.05.17
상세보기

더글라스 케네디 책은 내가 다 좋아한다.

자기발전 책이나 따분한 책은 읽지 않기에 흥미진진한 구도로 책을 쓰는 케네디 책을 내가 좋아하는 것 같다.

그래서 가장 마지막으로 나온 책 데드하트를 이북 리더기 크레마 사운드 구매한 기념으로 사서 읽어보았다.

 

책 리뷰


데드하트에 나오는 주인공은 책에서 양키라고 불린다. (간단하게 아래에서도 양키라고 명칭하겠다.)  양키는 아무하고도 인연을 맺지 않고 인터넷 기사를 쓰면서 따분하게 살아가는 기자였다. 그는 이제 따분함을 느끼고 기자를 그만두고 오스트리아에 있는 작은 신문회사에 기사로 취업을 하기로 했고 모든 재산을 팔고 오스트리아로 갔다.

가는길에 엔지라는 여자를 만났고 여행자들 특성상 거기서 만나는 여자를 하룻밤 여자로 생각하고 원나잇을 했다. 하지만 여자는 그렇지 않았고 사랑에 빠진 여자는 자신을 버릴거 같은 양키를 마취시켜서 오스트리아 근처에 황무지 마을로 데려갔다.

황무지 마을에는 도시로 갈 수 없는 위치에 있고 대디라는 통치권자 밑에서 세상에 갖혀 사는 곳이었다. 엔지라는 여자를 사랑하지도 않은데 강제로 결혼하게 되었고 실종되었지만 아무도 찾지 않는 자신에 삶을 비관하였고 탈출할 희마이 없는 상황에 좌절하며 미친척 행세를 했다.

그러던중 자신을 진심으로 아끼고 같이 탈출 계획을 세워주던 여자를 만났고 그 여자와 탈출을 하다가 대디에게 잡히고 여자가 죽고 대디까지 죽고 탈출했다. 

그러면서 어느 누구와의 인연을 맺지 않고 살아가던 자신의 삶에 대해 생각해보면서 끝났다.

스토리는 생각보다 단순하였다. 책을 억지로 쓴 느낌도 있고 재미도 없었다. ㅜㅜ 

조금 실망했다. 더글라스 케네디 책을 처음 본사람들은 재밌겠지만 자주 보던 아쉬웠다.

댓글()

크레마 사운드(sound) 개봉 및 사용기

상품리뷰|2019. 4. 16. 23:57

생일이 돌아왔다.

생일선물로 어떠한 것도 받고 싶은게 없었지만 그래도 하나 꼽자면 출퇴근시 가지고 다닐 이북 리더기를 가지고 싶었다.

 

휴대폰으로 이북을 자주보고 있었지만 아무래도 눈이 너무 피로해져서 금방 보지 않게되었다.

화면도 작고 자꾸 다른 메시지나 인터넷 유혹에 벗어나지 못해서도 있었다 ㅋㅋㅋ

 

그래서 여자친구와 같이 잠실에 알라딘을 방문하여 크레마 사운드를 샀다.

크레마 그랑데도 있었지만 굳이 10만원 더주고 비싼걸 사고 싶지 않았다. 두 개의 큰 차이도 없을 뿐더러 더 무겁다.

굉장히 고급진 포장을 하고 있다.

몬가 지식인이 된 기분 ㅋㅋ

알라딘에서 구매 시 친절하게 문제가 있을 시 다음과 같이 조치하라고 안내해주셨다.

 

기기가 조금 오래되서 그런지 안드로이드 업데이트와 내부에 있는 이북 리더 어플이 업데이트 되었다. 안드로이를 오랜만에 보니 몬가 반가웠다.

 

실제로 켜보니 내용이 무슨 볼펜으로 쓴거같이 보였다. 

확실히 눈이 덜 피로하다. 이쁘다 ㅋㅋㅋ 

 

케이스랑 액보필은 굳이 필요없을 것 같다.

어차피 떨어지면 깨질테니 조심히 가지고 다니는게 장땡이다.

그리고 애초에 없다. 그랑데는 조금 케이스나 액보필이있지만 사운드의 경우에는 거의 존재하지 않는다.

 

내부에 서재에서 yes24, 알라딘과 같은 여러 사이트와 계정을 연동하여 이북을 내려받을 수 있다.

기대된다. 많이 읽어보자 책

댓글()
  1. 2019.04.24 18:11 댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

[책프협] 2019 책쓰는 개발자 책노리 방문 후기

세미나|2019. 3. 31. 17:33

작년에 어떤 출판사에서 블로그 글을 보고 책을 내보는건 어떻냐고 연락이 왔었다.

겁도 나고 내가 부족하다 생각해서 답장을 하지 못했다. ㅜㅜ 조금 후회 된다. 답장이라도 한번 해볼껄.

지금까지 공부한 내용을 남들에게 설명하고 정리하면 책도 내보고 공부도 할 수 있을것 같은데 아쉽다. 나중에 또 오면 연락을 해봐야겠다.

 

우선 그래서 개발자들이 책을 어떻게 쓰게되고 작성하는지 알아보기 위해 책쓰는 개발자 협회에서 하는 강연에 참석했다.

참석 기념품으로 교보문고에서 제공하는 달력을 받았다. 크게 기능이 있는 달력은 아닌거 같다.

 

책을 작성한 개발자분들의 대다수는 처음 책을 작성할 때 내가 부족한데 가능할까? 이런 의문을 가지고 겁도 냈다고 했다. 

그래도 하고나니 자신감도 붙고 그렇게 어렵지는 않다고했다. 단, 엄청 노가다 작업과 긴 시간이 필요하다고 했다. 

그래도 한번 해보면 재밌을 것 같다 ㅋㅋ

 

조금 더 책을 작성하고 싶은 개발자는 어떻게 해야하는지 어떻게 접촉하고 준비해야하는지에 대한 내용이 있었으면 좋겠는데 너무 전략적으로 책을 홍보하고 글쓰기를 잘하는 방법에 대해서만 알려줘서 아쉬웠다.

시간이 없어 마지막 뒤풀이는 가지 못해서 아쉬웠지만 그래도 어느정도 도움이 된 것 같다. 

언제든 책 작성 관련해서 연락이 오게 되면 작성할 수 있도록 공부 열심히 해놓자!

'세미나' 카테고리의 다른 글

[책프협] 2019 책쓰는 개발자 책노리 방문 후기  (0) 2019.03.31

댓글()

무라카미 하루키 기사단장 죽이기 2

Book Review|2018. 8. 8. 23:53
기사단장 죽이기 2
국내도서
저자 : 무라카미 하루키(Haruki Murakami) / 홍은주역
출판 : 문학동네 2017.07.12
상세보기
친구 아버지의 집에 머물고 그곳에서 기사단장 죽이기 그림을 보면서 시작된 이야기가 드디어 종료되었다. 

멘시키의 그림을 부탁받고 마리에의 그림을 그려주면서 기사단장도 만나고 메타포들을 만나면서 주인공은 많은 깨달음을 얻었다. 

특히 이상한 현상을 경험하면서 현재의 모든것이 진짜일수도 있고 거짓을수도 있다는 생각을 가지게 되었고 모든건 사람의 마음먹기 달려있다는 말을 하며 이야기가 종료되었다. 

초상화를 그려주는 일을 하는 주인공이 여러 초상화를 완성시키지 않고 그대로 놔두어야 한다고 하는 대목이 많이 존재한다.  

이는 완성의 의미가 아니라 이미 그자체로 의미가 있고 그걸 어떻게 바라보고 믿느냐에 따라 생각이 바뀌고 이루어진다는 작가의 말이 담겨있는 것 같았다. 

무라카미 하루키의 흥미로운 글 전개에 관심이 많아 그에 책을 많이 읽었다. 
하지만 이번 기사단장 죽이기는 많은 이야기 전개가 있었지만 정리가 잘 안된거 같았다. 그래서 보는 내내 읽기 어려웠고 결론을 보면서 허무함도 컸던 것 같다.

하지만 어느것이 맞고 어느것이 틀린지는 알 수 없으며 내가 믿고 행동하는대로 이루어진다는 깨달음을 얻을 수 있어 좋았다.

댓글()