2021년 2월 27일 토요일

clojure로 카프카에 이벤트 발행

의존성


[org.apache.kafka/kafka-clients "2.5.0"]

사용코드


(ns kafka-demo2.core
  (:import [org.apache.kafka.common.serialization StringSerializer]
           [org.apache.kafka.clients.producer KafkaProducer ProducerRecord])
  (:gen-class))

(def config
  {"bootstrap.servers" "127.0.0.1:9092"
   "key.serializer" StringSerializer
   "value.serializer" StringSerializer})

(defn publish [topic str]
  (let [producer (KafkaProducer. config)
        record (ProducerRecord. topic str)]
    (try
      (.send producer record)
      (finally (.close producer)))))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (println "push A")
  (publish "yhnam-topic" "A"))

도커

https://github.com/ssisksl77/clojure-breadcrumb 위 깃허브 참고

실행

별거 없음 위 깃허브 참고

$ docker-compose up
$ lein uberjar
$ java -jar kafka-demo2-0.1.0-standalone.jar

그외 정리

https://www.notion.so/tombox/db6bc836f25d41948d28f3aff9ec1aff

2021년 2월 21일 일요일

[책리뷰] (빅 데이터 세상으로 떠나는 간결한 안내서) NoSQL

 이 책은 NoSQL의 개요를 담고있다.

NoSQL의 전체적인 추세가 그때와 지금은 다르지 않은 것 같다.

NoSQL이 어떤 종류가 있으며, 기존 문제들을 어떻게 풀려고 하는지 간결하게 설명한다.

흥미로운 책이었다. MongoDB를 아무생각없이 쓰고 있었는데 조만간 DB 관련된 책을 봐야겠다는 생각을 한다.

MySQL도 아무생각없이 썼던게 아닌가 싶다. 공부해야겠다.


서적 링크 : http://www.yes24.com/Product/Goods/8510944

2021년 2월 18일 목요일

Monad 정리

내가 이해하는 모나드에 대한 생각을 잠깐 정리해보려고 한다

1. Monoid
2. Functor
3. Applicative Functor
4. Monad

이 순서를 알아야 한다.

1. Monoid

모노이드는 아주 단순하다. 
 - 항등원을 가진다
 - 결합법칙
 - 이항연산

이 셋이 뭔지 모른다면 덧셈을 예로 들겠다. 덧셈은 Monoid다.
1. 항등원을 가진다. (0은 항등원이다)
2. 결합법칙을 가진다 (1 + (2 + 3)) == ((1 + 2) + 3)
3. 이항연산 (덧셈은 두개의 항이 필요하다)

모노이드는 함수형 프로그래밍에서 꽤나 중요한 역할을 한다. 
바로 병렬로 fold(fold가 뭔가 모른다면 reduce라고 생각하면 됨)를 할 수 있다는 것이다. 
순서가 필요없이 이항연산이 가능하기 때문에, 왼쪽부터 덧셈을 하거나, 오른쪽부터 덧셈을 하거나, 식을 반으로 쪼개서 각자 계산후에 머지를 하더라도 값이 동일하다는 것을 의미한다.

그러므로 모노이드는 꽤나 중요하다.
모노이드면 일단 '이항연산을 안전하게 할 수 있구나' 라는 생각을 하면 된다.


2. Functor

a Functor is a mapping between categories.
두 가지의 카테고리 사이를 이어주는(map) 사상을 말하는 것 같다. (사실 영어는 잘 모르겠다)

하스켈에서 functor는 `fmap` 을 구현한 녀석을 말한다.
`fmap`이란 뭘까?
이건 List 에서 map을 사용하는 것을 생각하면 쉽다.
List에서 map을 사용하면 어떻게 될까? 값이 변경되어도 그것이 List라는 것은 변함이 없다. 즉, Functor는 map이다 라고 생각하는 것이 좀 더 이해하기 쉬울 것 같다.

하스켈 Functor의 fmap의 구조는 아래와 같다. 

class Functor f where
    fmap :: (a -> b) -> f a -> f b
    (<$) :: a -> f b -> f a

3. Applicative Functor

중요한 리소스가 있다.

하스켈에서 Functor와 Applicative Functor의 타입차이를 한번 봐보자.
(<$>) :: Functor f => (a -> b) -> f a -> f b 

(<*>) :: Applicative f => f (a -> b) -> f a -> f b

그러니까 functor는 (a -> b) 이고 Applicative functor는 f (a -> b) 임을 보자.
결국 f (a -> b)에서 이 앞에 붙은 f가 무엇이냐는 것이다. 즉. Applicative Functor는 Functor 안에 함수도 들어갈 수 있는 경우를 말한다.

만약에 즉, 위에서 예를 들었던 List안에 [+1, +2] 이런식의 리스트가 존재하여, 합칠 수도 있다.
즉, 이런 타입 안에 함수를 넣을 수 있고, 이 함수는 그 타입에서 가지는 컨텍스트가 적용된다.
(여기서 컨텍스트란 그 타입 안에 내포되어 있는 의미를 말한다. 예를 들어 List는 여러개를 가진다를 말할 수도 있을 것 같다)

4. Monad

모나드는 좀 특이한데, 내 생각에 이것은 좀 필요에 의해서 만들어진 것 같다.
최근에 회사 내에서 스칼라 빨간책 스터디를 하면서 monad에 대한 이야기를 했다.

일반적으로 monad에 대한 가장 간단한 설명은 `flatMap`을 말한다고 할 수 있다. 그런데 flatMap이 왜 중요할까? 


class Applicative m => Monad m where
    (>>=) :: m a -> (a -> m b) -> m b
    (>>) :: m a -> m b -> m b
    return :: a -> m a

여기서 중요한 것은 >>= 이다

m a -> (a -> m b) -> m b 이 형태를 보면 flatMap임을 알 수 있다. (이것이 이상하다고 생각된다면, 자바나 다른 언어에서 map과 flatMap의 차이를 보면 좋을 것 같다)

flatMap이 왜 map이랑 그렇게 다른 것일까?
왜 

-- fmap or map (Functor)
(a -> b) -> f a -> f b 
-- flatMap (Monad)
m a -> (a -> m b) -> m b

이 둘이 뭐가 그렇게 다른 것일까?
아주 조금 다르지만 아주 크게 다르다. 여기서 중요한 것은 
(a -> m b) 이다. 이것이 아주 큰 일을 한다. 
일단 Monad는 Functor랑 아주 큰 차이는 Type을 생성하는데 주도권이 서로 다르다는 것이다.
당신은 List [1,2,3,4] 에 더하기 1을 하는 함수를 호출했다고 해보자.

var a = [1,2,3]

function addOne(x) {
 return x + 1;
}

a.map(addOne); // [2,3,4]

여기서 당신은 이런걸 원할 수도 있다.
리스트를 두배로 만드는 거다! 
var a = [1,2,3]

function double(x) { return [x,x] }

var b = a.map(double); // [[2,2],[3,3],[4,4]]
b.map(double); // [[[2,2],[2,2]],[[3,3],[3,3]],[[4,4],[4,4]]]
이래가지고, 함수를 함성할 수 있을까?
누군가는 이렇게 말할 수 있다. 애초에 왜! 리스트를 리턴하는 함수를 만든거야? 그냥 그 타입에 맞는 것만 리턴하지?! 

말은 쉽지만 그렇지 않다. List를 다루는 곳에는 List를 리턴하는 함수를 많이 사용할 수 밖에 없다. 
만약에 리턴하는 것이 IO라면? 그리고 IO를 리턴하는 객체가 계속 겹친다면? 제대로 작동할 수 없다.
자바의 Optional도 마찬가지이다. Optional을 실행했는데 안에 Optional이 있다면 어떻게 할 것인가? 재귀로 호출할 것인가?

이런 함수의 합성에서 예기치 않은 타입의 덮어씌움이 있기에 우리는 flatMap을 쓴다. 여기서 한가지 뇌피셜을 더해서 설명하면
monad는 두 개의 타입을 어떻게 concat을 하냐가 관건이다.
즉 파이썬의 키워드를 빌려서 직관적으로 설명을 시도해보겠다.
[1,2,3] ++ [4,5,6] # [1,2,3,4,5,6]
List를 concat한다면 이렇게 될 것이다. 만약에 다른 타입들에도 이 concat이라는 개념을 녹일 수 있다면(concat을 해서 두 타입 합치는 방식을 약속한다면)
flatMap안에 해당 타입에 어울리는 구현으로 만들어서 flatMap을 만들면 타입을 겹겹이 쌓이지 않을 수 있다. 그때그때 concat으로 합치면 되니까 말이다. 
우리가 concat이라는 개념을 생각해보는 것이 중요하다. concat은 1번에서 지칭한 Monoid와 같다. (왼쪽부터 수행하건, 오른쪽부터 수행하건 결과값은 동일해야 한다.)

이상 여기까지가 내가 이해한 Monad의 정리다.
모나딕 뭐 이런 말은 안쓰려고 노력했다. (사실 용어에 대해서 완벽하게 알지 못하면 안쓰는게 나을 것 같아서 쓰지 않았다)

사실 더 디테일한 내용들이 있다. 특히 모나드의 경우 위에 설명한 타입만 맞으면 되는 것은 아니고, 몇가지 조건을 만족해야만 한다.

2021년 2월 11일 목요일

2020년을 생각하며...

2020년이 갔고 2021년이 왔다.

아주 바쁘게 보냈지만, 그렇기에 너무 조용하고, 기억에 남는 것이 없는 한 해를 보낸 것 같다.

피로사회에서 바쁜 삶은 사람을 피로하게 하고 깊은 생각을 못하게 하고 자신을 되돌아볼 시간을 제한하게 한다고 주장한다. 그는 쉬는 시간에 게임을 하거나 여행을 가는 것 같이 `무언가를 하는 방식`으로는 근본적인 해결이 아니라고 한다. 

나는 그럼에도 되돌아 보려고 한다. 
내가 이번 해에서 무엇을 보았고, 무엇을 느꼈는지.

작년 초를 생각하면 나는 삶의 무료함을 느끼고 있었다.
다들 나와 같지 않은 마음, 안정감있는 삶. 아니 도태되어 가고 있는 삶에 행복감을 누리는 사람들과 몇년을 함께 지내면서 나 자신도 그렇게 변해가는 것에 환멸을 느꼈다.

나는 서울로 상경했으며, 현재 하고 있는 일도 정도를 걸어서 온 길이 아니다. 대학의 전공을 따르지 않고, 선택한 길이기에 나에게는 한계가 명확함을 인지하고 있었다. 누군가는 4년을 준비하고 좋은 회사를 거쳐가겠지만, 나는 작은 회사에서 2400이라는 숫자를 지니고 시작했다.

적은 숫자가 아닐까 라고 생각했지만 당시 나는 서울 고시원에 살고 있었다. 그것도 내창으로 (내창은 창문이 복도에 있는 것을 말한다. 나는 햇빛을 볼 수 없는 방에 살았다) 버는 돈이 없었기에, 나는 2400이라는 숫자를 받으면서 너무 행복했다. 

나도 사회의 일원이 되었구나
2400 
이것이 나에게 주어진 숫자구나

나는 현재 4,5년차가 되었고 회사는 3번을 이직했다. 마치 서울에 내리는 소나기처럼. 어디 한 곳에 뿌리내려 꽃을 피우는 것이 아니라, 하수구로 내려가 이리저리 더러운 것들을 닦고 묻혀서 결국에는 서울에서 밀려나지는 않을까 걱정한다.

이것은 나의 언더독 성향이 더 이런 경향을 강하게 만든다. 
개발을 하면서 Lisp에 빠져버렸을 때, 나의 커리어패스가 뒤틀어질 것을 예언했다.
개발학원에서 SICP마법사책을 읽고, Scheme을 공부하면서, 이걸로 취직을 하겠다고 학원을 수료하지 않고 뛰쳐나왔을 때. 
전혀 Scheme이나 Racket을 쓰는 회사를 찾을 수 없었을 때의 그 어둠은 창문이 없는 고시원에 사는 것보다 더 무서웠다.

결국 Spring을 여차여차 공부해보고 취직을 하고, 공부를 다시하고, 일을 하고 버텼던 것 같다.
수학을 공부하고, 함수형 프로그래밍을 공부하지만 
내 마음 속에는 Lisp가 항상 있다.

음식 평론가 황교익은 한 때 최고의 음식은 자장면이라고 뽑았다.
어렸을 때, 가난한 시절 부모님과 함께 먹었던 자장면을 기억하며,
최고의 음식은 맛만으로 평가할 수 없다는 그의 말처럼

나에게 Lisp는 그 시절 나의 악몽같던 시절에 
희망과 절망을 동시에 준 도구였다.

다시 돌아와서

나는 컬리라는 회사로 이직했다.
처음으로 사람들이 이름을 아는 회사.
사장님의 이름을 연예인처럼 많은 사람들이 기억하고 있는 회사.
부모님이 이름을 안다는 것에 괜히 기분이 좋았다.
그리고 무엇보다 변화를 두려워하기보다 변하지 못하는 것을 두려워 하는 사람들을 만난다는 것은
나에게 신선했고, 내 자신을 움츠려들게 했다.

왜냐하면
결국 가만히 있어도, 그들과 함께 있으면 변하기 때문일지도 모른다.
난 오히려 내가 어떻게 변하는지 소극적으로 바라만 봐야했다.

그동안 나는 해내는 것에 집중했었다.
해야할 것을 바로알고 어떻게 해야 할지, 정말 그들이 잘 쓸 수 있을지를 고민했다.
2400이라는 숫자로 일을 시작했을 때부터
나는 항상 감사했다. 이 감사함은 유저들에게 보답해야 한다고 나는 생각했다.

컬리에서 일하면서 새로운 경험을 하게 되었다.
무엇을 만들어야 한다고 하지만,
그것이 무엇인지 너무 추상적이기에 또 그걸을 알 수 없기에
우리는 개발하기보다는 대화를 하는 사람이 된 것 같다.
신기한 경험이었다. 
해야할 일이 있지만 할 수 없는 답답함.

코드 리팩토링, 좋은 코드는 세상을 바꿀까?
컬리에서 일을 하면서 이 말은 좋은 질문이 아니라는 생각을 하게 되었다. 
이 말은 그렇기도 하고 그렇지 않기도 하다.
모든 세상은 단순한 말로 표현할 수 없다.

각자의 서비스를 만들기 위해
각자의 팀이 가지는 프로젝트를 마치 자신의 사업처럼 사랑하면서 작업을 해야하며,
서로 함께 만들기 위해
회의하고 언성이 높아지고 
회의하고 언성이 낮아지고
회의하고 적막이 흐르고

반복에 반복을 하다보면
개발자는 코드를 만드는 사람이 아니라
꿈을 꾸는 사람들이며
무엇을 만드는지 상상하는 사람들이구나...
라는 생각을 했다.

개념적으로만 존재하던 개념들의 점점 실체화되고 구조과 완성이 되가는 그 시점부터
좋은 코드, 리팩토링에 대한 지식과 경험이 있으신 분들과 함께라면
상상한 구조를 만들어내는 데에는 마치 뻥 뚤린 고속도로가 펼쳐진 것처럼
정신없이 나아간다.

무엇을 만들지도 모르는 곳에 떨어져서
무엇을 어떻게 만들지 고민하는 순간의 고통을 느낄 때
나는 새로운 세상에 들어왔음을 느꼈다.

2021년에는 
더 겸손해지고
더 열심히 공부해야겠다.