Writing Correct Code

Aa077de7164201e19f9ebc15713797b8?s=47 jongman
July 28, 2014

Writing Correct Code

7월 28일 LG전자에서 한 세미나 슬라이드입니다.

링크가 살아 있는 PDF버전은 https://dl.dropboxusercontent.com/u/18062090/writing-correct-code-slides.pdf 여기에서 받으실 수 있습니다.

Aa077de7164201e19f9ebc15713797b8?s=128

jongman

July 28, 2014
Tweet

Transcript

  1. Writing Correct Code @ 손코딩뇌컴파일눈디버깅 구종만 jongman@gmail.com 1 / 128

  2. 자기소개 퀀트 개발자 : DRW Trading Group (~'09) GETCO (~'11)

    Two Sigma Investments ('14~) 알고리즘 문제 해결 전략 ('11) algospot.com 운영진 ('07~) 2 / 128
  3. 자기소개 프로그래밍 대회 참가 : 탑코더 오픈 준우승 ('07) 구글

    코드 잼 결선 ('04, '06, '08) ACM‑ICPC 결선 ('03, '04) 전문 분야 : 일단 일 벌리고 수습하느라 고통받기 모르는 것 잘 아는것처럼 얘기하기 3 / 128
  4. 오늘 할 이야기 좋은 프로그램을 작성하기 위한 우주적 지혜 !

    4 / 128
  5. 오늘의 토픽 #1 다음 중 무엇이 옳은가 ? / /

    K & R s t y l e f o r ( i n t i = 0 ; i < n ; + + i ) { . . . } / / B S D s t y l e f o r ( i n t i = 0 ; i < n ; + + i ) { . . . } 5 / 128
  6. 오늘의 토픽 #2 변수명 , 무엇으로 해야 하는가 ? c

    o n s t i n t a n s w e r _ t o _ l i f e _ t h e _ u n i v e r s e _ a n d _ e v e r y t h i n g = 4 2 ; c o n s t i n t A n s w e r T o L i f e T h e U n i v e r s e A n d E v e r y t h i n g = 4 2 ; c o n s t i n t g A n s w e r T o L i f e T h e U n i v e r s e A n d E v e r y t h i n g = 4 2 ; c o n s t i n t A n s w e r _ T o _ L i f e _ T h e _ U n i v e r s e _ A n d _ E v e r y t h i n g = 4 2 ; c o n s t i n t A N S W E R _ T O _ L I F E _ T H E _ U N I V E R S E _ A N D _ E V E R Y T H I N G = 4 2 ; c o n s t i n t A T L T U A E = 4 2 ; c o n s t i n t S I X _ B Y _ N I N E = 4 2 ; 6 / 128
  7. 오늘의 토픽 #3 탭이 옳은가 , 스페이스가 옳은가 ? 7

    / 128
  8. ( 죄송 ) 8 / 128

  9. 우주적 진리는 없고요 꾸준히 맨땅에 헤딩하는 게 답입니다 9 /

    128
  10. 진짜로 할 이야기 " 어떻게 하면 잘 동작하는 코드를 쉽게

    짤 수 있을까 ?" 연습할 필요가 있긴 할까 ? 흔한 실수들은 어디에서 올까 ? 그 실수들은 어떻게 피 할까 ? 어떻게 하면 좋은 코드를 짤 수 있을까 ? 앞으로 어떻게 수련하면 될까 ? 10 / 128
  11. 주의 오늘 하는 얘기는 모두 저의 사견 여러분의 취향 ,

    상황 , 목표에 맞지 않을 수도 있음 ! 적절히 취사선택해 주세요 ^^; 11 / 128
  12. 왜 공부해야 하나요 ? 테스팅이 있잖아요 ! 대충 짜도 테스팅만

    꼼꼼하게 하면 잘 되는 것 아닌가 요 ? 12 / 128
  13. 우리 마음 속 .jpg 13 / 128

  14. 현실 .jpg 14 / 128

  15. 범퍼카 프로그래밍 " 아이고 머리야 , 범퍼카라서 정말 다행이야 !

    이번엔 이쪽으로 돌려볼까 ?" " 어 , 이렇게 하니까 테스트가 실패하네 ? 이번엔 이렇게 고쳐보자 " 15 / 128
  16. 두 가지 문제 세상에 존재하는 모든 버그 : 모든 테스트를

    통과했다 ! 테스트는 코드에 대한 이해를 대체할 수 없다 범퍼카만 운전해서 주차 실력이 늘 수 있을까 ? " 범퍼카 운전 경력만 20 년입니다 걱정마세요 !" → ... 라고 말하는 발렛 파킹 요원이 있다면 ? 16 / 128
  17. 17 / 128

  18. 두 명의 거인 18 / 128

  19. 피터 : 테스트는 먹는 건가 ? d e f c

    r o s s ( A , B ) : " C r o s s p r o d u c t o f e l e m e n t s i n A a n d e l e m e n t s i n B . " r e t u r n [ a + b f o r a i n A f o r b i n B ] d i g i t s = ' 1 2 3 4 5 6 7 8 9 ' r o w s = ' A B C D E F G H I ' c o l s = d i g i t s s q u a r e s = c r o s s ( r o w s , c o l s ) u n i t l i s t = ( [ c r o s s ( r o w s , c ) f o r c i n c o l s ] + [ c r o s s ( r , c o l s ) f o r r i n r o w s ] + [ c r o s s ( r s , c s ) f o r r s i n ( ' A B C ' , ' D E F ' , ' G H I ' ) f o r c s i n ( ' 1 2 3 ' , ' 4 5 6 ' , ' 7 8 9 ' ) ] ) . . . 19 / 128
  20. 피터 : 테스트도 하지 뭐 ... d e f t

    e s t ( ) : " A s e t o f u n i t t e s t s . " a s s e r t l e n ( s q u a r e s ) = = 8 1 a s s e r t l e n ( u n i t l i s t ) = = 2 7 a s s e r t a l l ( l e n ( u n i t s [ s ] ) = = 3 f o r s i n s q u a r e s ) a s s e r t a l l ( l e n ( p e e r s [ s ] ) = = 2 0 f o r s i n s q u a r e s ) a s s e r t u n i t s [ ' C 2 ' ] = = [ [ ' A 2 ' , ' B 2 ' , ' C 2 ' , ' D 2 ' , ' E 2 ' , ' F 2 ' , ' G 2 ' , ' H 2 ' , [ ' C 1 ' , ' C 2 ' , ' C 3 ' , ' C 4 ' , ' C 5 ' , ' C 6 ' , ' C 7 ' , ' C 8 ' , [ ' A 1 ' , ' A 2 ' , ' A 3 ' , ' B 1 ' , ' B 2 ' , ' B 3 ' , ' C 1 ' , ' C 2 ' , a s s e r t p e e r s [ ' C 2 ' ] = = s e t ( [ ' A 2 ' , ' B 2 ' , ' D 2 ' , ' E 2 ' , ' F 2 ' , ' G 2 ' , ' H 2 ' , ' I ' C 1 ' , ' C 3 ' , ' C 4 ' , ' C 5 ' , ' C 6 ' , ' C 7 ' , ' C 8 ' , ' C ' A 1 ' , ' A 3 ' , ' B 1 ' , ' B 3 ' ] ) p r i n t ' A l l t e s t s p a s s . ' 20 / 128
  21. 피터 : 아 200 줄이나 짰다 . 끝 ! http://norvig.com/sudopy.shtml

    21 / 128
  22. 론 : 진짜 개발자는 테스트를 짠다 ! 22 / 128

  23. 론 : 자 봐 , 테스트를 시작했다 ! r e

    q u i r e ' t e s t / u n i t ' r e q u i r e ' s u d o k u t e s t . r b ' r e q u i r e ' p r o j e c t . r b ' c l a s s T C _ M y T e s t < T e s t : : U n i t : : T e s t C a s e d e f s e t u p e n d d e f t e s t _ h o o k u p a s s e r t _ e q u a l ( 5 , 2 + 2 ) e n d e n d 23 / 128
  24. c l a s s G a m e d

    e f G a m e : : t e s t _ g a m e g a m e = G a m e . n e w g a m e . t e s t _ g a m e g a m e e n d d e f t e s t _ g a m e @ c e l l s = [ ] f o r i i n 0 . . 8 0 @ c e l l s . p u s h i e n d e n d d e f c e l l ( i ) @ c e l l s [ i ] e n d e n d 론 : 게임 클래스도 만들어야지 ! 24 / 128
  25. 일 주일 후 25 / 128

  26. 26 / 128

  27. 동작하는 기능 격자의 이 칸에 이 숫자를 넣읍시다 이 격자의

    이 칸에 넣을 수 있는 숫자들은 뭔가요 ? 들어갈 수 있는 숫자가 하나만 있는 칸이 있나요 ? 게임이 끝났나요 ? ( 끝 ) 27 / 128
  28. 28 / 128

  29. 29 / 128

  30. TDD 를 하지 말자는게 아닙니다 어디 가서 " 구모씨가 테스트해봐야

    소용없다더라 " 하 시면 안됩니다 다만 : 테스트는 만능이 아니다 코드와 알고리즘을 이해하지 못하면 테스트도 도와 줄 수 없다 이해하기 쉽고 , 간결한 코드를 짜기 위한 꾸준한 수련 ! 어떻게 하면 더 좋은 코드를 짤 수 있나 감시하는 매의 30 / 128
  31. 무엇을 수련하고 무엇을 감시해야 하는가 ? 31 / 128

  32. 할 수 있는 실수가 너무 많다 ! ( 스택 |

    자료형 | 배열 크기 |...) 오버플로우 깨진 루프 불변식 잘못된 상수 요구 조건을 잘못 이해 라이브러리 잘못 사용하기 최소 크기의 입력 / 최대 크기의 입력 잘못 처리 답이 존재하지 않는 경우 잘못 구현 .... 32 / 128
  33. 어떻게 이들을 피해가야 할까 ? 원포인트 레슨 : 수많은 함정들을

    하나하나 공부해서 피해간다 방법론 : 함정들을 만나지 않을 수 있는 기본기를 갖춘 다 ( 현실 : 둘다 해야됨 ) 33 / 128
  34. Part I: Common Pitfalls 34 / 128

  35. 예제 문제 : LECTURE 길이 2n 인 소문자 문자열을 길이

    2 씩의 문자열로 분리한 뒤 , 정렬해 합쳐서 출력하라 . (n <= 500) abbaaccb ab ba ac cb ab < ac < ba < cb abacbacb 35 / 128
  36. / / c o d e # 1 : 1

    l i n e t o f i x s t r i n g s o r t _ b i g r a m s ( c o n s t s t r i n g & s ) { v e c t o r < s t r i n g > b i g r a m s ; / / 길이 2 인 문자열들로 분리 f o r ( i n t i = 0 ; i < s . s i z e ( ) ; i + = 2 ) b i g r a m s . p u s h _ b a c k ( s . s u b s t r ( i , 2 ) ) ; f o r ( i n t i = 0 ; i < b i g r a m s . s i z e ( ) ; + + i ) { / / 삽입 정렬 i n t j = i - 1 ; s t r i n g t = b i g r a m s [ i ] ; w h i l e ( j > = 0 & & b i g r a m s [ j ] > t ) { b i g r a m s [ j + 1 ] = b i g r a m s [ j ] ; - - j ; } b i g r a m s [ j ] = t ; } s t r i n g r e t ; / / 정렬된 조각들을 결합 f o r ( c o n s t a u t o & s : b i g r a m s ) r e t + = s ; r e t u r n r e t ; } 36 / 128
  37. / / c o d e # 1 : 1

    l i n e t o f i x s t r i n g s o r t _ b i g r a m s ( c o n s t s t r i n g & s ) { v e c t o r < s t r i n g > b i g r a m s ; / / 길이 2 인 문자열들로 분리 f o r ( i n t i = 0 ; i < s . s i z e ( ) ; i + = 2 ) b i g r a m s . p u s h _ b a c k ( s . s u b s t r ( i , 2 ) ) ; f o r ( i n t i = 0 ; i < b i g r a m s . s i z e ( ) ; + + i ) { / / 삽입 정렬 i n t j = i - 1 ; s t r i n g t = b i g r a m s [ i ] ; w h i l e ( j > = 0 & & b i g r a m s [ j ] > t ) { b i g r a m s [ j + 1 ] = b i g r a m s [ j ] ; - - j ; } b i g r a m s [ j ] = t ; / / 뭐가 문제? ? } s t r i n g r e t ; / / 정렬된 조각들을 결합 f o r ( c o n s t a u t o & s : b i g r a m s ) r e t + = s ; r e t u r n r e t ; } 37 / 128
  38. 삽입 정렬의 동작 s t r i n g t

    = b i g r a m s [ i ] ; 38 / 128
  39. 삽입 정렬의 동작 39 / 128

  40. 우리가 알고 있는 것 j 는 다음에 t 와 비교해야

    할 원소의 위치 j + 1 은 현재 t 가 있어야 할 자리 A [ j + 2 . . i ] 는 t 보다 큰 숫자들이 포함됨 이 사실들은 반복문의 진행 내내 성립한다 : → 반복문 불변식 ! 40 / 128
  41. 반복문 불변식 (Loop Invariant) 각 반복문 내용이 시작할 때 ,

    그리고 종료할 때 성립 중간 결과가 원하는 답으로 가는 길 위에 있나 ? / / ( 1 ) 여기서 성립한다 f o r ( . . . ; . . . ; . . . ) { / / ( 2 a ) 여기서 성립한다면 s o m e t h i n g ( ) ; s o m e t h i n g _ e l s e ( ) ; / / ( 2 b ) 여기서도 성립한다 } / / ( 3 ) 여기서 성립하면 → 우리가 원하는 결과 41 / 128
  42. 삽입 정렬과 반복문 불변식 i n t j = i

    - 1 ; s t r i n g t = b i g r a m s [ i ] ; w h i l e ( j > = 0 & & b i g r a m s [ j ] > t ) { b i g r a m s [ j + 1 ] = b i g r a m s [ j ] ; - - j ; } 1. b i g r a m s [ 0 . . j ] 는 정렬되어 있다 2. b i g r a m s [ j + 2 . . i ] 는 정렬되어 있고 , t 보다 크다 42 / 128
  43. / / c o d e # 1 : f

    i x e d s t r i n g s o r t _ b i g r a m s ( c o n s t s t r i n g & s ) { v e c t o r < s t r i n g > b i g r a m s ; / / 길이 2 인 문자열들로 분리 f o r ( i n t i = 0 ; i < s . s i z e ( ) ; i + = 2 ) b i g r a m s . p u s h _ b a c k ( s . s u b s t r ( i , 2 ) ) ; f o r ( i n t i = 0 ; i < b i g r a m s . s i z e ( ) ; + + i ) { / / 삽입 정렬 i n t j = i - 1 ; s t r i n g t = b i g r a m s [ i ] ; w h i l e ( j > = 0 & & b i g r a m s [ j ] > t ) { b i g r a m s [ j + 1 ] = b i g r a m s [ j ] ; - - j ; } b i g r a m s [ j + 1 ] = t ; } s t r i n g r e t ; / / 정렬된 조각들을 결합 f o r ( c o n s t a u t o & s : b i g r a m s ) r e t + = s ; r e t u r n r e t ; } 43 / 128
  44. 교훈 : 반복문 불변식 ! 반복문을 짜기 전에 반복문이 하는

    일과 내부의 변화 를 생각하기 ( 불변식을 주석으로 적어 두자 ) 44 / 128
  45. / / c o d e # 2 : 1

    l i n e t o f i x s t r i n g s o r t _ b i g r a m s ( c o n s t s t r i n g & s ) { v e c t o r < c o n s t c h a r * > s u f f i x ; / / 각 위치에서 시작하는 문자열 포인터 f o r ( i n t i = 0 ; i < s . s i z e ( ) ; i + = 2 ) / / 저장 s u f f i x . p u s h _ b a c k ( s . c _ s t r ( ) + i ) ; f o r ( i n t i = 0 ; i < s u f f i x . s i z e ( ) ; + + i ) / / 선택 정렬 f o r ( i n t j = i + 1 ; j < s u f f i x . s i z e ( ) ; + + j ) i f ( s t r n c m p ( s u f f i x [ i ] , s u f f i x [ j ] , 2 ) = = 1 ) / / 첫 2 글자만 비교하자 s w a p ( s u f f i x [ i ] , s u f f i x [ j ] ) ; c h a r b u f [ 1 0 0 1 ] ; f o r ( i n t i = 0 ; i < s . s i z e ( ) / 2 ; + + i ) / / 결과를 만든다 f o r ( i n t j = 0 ; j < 2 ; + + j ) b u f [ i * 2 + j ] = s u f f i x [ i ] [ j ] ; b u f [ s . s i z e ( ) ] = 0 ; r e t u r n s t r i n g ( b u f ) ; } 45 / 128
  46. / / c o d e # 2 : 1

    l i n e t o f i x s t r i n g s o r t _ b i g r a m s ( c o n s t s t r i n g & s ) { v e c t o r < c o n s t c h a r * > s u f f i x ; / / 각 위치에서 시작하는 문자열 포인터 f o r ( i n t i = 0 ; i < s . s i z e ( ) ; i + = 2 ) / / 저장 s u f f i x . p u s h _ b a c k ( s . c _ s t r ( ) + i ) ; f o r ( i n t i = 0 ; i < s u f f i x . s i z e ( ) ; + + i ) / / 선택 정렬 f o r ( i n t j = i + 1 ; j < s u f f i x . s i z e ( ) ; + + j ) i f ( s t r n c m p ( s u f f i x [ i ] , s u f f i x [ j ] , 2 ) = = 1 ) / / 첫 2 글자만 비교하자 s w a p ( s u f f i x [ i ] , s u f f i x [ j ] ) ; c h a r b u f [ 1 0 0 1 ] ; f o r ( i n t i = 0 ; i < s . s i z e ( ) / 2 ; + + i ) / / 결과를 만든다 f o r ( i n t j = 0 ; j < 2 ; + + j ) b u f [ i * 2 + j ] = s u f f i x [ i ] [ j ] ; b u f [ s . s i z e ( ) ] = 0 ; r e t u r n s t r i n g ( b u f ) ; } 46 / 128
  47. man strncmp RETURN VALUES The strcmp() and strncmp() functions return

    an integer greater than, equal to, or less than 0, according as the string s1 is greater than, equal to, or less than the string s2. The comparison is done using unsigned characters, so that '\200' is greater than '\0'. ‑1, 0, 1 외의 값도 반환된다 ! 47 / 128
  48. 교훈 : Know Your Tools! ( → C++ 은 이

    면에서는 헬게이트 !) 48 / 128
  49. C++ Pop Quiz (1) / / 일별 종가가 주어질 때

    하루 동안 일어난 최대 변화를 반환한다 i n t m a x _ p r i c e _ d i f f ( c o n s t v e c t o r < i n t > & p r i c e s ) { i n t r e t = 0 ; f o r ( i n t i = 0 ; i < p r i c e s . s i z e ( ) - 1 ; + + i ) r e t = m a x ( r e t , a b s ( p r i c e s [ i + 1 ] - p r i c e s [ i ] ) ) ; r e t u r n r e t ; } 뭐가 문제일까 ? 49 / 128
  50. C++ Pop Quiz (1) / / 일별 종가가 주어질 때

    하루 동안 일어난 최대 변화를 반환한다 i n t m a x _ p r i c e _ d i f f ( c o n s t v e c t o r < i n t > & p r i c e s ) { i n t r e t = 0 ; f o r ( i n t i = 0 ; i < p r i c e s . s i z e ( ) - 1 ; + + i ) r e t = m a x ( r e t , a b s ( p r i c e s [ i + 1 ] - p r i c e s [ i ] ) ) ; r e t u r n r e t ; } v e c t o r < i n t > e m p t y ; a s s e r t ( m a x _ p r i c e _ d i f f ( e m p t y ) = = 0 ) ; 런타임 오류 ! 50 / 128
  51. size_t f o r ( i n t i =

    0 ; i < p r i c e s . s i z e ( ) - 1 ; + + i ) Alias of one of the fundamental unsigned integer types. It is a type able to represent the size of any object in bytes: size_t is the type returned by the sizeof operator and is widely used in the standard library to represent sizes and counts. 64 비트 머신에서 대개 s i z e _ t 는 64 비트 부호 없는 정수 ! 51 / 128
  52. 대체 그럼 무슨 일이 ? A . s i z

    e ( ) = 0 A . s i z e ( ) - 1 = 2^64‑1 i < A . s i z e ( ) - 1 i 는 부호 있는 32 비트 정수 A . s i z e ( ) - 1 은 부호 없는 64 비트 정수 i 가 64 비트 부호 없는 정수로 캐스팅 ! 그런데 i 는 잘해봐야 32 비트 정수니까 비교는 항상 실패 ! 52 / 128
  53. C++ Pop Quiz (1) / / 방법1 f o r

    ( i n t i = 0 ; i < ( i n t ) p r i c e s . s i z e ( ) - 1 ; + + i ) r e t = m a x ( r e t , a b s ( p r i c e s [ i + 1 ] - p r i c e s [ i ] ) ) ; / / 방법2 f o r ( i n t i = 0 ; i + 1 < p r i c e s . s i z e ( ) ; + + i ) r e t = m a x ( r e t , a b s ( p r i c e s [ i + 1 ] - p r i c e s [ i ] ) ) ; / / 방법3 f o r ( i n t i = 1 ; i < p r i c e s . s i z e ( ) ; + + i ) r e t = m a x ( r e t , a b s ( p r i c e s [ i - 1 ] - p r i c e s [ i ] ) ) ; 53 / 128
  54. C++ Pop Quiz (2) / / 큰 정수 구현 s

    t r u c t B i g I n t e g e r { . . B i g I n t e g e r ( i n t x ) { . . } B i g I n t e g e r o p e r a t o r - ( c o n s t B i g I n t e g e r & r h s ) c o n s t { . . } B i g I n t e g e r o p e r a t o r ^ ( c o n s t B i g I n t e g e r & r h s ) c o n s t { . . } } ; o s t r e a m & o p e r a t o r < < ( o s t r e a m & o s , c o n s t B i g I n t e g e r & r h s ) { . . } i n t m a i n ( ) { / / l a r g e s t k n o w n m e r s e n n e p r i m e : 2 ^ 5 7 8 8 5 1 6 1 - 1 c o u t < < B i g I n t e g e r ( 2 ) ^ B i g I n t e g e r ( 5 7 8 8 5 1 6 1 ) - B i g I n t e g e r ( 1 ) < < e n d l ; } 컴파일 에러 ! 54 / 128
  55. 연산자 우선 순위 c o u t < < B

    i g I n t e g e r ( 2 ) ^ B i g I n t e g e r ( 5 7 8 8 5 1 6 1 ) - B i g I n t e g e r ( 1 ) < < e n d l ; 55 / 128
  56. C++ Pop Quiz (2): Fixed? / / 큰 정수 구현

    s t r u c t B i g I n t e g e r { . . B i g I n t e g e r ( i n t x ) { . . } B i g I n t e g e r o p e r a t o r - ( c o n s t B i g I n t e g e r & r h s ) c o n s t { . . } B i g I n t e g e r o p e r a t o r ^ ( c o n s t B i g I n t e g e r & r h s ) c o n s t { . . } } ; o s t r e a m & o p e r a t o r < < ( o s t r e a m & o s , c o n s t B i g I n t e g e r & r h s ) { . . } i n t m a i n ( ) { / / l a r g e s t k n o w n m e r s e n n e p r i m e : 2 ^ 5 7 8 8 5 1 6 1 - 1 c o u t < < ( B i g I n t e g e r ( 2 ) ^ B i g I n t e g e r ( 5 7 8 8 5 1 6 1 ) - B i g I n t e g e r ( 1 ) ) < < e n d l ; } 56 / 128
  57. c o u t < < ( B i g

    I n t e g e r ( 2 ) ^ B i g I n t e g e r ( 5 7 8 8 5 1 6 1 ) - B i g I n t e g e r ( 1 ) ) < < e n d l ; 57 / 128
  58. 연산자 우선 순위 c o u t < < (

    B i g I n t e g e r ( 2 ) ^ B i g I n t e g e r ( 5 7 8 8 5 1 6 1 ) ) - B i g I n t e g e r ( 1 ) < < e n d l ; Rule of thumb: ( 남이 ) 헷갈릴 가능성이 있다면 무조건 괄호로 감싸 라 ! 깔끔한 코드는 잠재적 오류만큼의 가치는 없다 ! 58 / 128
  59. C++ Pop Quiz (3) s t r u c t

    I t e m ; s t r u c t P l a y e r { v e c t o r < I t e m * > i t e m s ; i n t s t r e n g t h ; / / 들 수 있는 아이템의 최대 수는 힘과 같다 P l a y e r ( i n t s ) : s t r e n g t h ( s ) , i t e m s ( s t r e n g t h , n u l l p t r ) { } } ; 59 / 128
  60. C++ Pop Quiz (3) s t r u c t

    I t e m ; s t r u c t P l a y e r { v e c t o r < I t e m * > i t e m s ; i n t s t r e n g t h ; / / 들 수 있는 아이템의 최대 수는 힘과 같다 P l a y e r ( i n t s ) : s t r e n g t h ( s ) , i t e m s ( s t r e n g t h , n u l l p t r ) { } } ; v o i d t e s t _ p l a y e r ( ) { P l a y e r p ( 1 0 ) ; a s s e r t ( p . i t e m s . s i z e ( ) = = 1 0 ) ; / / 런타임 오류, 혹은 실패! } 60 / 128
  61. 초기화 리스트의 순서 s t r u c t P

    l a y e r { v e c t o r < I t e m * > i t e m s ; i n t s t r e n g t h ; / / 들 수 있는 아이템의 최대 수는 힘과 같다 P l a y e r ( i n t s ) : s t r e n g t h ( s ) , i t e m s ( s t r e n g t h , n u l l p t r ) { } 클래스 선언부 내의 순서대로 초기화됨 ! 초기화 리스트 내의 순서와 상관 없음 ! 61 / 128
  62. C++ Pop Quiz (3) s t r u c t

    P l a y e r { i n t s t r e n g t h ; v e c t o r < I t e m * > i t e m s ; / / 들 수 있는 아이템의 최대 수는 힘과 같다 P l a y e r ( i n t s ) : s t r e n g t h ( s ) , i t e m s ( s t r e n g t h , n u l l p t r ) { } 혹은 P l a y e r ( i n t s ) : s t r e n g t h ( s ) , i t e m s ( s , n u l l p t r ) { } 62 / 128
  63. C++ Pop Quiz (4) s t r u c t

    P e r s o n { s t r i n g n a m e ; v e c t o r < P e r s o n * > c h i l d r e n ; } ; v o i d c o l l e c t ( P e r s o n * p e r s o n , v e c t o r < P e r s o n * > & c o l l e c t e d ) { c o l l e c t e d . p u s h _ b a c k ( p e r s o n ) ; f o r ( a u t o c h i l d : p e r s o n - > c h i l d r e n ) c o l l e c t ( c h i l d , c o l l e c t e d ) ; } / / p e r s o n 과 그의 모든 자손을 배열에 모은다 v e c t o r < P e r s o n * > c o l l e c t _ f a m i l y _ r e c u r s i o n ( P e r s o n * p e r s o n ) { v e c t o r < P e r s o n * > c o l l e c t e d ; c o l l e c t ( p e r s o n , c o l l e c t e d ) ; r e t u r n c o l l e c t e d ; } 63 / 128
  64. ( 사실 이 코드는 잘 동작합니다 ) 64 / 128

  65. 재귀호출이 싫어요 ! s t r u c t P

    e r s o n { s t r i n g n a m e ; v e c t o r < P e r s o n * > c h i l d r e n ; } ; / / p e r s o n 과 그의 모든 자손을 배열에 모은다 v e c t o r < P e r s o n * > c o l l e c t _ f a m i l y ( P e r s o n * p e r s o n ) { v e c t o r < P e r s o n * > c o l l e c t e d ( 1 , p e r s o n ) ; f o r ( a u t o p : c o l l e c t e d ) f o r ( a u t o c h i l d : p - > c h i l d r e n ) c o l l e c t e d . p u s h _ b a c k ( c h i l d ) ; r e t u r n c o l l e c t e d ; } 65 / 128
  66. 파헤치자 f o r ( a u t o p

    : c o l l e c t e d ) { . . } f o r ( a u t o i t = b e g i n ( c o l l e c t e d ) ; i t ! = e n d ( c o l l e c t e d ) ; + + i t ) { P e r s o n * p = * i t ; . . } f o r ( a u t o i t = c o l l e c t e d . b e g i n ( ) ; i t ! = c o l l e c t e d . e n d ( ) ; + + i t ) { P e r s o n * p = * i t ; . . } 66 / 128
  67. 반복자 무효화 v e c t o r 에 원소를

    추가하거나 , 지우거나 , 크기를 변경 하면 이미 존재하는 모든 반복자는 무효화될 수 있다 i t 값을 참조하면 런타임 오류가 발생할 수 있음 ! 종류에 따라 다르지만 다른 모든 컨테이너에도 반복자 무효화 규칙이 존재 See Iterator invalidation rules 67 / 128
  68. 무효화의 이유 v e c t o r 는 여유분을

    포함한 적당히 큰 메모리를 미리 할당해 둔다 꽉 찼을 때 p u s h _ b a c k 이 들어오면 : 더 큰 메모리를 할당해서 현재 메모리 내용을 복사 ! 이전 메모리는 해제한다 그러면 기존 반복자는 해제된 메모리를 가리킴 ! 68 / 128
  69. 개선 가능하면 안하는게 좋습니다 s t r u c t

    P e r s o n { s t r i n g n a m e ; v e c t o r < P e r s o n * > c h i l d r e n ; } ; / / p e r s o n 과 그의 모든 자손을 배열에 모은다 v e c t o r < P e r s o n * > c o l l e c t _ f a m i l y ( P e r s o n * p e r s o n ) { v e c t o r < P e r s o n * > c o l l e c t e d ( 1 , p e r s o n ) ; f o r ( i n t i = 0 ; i < c o l l e c t e d . s i z e ( ) ; + + i ) f o r ( a u t o c h i l d : c o l l e c t e d [ i ] - > c h i l d r e n ) c o l l e c t e d . p u s h _ b a c k ( c h i l d ) ; r e t u r n c o l l e c t e d ; } 69 / 128
  70. 이대로 가면 끝이 없음 ! 오늘 밤 12 시에 집에

    가야 함 ! 70 / 128
  71. / / c o d e # 3 : 2

    l i n e s t o f i x s t r i n g s o r t _ b i g r a m s ( c o n s t s t r i n g & s ) { i n t n = s . s i z e ( ) ; c h a r * * b i g r a m s = ( c h a r * * ) m a l l o c ( s i z e o f ( c h a r * ) * n / 2 ) ; f o r ( i n t i = 0 ; i < n / 2 ; + + i ) { b i g r a m s [ i ] = ( c h a r * ) m a l l o c ( s i z e o f ( c h a r ) * 2 ) ; s t r n c p y ( b i g r a m s [ i ] , s . c _ s t r ( ) + i * 2 , 2 ) ; } f o r ( i n t i = 0 ; i < n / 2 ; + + i ) f o r ( i n t j = i + 1 ; j < n / 2 ; + + j ) i f ( s t r n c m p ( b i g r a m s [ i ] , b i g r a m s [ j ] , 2 ) > 0 ) s w a p ( b i g r a m s [ i ] , b i g r a m s [ j ] ) ; c h a r * b u f = ( c h a r * ) m a l l o c ( s i z e o f ( c h a r ) * 1 0 0 0 ) ; f o r ( i n t i = 0 ; i < n / 2 ; + + i ) f o r ( i n t j = 0 ; j < 2 ; + + j ) b u f [ i * 2 + j ] = b i g r a m s [ i ] [ j ] ; b u f [ n ] = 0 ; r e t u r n s t r i n g ( b u f ) ; } 71 / 128
  72. 문제 : 배열 크기 ! C 문자열은 NULL 로 끝나는

    배열이므로 , 실제 길이보 다 용량이 1 커야 한다 c h a r * b u f = ( c h a r * ) m a l l o c ( s i z e o f ( c h a r ) * 1 0 0 0 ) ; 아래 줄은 왜 괜찮을까 ? b i g r a m s [ i ] = ( c h a r * ) m a l l o c ( s i z e o f ( c h a r ) * 2 ) ; 72 / 128
  73. / / c o d e # 3 : 2

    l i n e s t o f i x s t r i n g s o r t _ b i g r a m s ( c o n s t s t r i n g & s ) { i n t n = s . s i z e ( ) ; c h a r * * b i g r a m s = ( c h a r * * ) m a l l o c ( s i z e o f ( c h a r * ) * n / 2 ) ; f o r ( i n t i = 0 ; i < n / 2 ; + + i ) { b i g r a m s [ i ] = ( c h a r * ) m a l l o c ( s i z e o f ( c h a r ) * 2 ) ; s t r n c p y ( b i g r a m s [ i ] , s . c _ s t r ( ) + i * 2 , 2 ) ; } f o r ( i n t i = 0 ; i < n / 2 ; + + i ) f o r ( i n t j = i + 1 ; j < n / 2 ; + + j ) i f ( s t r n c m p ( b i g r a m s [ i ] , b i g r a m s [ j ] , 2 ) > 0 ) s w a p ( b i g r a m s [ i ] , b i g r a m s [ j ] ) ; c h a r * b u f = ( c h a r * ) m a l l o c ( s i z e o f ( c h a r ) * 1 0 0 1 ) ; f o r ( i n t i = 0 ; i < n / 2 ; + + i ) f o r ( i n t j = 0 ; j < 2 ; + + j ) b u f [ i * 2 + j ] = b i g r a m s [ i ] [ j ] ; b u f [ n ] = 0 ; r e t u r n s t r i n g ( b u f ) ; } 73 / 128
  74. 진짜 문제 : 쓸데 없이 복잡한 도구 사용 ! 74

    / 128
  75. C 문자열이 복잡하다고 ? " 옛 선현들은 다 이걸로 코딩했어

    복잡하긴 뭘 " " 진정한 개발자는 바이트 단위에서 노는거야 C++ 문 자열은 똥이야 ! 똥이라고 " "80 년대생들이 K&R C 를 알겠냐 ? 요즘 애들은 로망이 없어요 " 75 / 128
  76. 복잡하다 ≠ 어렵다 76 / 128

  77. 쉽다 vs 어렵다 : 접근성 쉽다 : 내가 이미 알고

    있다 이미 내 컴퓨터에 깔려 있다 어렵다 : 학습 커브를 다시 통과해야 한다 고생해서 구해서 설치해야 한다 77 / 128
  78. 간결하다 vs 복잡하다 : 논리적 간결하다 : 한번에 한 가지의

    일을 한다 문맥에 신경쓰지 않아도 된다 복잡하다 : 여러 개의 일이 섞여 있다 문맥에 신경써야 한다 78 / 128
  79. 왜 간결함을 선호해야 하는가 ? 프로그래밍은 저글링과 같다 신경써야 하는

    모든 것들이 하나의 공 ! " 이 공을 던지고 싶나 ? 이 공은 사실 두개란다 " 공 하나의 가격은 비싸다 ! 나는 2 개의 공을 던지고 받을 수 있다 세계 기록 : 고작 13 개 ! 79 / 128
  80. C 스타일 문자열은 왜 복잡한가 ? 추가적인 문맥을 달고 온다

    ! 문자열의 최대 길이는 배열의 길이 ‑1 을 넘어갈 수 없다 strncpy 는 NULL 문자를 추가하기도 하고 , 하지 않 기도 한다 ! strncmp 만 사용하면 NULL 문자가 필요없다 ! 문자열을 사용하는 입장에서 이 문맥은 노이즈일 뿐 ! 80 / 128
  81. 복잡한 도구는 왜 복잡할까 ? 81 / 128

  82. 지인짜 문제 : 추상화가 부족하다 ! 82 / 128

  83. 추상화와 간결한 코드 문맥을 제거함으로써 더 높은 레벨에서 사고할 수

    있 게 해준다 ! 어떤 도구를 어떻게 사용해야 하는가 ? Part II 에서 계속 83 / 128
  84. / / c o d e # 4 : 1

    l i n e t o f i x s t r i n g s o r t _ b i g r a m s ( c o n s t s t r i n g & s ) { v e c t o r < s t r i n g > b i g r a m s ; f o r ( i n t i = 0 ; i < s . s i z e ( ) ; i + = 2 ) b i g r a m s . p u s h _ b a c k ( s . s u b s t r ( i , 2 ) ) ; f o r ( i n t i = 0 ; i < s . s i z e ( ) ; + + i ) { i n t j = i - 1 ; s t r i n g t = b i g r a m s [ i ] ; w h i l e ( j > = 0 & & b i g r a m s [ j ] > t ) { b i g r a m s [ j + 1 ] = b i g r a m s [ j ] ; - - j ; } b i g r a m s [ j + 1 ] = t ; } s t r i n g r e t ; f o r ( c o n s t a u t o & s : b i g r a m s ) r e t + = s ; r e t u r n r e t ; } 84 / 128
  85. s t r i n g s o r t

    _ b i g r a m s ( c o n s t s t r i n g & s ) { v e c t o r < s t r i n g > b i g r a m s ; f o r ( i n t i = 0 ; i < s . s i z e ( ) ; i + = 2 ) b i g r a m s . p u s h _ b a c k ( s . s u b s t r ( i , 2 ) ) ; f o r ( i n t i = 0 ; i < s . s i z e ( ) ; + + i ) { i n t j = i - 1 ; s t r i n g t = b i g r a m s [ i ] ; w h i l e ( j > = 0 & & b i g r a m s [ j ] > t ) { b i g r a m s [ j + 1 ] = b i g r a m s [ j ] ; - - j ; } b i g r a m s [ j + 1 ] = t ; } s t r i n g r e t ; f o r ( c o n s t a u t o & s : b i g r a m s ) r e t + = s ; r e t u r n r e t ; } 85 / 128
  86. s t r i n g s o r t

    _ b i g r a m s ( c o n s t s t r i n g & s ) { v e c t o r < s t r i n g > b i g r a m s ; f o r ( i n t i = 0 ; i < s . s i z e ( ) ; i + = 2 ) b i g r a m s . p u s h _ b a c k ( s . s u b s t r ( i , 2 ) ) ; f o r ( i n t i = 0 ; i < b i g r a m s . s i z e ( ) ; + + i ) { i n t j = i - 1 ; s t r i n g t = b i g r a m s [ i ] ; w h i l e ( j > = 0 & & b i g r a m s [ j ] > t ) { b i g r a m s [ j + 1 ] = b i g r a m s [ j ] ; - - j ; } b i g r a m s [ j + 1 ] = t ; } s t r i n g r e t ; f o r ( c o n s t a u t o & s : b i g r a m s ) r e t + = s ; r e t u r n r e t ; } 86 / 128
  87. 87 / 128

  88. 정줄놓 앞에 장사 없다 어떠한 원칙과 기법도 신중하고 주의깊은 프로그래머

    의 대체재가 될 수 없다 ! 은총알을 항상 경계하자 ! 88 / 128
  89. 이 외의 중요한 오류 클래스들 물리적 기계의 한계에서 오는 문제

    변수형 오버플로우 스택 오버플로우 실수 연산의 정확성 문제 ( 여기도 지뢰밭 ) http://floating‑point‑gui.de/ TopCoder Tutorial Part 1, Part 2 89 / 128
  90. 휴식 ! 90 / 128

  91. Part II: Writing Good Code 91 / 128

  92. Disclaimer 이 파트는 더더욱 주관적인 취향의 영역 모두에게 자신의 기준이

    있음 오늘의 이야기도 우주적 기준이 아님 미시적 관점 (X) 좋은 소프트웨어 아키텍처 , 디자인 패턴 , 소프 트웨어 스택 (O) 어떻게 간결한 함수를 작성할까 ? 어떻게 이 클 래스를 잘 만들까 ? 92 / 128
  93. 간결성 revisited 한 번에 하나의 일만 하기 문맥의 수로 결정된다

    혹이 달려오는 도구는 쓰지 말자 다양한 단계에서의 간결성 도구의 선택 함수 하나 클래스 구조 설계 93 / 128
  94. 같은 값이면 추상화 ! 복잡 간결 i n t A

    [ M A X _ N ] ; v e c t o r < i n t > A ; / / 정렬한 상태로 유지한다 i n t A [ M A X _ N ] ; s e t < i n t > A ; / / 모든 P e r s o n 에 대해 P e r s o n p e o p l e [ M A X _ N ] ; f o r ( i n t i = 0 ; i < n ; + + i ) { f o r ( a u t o p e r s o n : p e o p l e ) / / 최대값을 구한다 f o r ( i n t i = 0 ; i < n ; + + i ) { . . } * m a x _ e l e m e n t ( b e g i n ( A ) , e n d ( A ) ) / / 두 P e r s o n 을 비교 s t r u c t C o m p a r a t o r { . . } ; [ ] ( c o n s t P e r s o n & a , c o n s t P e r s o n & b ) { . . } i n t x [ N ] , y [ N ] , z [ N ] ; v e c t o r < P o i n t > p o i n t s ; 94 / 128
  95. 지옥에서 온 코드 .cpp s t r i n g

    c o m p l e x i t y _ h e l l ( c o n s t s t r i n g & s ) { c h a r b u f [ 1 0 2 4 ] , t m p [ 1 0 2 4 ] ; s t r c p y ( b u f , s . c _ s t r ( ) ) ; f o r ( i n t i = 0 ; i < s . s i z e ( ) ; i + = 2 ) f o r ( i n t j = i + 2 ; j < s . s i z e ( ) ; j + = 2 ) { i f ( b u f [ i ] > b u f [ j ] | | ( b u f [ i ] = = b u f [ j ] & & b u f [ i + 1 ] > b u f [ j + 1 ] ) ) { s t r n c p y ( t m p , & b u f [ i ] , 2 ) ; s t r n c p y ( & b u f [ i ] , & b u f [ j ] , 2 ) ; s t r n c p y ( & b u f [ j ] , t m p , 2 ) ; } } r e t u r n s t r i n g ( b u f ) ; } 95 / 128
  96. 어느 쪽 ? 96 / 128

  97. 개선 s t r i n g s o r

    t _ b i g r a m s ( c o n s t s t r i n g & s ) { v e c t o r < s t r i n g > b i g r a m s ; f o r ( i n t i = 0 ; i < s . s i z e ( ) ; i + = 2 ) b i g r a m s . p u s h _ b a c k ( s . s u b s t r ( i , 2 ) ) ; s o r t ( b i g r a m s . b e g i n ( ) , b i g r a m s . e n d ( ) ) ; s t r i n g r e t ; f o r ( c o n s t a u t o & b : b i g r a m s ) r e t + = b ; r e t u r n r e t ; } 97 / 128
  98. Mutable vs Immutable C 의 문자열 : 문자를 바꾸고 ,

    길이를 늘리고 , 줄일 수 있다 ! c h a r b u f [ 6 4 ] ; s t r c p y ( b u f , " H e l l o W o r l d ! " ) ; b u f [ 4 ] = ' ' ; Python 의 문자열 : 새 문자열을 얻는다 ! h e l l o = ' H e l l o W o r l d ! ' h e l l = h e l l o [ : 4 ] + ' ' + h e l l o [ 5 : ] 98 / 128
  99. 변수의 개념 Immutable: 특정 값에 이름을 붙인다 조작하면 새로운 값을

    얻는다 Mutable: 값을 담을 수 있는 메모리 " 조각 " 에 이름을 붙인다 메모리에 새 값을 써넣으면 모든 사람들의 값이 바 뀐다 ! 99 / 128
  100. 변경 가능한 값은 추가 문맥을 가져온다 100 / 128

  101. Immutable 프로그래밍 모든 함수는 " 이전의 값을 이용해 새 값을

    계산한 다 " 의 연속 이전의 값이 바뀌면서 이전 부분과 다음 부분이 섞일 여지를 주지 않는다 파이프라인 ‑ 지향 프로그래밍 101 / 128
  102. 고려할 점 : 오버헤드 데이터를 생성하고 바로 처리하면 더 빠를

    수는 있다 ! 대부분의 경우 주의깊은 알고리즘과 자료 구조 선택으 로 극복 지원되는 경우에는 lazy evaluation 을 적극 활용 102 / 128
  103. 보다 고수준에서의 간결성 SRP (Single Responsibility Principle) 객체간의 직접적 의존성을

    최대한 줄인다 남아 있는 직접적 의존성 ‑ 추상화하라 ! 필요한 문맥만 남기고 없앤다 간결하다 ≠ 컴포넌트의 개수가 적다 가능한 상태의 수가 적다 Stateless 시스템을 향해 ! 103 / 128
  104. 예 : 온라인 채점 시스템 1. 새 소스 코드가 제출됨

    2. 해당 문제가 채점 준비된 상태인지 확인 3. 파일서버에서 채점 데이터 다운로드 4. 샌드박스 생성해서 프로그램 컴파일 및 실행 5. 채점 결과 확인 104 / 128
  105. Initial design 105 / 128

  106. 106 / 128

  107. 대체 뭐가 문제야 ? 엄청 많은 직접적 의존성 ! Actor

    들은 모두 상태를 잔뜩 쥐고 있다 문제들 : 재시도는 어떻게 하지 ? 한 Actor 가 실패하면 전체 시스템이 멈춘다 Actor 간 리소스 공유 107 / 128
  108. Task Queue 108 / 128

  109. 왜 더 나은가 ? 컴포넌트도 , 의존성도 없다 각 작업에는

    아무런 상태가 없다 한 작업 실패가 다른 작업 실패에 영향을 주지 않음 투명한 재시도 정책 각 액터 단위로 관리하지 않고 태스크 큐 자체에서 관리 109 / 128
  110. 요점 정리 문맥의 수를 줄이는 것이 최우선 적절한 도구 선택

    전후 코드간 의존성 줄이기 : " 파이프라인 " 직접적 의존성 줄이기 추상화 의존성 만들기 110 / 128
  111. 이런 코드를 보셨나요 ? s t r u c t

    P l a y e r { s t r i n g n a m e ; } ; s t r u c t T e a m { v e c t o r < P l a y e r > m e m b e r s ; } ; / / 팀 내에 주어진 이름을 가진 사람이 있는가? b o o l h a s _ m e m b e r ( T e a m * t e a m , c o n s t s t r i n g & n a m e ) { b o o l f o u n d = f a l s e ; i f ( t e a m ! = n u l l p t r ) { i n t i ; f o r ( i = 0 ; i < t e a m - > m e m b e r s . s i z e ( ) ; + + i ) { i f ( t e a m - > m e m b e r s [ i ] . n a m e = = n a m e ) { b r e a k ; } } f o u n d = i < t e a m - > m e m b e r s . s i z e ( ) ; } r e t u r n f o u n d ; } 111 / 128
  112. 이런 코드를 보셨나요 ? / / A 에서 세 원소를

    골라 합이 s 가 되도록 할 수 있나? b o o l f i n d 3 ( c o n s t v e c t o r < i n t > & A , i n t s ) { b o o l f o u n d = f a l s e ; f o r ( i n t i = 0 ; i < A . s i z e ( ) ; + + i ) { f o r ( i n t j = i + 1 ; j < A . s i z e ( ) ; + + j ) { f o r ( i n t k = j + 1 ; k < A . s i z e ( ) ; + + k ) { i f ( A [ i ] + A [ j ] + A [ k ] = = s ) { f o u n d = t r u e ; b r e a k ; } } i f ( f o u n d ) b r e a k ; } i f ( f o u n d ) b r e a k ; } r e t u r n f o u n d ; 112 / 128
  113. 이런 코드를 보셨나요 ? s t r u c t

    P l a y e r { s t r i n g n a m e ; i n t s t r , d e x , m a n a ; } ; b o o l o p e r a t o r < ( c o n s t P l a y e r & a , c o n s t P l a y e r & b ) { i f ( a . s t r = = b . s t r ) { i f ( a . d e x = = b . d e x ) { i f ( a . m a n a = = b . m a n a ) { r e t u r n a . n a m e < b . n a m e ; } r e t u r n a . m a n a < b . m a n a ; } r e t u r n a . d e x < b . d e x ; } r e t u r n a . s t r < b . s t r ; } 113 / 128
  114. 깊은 중첩 (nesting) if 안에 for 안에 if 안에 for..

    답을 찾았는지 기록하기 위한 북키핑 변수들 루프 밖에서 선언된 카운터 114 / 128
  115. 다시 짜기 s t r u c t P l

    a y e r { s t r i n g n a m e ; } ; s t r u c t T e a m { v e c t o r < P l a y e r > m e m b e r s ; } ; / / 팀 내에 주어진 이름을 가진 사람이 있는가? b o o l h a s _ m e m b e r _ r e w r i t e ( T e a m * t e a m , c o n s t s t r i n g & n a m e ) { i f ( ! t e a m ) r e t u r n f a l s e ; f o r ( c o n s t a u t o & m e m b e r : t e a m - > m e m b e r s ) i f ( m e m b e r . n a m e = = n a m e ) r e t u r n t r u e ; r e t u r n f a l s e ; } 115 / 128
  116. 다시 짜기 / / A 에서 세 원소를 골라 합이

    s 가 되도록 할 수 있나? b o o l f i n d 3 _ r e w r i t e ( c o n s t v e c t o r < i n t > & A , i n t s ) { f o r ( i n t i = 0 ; i < A . s i z e ( ) ; + + i ) f o r ( i n t j = i + 1 ; j < A . s i z e ( ) ; + + j ) f o r ( i n t k = j + 1 ; k < A . s i z e ( ) ; + + k ) i f ( A [ i ] + A [ j ] + A [ k ] = = s ) r e t u r n t r u e ; r e t u r n f a l s e ; } 116 / 128
  117. 다시 짜기 s t r u c t P l

    a y e r { s t r i n g n a m e ; i n t s t r , d e x , m a n a ; } ; b o o l o p e r a t o r < ( c o n s t P l a y e r & a , c o n s t P l a y e r & b ) { i f ( a . s t r ! = b . s t r ) r e t u r n a . s t r < b . s t r ; i f ( a . d e x ! = b . d e x ) r e t u r n a . d e x < b . d e x ; i f ( a . m a n a ! = b . m a n a ) r e t u r n a . m a n a < b . m a n a ; r e t u r n a . n a m e < b . n a m e ; } 117 / 128
  118. Return early " 하나의 return 문 ": 파스칼 시절의 유물

    언제 반환할까 ? 예외 상황 발생 반환값이 정해짐 재귀호출시의 기저사례 코드를 첫줄에서 아래줄까지 쭉 읽을 수 있게 한다 각 중첩은 새로운 문맥을 만든다 ! 118 / 128
  119. Design by Contract Design by contract (DbC), also known as

    contract programming, programming by contract and design‑by‑contract programming, is an approach for designing software. It prescribes that software designers should define formal, precise and verifiable interface specifications for software components, which extend the ordinary definition of abstract data types with preconditions, postconditions and invariants. Wikipedia 119 / 128
  120. 머릿속에서 계약하기 머릿속에서 , 혹은 주석으로 : 이 함수는 무엇을

    가정할까 ? 이 함수의 결과는 무엇일까 ? 머릿속 시나리오 쓰려면 함수가 간결해야 한다 ! 함수의 처음과 끝부터 작성하기 120 / 128
  121. 선언적 프로그래밍 " 무엇을 "/" 어떻게 " 분리하기 SQL/regexp 의

    생산성 ! 직접 다 만들어 쓸 수는 없어도 유용한 생각 도구 ! 121 / 128
  122. map d e f d o u b l e

    _ e l e m e n t s ( A ) : B = [ ] f o r i i n x r a n g e ( l e n ( A ) ) : B . a p p e n d ( A [ i ] * 2 ) r e t u r n B d e f d o u b l e _ e l e m e n t s 2 ( A ) : r e t u r n m a p ( l a m b d a x : x * 2 , A ) 122 / 128
  123. Closing Remarks 123 / 128

  124. 수련의 방법 짧은 코드 여러개 짜기 하비 프로젝트 온라인 채점

    시스템 , 프로젝트 오일러 실패 기록하기 , 포스트모템 다양한 수준의 추상화 , 도구를 사용해 보기 다양한 프로그래밍 패러다임 124 / 128
  125. 마지막으로 드리고 싶은 말씀 125 / 128

  126. 매의 눈 126 / 128

  127. Talk Inspired By: 생각하는 프로그래밍 ( 인사이트 ) Beautiful Code

    ( 한빛미디어 ) http://iq0.com/notes/deep.nesting.html Rich Hickey Simple Made Easy Value of Values 127 / 128
  128. 감사합니다 128 / 128