레이블이 web인 게시물을 표시합니다. 모든 게시물 표시
레이블이 web인 게시물을 표시합니다. 모든 게시물 표시

2018-04-29

2018년 17번째 주

이 포스팅은 그냥 지난 한 주간 읽었던 것들을 정리하는 포스트입니다. 그냥 예전에 봤던 글 중 나중에 필요한데 뭐였는지 기억 안 나는 글들이 있어서 쓰기 시작했습니다.
보통 하는 일과 관련된 글들이 올라오겠지만 딱히 정해둔 주제는 없고, 그때그때 관심 있었던 것을 읽었기 때문에 지난주에 쓰인 글일 수도 있고 몇 년 전에 쓰인 글일 수도 있습니다.


The Configuration Complexity Clock

Configuration을 만들다 보면 Rules engine이나 심할 때는 DSL(Domain Specific Language)까지 만들기도 하는데, 어떨 때는 그냥 하드코딩 하는 것이 가장 적절한 방법일 수 있다는 글이다.

Linus's Law

given enough eyeballs, all bugs are shallow

리누스의 법칙은 위의 한 줄로 정리된다. 오픈 소스의 근간이 되는 문장이고, peer-review가 필요한 이유로도 많이 언급된다. 문제는 최근의 거대한 소프트웨어서는 버그를 발견하는 데 필요한 enough의 수가 너무 크다는 것이다. 게다가 시스템이 복잡하다면, 그 시스템을 이해하지 못한 개발자는 버그를 발견하기 위한 eyeballs 중 하나가 되지도 못한다. 그렇기 때문에 시스템을 단순하게 유지하는 것이 중요하다.

Language Health

각 언어가 오픈 소스에서 얼마나 많이 사용되는지 비교해보는 사이트다. 다만, 어디까지나 오픈소스에서 얼마나 많이 커밋이 있었는지에 대한 비교이지, 얼마나 많은 사람이 사용하는지나, 클로즈드 프로젝트에서 얼마나 많이 사용하는지는 알 수 없다.

An introduction to the GNU Core Utilities

리눅스에서 작업하다 보면 필요한 유틸리티 모음. 터미널에서 작업할 때 알면 좋은 것들이다.

REST APIs are REST-in-Peace APIs. Long Live GraphQL.

GraphQL의 장점에 관해서 쓴 글이다. 근데 여전히 GraphQL을 쓸지는 모르겠다. 복잡한 웹 서버를 짤 일이 있으면 모르겠는데 요새는 웹 서버라기보다는 그냥 간단한 툴의 UI를 웹으로 사용하는 정도로만 웹 코딩을 하고 있다. 이 정도 수준의 앱에서는 GraphQL을 사용하는 것이 오버헤드가 더 클 것 같다. 사실 반대로 말하면 뭘 써도 상관 없는 크기라서 GraphQL을 써도 된다. 하지만 다른 라이브러리에 디펜던시 없이 구현할 수 있는 REST에 비해서 GraphQL을 쓰려면 GraphQL을 구현하는 라이브러리를 써야 하므로 의존성을 추가해야 하는데 아직 그만한 필요성을 못 느끼겠다.

GO's New Brand

GO가 새 로고를 발표했다. 드디어 이상한 쥐를 버린 줄 알았는데 Gopher는 마스코트로 여전히 남겨두는 듯 하다.

Flask 1.0 Released

Flask가 드디어 1.0이 됐다. 사실 전에도 0.X인걸 신경 쓰지 않고 썼기 때문에 상관없지만 1.0을 쓰면 괜히 기분이 좋다.

2016-08-18

[Web] SpeechSynthesis - TTS API

 SpeechSynthesis는 Web Speech API의 하나로 주어진 텍스트를 소리로 바꿔주는 TTS API이다. SpeechSynthesis 이전에도 TTS 서비스가 있었지만, 이들은 유료이거나 웹에서 사용하기 불편한 경우가 대부분이었는데 SpeechSynthesis의 경우 브라우저에 내장되는 API이므로 무료로 쉽게 사용할 수 있다는 장점이 있다.
 물론 Web Speech API 자체가 아직 draft에 해당하기 때문에 브라우저가 지원해야만 사용 가능하다는 문제는 있지만, 2016년 8월 15일 현재 데스크탑에서는 크롬과 사파리, 안드로이드 기본 브라우저인 크롬, 아이폰의 기본 브라우저인 사파리에 지원하고, 파이어폭스는 9월에 지원할 예정이므로 대부분의 모던 브라우저에서는 사용할 수 있다.

 speechSynthesis는 5개의 함수를 가지고 있다. 그중 4개는 speak, cancel, pause, resume이다. 이를 이용해서 재생할 음성을 추가하거나 취소하거나 일시 정지할 수 있다.  이 중 speak 함수는 SpeechSynthesisUtterance를 인자로 받는다. speak 함수를 호출했을 때, 이미 재생 중인 utterance가 없고 speechSynthesis가 pause 되어 있지 않으면, 요청된 utterance는 즉시 재생된다. 하지만 이미 재생 중인 utterance가 있거나 speechSynthesispause 되어 있다면, utterance는 바로 재생되지 않고 queue에 저장되었다가 후에 재생된다.
 따라서 실제로 언제 재생되는지는 utterance의 콜백을 통해서만 알 수 있다. 이벤트의 종류에 따라서 onstart, onend, onerror, onpause, onresume 등의 콜백을 등록할 수 있다.

 또한, SpeechSynthesisUtterance는 6개의 속성을 가지고 있다.
 첫 번째 속성은 text로 읽을 텍스트를 지정한다. 객체를 생성할 때 생성자에 넘겨줄 수도 있고, 생성한 뒤 text attribute에 값을 할당할 수도 있다.
 두 번째 속성은 lang으로 어떤 언어로 읽을지를 결정해준다. 만약 아무런 값도 지정하지 않으면 기본적으로는 html 태그의 lang 값을 이용한다.
 세 번째 속성은 voice다. voiceSpeechSynthesisVoice 객체를 값으로 설정할 수 있는데, 아무런 값도 할당 안 하면 default voice를 사용하게 된다.
 네 번째 속성은 volume이다. volume은 최소 0에서 최대 1의 값을 가질 수 있다. 아무런 값을 주지 않으면 기본값은 1이 된다.
 다섯 번째 속성인 rate는 소리의 속도를 결정한다. 기본값은 1이고, 값이 커지면 빠른 속도로, 값이 작으면 느린 속도로 발음한다.
 마지막 속성인 pitch는 소리의 전체적인 높이를 결정한다. 기본값은 1이고, 0에서 2 사이의 값을 가질 수 있는데 최저와 최고일때 어떤 음을 가질지는 브라우저의 구현에 따라서 다르다.

 speechSynthesis에 있는 마지막 함수는 getVoices다. 이 함수는 SpeechSynthesis가 사용할 수 있는 SpeechSynthesisVoice 목록을 반환한다. 하지만 처음에는 아무런 값도 없을 수도 있다. 사용할 수 있는 voice 목록이 초기화되면 voiceschanged 이벤트가 호출되는데, 이 이벤트가 호출되어야 getVoices 이벤트가 정상적으로 사용할 수 있는 voice 목록을 리턴한다.  이렇게 가지고 온 SpeechSynthesisVoicename, lang, voiceURI, localService, default 5개의 속성을 가진다. 이때 lang은 해당 목소리가 어느 나라의 언어를 표현하는지를 나타내고, name은 목소리의 이름을 나타낸다. 하지만 이 둘 다 유일할 것이 보장되지 않는다. 어떤 나라의 언어를 표현하는 목소리가 여러 개 있을 수 있고, 같은 이름의 서로 다른 목소리가 존재할 수도 있다. 하지만 현재 안드로이드 크롬에는 버그가 있어서 voice를 설정해도 목소리가 변하지 않고, lang을 설정해야 목소리가 변한다. 따라서 한 언어에 여러 개의 목소리가 있다고 해도 한 가지 목소리밖에 쓰지 못한다.

 SpeechSynthesis는 데스크탑과 모바일 등 다양한 플랫폼에서 사용할 수 있고, 사용하기도 편하다. 하지만 현재 크롬 구현체에는 약간 문제가 있다. 현재는 크롬은 60개 이상의 문자를 말하고 나면 그다음 utterance에 대해서 소리가 끝나도 end 이벤트도 error 이벤트도 발생하지 않는다. 라이브러리의 버그로 보이는데 작년 6월부터 이슈가 나왔던 문제인데 올해 6월 드디어 원인이 나왔다. 가비지 컬렉팅과 관련된 문제로 보이는데, utterance를 전역변수로 보관하고 있으면 문제가 발생하지 않는다. 원인이 나왔으니 곧 고쳐질 것으로 보이지만, 그동안은 utterance를 전역변수에 저장하는 식으로 우회해야 한다.

2015-09-20

confirm password 필드는 더 이상 필요 없는가

 비밀번호는 보안상의 문제로 ""으로 표시되기 때문에 오타를 냈어도 확인할 수 없고 잘못 입력하면 앞으로 로그인할 수도 수정할 수도 없어 계정을 그대로 버리는 문제를 발생시킨다. 따라서 비밀번호의 오타는 다른 정보들과는 다르게 큰 문제가 된다.
 그래서 일반적으로 회원가입을 할 때, 비밀번호를 두 번 입력하도록 한다. 하지만 이런 방식이 UX를 크게 저하한다면서 다른 방식을 사용해야 한다고 주장하는 글이 있었다. 이 글에서는 비밀번호를 두 번 입력하는 대신 입력한 비밀번호를 읽을 수 있게 보여주는 토글 버튼이 있어야 한다고 주장한다.

 언뜻 들으면 그럴싸해 보이지만 결론부터 말하면 절대 좋은 방식이 아니다. 최소한 웹 환경에서는 절대 해서는 안 되는 방식이다. 비밀번호를 보여줄 수 있게 만드는 방법은 다음과 같은 문제가 몇 가지 있다.

 우선 브라우저에서 지원하지 않는다. 현재의 웹 스펙에 password input을 보여주는 방법은 없다. 따라서 text input을 이용해야 한다. 문제는 브라우저, 최소한 제대로 된 브라우저(심지어 I.E조차도)는 text input과 password input을 완전히 별도로 처리한다는 것이다. 이 둘의 차이는 단순히 내용이 눈에 보이는가 아니면 ""으로 보이는가의 차이가 아니다.
 일단 당장 눈앞의 문제로 text input은 password input과 다르게 브라우저가 캐싱하고 자동 완성 한다는 것이나, 브라우저의 비밀번호 저장 기능을 생각해볼 수 있다. 캐시와 관련한 것은 autocomplete를 이용해서 조정할 수 있지만, 비밀번호 저장 기능은 password input만을 저장하기 때문에, text input을 이용한 상태에서는 어떻게 할 방법이 없다.
 사실 비밀번호 저장기능이 중요한 기능이 아니기는 하다. 하지만 이 기능은 포기한다고 해도 여전히 브라우저가 password input과 text input 전혀 별개의 것으로 처리한다는 것은 문제다. 브라우저 개발자들은 비밀번호를 password input을 이용할 것을 기대하지 text input을 사용할 것으로 생각하지 않는다. 최소한 HTML 6가 나와 스펙이 변하거나, 많은 사람이 text input을 이용해서 비밀번호를 저장할 때까지는 그럴 것이다.

 게다가 비밀번호를 눈으로 확인하게 하는 시스템은 기존의 방식보다 시간이 오래 걸린다. 단순히 절차상으로 걸리는 시간이 길어지는 것뿐 아니라, 내 비밀번호와 화면에 출력되는 시간이 길어진다.
 이 시간은 보안에도 큰 문제가 된다. 내가 눈으로 내 비밀번호를 확인할 수 있다는 것은 내 등 뒤의 사람도 그 비밀번호를 볼 수 있다는 것이다. 설령 시스템이 아무리 안전하게 구성되어 있다고 해도 정작 다른 경로로 비밀번호가 노출될 가능성이 있다면, 이 시스템은 안전하지 않은 시스템이다. 즉, 비밀번호를 눈으로 보고 확인하게 하는 방식은 보안적으로 안전하지 않은 방식이다.

 그다음 문제는 강력한 비밀번호일수록 사람의 눈으로 읽고 확인하는 것이 좋은 확인 수단이 아니라는 것이다. 짧고 간단한 비밀번호라면 금방 확인할 수 있다. 하지만 특수기호와 영대소문자를 섞어가면서 20글자의 비밀번호를 만들었다면? 그 비밀번호를 눈으로 보고 자신이 의도한 대로 친 것이라고 확신할 수 있을까?
 기존의 비밀번호를 확인하는 방식으로 잘못된 비밀번호를 확인 못 하는 경우도 있다. Caps lock 키가 눌려서 대소문자가 바뀌어서 입력된 경우는 기존의 방식으로 잘못된 비밀번호를 확인할 수 없다. 하지만 이는 caps lock 키가 눌렸는지를 확인해서 해결해야 할 문제이지 위와 같은 문제를 감수하고 비밀번호를 보여주는 옵션을 추가해서 해결할 문제는 아니다.

 즉, 비밀번호를 보여주는 방식은 기존의 방식에 비해서 제대로 된 비밀번호를 적었을 것을 보장하지도 않고, 안전하지도 않고, 플랫폼에서 지원하지도 않는다. 물론 이것은 웹에서의 이야기이고 위의 문제가 발생하지 않는 환경이라면 딱히 상관없다. 예를 들면, 데스크탑 OS나 서버 프로그램의 설치 화면이라면 그래도 상관없다고 생각한다. 하지만 이것은 오히려 특수한 경우이고 일반적으로 특히나 웹 환경에서 쓸만한 이야기는 아니라고 생각한다.

 하지만 비밀번호를 두 번 타이핑하는 것이 사용자에게 안 좋은 UX를 제공할 수 있다는 의견에는 동의한다. 그렇지만 이를 해결하는 방법이 비밀번호를 보여주는 것은 아니다. 최소한 웹에서 쓸만한 방법은 아니다.
 게다가 사실 비밀번호를 다시 타이핑하지 않고 가입하는 좋은 방법은 이미 나와있다. 이미 github이나 facebook이나 twitter 등에서 사용하고 있다. 가입 시 이메일을 받고 이메일을 통해서 인증받도록 하는 것이다. 이렇게 가입을 받으면 비밀번호를 잘못 입력했더라도 이메일을 통해 바꾸도록 하면 되니 문제 없고, 이메일을 잘못 입력하였더라도 일정 기간 내로 인증을 받지 않은 회원가입은 무효화 하면 되니 잘못 타이핑할 걱정을 하지 않아도 된다.

2015-02-03

Glowing Bear - 터미널에서 하던 IRC 웹에서 그대로

 나는 freenode를 구경하거나 친구들과 놀기 위한 용도로 IRC를 사용한다. 데스크탑 어플리케이션도 많이 쓰이지만, IRC라는 프로토콜의 특성상 접속하여 있지 않으면 대화를 볼 수 없어서 freenode에 있는 사람들은 IRC를 계속 접속해놓을 방법을 찾는다. 가장 쉬운 방법은 컴퓨터를 끄지 않고 다니는 방식이지만, 보통 개발자 중에 이런 방식을 사용하는 사람은 없다. 보통은 서버에 터미널 기반의 IRC 클라이언인 WeeChat이나 Irssi 띄우거나, IRC Cloud라는 서비스를 사용한다.
 하지만 터미널 클라이언트를 사용하면 언제서나 접속할 수 있는 웹 클라이언트가 아쉬워지고, IRC Cloud를 사용하기에는 한 달에 5$ 하는 비용뿐 아니라 WeeChat의 plug-in기능이 아쉬워진다. 그래서 보통은 WeeChat과 IRC Cloud 양쪽을 사용하는 방식을 택하지만, 그렇게 되면 2개의 접속이 연동되지 않기 때문에 불편한 건 어쩔 수 없다.
 그래서 WeeChat plug-in을 이용해 위와 같은 웹 서비스를 만들어볼 계획이었다. 우선 채팅 로그를 DB에 저장하는 스크립트를 만들던 중 WeeChat에 완전히 같은 목적을 가진 relay protocol이 있다는 것을 알게 되었다. Relay protocol은 WeeChat client가 relay 서버가 되어, Relay 클라이언트와 TCP socket을 이용해 통신을 하게 된다. Relay protocol을 사용하면 WeeChat과 완전히 같은 화면을 볼 수 있는 데다가 WeeChat plug-in을 그대로 사용할 수 있다는 장점이 있다.
 Relay protocol을 사용하는 client는 여러 가지가 있다. Qt를 사용해서 데스크탑 애플리케이션을 만든 QWeeChat, node.js를 이용한 웹 서버 WeeCloud 등도 많이 사용된다. 하지만 내가 사용하는 클라이언트는 Glowing Bear다. Glowing Bear는 완전히 static 한 web page에서 WebSocket을 이용해 WeeChat relay server와 통신하기 때문에 WeeCloud와 달리 웹 서버와의 통신은 필요하지 않아서 순전히 WeeChat 서버하고만 통신한다는 장점과 웹 서버 이외에 별도의 서버가 필요하지 않다는 장점이 있다.
 일단 지금 3~4일째 사용하고 있는데 키보드로 채널을 이동할 수 없다는 것을 제외하고는 딱히 문제를 찾을 수 없어서 앞으로도 계속 사용할 것으로 보인다.

2014-12-18

file URI와 same-origin policy

 modern web browser에는 보안을 위한 여러 가지 기능들이 들어있다. 그중 가장 대표적인 기능이 same-origin policy다. same-origin policy 덕분에 (개발자 입장에서는 약간 짜증 나기는 하지만) 특별히 신경을 쓰지 않아도 보안에 관해 상당히 많은 부분을 커버할 수 있다. same-origin policy의 원칙은 매우 간단하다. 내 사이트가 다른 사이트에서 호스팅 되는 리소스에 의존하는 것을 금지해서, 내 사이트가 오염되거나 다른 사이트에 의해 공격당하는 것을 막는 것이다.

 same-origin인지 결정하는 것은 매우 간단한데 프로토콜, 호스트, 포트가 같은 URI를 same-origin이라고 판단한다. 요새는 대부분 개인 서버와 개인 도메인을 사용하기 때문에, 프로토콜과 포트까지 같은지 판단하는 것은 너무 빡빡한 기준이라고 생각할 수도 있지만, 워크스테이션이나 공용 서버에서 작업하는 일도 많다는 것을 생각하면 포트와 프로토콜까지 고려하는 것은 역시 상식적인 판단이라고 할 수 있다.

 브라우저에서 많이 쓰이는 http나 https에서는 이 규칙이 상식적이라고 할 수 있다. 문제는 file URI에서의 동작이다. file URI에 대해서는 어떤 URI를 same-origin이라고 할 것인지 정해진 것이 없고, 브라우저마다 알아서 자신이 옳다고 생각하는 방식으로 구현했다.

 우선 오페라는 file URI도 다른 URI와 같은 정책으로 처리한다. 따라서 file URI로 접근한 페이지에서는 읽기 권한이 있는 모든 파일을 읽어서 리소스로 활용할 수 있다. 어차피 파일은 OS가 access list로 보호하고 있으니, 로컬 파일에 대한 보안을 OS에 맡겨 버린 것이라고 할 수 있겠다. 약간 무책임한 것 같지만, 오페라의 구현이 가장 웹서버 없이 웹 페이지를 테스트하기 편한 구현이다.

 반면 크롬은 modern browser 중에 가장 빡빡한 규칙을 적용한다. 크롬에서는 file URI로 들어오는 요청에 대해 무조건 다른 origin인 것으로 처리한다. 심지어 host name을 명시적으로 입력해서 겉으로 보기에는 protocol, host name, port가 같아서 같은 origin으로 보이는 경우도 다른 origin인 것처럼 처리한다. 따라서 크롬에서는 웹 서버 없이 웹 페이지를 테스트하는 것이 불가능한 경우도 생긴다.
 이렇게 빡빡한 규칙을 적용한 이유는 찾을 수 없었다. 아마도 크롬이 Chrome OS와 코드를 공유하기 때문으로 추측된다. Chrome OS의 파일 권한이 앱별로 있는 것이 아니라서 다른 앱에서 로컬에 있는 파일을 읽는 것을 막기 위해서 file URI를 모두 다른 origin으로 취급해야 했던 게 아닐까 싶다.

 파이어폭스는 크롬과 오페라의 중간 정도 되는 정책을 취한다. 파이어폭스에서 file URI를 쓰면 현재 directory를 기준으로 자신보다 아래 경로에 있는 파일은 읽을 수 있도록 허용한다.1) 덕분에 파이어폭스도 웹 서버 없이 테스트하지 못하는 웹 페이지가 생기기도 한다. 하지만 크롬보다는 상황이 조금 나은 게 최소한 자신의 것이 확실한 (자기 디렉토리 아래에 있는)리소스는 마음껏 사용할 수 있다.

 크롬 브라우저에는 file URI를 이용하면서도 다른 파일을 같은 origin인 것처럼 사용하는 방법도 있다. 크롬을 실행할 때 --allow-file-access-from-files switch를 이용하면 file URI에서 모든 파일에 접근할 수 있도록 해준다. 주의해야 할 것은 기존에 실행시켰던 크롬이 백그라운드로 떠 있으면, 새로 크롬을 실행시켜도 백그라운드 프로세스로 떠 있던 크롬이 포크 되며 실행되기 때문에 switch가 반영되지 않는다. 따라서 switch를 주면서 크롬을 실행시킬 때는 기존의 프로세스가 전부 꺼졌는지 확인하고 실행해야 한다.
 파이어폭스도 file URI에 대한 동작을 변경할 수 있다. security.fileuri.strict_origin_policy 설정을 이용하면 오페라와 같이 모든 로컬파일을 리소스로 쓸 수 있게 된다.

 이런 식으로 크롬이나 파이어폭스를 이용해도 switch나 preference를 통해서 file URI로 로컬에 있는 페이지에 접근해서 테스트할 수도 있다. 하지만 테스트를 위해서가 잠시 값을 바꿔서 쓰는 게 아니라 기본값을 바꿔서 계속 사용하는 것은 좋은 방식이 아니라고 생각한다. same-origin policy라는 것의 목적은 보안을 위한 것이다. 보안을 위한 기능을 편의를 위해 끄고 쓰는 것은 열쇠 가지고 다니기 귀찮다고 문 열어놓고 다니는 것과 마찬가지의 행동이다.
 게다가 file URI를 통해 간단한 테스트는 가능할 수도 있지만, file URI는 http나 https와 동작이 달라서 실제 웹앱과 완벽하게 같은 테스트는 안된다. 따라서 실제로 웹 서버를 띄우는 것이 가장 확실한 방법이다.

 하지만 구태여 웹 페이지를 file URI로 테스트하려고 했던 것은, 현재 머신에 웹서버를 설치하기 싫거나, 설치할 수 없거나, 설정하기 귀찮은 경우일 것이다. 그런 상태에서 웹 서버를 설치하고 테스트하라고 말해봐야 보안에 구멍이 생기더라도 브라우저 설정을 바꾸는 것을 택할 것이다. 그런 사람들을 위해 간단하게 웹서버 돌리는 방법을 소개해 주겠다.

 어디든지 실행시키고 싶은 웹 앱의 최상단 경로에서 python3 -m http.server {port}를 입력하면 python으로 웹 서버가 실행된다. 아무 기능도 없지만, 최소한 file URI로 테스트하려던 수준의 웹 페이지라면 충분히 테스트할 수 있다.

1) https://developer.mozilla.org/en-US/docs/Same-origin_policy_for_file:_URIs