아이디어 구현하기

난 만들어보면 재미있을 것 같은 아이템 목록을 적어둔다. 이 아이디어들은 혼자서 심심할 때 혹은 해커톤에 나갈 때 하나씩 구현된다. 바쁘다는 핑계로 목록 개수만 늘이고 있었는데 요새 시간이 많아져서 몇 가지 만들어보기로 했다. 좀 정상적인 아이템들은 해커톤 나가서 다른 사람들과 같이 만들어 볼 수 있기 때문에, 그렇지 않은 걸로만 몇 개 골랐다.

Dynamic Dictation

https://vichyssoise.io/dynamic-dictation/

음성과 음량을 글자로 바꿔준다. SpeechRecognition APIAudio API를 적절히 섞어서 목소리의 음량과 표시되는 글자의 크기가 비례하도록 했다.

Uncertainty

https://github.com/vichyssoise/uncertainty

측정될 때 값이 정해지는 데이터 타입. 현재 양자역학의 주류인 코펜하겐 해석에 의하면 입자의 상태는 관측하는 그 순간에 정해진다. Uncertainty 타입의 데이터도 값이 정해지지 않은 상태로 메모리에 존재하지만 사용하는 순간에 값이 특정된다. Object.defineProperty()로 구현할 수 있었다.

idiots.io

https://idiots.io/

익명 직장 채팅 어플. 블라인드라는 앱의 채팅버전이다. 아이템 자체로 특별한 건 없고 GraphQL Subscription을 써보고 싶어서 만들었다. 한 일주일이면 서버와 앱까지 다 만들 수 있을 줄 알았는데, React Native가 발목을 잡아서 며칠 더 걸렸다. 역시 프론트엔드는 어려워.

jongfill

https://github.com/vichyssoise/jongfill

한글에 종성을 채워준다. 숫자를 문자로 출력할 때 고정된 길이로 0을 붙혀서 출력하는 것을 zerofill 또는 zfill이라고 한다. 또 ‘곣맋웏욗’처럼 종성을 분리해서 문장을 쓰는게 인터넷에서 유행했던 적이 있었다. jongfill이란 이름의 이 라이브러리는 얼핏 듣기에는 마치 사람 이름 같지만 어떤 기능을 하는지 직관적으로 표현해주는 가장 완벽한 이름을 가지고 있다.

프로그래밍에서 창의성이란 무엇인가?

넷플릭스에 알파고 다큐멘터리가 올라와서 봤다. 영상은 이세돌과 알파고의 Google Deepmind Challenge match의 비하인드 스토리를 흥미롭게 풀어냈다. 재미있게 시청중에 이세돌의 멘트에 정신이 번쩍했다.

바둑에 정말 창의성이 필요한가? 바둑에서 창의성이란 무엇인가?

프로그래밍에 정말 창의성이 필요한걸까? 프로그래밍에서 창의성이란 무엇인가?

이런 고민들을 앞서 해본 다른 사람들의 생각을 구글링하여 읽어봤다. 대체적인 의견은 프로그래밍은 예술활동에 비견될 수 있다는 것이다. 이 둘은 결과물을 만들기 위해 여러가지 도구를 다양한 방법으로 사용하여 무엇인가를 만드는데에 그 공통점이 있다.

그렇다면 프로그래밍에서 도구는 무엇이고, 다양한 방법은 어떤 것들이 있으며, 작품은 무엇이란 말이지? 장비와 에디터등 개발 환경이 도구라면, 그 위에서 사용하는 언어와 프레임워크, 라이브러리는 개발 방법인가? 아니면 이런것들 모두 도구라고 볼 수 있으니, OOP나 functional programming 같은 개발 패러다임이 개발 방법인가? 심지어 완성된 코드는 누군가에겐 또 다른 도구가 될 수 있다. 이런 것들을 명확하게 구분지을 순 있는 것인가? 구분지을 필요는 있을까?

Socket.io로 카운터 만들기

웹에서 전통적인 HTTP는 클라이언트가 요청을 하면 서버가 응답하는 방법으로 통신한다. 내 게시글에 새 댓글이 달렸는지 확인하기 위해서 새로고침을 눌러봐야 한다. 즉, 요청-응답이 끝나면 연결을 종료하기 때문에 클라이언트가 다시 요청하기 전까지는 서버에서 업데이트된 데이터를 받아올 수 없다. 내놓으라고 하기 전까진 스스로 토해내지 않는게 마치 통신사 환급금을 보는 것 같다.

정말로?

CS 전공을 한 사람이라면 네트워크 실습시간에 소켓 통신으로 TCP와 UDP 채팅 프로그램을 만들어 본 적이 있을 것이다. TCP는 연결된 상대가 데이터를 잘 받았는지 확인하고, UDP는 받던 말던 그냥 보내고 본다는 차이가 있으며, TCP는 전화, UDP는 편지에 비유했던 것으로 기억한다. TCP와 UDP에서 중요한 것은 서버와 클라이언트가 소켓으로 연결되어 있다는 점이다. 소켓은 상대방의 주소(목적지)를 담고 있기 때문에 내가 누구에게 데이터를 보내야하는지 명확하다. 소켓으로 연결되어 있다면 서로 누구나 먼저 데이터를 보낼 수 있다. HTTP는 TCP 프로토콜을 이용한다. 그러니까 웹에서도 TCP를 이용하여 소켓 통신을 할 수 있다. HTML5의 웹소켓(Web Socket)으로 말이다.

Socket.io는 웹소켓을 이용하여 서버와 클라이언트 간의 실시간 양방향 통신을 가능케하는 라이브러리다. Socket.io가 지원하는 브라우저 목록을 보면 웹소켓을 지원하는 브라우저가 아닌 것들이 있다. 웹 소켓을 사용할 수 없는 브라우저는 다른 방식을 이용해서 마치 웹소켓이 작동하는 것처럼 보이게 한단다. 많은 Socket.io를 주제로 작성된 블로그 포스트들이 이 내용을 언급하고 있지만 난 그 내용이 어디있는지 찾지 못했다.


Socket.io를 이용해서 간단한 웹 애플리케이션을 만들어보자. 채팅 프로그램을 구현한 튜토리얼은 이미 아주 많으니까 나는 더 단순한 앱을 만들어보려고 한다.

버튼에 숫자가 적혀있다. 버튼을 누르면 숫자가 1 증가한다. 이 숫자는 모든 클라이언트에게 동일하게 보인다. 내가 버튼을 눌러서 숫자를 높히면, 이 웹에 접속 중인 다른 사람들도 실시간으로 숫자가 늘어나는 것을 볼 수 있다.

먼저 간단하게 Node.js 프로젝트를 만들고 필요한 모듈을 설치한다.

mkdir socket.io-test
cd socket.io-test && npm init
npm install -S express socket.io

server.js 파일을 만들고 서버를 작성한다.

// server.js
const app = require('express')()
const http = require('http').Server(app)
const io = require('socket.io')(http)

let count = 0

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/client.html');
})

io.on('connection', socket => {               // 1
  console.log('user connected: ', socket.id)
  socket.emit('get count', count)             // 2
      
  socket.on('increase count', () => {         // 3
    console.log('increase!', count)
    count++
    io.emit('get count', count)               // 4
  })

  socket.on('disconnect', () => {             // 5
    console.log('user disconnected: ', socket.id)
  })
})

http.listen(3000, () => {
  console.log('server on!')
})

클라이언트가 접속하면, 현재 소켓의 id를 콘솔에 출력하고 count 값을 전달한다. 이 클라이언트가 ‘increase count’ 이벤트를 발생시키면, count 값을 1 증가하고 접속중인 모든 클라이언트에게 ‘get count’ 이벤트로 증가한 count 값을 전달한다. 이 클라이언트가 접속을 종료하면, 현재 소켓의 id를 콘솔에 출력한다.

  1. on()은 어떤 이벤트가 발생했을 때 어떤 함수를 실행할지 정의하는 메소드다. 클라이언트가 서버에 접속하면 ‘connection’ 이벤트가 발생한다. 함수의 파라미터로는 해당 연결에 대한 Socket이 넘어온다.
  2. emit()는 이벤트를 발생시키는 메소드다. 현재 소켓에 ‘get count’ 이벤트를 발생시킨다. count를 이벤트 데이터로 보낸다.
  3. 소켓으로부터 ‘increase count’ 이벤트가 발생하면 count를 증가시킨다.
  4. 모든 연결된 모든 소켓에 증가한 count를 담은 ‘get count’ 이벤트를 발생시킨다.
  5. 클라이언트가 접속을 종료하면 해당 소켓으로부터 ‘disconnect’ 이벤트가 발생한다.

다음은 클라이언트를 만들자. 파일명은 client.html.

<!-- client.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Counter</title>
  </head>
  <body>
    <button id="count" value="increase"></button>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script>
      const socket = io()
      $('button').click(e => {
        socket.emit('increase count')   // 1
        e.preventDefault()
      })
      socket.on('get count', count => { // 2
        $('#count').text(count)
      })
    </script>
  </body>
</html>
  1. 버튼을 누르면 ‘increase count’ 이벤트를 발생한다.
  2. 서버로부터 ‘get count’ 이벤트가 발생하면 count를 받아 버튼 라벨에 반영한다.

완성했다. 이제 node server.js로 서버를 실행한다. 브라우저 두 개를 띄우고 http://localhost:3000로 접속해서 버튼을 눌러보자.