리치히키는 Clojure를 이끄는 리더이다. Clojure를 알지 못하여도 그의 발표는 너무나도 멋지다. 사실 단어의 사용이 너무 고급스러워서 때때로 못알아듣는다.
영어공부를 해야할 때인 것 같다.
이런 사람들이 발표를 하는 것을 보면, 정말 작은 것에 많은 고민을 한다는 생각을 한다.
리치히키는 null이라는 것을 시작으로 끝없는 고심을 하고 새로운 대안책을 제시한다.
null값이 만들어내는 비극을 그는 이 강연에서 설명해준다. 그리고 다른 언어들은 무엇을 하고 있는지 알려준다.
하스켈은 모나드를 사용한다. (Maybe)
스칼라는 여러가지 타입(?)으로 정의한다. (Any 등등등 꽤 많다)
코틀린의 Nullable타입
자바의 Optional
클로저는 리스프를 사용하며 함수형프로그래밍이다.
그러므로 새로운 타입을 생성하지 않는다.
클로저는 map을 이용하여 모든 것을 표현한다.
우리는 값을 넘기고 받을 때, 그 값들의 모음을 aggregate이라고 한다.
아래는 aggregate의 어원이라고 한다.
from ad- "to" + gregare "flock / herd"
바로 염소 같은 것들의 무리들이 움직이는 것이다. 바로 우리가 데이터를 쓰는 방식이다. 여러 무리들을 데리고 이리저리 돌아다닌다.
클로저는 이렇게 큰 자유를 가지고 있어서 저런 Nullable같은 것에 자유롭다. 값이 없다고? 그냥 넣지 않으면 된다.
하지만 spec이라는 라이브러리를 이용하기 시작하면 아주 동일한 문제를 가지게 된다.
spec은 동적프로그래밍을 하는 클로저에 타입과 비슷한 제약을 추가하는 것이다. 말그대로 스펙을 적어주는 것이다.
왜 spec을 쓸꺼면, 그냥 언어자체에서 타입이나 제약을 사용하지 굳이 맵을 쓴다음에 거기에 spec을 얹는 것일까?
그것은 바로 직교성 때문이다. A와 B가 직교하면 A의 변화에 B는 상관이 없게 된다.
그렇게 코드와 스펙을 나눈 것이다.
그러므로 빠르게 맵을 보내면서 개발을 하고, 정확한 스펙은 spec으로 지정해도 되는 것이다.
그러면 spec을 바꿔도 코드는 그대로 일 것이다. 코드를 바꿔도 spec은 상관이 없다.
각설하고 그런데 왜 여기서 null에 대한 이야기를 한 것일까?
spec에는 똑같이 필수 변수나 값이 옵션이 경우가 있다. 여기서 옵션인 경우가 문제가 된다. 그렇다. 우리는 여기에 값이 언제 올지 알 수 없다.
옵셔널은 아주 큰 특수성을 만든다. spec을 지정했지만 그것 하나하나에 특별한 경우가 생기면 비슷한 모양의 spec이 계속 생긴다.
리치히키는 자신의 설계 잘못을 인정한다. (난 언어개발자 중에 자신의 잘못을 인정한 사람을 찾기가 정말 힘들다.
그런데 그는 세미나에서 자신의 과오를 고백하고 쓰면 안되는 방식으로 쓰는 코드를 보면서 많은 고민을 해왔다고 한다.)
그리고 그는 새로운 해결책을 제시한다. 바로 spec을 다시 둘로 쪼개는 것인다.
그리하여 def/schema로 나뉘어 정의하는 것 같다.
어떤 개념을 def로 정의하고 해당 정의에 대한 형태를 schema로 정의하는 것 같다.
Clojure를 만져본지 꽤 되었지만 이런 세미나를 보면 어느새 Clojure 사이트를 한번 이리저리 구경하게 된다.
저런 사람들과 함께 일한다는 것은 어떤 느낌일까.
나도 저 안에 끼고 싶다.
2019년 7월 3일 수요일
2019년 7월 1일 월요일
[책리뷰] 객체지향의 사실과 오해 -조영호 저-
사실 2년 전에 서점에서 중간 정도 읽은 기억이 있다.
그 이후로 이 책에 언급한 몇가지 내용들이 계속 기억에 남았었는데,
시간이 지나고 그 내용들의 문장은 기억나지만 문맥이 흐릿해져 느긋하게 정독을 하고자 책을 구매했다.
이 책은 코드는 거의 없고 저자의 철학 혹은 저자가 공부해온 전문가들의 이론을 설명하는데 대부분을 사용한다.
UML도 찾기 어렵고 수도코드도 없다. 하지만 어떻게 개발을 해야 하는지 설명을 해주는 책이다.
이 책은 표지에서도 나오듯이 객체지향이랑 역할,책임,협력이라는 관점을 설명하는 것이 주 목적이다.
역할은 그 객체의 존재이유이며 책임은 그 역할이 어떤 책임들을 가지느냐로 정의된다고 나는 이해했다.
그리고 협력은 그 역할/책임들로 서로 어떻게 연결이 되느냐 하는 것이다.
이 책은 객체지향의 패러다임을 좀 더 이해하게 해주는 주옥같은 책이다.
사실 여러 언어를 사용해봤지만, 결국 문제는 사람이라는 걸 모르는 사람은 없을 것이다.
완벽한 제약을 걸지 않는 이상 우리는 결국 옳다고 생각하는 길보다는 쉬운 길을 택할 것이다.
블로그에 보면 하스켈을 공부하던 시기도 있었다.
하스켈을 공부하면서 느낀 점은 꽤나 많은 제약으로 인해 결국 하스켈이 원하는 개발방법을 따르려고 노력하지 않으면
개발을 할 수 없다는 것이다.
모나드를 이해하려고 노력하지 않으면 안되며, 함수지향적인 생각을 해야 한다.
스몰토크를 공부한 적은 없지만 아마 스몰토크도 그러할 것이다.
내가 개인적으로 좋아하는 리스프쪽 언어 또한 그 언어와 어울리는 개발방식이 있다. 그렇기에 그에 맞게 사람은 생각을 하게 된다.
하지만 우리가 생각하는 소위 많은 사람들이 사용하는 언어들(자바,파이썬,자바스크립트,C++,C#) 등은 사람들은 사로잡기 위해 모든 것들을 넣었다.
자바는 나의 작은 생각으로 객체지향언어라고 하기에는 정말 많은 부가기능들이 많다.
아마 모든 사람들의 니즈를 충족시키기 위해서 였을까?
그 깊은 뜻을 알지는 못한다. 아마 많은 사람들이 욕하면서도 쓰는 이유는 결국 어떻게든 개발을 하면 돌아가기 때문인 것 같다.
하지만 어떤 개발방식 예를 들어 객체지향/함수지향/TDD/RDD/DDD 등의 방식을 사용하려 한다면 자기자신을 제약하고 채찍질하여
통제해야 하지 않을까 싶은 생각이 이 책을 읽으면서 들었다. 물론 더더욱 공부해야 하는 것은 물론이고!
두고두고 읽으면서, 항상 기억을 하도록 해야겠다.
이 책은 위키북스의 조영호라는 분이 만든 책이다. 정말 감사하다는 말을 올려야 겠다. 새로운 책을 최근에 발행하셨다.
조만간 읽어야겠다.
2019년 6월 28일 금요일
[책리뷰] 함께 자라기
이 작은 책은 나를 겸손하게 만들었다.
함께 자라기는 무엇이 진국인가를 알려주는 것 같았다.
함께 만들어 간다는 것에 대해서 많은 생각을 하게 한다.
또한 가장 무서웠던 통계는 기술보다는 관리/협업이라는 것이다.
어떤 프로젝트가 끝나고 개발자를 대상으로 진행한 설문조사에서 가장 중요한 요소를 '관리', 하위권에 '툴'이 있다.
하지만 관리자들은 '관리'를 바꾸는 것이 아니라 대부분 '툴'을 바꾸려 한다. (여기서 '툴'을 바꾸는 관리자를 책에서는 간접적으로 무능하다고 말하는 듯하다)
맞는 말이다.
'관리'를 바꾼다는 것은 자기자신을 바꾸는 것인데, 그러면 지금까지 자신이 잘못한 것이 되는 거 아닌가(여기까지라도 생각하면 양반이겠지만)
하지만 '툴'을 바꾼다는 것은 자신의 등장으로 새로 접목한 '툴'이 되는 것이다.
이렇듯 나는 지금까지 개발에 가장 중요한 요소 '협업'을 꽤나 등한시 했다.
하지만 '협업'이란 함께 일하는 것인데, 거기에 어떤 스킬이 필요한 것인가.
'협업'에 관련된 책이 있지만, 연애를 책으로 배우는 것과 비슷한 것 아닐까?
하지만 이 책을 보면서 그것또한 나의 고정관념임을 알았다.
'협업'은 분명 다채로운 감성을 가진 개개인과의 관계이지만
동일한 목표를 향해 달려가는 프로젝트를 진행할 때, 그 '협업'이 매끄럽게 되도록 하는 마음가짐과 스킬이 있다.
어쩌만 가장 쉬워보이고 어려워보이는 과업이다.
영화 [킹덤오브헤븐] 마지막 씬에서 주인공이 '살라딘'에게 예수살렘이 당신에게 무엇을 의미하는가 라는 말에 대답이 갑자기 머리에 떠올라 적는다.
"Nothing... Everything"
아무것도 아니다... (그렇기에) 전부이다.
돈은 무언가를 살 수 있고, 얻을 수 있는 기준통화이기 때문에 원하는 것이다.
그에 비하면 종교로는 눈앞에 얻을 수 없다. 그걸 얻는다고 실제로 얻는 것은 없다. (얻는 것은 우리가 그렇게 믿기 때문에 얻는 것이다.)
그렇기에 종교는 인생의 전부가 될 수 있고, 돈은 전부가 될 수 없다.
나 자신을 바꾸는 것, 아무것도 아닐 수도 있지만, 그것으로 세상이 바뀔 수도 있겠다 라는 생각을 해본다.
함께 자라기는 무엇이 진국인가를 알려주는 것 같았다.
함께 만들어 간다는 것에 대해서 많은 생각을 하게 한다.
또한 가장 무서웠던 통계는 기술보다는 관리/협업이라는 것이다.
어떤 프로젝트가 끝나고 개발자를 대상으로 진행한 설문조사에서 가장 중요한 요소를 '관리', 하위권에 '툴'이 있다.
하지만 관리자들은 '관리'를 바꾸는 것이 아니라 대부분 '툴'을 바꾸려 한다. (여기서 '툴'을 바꾸는 관리자를 책에서는 간접적으로 무능하다고 말하는 듯하다)
맞는 말이다.
'관리'를 바꾼다는 것은 자기자신을 바꾸는 것인데, 그러면 지금까지 자신이 잘못한 것이 되는 거 아닌가(여기까지라도 생각하면 양반이겠지만)
하지만 '툴'을 바꾼다는 것은 자신의 등장으로 새로 접목한 '툴'이 되는 것이다.
이렇듯 나는 지금까지 개발에 가장 중요한 요소 '협업'을 꽤나 등한시 했다.
하지만 '협업'이란 함께 일하는 것인데, 거기에 어떤 스킬이 필요한 것인가.
'협업'에 관련된 책이 있지만, 연애를 책으로 배우는 것과 비슷한 것 아닐까?
하지만 이 책을 보면서 그것또한 나의 고정관념임을 알았다.
'협업'은 분명 다채로운 감성을 가진 개개인과의 관계이지만
동일한 목표를 향해 달려가는 프로젝트를 진행할 때, 그 '협업'이 매끄럽게 되도록 하는 마음가짐과 스킬이 있다.
어쩌만 가장 쉬워보이고 어려워보이는 과업이다.
영화 [킹덤오브헤븐] 마지막 씬에서 주인공이 '살라딘'에게 예수살렘이 당신에게 무엇을 의미하는가 라는 말에 대답이 갑자기 머리에 떠올라 적는다.
"Nothing... Everything"
아무것도 아니다... (그렇기에) 전부이다.
돈은 무언가를 살 수 있고, 얻을 수 있는 기준통화이기 때문에 원하는 것이다.
그에 비하면 종교로는 눈앞에 얻을 수 없다. 그걸 얻는다고 실제로 얻는 것은 없다. (얻는 것은 우리가 그렇게 믿기 때문에 얻는 것이다.)
그렇기에 종교는 인생의 전부가 될 수 있고, 돈은 전부가 될 수 없다.
나 자신을 바꾸는 것, 아무것도 아닐 수도 있지만, 그것으로 세상이 바뀔 수도 있겠다 라는 생각을 해본다.
2019년 6월 4일 화요일
[책리뷰] 자바 최적화 를 읽고
자바 최적화에 큰 관심이 있지는 않지만, 그 안이 어떤 형태로 움직이는 지는 관심이 많다.
예전에는 Unsafe클래스라던가, ASM이라던가 정말 주위 사람들이 쓸모없는 기술이라 자신하는 것들을 많이 탐했었다.
그것들을 잘 이해하지 못하면서 탐했던 이유는 역시나... 재미라는 것이다.
내가 하는 일이 무엇인지 제대로 알고 싶은 마음 때문이다.
이 책이 나의 그런 마음을 어느 정도는 정리되게 해준다.
모든 내용을 다 읽지는 못했지만, 이런 최적화 방법에 대한 이야기를 여타 다른 선임 개발자들에게 들어본 적도 없고 대부분 경시하는 내용이기 때문에.
이 책은 나의 배고픔에 적당한 배부름을 줄 거라고 생각한다.
이 책은 확실하게 알려준다. 무엇이 어떻게 돌아가는지, 어떻게 확인하는지, 이해가 안되는 것같으면 조용히 그림을 보여준다. 게다가 컬러로!
컬러 그림이 들어간 자바책이라니, 그건 입문서에나 있는 것이다.
꽤나 사람들에게 생소한 이야기를 좀 더 재미있는 놀이처럼 보이게 하려는 저자의 마음이 들어 있는게 아닐까 생각된다.
맞다 이것은 자바 최적화 입문서다. 그리고 최적화를 할 필요가 없더라도, 최적화를 하는 방법을 읽다보면, 내가 자바를 더 잘 이해하게 되는 것 같아진다.
그리고 꼭 이런 내용이 자바에만 국한될까. 자바와 비슷한 언어도 비슷한 방식으로 최적화 할 것이다. 혹은 JVM을 사용하는 언어도 비슷한 방식으로 돌아갈 것이다.
이 책을 구매하기 전에 꼭 알아야 할 점이 있다.
1. 떠먹여 주는 책은 아니다.
위 글에서 컬러그림 같은 것들이 있다고 아주 쉽게 설명되어 있다고 생각하면 안된다. 이 내용은 쉬운 내용이 아니다. 그리고 그것을 어린아이 가르치듯 설명해서는 안된다. 이 주제는 진지한 주제이며, 쉽게 흥얼흥얼 거리면서 읽을 수 있는 책의 성질을 가지고 있지 않다.
2. 자습서가 아니라 사전이다.
이 책은 1장을 읽고 2장을 읽고... 뭐 이런 순서가 있는 책이 아니다. 필요할 때 차례를 보고 나에게 필요해 보이는 몇 개를 메뉴처럼 선택해서 읽는 것이 가능하다. JVM이라는 주제는 JAVA라는 언어를 공부하는 것과 다른 것일까? 자바라는 언어를 배우듯이 만들어졌으면 더 좋았을 것 같다는 생각이 든다.
이 정도가 나의 사견이다. 누누히 말하지만 이 책은 떠먹여 주는 책이 아니다. 기어이 떠먹으려는 사람들을 위한 책이다.
이 책은 자바개발자에게 유용하다. 자바 개발자로서 삶의 여분의 시간이 있다면 이 책을 읽기 딱 좋은 시간일 것이다.
링크 : http://www.hanbit.co.kr/store/books/look.php?p_code=B7707787549
예전에는 Unsafe클래스라던가, ASM이라던가 정말 주위 사람들이 쓸모없는 기술이라 자신하는 것들을 많이 탐했었다.
그것들을 잘 이해하지 못하면서 탐했던 이유는 역시나... 재미라는 것이다.
내가 하는 일이 무엇인지 제대로 알고 싶은 마음 때문이다.
이 책이 나의 그런 마음을 어느 정도는 정리되게 해준다.
모든 내용을 다 읽지는 못했지만, 이런 최적화 방법에 대한 이야기를 여타 다른 선임 개발자들에게 들어본 적도 없고 대부분 경시하는 내용이기 때문에.
이 책은 나의 배고픔에 적당한 배부름을 줄 거라고 생각한다.
이 책은 확실하게 알려준다. 무엇이 어떻게 돌아가는지, 어떻게 확인하는지, 이해가 안되는 것같으면 조용히 그림을 보여준다. 게다가 컬러로!
컬러 그림이 들어간 자바책이라니, 그건 입문서에나 있는 것이다.
꽤나 사람들에게 생소한 이야기를 좀 더 재미있는 놀이처럼 보이게 하려는 저자의 마음이 들어 있는게 아닐까 생각된다.
맞다 이것은 자바 최적화 입문서다. 그리고 최적화를 할 필요가 없더라도, 최적화를 하는 방법을 읽다보면, 내가 자바를 더 잘 이해하게 되는 것 같아진다.
그리고 꼭 이런 내용이 자바에만 국한될까. 자바와 비슷한 언어도 비슷한 방식으로 최적화 할 것이다. 혹은 JVM을 사용하는 언어도 비슷한 방식으로 돌아갈 것이다.
이 책을 구매하기 전에 꼭 알아야 할 점이 있다.
1. 떠먹여 주는 책은 아니다.
위 글에서 컬러그림 같은 것들이 있다고 아주 쉽게 설명되어 있다고 생각하면 안된다. 이 내용은 쉬운 내용이 아니다. 그리고 그것을 어린아이 가르치듯 설명해서는 안된다. 이 주제는 진지한 주제이며, 쉽게 흥얼흥얼 거리면서 읽을 수 있는 책의 성질을 가지고 있지 않다.
2. 자습서가 아니라 사전이다.
이 책은 1장을 읽고 2장을 읽고... 뭐 이런 순서가 있는 책이 아니다. 필요할 때 차례를 보고 나에게 필요해 보이는 몇 개를 메뉴처럼 선택해서 읽는 것이 가능하다. JVM이라는 주제는 JAVA라는 언어를 공부하는 것과 다른 것일까? 자바라는 언어를 배우듯이 만들어졌으면 더 좋았을 것 같다는 생각이 든다.
이 정도가 나의 사견이다. 누누히 말하지만 이 책은 떠먹여 주는 책이 아니다. 기어이 떠먹으려는 사람들을 위한 책이다.
이 책은 자바개발자에게 유용하다. 자바 개발자로서 삶의 여분의 시간이 있다면 이 책을 읽기 딱 좋은 시간일 것이다.
링크 : http://www.hanbit.co.kr/store/books/look.php?p_code=B7707787549
2019년 5월 18일 토요일
[책리뷰][켄트벡 전작주의] 켄트벡의 구현패턴
켄트벡은 수 많은 개발을 해오면서, 그것들을 패턴화 시켰다.
그 패턴들은 본능적으로 해오던 것이 아니라, 오랜시간동안 만든 패턴들을 모은 것이다.
그러니까 아무렇게나 짜고보니 패턴이었네?
이런게 아니라 고심끝에 만들어낸 패턴이라는 것이다.
하지만 이 책은 크게 추천하고 싶지는 않다.
1. 읽기가 쉽지 않다.
정말 많은 번역책을 읽었다. 책은 내용이 어려워서 읽기 힘든 경우도 있지만, 번역이 이상하여 읽기 힘든 경우가 있다.
GoF의 디자인패턴을 한 번 보자. 읽기가 쉽지는 않다. 하지만 두어번 읽어보면 GoF는 간결하게 필요한 글을 써놔서 그 글에 적응하면 읽기가 수월해진다. 하지만 이 책은 두서 없이 써나간 책이다. 패턴이라는 말을 붙이고 클래스, 메소드 뭐 이런식으로 내용들을 나눠놨지만 메소드끼리 엮여있다고 그 안에 내용들이 같은 것으로 관통하는 것이 아니다.
겉모습만으로 챕터를 나눠놨기 때문에, 중간을 넘어간 후에 책을 덮고 자세히 생각해보면, 앞 장에서 클래스에서 이야기 했던 패턴과 관통하는 것을 알 수도 있다. 그러므로 내용은 반복되고(반복이라니!) 이 반복과 저 반복이 무슨 차이인지 헷갈린다.
2. 이 책은 패턴을 익히기 위한 책이 아닌 것 같다.
말했다시피, 행동패턴, 구조패턴, 생성패턴 뭐 이렇게 만든것이 아니라. 어떤 상황이 왔을 때 어떻게 할까? 라는 문제를 이야기 한다. 이 상황들은 꽤나 정형적이지 않고, 아주 특별한 경우들이다. 이 경우들이 상상은 가지만 와닿지 않는다. "켄트벡은 정말 많은 프로젝트를 했구나..."라는 생각을 했다. 하지만 이 켄트벡이 제안하는 패턴방식은 어떤 특별한 원칙이 있지 않다. 이 내용은 밑에서 설명할 것인데, 그는 지속적으로 특별한 경우를 만들고, 이것이 어떻게 어려운지를 말하고, 왜 이렇게 밖에 코딩을 할 수 없는지 설명한다. 이런 화법을 쓰면 "어쩔 수 없이 저렇게만 써야 하는건가" 라는 생각이 들게 한다. 그리고 그는 실용성을 많이 따지면서 타인이 읽는 것을 생각하며 코딩하라고 한다. 그는 미학보다는 일을 제대로 끝내는 것에 관심이 있는 것 같다. (이것은 이전 2권을 읽으면서도 느꼈던 것이다. 그래서 더 관심이 갔다.) 하지만 본 책에서 그는 가끔씩 미학을 강조한다. 미학를 추구하는 것이 얼마나 중요한지를 말한다. 그리고 그것이 실효성과는 관련이 없다는 것도 시인한다.
그런면에서 "켄트벡 또한 사람이구나" 싶었다. (아름다움을 추구하는 것은 당연한 것이라고 어떤 철학자가 말했던가)
3. 이 책에서 원칙은 간결성, 객체지향 같은 것이 아니라 켄트벡이 남을 생각하는 마음에 가깝다.
그러므로 켄트벡의 지극한 사견이다. 이 패턴들은 그가 고민했던 내용들은 적어놓고 그것들을 모아놓은 것이다.
사실 그는 말을 번복하는 것처럼 보이지만, 번복하는 것이 아니라 상황마다 다르다는 것을 보여주려고 한 것일 것이다.
그것은 꽤나 미세한 차이로 보일 때도 있다. 전혀 다른 상황처럼 보이는 것들을 자세히 비교하면 결국 어떤 상태를 밖으로 보이게 할 것이냐,
아니면 타입을 어떻게 확인 할 것이냐 하는 것임을 알게 된다. 거기에 어떤 환경을 제시하고, 어떻게 한다.
기존에 켄트벡 저의 2권을 읽인 후, 이 책을 기대했지만 기대에는 좀 아쉬웠다.
이전 책과는 달리... 마치 하루키의 잡문집 같았다.
하지만 그러기에 켄트벡의 마음을 조금이나마 알 수 있었고,
객체지향/함수지향 그런 것보다는 자신/당신/우리를 생각하려는 마음의 중요성을 느꼈다.
사실 개발자는 모두 그런것들을 어렴풋이나마 알고 있었을 것이다.
아니면 큰 의미 없이 그렇게 주장해왔을 것이다.
하지만 그는 아무 생각없이 주장하지 않는다.
그의 구현패턴이 그 증거이다.
그 패턴들은 본능적으로 해오던 것이 아니라, 오랜시간동안 만든 패턴들을 모은 것이다.
그러니까 아무렇게나 짜고보니 패턴이었네?
이런게 아니라 고심끝에 만들어낸 패턴이라는 것이다.
하지만 이 책은 크게 추천하고 싶지는 않다.
1. 읽기가 쉽지 않다.
정말 많은 번역책을 읽었다. 책은 내용이 어려워서 읽기 힘든 경우도 있지만, 번역이 이상하여 읽기 힘든 경우가 있다.
GoF의 디자인패턴을 한 번 보자. 읽기가 쉽지는 않다. 하지만 두어번 읽어보면 GoF는 간결하게 필요한 글을 써놔서 그 글에 적응하면 읽기가 수월해진다. 하지만 이 책은 두서 없이 써나간 책이다. 패턴이라는 말을 붙이고 클래스, 메소드 뭐 이런식으로 내용들을 나눠놨지만 메소드끼리 엮여있다고 그 안에 내용들이 같은 것으로 관통하는 것이 아니다.
겉모습만으로 챕터를 나눠놨기 때문에, 중간을 넘어간 후에 책을 덮고 자세히 생각해보면, 앞 장에서 클래스에서 이야기 했던 패턴과 관통하는 것을 알 수도 있다. 그러므로 내용은 반복되고(반복이라니!) 이 반복과 저 반복이 무슨 차이인지 헷갈린다.
2. 이 책은 패턴을 익히기 위한 책이 아닌 것 같다.
말했다시피, 행동패턴, 구조패턴, 생성패턴 뭐 이렇게 만든것이 아니라. 어떤 상황이 왔을 때 어떻게 할까? 라는 문제를 이야기 한다. 이 상황들은 꽤나 정형적이지 않고, 아주 특별한 경우들이다. 이 경우들이 상상은 가지만 와닿지 않는다. "켄트벡은 정말 많은 프로젝트를 했구나..."라는 생각을 했다. 하지만 이 켄트벡이 제안하는 패턴방식은 어떤 특별한 원칙이 있지 않다. 이 내용은 밑에서 설명할 것인데, 그는 지속적으로 특별한 경우를 만들고, 이것이 어떻게 어려운지를 말하고, 왜 이렇게 밖에 코딩을 할 수 없는지 설명한다. 이런 화법을 쓰면 "어쩔 수 없이 저렇게만 써야 하는건가" 라는 생각이 들게 한다. 그리고 그는 실용성을 많이 따지면서 타인이 읽는 것을 생각하며 코딩하라고 한다. 그는 미학보다는 일을 제대로 끝내는 것에 관심이 있는 것 같다. (이것은 이전 2권을 읽으면서도 느꼈던 것이다. 그래서 더 관심이 갔다.) 하지만 본 책에서 그는 가끔씩 미학을 강조한다. 미학를 추구하는 것이 얼마나 중요한지를 말한다. 그리고 그것이 실효성과는 관련이 없다는 것도 시인한다.
그런면에서 "켄트벡 또한 사람이구나" 싶었다. (아름다움을 추구하는 것은 당연한 것이라고 어떤 철학자가 말했던가)
3. 이 책에서 원칙은 간결성, 객체지향 같은 것이 아니라 켄트벡이 남을 생각하는 마음에 가깝다.
그러므로 켄트벡의 지극한 사견이다. 이 패턴들은 그가 고민했던 내용들은 적어놓고 그것들을 모아놓은 것이다.
사실 그는 말을 번복하는 것처럼 보이지만, 번복하는 것이 아니라 상황마다 다르다는 것을 보여주려고 한 것일 것이다.
그것은 꽤나 미세한 차이로 보일 때도 있다. 전혀 다른 상황처럼 보이는 것들을 자세히 비교하면 결국 어떤 상태를 밖으로 보이게 할 것이냐,
아니면 타입을 어떻게 확인 할 것이냐 하는 것임을 알게 된다. 거기에 어떤 환경을 제시하고, 어떻게 한다.
기존에 켄트벡 저의 2권을 읽인 후, 이 책을 기대했지만 기대에는 좀 아쉬웠다.
이전 책과는 달리... 마치 하루키의 잡문집 같았다.
하지만 그러기에 켄트벡의 마음을 조금이나마 알 수 있었고,
객체지향/함수지향 그런 것보다는 자신/당신/우리를 생각하려는 마음의 중요성을 느꼈다.
사실 개발자는 모두 그런것들을 어렴풋이나마 알고 있었을 것이다.
아니면 큰 의미 없이 그렇게 주장해왔을 것이다.
하지만 그는 아무 생각없이 주장하지 않는다.
그의 구현패턴이 그 증거이다.
2019년 5월 15일 수요일
[책리뷰][켄트벡 전작주의] 테스트 주도 개발
켄트벡이라는 사람의 책의 번역본을 전부 읽어보려고 한다.
이 형은 코드와 설계 그 사이의 간극을 메우기 위해 어떤 행동을 취해야 하는지 알려준다.
그 중에 하나가 익스트림 프로그래밍에서 보여준 반복이다.
돌아가는 작은 것을 만들고, 함께 만들고, 바꾸고, 더 크기를 키우고, 더 복잡하게 하고, 완성한다.
이것의 그가 가진 중요 통찰인 것 같다.
나는 그의 생각을 더 제대로 알기 위해 다른 책을 빌렸다. 바로 [테스트 주도 개발]이다.
이 책은 크게 3가지 파트로 나뉜다.
1. 여러 통화를 가진 Money객체와 그 안에 비즈니스 로직 만들기.
2. TDD 툴을 만들기
3. 테스트 주도 개발을 위한 팁
이렇게 3가지로 나뉜다.
여기서 가장 중요한 진수는 파트 1에 있다고 생각한다.
마치 파트 2는 툴이 없는 사람을 위해 툴을 만들도록 도와주는 것 같았고
파트 3은 여러가지 상황에 따른 대처방법이나 철학을 말한다.
하지만 나에게 필요한 것은 켄트벡이 개발을 하면서 어떤 생각을 하는 지다.
그는 요구사항을 할 일에 적고(이게 중요하다고 생각한다)
일단 테스트로 만든다. (컴파일 에러가 나도 상관없다. 나의 상상 속에서 이것을 어떻게 호출할 지 생각하고 테스트로 일단 적어 보는 것이다. 아무 생각없이 클래스 부터 생성하고 보면 나의 상상과는 다른 설계가 될 수 있을 테니까)
그 테스트를 통과하기 위해 (요행을 써서라도) 빠르게 통과를 시키고
실제 요구사항에 맞게 개발을 하고
리팩토링 할 것을 할일에 적는다.(바로 리팩토링을 하기도 하지만 꼭 할 일에 적는다.)
그리고 한가지 Task를 끝내면 할일에서 줄을 긋는다.
숙련이 된다면 아주 작은 일들을 한꺼번에 처리해도 된다고 켄트벡은 말한다. (한칸 올라갔던 내가 나중에는 두 세 칸씩 올라가는 나를 보면 흐믓할지도 모르겠다.)
파트 1의 내용은 처음부터 마지막 까지 TDD를 이용한 Money객체가 어떻게 변해가는지에 대한 이야기다.
처음 만든 설계와는 전혀 다른 아이가 되어 있다.
상속을 사용해서 만든 Dollar/Franc객체가 사라지는 순간이나 (상속 또한 사라진다)
여러 환율을 서로 더하기 위해 만들어진 Bank/Expression/Sum 객체가 만들어지는 순간은 정말 인상적이다.
TDD에서 특이한 점은 리팩토링을 아주 편하게 할 수 있다는 점이다. 나는 기존의 요구사항보다는 무엇이 바뀌었는지를 신경쓸 수 있다.
그리고 실수를 해도 바로 테스트에서 실패하니 그곳을 확인하면 되는 것이다.
그는 테스트를 통해서 나 뿐만이 아니라 당신 또한 편안해지기를 바란다.
나 뿐만 아니라 팀이 코드를 믿고 쓰기를 바란다.
게다가 그는 겸손하다. 그는 좋은 코드만으로는 성공을 보장하지 못한다는 것을 강조한다. 하지만 나쁜 코드는 성공을 할 수 없게 만든다는 것 또한 잊지 않게 한다.
켄트벡이라는 사람은 성실하고, 실수를 하지 않으려고 고민하는 사람이며 게다가 실행하는 사람이다(테스트가 성공할 때까지 코딩을 하는 사람이다)
켄트벡이라는 사람의 다음 책 또한 기대된다.
아래는 TDD 켄트벡의 책을 이용한 전체 소스이다. (Test 코드 제외)
https://github.com/ssisksl77/java-demo/tree/master/src/main/java/kentbeck/tdd
이 형은 코드와 설계 그 사이의 간극을 메우기 위해 어떤 행동을 취해야 하는지 알려준다.
그 중에 하나가 익스트림 프로그래밍에서 보여준 반복이다.
돌아가는 작은 것을 만들고, 함께 만들고, 바꾸고, 더 크기를 키우고, 더 복잡하게 하고, 완성한다.
이것의 그가 가진 중요 통찰인 것 같다.
나는 그의 생각을 더 제대로 알기 위해 다른 책을 빌렸다. 바로 [테스트 주도 개발]이다.
이 책은 크게 3가지 파트로 나뉜다.
1. 여러 통화를 가진 Money객체와 그 안에 비즈니스 로직 만들기.
2. TDD 툴을 만들기
3. 테스트 주도 개발을 위한 팁
이렇게 3가지로 나뉜다.
여기서 가장 중요한 진수는 파트 1에 있다고 생각한다.
마치 파트 2는 툴이 없는 사람을 위해 툴을 만들도록 도와주는 것 같았고
파트 3은 여러가지 상황에 따른 대처방법이나 철학을 말한다.
하지만 나에게 필요한 것은 켄트벡이 개발을 하면서 어떤 생각을 하는 지다.
그는 요구사항을 할 일에 적고(이게 중요하다고 생각한다)
일단 테스트로 만든다. (컴파일 에러가 나도 상관없다. 나의 상상 속에서 이것을 어떻게 호출할 지 생각하고 테스트로 일단 적어 보는 것이다. 아무 생각없이 클래스 부터 생성하고 보면 나의 상상과는 다른 설계가 될 수 있을 테니까)
그 테스트를 통과하기 위해 (요행을 써서라도) 빠르게 통과를 시키고
실제 요구사항에 맞게 개발을 하고
리팩토링 할 것을 할일에 적는다.(바로 리팩토링을 하기도 하지만 꼭 할 일에 적는다.)
그리고 한가지 Task를 끝내면 할일에서 줄을 긋는다.
숙련이 된다면 아주 작은 일들을 한꺼번에 처리해도 된다고 켄트벡은 말한다. (한칸 올라갔던 내가 나중에는 두 세 칸씩 올라가는 나를 보면 흐믓할지도 모르겠다.)
파트 1의 내용은 처음부터 마지막 까지 TDD를 이용한 Money객체가 어떻게 변해가는지에 대한 이야기다.
처음 만든 설계와는 전혀 다른 아이가 되어 있다.
상속을 사용해서 만든 Dollar/Franc객체가 사라지는 순간이나 (상속 또한 사라진다)
여러 환율을 서로 더하기 위해 만들어진 Bank/Expression/Sum 객체가 만들어지는 순간은 정말 인상적이다.
TDD에서 특이한 점은 리팩토링을 아주 편하게 할 수 있다는 점이다. 나는 기존의 요구사항보다는 무엇이 바뀌었는지를 신경쓸 수 있다.
그리고 실수를 해도 바로 테스트에서 실패하니 그곳을 확인하면 되는 것이다.
그는 테스트를 통해서 나 뿐만이 아니라 당신 또한 편안해지기를 바란다.
나 뿐만 아니라 팀이 코드를 믿고 쓰기를 바란다.
게다가 그는 겸손하다. 그는 좋은 코드만으로는 성공을 보장하지 못한다는 것을 강조한다. 하지만 나쁜 코드는 성공을 할 수 없게 만든다는 것 또한 잊지 않게 한다.
켄트벡이라는 사람은 성실하고, 실수를 하지 않으려고 고민하는 사람이며 게다가 실행하는 사람이다(테스트가 성공할 때까지 코딩을 하는 사람이다)
켄트벡이라는 사람의 다음 책 또한 기대된다.
아래는 TDD 켄트벡의 책을 이용한 전체 소스이다. (Test 코드 제외)
https://github.com/ssisksl77/java-demo/tree/master/src/main/java/kentbeck/tdd
2019년 5월 12일 일요일
[책리뷰][켄트벡 전작주의] 익스트림 프로그래밍
최근 Object Thinking 이라는 책을 한 반정도 읽다가 포기했다. 수 많은 메타포들과 마치 어학영수시절 글쓰기 시절의 글처럼 한 문장을 지나갈 때마다 의미가 동일해도 무슨 토플 시험 보듯, 단어가 계속 바뀌고 바뀌다 보니 점점 읽어가는 속도가 느려졌다. 그러면서 포기를 하게 되었다. 나중에 읽어야지...
하지만 읽으면서 느꼈던 것이 객체지향 프로그래밍은 애자일/익스트림 프로그래밍이 태어날 때, 함께 자라난 개념이라는 것이었다. 객체지향 시뮬라에서 파생된 C++와 스몰토크에서 스몰토크는 시뮬라의 디자인을 따라가려 했으며, C++는 디자인을 따라가기에는 너무 속도가 느리다고 판단, 시뮬라의 디자인을 완벽하게 구현하지는 않았다고 한다.(Object Thinking 참고)
그후로 계속 익스트림 프로그래밍과 애자일에 대해서 이야기를 한다. 자바,객체지향 책을 읽어서는 객체지향의 진수를 알 수 없고, 겉에 보여지는 것만 알게 될 것이라고 그는 말한다. 그러니까 우리는 겉모습만 따라하고 실재로 무엇이 중요한지 모른다는 말 같다.
마치, 짝프로그래밍을 한다고는 하지만, 정확이 이것으로 무엇을 성취하는지는 모르는... 그런 것일까나?
그리고 자주 언급되는 사람들이 있었다. 나는 Object thinking이라는 책을 덮고 일단 그 사람들에 대해서 그리고 그 언어들에 대해서 공부를 해볼까 한다.
일단 나는 켄트벡 아저씨에 대해 알아보려고 한다. 그는 책을 정말 많이 썼다. 게다가 이분 책을 읽어 본 적이 있다. 바로 [익스트림 프로그래밍] 이다.
처음 개발을 시작할 때, 읽었던 책이다. 그 당시 중간 정도 읽다가 대체 무엇이 중요한 거지? 라는 생각과 기억에 남은 거라곤, 도요타 공장라인에 대한 이야기 뿐이었다. 문제가 생기는 것을 보면 줄을 잡아당겨 모든 생산라인을 정지시키고 모두 함께 문제를 해결하는 것. 그리고 필요한 만큼만 준비하고 생산하는 효율이라는 마인드. 그것뿐이었다.
나는 이전에 봤던 그 책을 한번 다시 보기로 했다.
요즘은 도서관에 갈 필요도 없이 나랑 멀리있는 도서관도 내 집 근처 역으로 배송을 해준다.
나는 익스트림 프로그래밍 책을 빌렸다.
그리고 다시 읽으면서 아... 그때 아무생각 없이 읽었던 내용들이 이런 것들이었구나... 하는 것을 느겼다.
그래도 아마 나는 제대로 이해한 것이 아닐 것이다. 정말로 해보기 전까진 모를 것이다. 정말 닥치기 전까지 자신이 어떤 행동을 할지 모르듯이...
하지만 정말 멋진 방법같다.
====
계속 하나의 프로그램을 작게 쪼개면서 개발을 하는데, 차라리 쪼갠 부분이 하나의 프로그램이라면, 어떨까.
그렇다면 그것을 하나의 프로그램으로 보고 테스트해보고 확인하고 개선하고 또 새로운 프로그램이 탄생하고.
그런 주기를 계속 이어간다는 것.
===
그럼으로 몇주일 단위로 배포되던 것들이, 일주일 단위로 그리고 하루 단위로 배포가 되면서 눈 앞에 살아있는 생명처럼 보이기 시작한다면,
우리는 무엇을 만드는지 알 수 있고, 무엇을 개선해야 하는지 빠르게 알 수 있을 것이다.
정말 이런 개발이 가능할까.
정말 이런 문화가 가능한 것일까.
이런 문화를 한번쯤은 겪어보고 싶은 생각이 있다.
켄트벡 아저씨의 책을 더 읽어보고 싶다. 도서관에서 구할 수 없는 책들은 구매도 하고 싶다. 하지만 지금 집에 쌓인게 책들이라... 책을 구매하는 것은 집에 있는 책들을 다 치우고 생각해봐야겠다.
이 책은 개발자만을 위한 책은 아닌 것 같다. 무언가 계획을 관리함에 있어, 익스트림 프로그래밍의 철학과 맞닿는 분야라면 가능하다고 생각한다.
특히 요구사항이 생명체처럼 변하는 세상의 부름처럼 자연스레 바뀌어야 하는 상화이라면 익스트림 프로그래밍이라는 책 읽어볼만 하다고 생각한다.
하지만 읽으면서 느꼈던 것이 객체지향 프로그래밍은 애자일/익스트림 프로그래밍이 태어날 때, 함께 자라난 개념이라는 것이었다. 객체지향 시뮬라에서 파생된 C++와 스몰토크에서 스몰토크는 시뮬라의 디자인을 따라가려 했으며, C++는 디자인을 따라가기에는 너무 속도가 느리다고 판단, 시뮬라의 디자인을 완벽하게 구현하지는 않았다고 한다.(Object Thinking 참고)
그후로 계속 익스트림 프로그래밍과 애자일에 대해서 이야기를 한다. 자바,객체지향 책을 읽어서는 객체지향의 진수를 알 수 없고, 겉에 보여지는 것만 알게 될 것이라고 그는 말한다. 그러니까 우리는 겉모습만 따라하고 실재로 무엇이 중요한지 모른다는 말 같다.
마치, 짝프로그래밍을 한다고는 하지만, 정확이 이것으로 무엇을 성취하는지는 모르는... 그런 것일까나?
그리고 자주 언급되는 사람들이 있었다. 나는 Object thinking이라는 책을 덮고 일단 그 사람들에 대해서 그리고 그 언어들에 대해서 공부를 해볼까 한다.
일단 나는 켄트벡 아저씨에 대해 알아보려고 한다. 그는 책을 정말 많이 썼다. 게다가 이분 책을 읽어 본 적이 있다. 바로 [익스트림 프로그래밍] 이다.
처음 개발을 시작할 때, 읽었던 책이다. 그 당시 중간 정도 읽다가 대체 무엇이 중요한 거지? 라는 생각과 기억에 남은 거라곤, 도요타 공장라인에 대한 이야기 뿐이었다. 문제가 생기는 것을 보면 줄을 잡아당겨 모든 생산라인을 정지시키고 모두 함께 문제를 해결하는 것. 그리고 필요한 만큼만 준비하고 생산하는 효율이라는 마인드. 그것뿐이었다.
나는 이전에 봤던 그 책을 한번 다시 보기로 했다.
요즘은 도서관에 갈 필요도 없이 나랑 멀리있는 도서관도 내 집 근처 역으로 배송을 해준다.
나는 익스트림 프로그래밍 책을 빌렸다.
그리고 다시 읽으면서 아... 그때 아무생각 없이 읽었던 내용들이 이런 것들이었구나... 하는 것을 느겼다.
그래도 아마 나는 제대로 이해한 것이 아닐 것이다. 정말로 해보기 전까진 모를 것이다. 정말 닥치기 전까지 자신이 어떤 행동을 할지 모르듯이...
하지만 정말 멋진 방법같다.
====
계속 하나의 프로그램을 작게 쪼개면서 개발을 하는데, 차라리 쪼갠 부분이 하나의 프로그램이라면, 어떨까.
그렇다면 그것을 하나의 프로그램으로 보고 테스트해보고 확인하고 개선하고 또 새로운 프로그램이 탄생하고.
그런 주기를 계속 이어간다는 것.
===
그럼으로 몇주일 단위로 배포되던 것들이, 일주일 단위로 그리고 하루 단위로 배포가 되면서 눈 앞에 살아있는 생명처럼 보이기 시작한다면,
우리는 무엇을 만드는지 알 수 있고, 무엇을 개선해야 하는지 빠르게 알 수 있을 것이다.
정말 이런 개발이 가능할까.
정말 이런 문화가 가능한 것일까.
이런 문화를 한번쯤은 겪어보고 싶은 생각이 있다.
켄트벡 아저씨의 책을 더 읽어보고 싶다. 도서관에서 구할 수 없는 책들은 구매도 하고 싶다. 하지만 지금 집에 쌓인게 책들이라... 책을 구매하는 것은 집에 있는 책들을 다 치우고 생각해봐야겠다.
이 책은 개발자만을 위한 책은 아닌 것 같다. 무언가 계획을 관리함에 있어, 익스트림 프로그래밍의 철학과 맞닿는 분야라면 가능하다고 생각한다.
특히 요구사항이 생명체처럼 변하는 세상의 부름처럼 자연스레 바뀌어야 하는 상화이라면 익스트림 프로그래밍이라는 책 읽어볼만 하다고 생각한다.
2019년 4월 26일 금요일
[리뷰][scheme] Programming and Meta-Programming in Scheme 을 읽고
https://www.amazon.com/Programming-Meta-Programming-Undergraduate-Computer-Science/dp/1461272432
이 책은 얼떨결에 읽게 되었다.
Scheme 관련 책을 골라보려고 샘플을 받았는데 페이지를 넘기다가 얼떨결에 구매해 버린것이다!
게다가 만원 2만원도 아닌 60달러 이상이 되는 책이었다.
Scheme에 대해 꽤나 자세하게 되어있고, SICP에서 설명하는 강의의 내용과 꽤나 비슷한 내용들이 많았다.
SICP를 읽기 위한 전과정이라 생각해도 될 것 같다는 생각을 했다.
일단 Scheme책이기 때문에 Scheme에 대한 깊은 내용이 나올 때도 있다. 관심이 없지만 아마 다른 Lisp들도 비슷한 컨셉으로 만들어져있지 않을까 하는 마음이 들어서 계속 읽었다.
매크로에 대한 내용은 생각보다 많이 나오진 않았다.
오히려 개발에 대한 일반철학을 설명할 때가 좋았다. 아마 그런 걸 더 느끼고 싶어서 SICP를 읽어보려는 걸지도 모르겠다.
아쉬운 점은 해당 사이트를 찾아보려고 했는데 잘 작동하는 것 같지 않았다.
http://www.cs.sjsu.edu/faculty/pearce/scheme/index.html
읽으면서 가장 기억에 남는 것은 heap을 구현해보는 것이었다.
아직도 좀 난해한데 나중에 시간 나면 그 부분만 다시 따라쳐보면서 이해해볼까 한다.
글로는 대충 느낌이 오는데 소스코드가 난해하다.
그래서 타입체크 하는 부분을 좀 줄이고 한가지 타입만 저장가능하도록 줄여서 구조를 이해해볼까 한다.
다음은 How to Design Program을 도서관에서 빌려 볼까 한다.
이 책은 얼떨결에 읽게 되었다.
Scheme 관련 책을 골라보려고 샘플을 받았는데 페이지를 넘기다가 얼떨결에 구매해 버린것이다!
게다가 만원 2만원도 아닌 60달러 이상이 되는 책이었다.
Scheme에 대해 꽤나 자세하게 되어있고, SICP에서 설명하는 강의의 내용과 꽤나 비슷한 내용들이 많았다.
SICP를 읽기 위한 전과정이라 생각해도 될 것 같다는 생각을 했다.
일단 Scheme책이기 때문에 Scheme에 대한 깊은 내용이 나올 때도 있다. 관심이 없지만 아마 다른 Lisp들도 비슷한 컨셉으로 만들어져있지 않을까 하는 마음이 들어서 계속 읽었다.
매크로에 대한 내용은 생각보다 많이 나오진 않았다.
오히려 개발에 대한 일반철학을 설명할 때가 좋았다. 아마 그런 걸 더 느끼고 싶어서 SICP를 읽어보려는 걸지도 모르겠다.
아쉬운 점은 해당 사이트를 찾아보려고 했는데 잘 작동하는 것 같지 않았다.
http://www.cs.sjsu.edu/faculty/pearce/scheme/index.html
읽으면서 가장 기억에 남는 것은 heap을 구현해보는 것이었다.
아직도 좀 난해한데 나중에 시간 나면 그 부분만 다시 따라쳐보면서 이해해볼까 한다.
글로는 대충 느낌이 오는데 소스코드가 난해하다.
그래서 타입체크 하는 부분을 좀 줄이고 한가지 타입만 저장가능하도록 줄여서 구조를 이해해볼까 한다.
다음은 How to Design Program을 도서관에서 빌려 볼까 한다.
2019년 4월 18일 목요일
[SICP][scheme][javascript] 아무것도 없는 것에서 무언가를 추상화할 수 있을까?
출처 : https://youtu.be/ymsbTVLbyN4
SICP의 강의는 손이 잘 가지 않는 영상이다.
난 항상 SICP를 읽어보려고 하지만 일주일이 지나면 역시나 다른책을 꺼내 읽고 있다. 이 못난 학생은 그럼에도 황새를 쫓아가보겠다고 공부를 하다. 그러다 나는 아래의 코드를 보게 되었다.
이 코드가 대체 무엇이길래 그러는가. 난 이 코드에서 모든 추상화가 시작되진 않았을까 상상해본다.
데이터 추상화란 무엇인가.
1. "부를 수 있게 된다"는 것이다. (그것은 이름업슨 데이터에 이름을 부여함으로써 시작된다. 하여 머릿속으로도 다룰 수 있게 된다.) 2. 그것은 마치 마술사가 주문에 이름을 부여하는 것처럼 마법과 같다.
3. 우리는 이 개념의 정확한 정의를 나중에 내릴 수 있게 된다. (일단 이름을 부름으로써 나중에 해당 개념에 대한 정의가 바뀌면 그 정의만 바꾸면 되는 것이다.)
4. (추가적인 특징) 우리는 이 추상화된 데이터를 강제할 수 있다.
우리는 일단 데이터를 추상화 해야 한다.
분자 n, 분모 d가 있다.
이것들을 make-rat에 넣어서 하나의 패키지를 생성하는 것이다.
하나의 데이터는 이렇게 constructor와 selector로 추상화될 수 있다.
이렇게 유리수를 make-rat, numer, denom으로 추상화 하였다.
한번 더하기를 해보자.
곱하기도 만들자.
그러니 rational-number란 무엇인가?
이것은 사실 pair일 뿐이다. 첫번째와 두번째라는 박스가 있는 자료구조일 뿐이다.
그렇다면 pair라는 것은 무엇인가? 이것도 또한 두개의 값이 쌍으로 있는 추상적인 개념이다.
쌍의 개념은 cons라는 constructor와 car, cdr이라는 selector로 표현할 수 있다.
여기서 car는 첫번째 값을 말하며, cdr는 두번째 값을 지칭한다.
여기서 저자는 아무것도 없는 곳에서 생성된다고 한다.
쌩뚱맞게 lambda가 보인다. cons는 일단 procedure를 다시 리턴한다.
그리고 pick이라는 변수를 받는데 그것이 1이면 a를 리턴하고, 2이면 b를 리턴하는 함수를 리턴한다.
car를 보자. (x 1)라는 함수가 있는데, 여기서 1이 매개변수 pick에 매핑될 것이다. 첫번째 값(즉 a)이 리턴
cdr에서는 (x 2)로써, pick=2가 되고 두번째 값(b)가 리턴된다.
대체 어디에 a,b는 어떤 자료구조로 저장되는 건가? 아무것도 아닌 것에 저장되는 느낌이다.
closure를 이해한다고 생각했는데 이 코드를 보자마자 '이해한다는 것이 무엇인지조차 모르고 있었구나' 라는 생각이 들었다.
공부를 하면 할 수록, 항상 겸손해야 한다는 생각을 할 수 밖에 없다.
겸손하지 않으면, 배울 수가 없으니...
강의 교수님이 한 말씀을 여기 기록하지 않을 수가 없다.
강의가 끝나고 한 지적인 학생이 엄청난 질문은 하는데 그것은 바로
(cons 1 2)의 값과 1초 후 동일한 프로시저호출인(cons 1 2)는 동일한 녀석인가? 이다.
이 말은 (+ 2 2)와 4는 동일한 녀석인가?
를 고민하는 문장인데, 한시간의 수업에서 대체 이런 질문이 어떻게 나올 수 있었을까? 라는 생각이 든다.
이 질문에 대해 교수님은 당장은 대답할 수 없지만, 곧 하게 될 것이라는 말을 하며 끝낸다.
언제 저 답을 알 수 있을까? 빨리 다음을 알고 싶다.
여담으로 아래 scheme코드를 js로 변경해보자.
SICP의 강의는 손이 잘 가지 않는 영상이다.
난 항상 SICP를 읽어보려고 하지만 일주일이 지나면 역시나 다른책을 꺼내 읽고 있다. 이 못난 학생은 그럼에도 황새를 쫓아가보겠다고 공부를 하다. 그러다 나는 아래의 코드를 보게 되었다.
(define (cons a b) (lambda (pick) (cond ((= pick 1) a) ((= pick 2) b)))) (define (car x) (x 1)) (define (cdr x) (x 2)) ;; 설명을 위해 더해진 것. (define A (cons 1 2)) (print (car A)) (print (cdr A))이 비디오를 보는 사람들 중 몇몇은 이미 이 내용을 설명할 때, 경악을 금치 못했다.
이 코드가 대체 무엇이길래 그러는가. 난 이 코드에서 모든 추상화가 시작되진 않았을까 상상해본다.
데이터 추상화란 무엇인가.
1. "부를 수 있게 된다"는 것이다. (그것은 이름업슨 데이터에 이름을 부여함으로써 시작된다. 하여 머릿속으로도 다룰 수 있게 된다.) 2. 그것은 마치 마술사가 주문에 이름을 부여하는 것처럼 마법과 같다.
3. 우리는 이 개념의 정확한 정의를 나중에 내릴 수 있게 된다. (일단 이름을 부름으로써 나중에 해당 개념에 대한 정의가 바뀌면 그 정의만 바꾸면 되는 것이다.)
4. (추가적인 특징) 우리는 이 추상화된 데이터를 강제할 수 있다.
rational number
이 책에서 설명하는 rational number에 대해 알아보자.우리는 일단 데이터를 추상화 해야 한다.
분자 n, 분모 d가 있다.
이것들을 make-rat에 넣어서 하나의 패키지를 생성하는 것이다.
(make-rat n d) ; rational-number (n,d의 저장형태는 알 필요없음) (numer rational-number) ; numerator 분자 (denom rational-number) ; denominator 분모여기서 make-rat는 constructor, numer/denom은 selector라고 불린다.
하나의 데이터는 이렇게 constructor와 selector로 추상화될 수 있다.
이렇게 유리수를 make-rat, numer, denom으로 추상화 하였다.
한번 더하기를 해보자.
(define (+rat x y) (make-rat (+ (* (numer x) (denom y)) (* (numer y) (denom x))) (* (denom x) (denom y))))여기서 x,y는 rational-number이다. 우리는 x,y가 어떻게 구현되어 있는지는 모르지만, make-rat으로 유리수를 만들 수 있고, numer/denom으로 꺼낼 수 있는 것은 알고 있다.
곱하기도 만들자.
(define (*rat x y) (make-rat) (* (number x) (number y)) (* (denom x) (denom y)))자 이제 유리수를 구현해보자. 어떻게 담아야 할까?
(define (make-rat n d) (cons n d)) (define (numer x ) (car x)) (define (denom x) (cdr x))이렇게 cons를 이용하여 pair(리스트)를 만든다.
그러니 rational-number란 무엇인가?
이것은 사실 pair일 뿐이다. 첫번째와 두번째라는 박스가 있는 자료구조일 뿐이다.
그렇다면 pair라는 것은 무엇인가? 이것도 또한 두개의 값이 쌍으로 있는 추상적인 개념이다.
쌍의 개념은 cons라는 constructor와 car, cdr이라는 selector로 표현할 수 있다.
여기서 car는 첫번째 값을 말하며, cdr는 두번째 값을 지칭한다.
아무것도 없는 곳에서 추상화하기
그렇다면 pair라는 추상적인 개념은 무엇을 기반으로 만들어진 개념일까?(무엇 위에서 쌓여 올라왔는가)여기서 저자는 아무것도 없는 곳에서 생성된다고 한다.
(define (cons a b) (lambda (pick) (cond ((= pick 1) a) ((= pick 2) b)))) (define (car x) (x 1)) (define (cdr x) (x 2))여기에 데이터가 보이는가? 어떤 자료구조가 보이는가?
쌩뚱맞게 lambda가 보인다. cons는 일단 procedure를 다시 리턴한다.
그리고 pick이라는 변수를 받는데 그것이 1이면 a를 리턴하고, 2이면 b를 리턴하는 함수를 리턴한다.
car를 보자. (x 1)라는 함수가 있는데, 여기서 1이 매개변수 pick에 매핑될 것이다. 첫번째 값(즉 a)이 리턴
cdr에서는 (x 2)로써, pick=2가 되고 두번째 값(b)가 리턴된다.
대체 어디에 a,b는 어떤 자료구조로 저장되는 건가? 아무것도 아닌 것에 저장되는 느낌이다.
closure를 이해한다고 생각했는데 이 코드를 보자마자 '이해한다는 것이 무엇인지조차 모르고 있었구나' 라는 생각이 들었다.
공부를 하면 할 수록, 항상 겸손해야 한다는 생각을 할 수 밖에 없다.
겸손하지 않으면, 배울 수가 없으니...
강의 교수님이 한 말씀을 여기 기록하지 않을 수가 없다.
So in some sense, we don't need data at all to build these data abstractions.
We can do everything in terms of procedures.
procedures are not just the act of doing something.
procedures are conceptual entities, objects.
강의가 끝나고 한 지적인 학생이 엄청난 질문은 하는데 그것은 바로
(cons 1 2)의 값과 1초 후 동일한 프로시저호출인(cons 1 2)는 동일한 녀석인가? 이다.
이 말은 (+ 2 2)와 4는 동일한 녀석인가?
를 고민하는 문장인데, 한시간의 수업에서 대체 이런 질문이 어떻게 나올 수 있었을까? 라는 생각이 든다.
이 질문에 대해 교수님은 당장은 대답할 수 없지만, 곧 하게 될 것이라는 말을 하며 끝낸다.
언제 저 답을 알 수 있을까? 빨리 다음을 알고 싶다.
여담으로 아래 scheme코드를 js로 변경해보자.
function cons (a , b) { return function(pick) { switch(pick) { case 1 : return a; case 2 : return b; default: return; } } } function car(x) { return x(1); } function cdr(x) { return x(2); } var procedure = cons(10,20); car(procedure); cdr(procedure);
2019년 3월 20일 수요일
[리뷰][Coursera] 코세라의 [Concurrent Programming in Java] 수강을 마치며
Coursera에서 수강할 수 있는 Concurrent Programming의 수강을 마쳤다.
이번에는 lock와 readwritelock에 대해 배웠으며, Actor의 개념도 살짝 나왔다.
실제로 Actor를 제대로 구현해서 사용하는 것은 아니지만 개념정도 알고 어떻게 사용되는
지만 알아도 Actor가 좀 더 친근해진 느낌이다.
이번에는 lock와 readwritelock에 대해 배웠으며, Actor의 개념도 살짝 나왔다.
실제로 Actor를 제대로 구현해서 사용하는 것은 아니지만 개념정도 알고 어떻게 사용되는
지만 알아도 Actor가 좀 더 친근해진 느낌이다.
조금 어려운 내용이 나오기도 했지만 프로젝트 자체는 어렵지 않고, 친절하게 프로젝트 자체를 설명해주기 때문에, 잘 넘길 수 있었다. 내 생각에 이 코스에서 중요한 부분은 프로젝트 어사인먼트가 아니라 QUIZ인 것 같다.
개념을 잘 이해해야 하는 경우가 있으며, 내가 어떤 부분을 헷갈려 하는지 알 수 있기 때문에 같은 부분을 계속 듣고 확인하게 만들어 준다.
괜찮은 강의였으나, 좀 더 설명이 길었으면 하는 아쉬움이 있다.
2019년 3월 5일 화요일
[javascript] 그래서 커리를 어떻게 쓰려고?
내가 처음 커리를 써야겠다고 생각했던 것은 로직이 계속 겹치고 있었기 때문이다.
예를들어보자. 인풋별로 유효성을 체크하는데 유효성을 체크할 때마다 하는일이 조금씩 다르다.
curry라는 함수 한번 가지고 놀아봤다.
예를들어보자. 인풋별로 유효성을 체크하는데 유효성을 체크할 때마다 하는일이 조금씩 다르다.
// 핸드폰 인풋 묶음 3개 유효성검사 var phone_1 = trim($("#phone_1").val()); var phone_2 = trim($("#phone_2").val()); var phone_3 = trim($("#phone_3").val()); if (phone_1 < 3 && phone_1 ...) { // 여러 and문과 유효성검사 $("#phone_1").focus(); alert("휴대폰 유효성검사실패"); return; } ... phone_2, phone_3 $("#hidden_phone_").val(phone_1 + "-" phone_2 + "-" + phone_3);이런 코드가 있다. 익숙하다. 일단 커리를 쓰기 전에 여기서 if문에 있는 모든 유효성검사는 하나의 함수로 추상화 해놓자.
if (validate(phone_1) { // 여러 and문과 유효성검사 $("#phone_1").focus(); alert("휴대폰 유효성검사실패"); return; } if (validate(phone_2) { $("#phone_2").focus(); alert("휴대폰 유효성검사실패"); return; } if (validate(phone_3) { $("#phone_3").focus(); alert("휴대폰 유효성검사실패"); return; }이런 코드를 본 적 없는가? 여기서 분명 우리는 뭔가 더 할 수 있을 것 같다. 어떻게 해야 할까? 맞다 객체를 넘기는 것이다.
function validateAndFocus(phone, $phone) { if (!validatePhone(phone) { alert("휴대폰 유효성검사 실패"); $phone.focus(); return false; } return true; }이제 이걸 사용해보자
if(!validateAndFocus(phone_1, $("#phone_1")) { return; } if(!validateAndFocus(phone_2, $("#phone_2")) { return; } if(!validateAndFocus(phone_3, $("#phone_3")) { return; } ...뭔가 여기도 겹치는 것 같다.
if (!(validateAndFocus(phone_1, $("#phone_1")) && validateAndFocus(phone_2, $("#phone_2")) && validateAndFocus(phone_3, $("#phone_3"))) { return; }undersocre.js의 and가 있다면 더 좋을 것 같다. 끝이 없을 것 같으니 여기서 넘어가자. underscore를 쓸 수 없어서 curry만 임시 사용하는 것이다. 이정도만 깔끔해보인다. 그런데 여기 주민번호와 카드번드까지 추가되었다.
var card1 = $("#card1"); var card2 = $("#card2"); var card3 = $("#card3"); var card4 = $("#card4"); var national_id_1 = $("#national_id"); var national_id_2 = $("#national_id");우리는 validateAndFocus를 사용할 수 있는가? 사용할 수 없다. 1. 휴대폰번호의 유효성과 아이디의 유효성은 다르다. (predicate의 분리 필요) 2. 유효성 검사 이후 하는 일이 각각 다를 것이다. 하지만 형태는 동일하다. 1. 주어진 값의 유효성을 검사한다. 2. 통과하면 true 실패하면 false를 리턴한다. 3. 유효성검사에 실패하여 false를 리턴하기 전에 각각 해야하는 일이 있다.
// 동일한 형태의 일을 하는 함수 템플릿 정의 function validateTemplate(pred, func, obj1, obj2, obj3) { if (pred(obj1, obj2, obj3)) { func(obj1, obj2, obj3); return false; } return true; }자 이 형태를 만들었다. 이제 어떻게 사용할지 보자. 유효성 검사를 분리해서 넣을 것이다. 그렇다면 이렇게 될 것이다.
var curried = curry(validateTemplate); var validatePhoneCurried = curried(function(n) { return validatePhone(n); }); var validateCardCurried = curreid(function(n) { return validatePhone(n); }); var validateNationalidCurreid = curried(function(n) { return validateNationalid(n); });뭐 대충 이렇게 코딩했다. 현재까지는 pred를 커리하고 이제는 각 pred마다 할일을 다르게 넣을 수 있겠다. 첫번째 인자를 _로 한 이유는 focus나 val("") 등 DOM조작을 위한 객체를 따로 넘긴다고 하자.
var validatePhoneFinal = validatePhoneCurried(function(_, $dom) { alert("헨드폰문제!"); $dom.focus(); }); var validateCardFinal = validateCardCurried(function(_, $dom) { alert("카드문제"); $dom.focus(); }); var validateNationalidFinal = validateNationalidCurreid (function(_, $dom) { alert("주민번호문제"); $dom.focus(); });이렇게 만들었다 치자. 이제 위에 코드를 저것들로 바꾸면 된다.
if (!(validatePhoneFinal(phone_1, $("#phone_1")) && validatePhoneFinal(phone_2, $("#phone_2")) && validatePhoneFinal(phone_3, $("#phone_3"))) { return; } .... if (!(validateCardFinal(card_1, $("#card_1")) && validateCardFinal(card_2, $("#card_2")) && validateCardFinal(card_3, $("#card_3")) && validateCardFinal(card_4, $("#card_4"))) { return; } ... if (!(validateNationalidFinal(national_id_1 , $("#national_id_1")) && validateNationalidFinal(national_id_2 , $("#national_id_2"))) { return; }여기서 map이나 every 같은 것을 이용하는 것이 큰 도움이 될 것 같지만 그러진 않겠다. 오늘의 주제는 커리니까.
curry라는 함수 한번 가지고 놀아봤다.
[javascript]자바스크립트 curry 구현소스를 파악해보자.
출처 :
https://edykim.com/ko/post/writing-a-curling-currying-function-in-javascript/
https://medium.com/@kevincennis/currying-in-javascript-c66080543528
커링이라는 개념은 하스켈을 공부할 당시 알게 되었다.
clojure의 partial과 비슷한 개념이다. (동일한가?)
여튼 자바스크립트로 curry를 쓰고 싶은 욕구가 강했지만, underscore.js같은 라이브러리를 사용할 수 없는 제약이 있어,
다른 누군가가 어떻게 curry만을 구현했는지 확인하고 복붙을 하기로 하였다.
그 중에 위의 링크를 확인했고 하나하나 파고들어갔다. 아래 내용은 위 블로그를 읽고 나만의 부연설명을 추가한 것이다.
한번 생성한 커리에 함수를 넣어보자. 지금 함수를 넣으면 인자 fn에 들어가는 것이다.
====
이제 아래 코드를 보면서 어떻게 되는지 보자.
함수를 리턴받아서 curried에 넣었다. 여기에 다른 인자들을 넣어보자.
일단 2를 넣을 것인데 l, w, h 총 3개가 필요한 함수에게는 부족한 인자 갯수이다.
어떤 일이 일어나는지 아래를 보자.
한번 더
이제 마지막으로 하나의 인자만 더 넣으면 실행될 것이다.
왜 그렇게 되는지 아래를 보자.
https://edykim.com/ko/post/writing-a-curling-currying-function-in-javascript/
https://medium.com/@kevincennis/currying-in-javascript-c66080543528
커링이라는 개념은 하스켈을 공부할 당시 알게 되었다.
clojure의 partial과 비슷한 개념이다. (동일한가?)
여튼 자바스크립트로 curry를 쓰고 싶은 욕구가 강했지만, underscore.js같은 라이브러리를 사용할 수 없는 제약이 있어,
다른 누군가가 어떻게 curry만을 구현했는지 확인하고 복붙을 하기로 하였다.
그 중에 위의 링크를 확인했고 하나하나 파고들어갔다. 아래 내용은 위 블로그를 읽고 나만의 부연설명을 추가한 것이다.
function curry(fn) { var arity = fn.length; // 함수의 필요 인자 // 매번 curry된 함수를 호출할 때마다 새로운 인자를 배열에 넣어 클로저 내에 저장한다. // 배열의 길이는 fn.length와 동일해야 한다. (실행될 때) // 혹여 인자의 수가 동일하지 않으면 새로운 함수로 반환한다. // 인자 목록을 가지는 클로저가 필요하다 (함수로 둘러쌓아야 한다 // 또 여기서 개별의 클로저가 생성되야 하니까 즉시 실행함수로 만든다.) // 전체인자(배열)과 fn.length를 확인 // 인자의 수가 부족하면 부분적으로 적용된 함수를 반환 // 인자의 수가 충족하면 fn에 모든 인자를 적용,호출하여 리턴 return (function resolver() { // 지금까지 받은 인자를 복사한다. // 이전 클로저가 오염되지 말게 var memory = Array.prototype.slice.call(arguments); // resolver는 익명함수를 반환한다. // resolver는 인자가 부족할 때 반환한다. // resolver가 새로 반환되는 이유는 클로저를 위한 것같다. // resolver는 바로 실행되고 익명함수를 하나 리턴한다. // resolver가 이전까지 모은 인자를 가지고 있다. (memory) // 이걸 변수에 담았다가 나중에 실행시킬 것이다. // 실행시키면 arguments에서 인자를 memory와 합체한다. // 그리고 원래 실행되어야할 함수(fn)이 필요로 하는 인자의 갯수와 비교 // 지금까지 모은 인자(local)과 arity의 길이가 맞다면 // 원래함수를 호출(fn), 그렇지 않으면 resolver를 다시 반환 (인자를 더 받는다) return function() { var local = memory.slice(); Array.prototype.push.apply(local, arguments); next = local.length >= arity ? fn : resolver; return next.apply(null, local); }; }()); }
한번 생성한 커리에 함수를 넣어보자. 지금 함수를 넣으면 인자 fn에 들어가는 것이다.
====
function volume(l, w, h) { return l * w * h; } var curried = curry(volume);
이제 아래 코드를 보면서 어떻게 되는지 보자.
function curry(fn) { var arity = fn.length; // 1. 숫자 3이 저장된다. return (function resolver() { var memory = Array.prototype.slice.call(arguments); // 2. resolver를 인자없이 실행하였다.(현재는 커리만 되는 상태) return function() { var local = memory.slice(); Array.prototype.push.apply(local, arguments); next = local.length >= arity ? fn : resolver; // 3. arity가 부족하므로 함수를 리턴. return next.apply(null, local); }; }()); }
함수를 리턴받아서 curried에 넣었다. 여기에 다른 인자들을 넣어보자.
일단 2를 넣을 것인데 l, w, h 총 3개가 필요한 함수에게는 부족한 인자 갯수이다.
var length = curried(2);
어떤 일이 일어나는지 아래를 보자.
function curry(fn) { var arity = fn.length; return (function resolver() { var memory = Array.prototype.slice.call(arguments); return function() { // 1. resolver로 반환된 익명함수가 실행됨. var local = memory.slice(); // 2. memory는 현재 0개의 인자를 가지고 있다. Array.prototype.push.apply(local, arguments); // 3.이번에 추가된 2가 local에 push된다. next = local.length >= arity ? fn : resolver; // 4.아직 인자가 1개이기 때문에 다시 resolver를 반환한다. return next.apply(null, local); // 4. 알다시피 이번에 던져지는 resolver는 또한 새로운 클로저와 함께하는 새로운 함수다. }; }()); }
한번 더
var lengthAndWidth = length( 3 );
function curry(fn) { var arity = fn.length; return (function resolver() { var memory = Array.prototype.slice.call(arguments); return function() { var local = memory.slice(); // 1. 새로운 클로저에 들어있는 memory는 [2] 이다. local에 복사한다. (이전 클로저에 해를 끼치지 않게) Array.prototype.push.apply(local, arguments); // 2. 새로운 인자 3을 추가한다. [2,3] next = local.length >= arity ? fn : resolver; // 3.아직 인자가 2개이기 때문에 다시 resolver를 반환한다. return next.apply(null, local); // 4. 알다시피 이번에 던져지는 resolver는 또한 새로운 클로저와 함께하는 새로운 함수다. }; }()); }
이제 마지막으로 하나의 인자만 더 넣으면 실행될 것이다.
console.log( lengthAndWidth( 4 ) ); // 24
왜 그렇게 되는지 아래를 보자.
function curry(fn) { var arity = fn.length; return (function resolver() { var memory = Array.prototype.slice.call(arguments); return function() { var local = memory.slice(); // 1. 새로운 클로저에 들어있는 memory는 [2,3] 이다. local에 복사한다. (이전 클로저에 해를 끼치지 않게) Array.prototype.push.apply(local, arguments); // 2. 새로운 인자 4을 추가한다. [2,3,4] next = local.length >= arity ? fn : resolver; // 3.아직 인자가 3개이기 때문에 fn을 넣는다. (fn은 지금까지 변경된 적도 사용된 적도 있다. 하지만 이날을 위해 기다렸다) return next.apply(null, local); // 4. 이번에는 함수를 던지지 않고 fn의 리턴값이 실행될 것이다. (하지만 fn이 리턴하는게 함수라면... 음...) }; }()); }
2019년 2월 15일 금요일
[clojure] 4clojure easy버전 0에서 50까지 문제 풀고 중간점검
clojure로 뭘 할지 감이 잡히지 않아서, 그냥 4clojure나 가끔씩 풀어보기로 했다.
elementary, easy부분만 풀었는데 괜찮았다. 글자그대로 쉬웠지만 어떤 것들은 꽤나 생각을 해야 했다.
4clojure를 풀다보면 내 뇌의 생각하는 방식이 바뀌어야 한다는 느낌이 든다. 운동을 할 때도 가동범위가 중요한데, 사용하지 않던 뇌부분을 사용한 느낌이 들면서, 나의 뇌 가동범위가 부족한 것이 아닌가 싶었다.
clojure로 언젠가 개발을 하지 않더라도, 이 문제를 풀면서 뭔가 개발을 할 때 생각하는 방식이 늘어나는 느낌을 받을 것 같다. (좀더 난이도가 올라가면 말이다)
결과적으로 4clojure를 풀기로 결심한 것은 만족이다.
https://github.com/ssisksl77/clj-web-demo/blob/master/src/web_demo/4clojure/elementary.clj
51~100도 금방 가자.
elementary, easy부분만 풀었는데 괜찮았다. 글자그대로 쉬웠지만 어떤 것들은 꽤나 생각을 해야 했다.
4clojure를 풀다보면 내 뇌의 생각하는 방식이 바뀌어야 한다는 느낌이 든다. 운동을 할 때도 가동범위가 중요한데, 사용하지 않던 뇌부분을 사용한 느낌이 들면서, 나의 뇌 가동범위가 부족한 것이 아닌가 싶었다.
clojure로 언젠가 개발을 하지 않더라도, 이 문제를 풀면서 뭔가 개발을 할 때 생각하는 방식이 늘어나는 느낌을 받을 것 같다. (좀더 난이도가 올라가면 말이다)
결과적으로 4clojure를 풀기로 결심한 것은 만족이다.
https://github.com/ssisksl77/clj-web-demo/blob/master/src/web_demo/4clojure/elementary.clj
51~100도 금방 가자.
피드 구독하기:
글 (Atom)