마이크로소프트 유니버셜 폴더블 키보드

언제쯤이면 스크린에 뜬 키보드를 사용하는데 더 편하다고 생각하게 될까. 자판 세대를 살면서 쓰기 좋은 키보드를 찾기 위한 검색을 반복하는 것은 어쩔 수 없는 일 같다. 이전부터 눈여겨 봤던 마이크로소프트의 유니버셜 폴더블 키보드를 구입했다.

그동안 아이패드 스마트 키보드를 사용해왔다. 하지만 9.7인치 스크린의 세로폭에 맞춘 키보드라서 키도 작고 손도 모아서 쳐야 했다. 매일 사용하면 어색함이 없지만 다른 키보드를 잠시라도 만지고 오면 바로 이질적인 느낌이 들 수 밖에 없다. 그런 키보드에도 아이패드를 많이 썼던 이유는 그동안 아이폰 5s를 계속 사용해왔고 작은 크기에서 글쓰는데 늘 답답함이 컸던 탓이다.

하지만 아이폰 X를 구입하고 나서는 달라졌다. 더 많은 내용을 볼 수 있어서 그런지 글을 쓰고 다시 보는데도 큰 어려움이 없다. 스마트 키보드를 아이폰X에서 사용할 수 있다면 조금 더 편했을지 모르겠다.

그래서 블루투스 키보드를 대신 들고 다니기도 했다. 애플 키보드도, 싱크패드 키보드도 들고 다녀봤다. 애플 키보드는 모서리가 날카로워서 케이스에 넣지 않으면 가방 안에 모든 것에 흔적을 남겼다. 싱크패드 키보드는 내가 들고 다니는 작은 가방엔 맞질 않아서 백팩을 매고 다녀야 했다. 무슨 키보드든 들고 다니면서 혹시 다른 키보드는 없나 매번 생각했다. 가방에 넣고도 그냥 잊고 지내다가 필요할 때 불쑥 꺼내서 쓸 수 있는 그런 키보드는 없을까.

그러던 중 마이크로소프트의 유니버셜 폴더블 키보드를 다시 보게 되었다. 예전에도 구입할까 고민하긴 했었는데 비싼 가격에 구입하지 않았었다. 이번에는 Ebay에서 AUD$79에 판매하고 있길래 구입했다.


포장은 여느 마이크로소프트 제품과 같다. 점점 덕지덕지함을 벗어나는 패키징이 마음에 든다. 키보드 소재는 부드럽고 무게도 무겁지 않다.

2대의 기기까지 페어링을 지원하고 운영체제를 변경할 수 있는 키도 붙어 있다. USB 케이블도 동봉되어 있고 한 번 충전으로 꽤 오래 사용할 수 있다고 한다. 충전이 얼마나 되었는지 표시가 없는건 아쉽지만 충전하면서도 사용하는데는 전혀 문제 없었다.

Microsoft Universal Foldable Keyboard

타이핑하는 느낌은 애플 블루투스 키보드를 눌렀을 때와 가장 비슷하며 좀 더 정숙하다. 키 피치는 높지 않아서 스마트 키보드 보다는 나은 경험이지만 일반적인 블루투스 키보드보다는 얕은 느낌이 든다. 서피스 키보드와도 유사하게 느껴진다.

Microsoft Universal Foldable Keyboard

키보드 레이아웃도 전혀 작다고 느껴지지 않고 키도 마음에 든다. 다만 오른쪽에는 키를 좀 더 오밀하게 배치한 탓에 특수 문자를 입력할 때 잘못 누르는 경우가 좀 있다. 더불어 방향키도 작은 편이다. 탐색을 터치 스크린으로 한다면 큰 문제는 아니다. 그리고 B키가 왼쪽에 위치하고 있다. 나는 B는 왼손으로 누르는데 ㅠ는 오른손으로 누르고 있었다. 익숙해질 때까지 좀 시간이 걸렸는데 쉽게 고칠 수 없다면 이 키보드에서 가장 큰 단점이지 않을까 싶다.

Microsoft Universal Foldable Keyboard

장점은 역시 접을 수 있다는 점이다. 평소 들고 다니는 수첩과 큰 차이가 없다. 재질도 부드러워서 가방 안 다른 물건에 손상을 주는 일도 없다. 휴대성에 있어서는 최고다.

Microsoft Universal Foldable Keyboard

가끔 뭔가 잘 안되면 지름으로 해결하려는 경향이 있는데 아마 글이 잘 안쓰여지니 또 키보드를 질러서 풀어보려는 모양이다. 그래도 생각했던 용도대로 가방에 수첩과 함께 넣어두고 지내다가 필요할 때 언제든 꺼내서 쓸 수 있는 좋은 키보드다. 부지런히 사용해서 본전 찾아야겠다.

Stop and smell the roses 🌹

오늘이 마지막 출근이다.

1년 조금 넘는 기간을 다닌 이번 회사에서는 이전 다녔던 곳과는 확연히 다른 경험을 했다. 규모도 달랐고 프로세스도 갖춰져 있었다. 다른 부서와 함께 일하는 경험은 처음이었다. PM과 BA와 함께 일하고, 아키텍트에게 리뷰도 받고, 수많은 단계를 거쳐 배포와 retrospective까지 가는 모든 과정이 배움의 연속이었다. 모두 친절하고 많이 도움 받았다.

회사 다니는 동안 크고 작은 다양한 업무를 했고 프로젝트는 대외적으로 인정도 받아 즐거웠다. 업무 프로세스가 많고 내 영어가 부족해서 지치는 면도 좀 있었지만 좋은 사람들과 함께 재미있는 프로젝트를 할 수 있었다. 프로젝트에서 대학에서만 볼 수 있는 그런 도메인 지식을 배운 것도 즐거운 경험이었다.

또한 성평등과 문화 다양성이 로드맵에 들어있을 정도로 신경을 많이 쓰는 회사라서 그런지 지난 회사에서 겪었던 작은 편견조차 여기서는 볼 수 없었다. 덕분에 회사가 차별에 맞서기 위해서는 어떤 역할을 해야 하는지, 어떤 장치를 둬야 하는지도 업무 외적으로도 많이 배웠다.

다음은 어느 회사로 갈지 정해지지 않았다. 다음 회사에서는 다른 기술을 사용해서 일하고 싶다는 막연한 생각만 있다. 오랜만에 어디에도 소속되지 않은 상태로 시간을 보낼 예정이다. 그동안 만나지 못했던 사람들도 보고, 책도 읽고, 여유도 가질 참이다. 물론 나날이 들어오던 돈이 더 이상 없다는 상상은 좀 걱정이 된다. 이런 면에서 보면 월급 중독이 심한 것 아닌가 싶기도 하고.

매년 무언가 배우면서 미래를 대비하려고 했지만 조급한 마음만 앞서서 그런지 1, 2년이면 닳아버리는 지식만 반복해서 접했던 것 같다. 급함에 너무 좁은 시각으로 살지 않았나 생각이 많이 들었다. 그래서 이번에는 기간을 두고 집중해서 볼 수 있는 지구력도 좀 만들고, 무엇을 오래 보고 배울지 부지런히 찾아야지 싶다. 무엇이 미래에 정말 필요할까, 나는 어떤 역할로 그 기류 속에 서 있을 수 있을까.

무엇을 준비하고 어떻게 대비하는지 고민과 함께 정말 하고 싶은 것은 무엇인지도 생각하게 된다. 하고싶은 일이 기술적 깊이가 있는 엔지니어링인지, 아니면 비즈니스와 더 맞닿아 있는 기술 컨설팅인지, 아니면 좀 더 큰 그림을 그리는 아키텍트가 되고 싶은 건지. 이 전환 기간동안 좋은 결정을 내릴 수 있는 토대를 잘 가꿔서 결정 하고싶다.


벌써 멜번에서 만 6년의 시간을 보냈다. Stop and smell the roses. 고민도 많고 고생도 했던 기간이지만 몸 건강히 잘 지내는게 얼마나 다행인지 생각한다. 지금까지 지내온 시간과 받은 도움에 감사하는 시간을 보내고 싶다.

공변성과 반공변성은 무엇인가?

Stephan BoyerWhat are covariance and contravariance?을 번역한 글이다.


공변성과 반공변성은 무엇인가?

서브타이핑은 프로그래밍 언어 이론에서 까다로운 주제다. 공변성과 반공변성은 오해하기 쉬운 주제이기 때문에 까다롭다. 이 글에서는 이 용어를 설명하려고 한다.

이 글에서는 다음과 같은 표기법을 사용한다.

  • A <: BAB의 서브타입이라는 뜻이다.
  • A -> B는 함수 타입으로 함수의 인자 타입은 A며 반환 타입은 B라는 의미다.

동기부여 질문

다음과 같은 세 타입이 있다고 가정하자.

Greyhound <: Dog <: Animal

GreyhoundDog의 서브타입이고 DogAnimal의 서브타입이다. 서브타입은 일반적으로 추이적 관계(transitive)를 갖는다. 그래서 GreyhoundAnimal의 서브타입이라 할 수 있다.

여기서 질문이다. 다음 중 Dog -> Dog의 서브타입이 될 수 있는 경우는 어느 것일까?

  1. Greyhound -> Greyhound
  2. Greyhound -> Animal
  3. Animal -> Animal
  4. Animal -> Greyhound

이 질문에 어떻게 답할 수 있을까? Dog -> Dog 함수를 인자로 받는 f 함수를 살펴보자. 반환 타입에 대해서는 크게 생각하지 않는다. 구체적으로 적어보면 다음과 같다. f : (Dog -> Dog) -> String.

이제 f를 다른 함수인 g와 함께 호출해보자. g에는 위에서 나열했던 각각의 함수를 넣어서 어떤 일이 나타나는지 관찰한다.

1. g : Greyhound -> Greyhound로 가정하면 f(g)는 타입 안전(type safe)한가?

아니다. 함수 f는 인자 g를 사용하면서 Dog의 다른 서브타입, 예를 들면 GermanShepherd를 사용해서 호출할 수도 있기 때문이다.

2. g : Greyhound -> Animal로 가정하면 f(g)는 타입 안전한가?

아니다. 1과 동일한 이유다.

3. g : Animal -> Animal로 가정하면 f(g)는 타입 안전한가?

아니다. f에서 인자 g를 호출하면서 개가 어떻게 짖는지 그 반환 값을 얻으려고 할 수 있다. 하지만 모든 Animal이 짖는 것은 아니다.

4. g : Animal -> Greyhound로 가정하면 f(g)는 타입 안전한가?

그렇다. 이 경우는 안전하다. f 함수는 인자인 g를 호출할 때 어떤 종류의 Dog든 사용할 수 있다. 모든 DogAnimal이기 때문이다. 또한 반환값은 Dog로 가정할 수 있는데 모든 GreyhoundDog이기 때문이다.

무슨 일이 일어나고 있나요?

결과적으로 다음 경우에 안전하다.

(Animal -> Greyhound) <: (Dog -> Dog)

반환 타입은 간단하다. GreyhoundDog의 서브타입이다. 하지만 인자 타입은 반대다. AnimalDog의 수퍼타입이다!

이 독특한 동작 방식을 적당한 용어를 사용해서 설명한다. 함수 타입에서 반환 타입은 공변적(covariant) 이고, 인자 타입은 반공변적(contravariant) 이다. 반환 타입의 공변성은 A <: B(T -> A) <: (T -> B)로 적용된다는 뜻이다. (A<:의 좌측에, B는 우측에 남아 있다.) 인자 타입의 반공변성은 A <: B(B -> T) <: (A -> T)로 적용된다는 의미다. (AB가 위치를 바꾸게 된다.)

재미있는 사실 타입스크립트에서는 인자 타입이 이변적(bivariant), 즉 공변성과 반공변성을 동시에 지닌다. 뭔가 말이 안되는거 같겠지만 말이다. (TypeScript 2.6부터 --strictFunctionTypes 또는 --strict를 사용하면 이 문제를 해결할 수 있다.) Eiffel은 인자 타입을 반공변적이 아닌 공변적으로 잘못 구현했다.

다른 타입은?

또 다른 질문이다. List<Dog>List<Animal>의 서브타입이 될 수 있을까?

답변하기 좀 미묘하다. 만약 목록이 불변이면 맞다고 답할 수 있다. 하지만 가변적이라면 당연히 안전하지 않다!

이유를 생각해보자. 나는 List<Animal>이 필요한데 List<Dog>를 넘겨줬다고 해보자. 나는 당연히 List<Animal>을 갖고 있다고 생각하고 Cat을 집어넣었다. 이제 List<Dog>Cat이 들어있게 된다! 타입 시스템은 이런 동작을 허용하지 않을 것이다.

불변 목록의 타입이라면 타입 파라미터가 공변적일 수 있지만 가변 목록의 타입은 반드시 공변적이지도, 반공변적이지도 않아야(invariant) 한다.

재미있는 사실 자바에서의 배열은 가변적이면서도 공변적이다. 물론 부적절하다.


추가로, 원문의 덧글 중에 시각적으로 잘 설명하는 자료가 있었다.