스토리 홈

인터뷰

피드

뉴스

조회수 1042

flake8-import-order-spoqa

안녕하세요. 스포카 프로그래머 홍민희입니다.스포카 사내에서는 파이썬 코드의 스타일을 맞추기 위해 flake8을 사용해왔습니다. PEP 8 스타일을 준수하게 해주고, 안 쓰는 임포트를 꼭 지우게 하는 등의 좀더 구체적인 규칙도 지키게 해주는 린트 도구입니다. 사실상의 표준이기 때문에 파이썬을 이미 쓰고 있는 분들이라면 많이들 알고 계실 것입니다.그렇지만 import문의 사용에 대해서는 우리가 원하는 것만큼의 규칙을 제공하지 않아서, 예전부터 동료 강효준 님이 import-order를 별도로 만들어서 써왔습니다. 만들었을 당시에는 import문의 쓰임에 대한 린트 도구가 없었기 때문에 유용하게 써왔고, 다른 파이썬 오픈 소스 프로젝트에서도 유용할 것 같다고 생각하여 쓰인지 1년쯤 지난 뒤에 오픈 소스로 공개했습니다.하지만 flake8과는 다르게 외부 커뮤니티에서 널리 쓰이지는 못했고, 사실상의 표준이 되었다면 편집기 연동 등이 이뤄졌겠지만, 그에 미치지는 못했습니다. pre-commit hook이나 CI에서나 검사가 이뤄지기 때문에, 코딩을 마쳤다고 생각한 이후에 뒷북으로 실수를 바로잡는 일이 많아 불편했습니다.그 뒤로 시간이 지나자 커뮤니티에서는 flake8-import-order라는 도구가 나와서 사실상의 표준이 됐습니다. 이미 많은 편집기에서 연동이 되는 flake8의 확장으로 구현됐기 때문에 편집기에서 즉시 확인이 가능했고, 더 많은 옵션도 제공했습니다. 그렇지만 cryptography 프로젝트 사람들이 만든 도구다보니, cryptography 스타일 및 Google 스타일 등 몇 가지만 제공했고, 이 도구를 활용하려면 스포카에서 3년 넘게 쓰이던 import 스타일을 포기하고 사내의 모든 코드를 전부 수정하는 난리를 피우거나, flake8-import-order에 스포카 사내 스타일을 옵션으로 추가하거나, 프로젝트를 포크해서 별도로 유지보수하며 써야 했습니다.사내 모든 코드를 전부 수정하는 것은 쉽지도 않을 뿐더러, 스포카에서 쓰이던 스타일에도 나름의 논거는 있기 때문에 쉽게 포기하기는 힘든 결정이었습니다. 일부 프로젝트부터 옮겨가는 시도도 있었으나, 같은 회사에서 코드마다 스타일의 일관성이 달라지는 혼란이 있었습니다.저는 flake8-import-order에 스타일을 추가하는 것을 주저했습니다. Google 스타일처럼 문서화가 이미 아주 자세히 되어 있지도 않고 유명하지도 않은, 일개 회사의 사내 스타일을 사실상의 표준 린트 도구의 7번째 공식 지원 스타일로 추가하는 것이 이뤄질 개연성이 낮다고 봤습니다.그래서 프로젝트를 포크하기로 마음먹은 것이 보름 전쯤입니다. 그런데 코드를 열어보니 좀더 나은 아이디어가 떠올랐습니다. flake8-import-order의 코드를 고치지 않고 런타임에 스타일을 확장 가능한 플러그인 구조를 추가하면, 스포카에서 쓰는 import 스타일을 별도 패키지로 구현할 수도 있다는 생각이 든 것입니다. 당시 flake8-import-order의 스타일 구현은 Style의 기반 클래스를 상속받는 식으로 이뤄져 있었고, 다만 스타일의 목록이 하드코딩되어 있는 것이 문제였습니다. 막상 코드를 읽어보니 플러그인 구조를 도입하는 것이 어렵지 않을 것이라는 생각이 든 것입니다.파이썬 생태계에서는 서로 다른 패키지 사이에서 런타임에 확장 가능한 의존성 주입을 위해 setuptools 시스템이 엔트리 포인트라는 개념을 제공합니다. 예를 들어 국제화 라이브러리인 Babel은 파이썬 이외의 프로그래밍 언어에서도 gettext 문자열을 extract할 수 있게 하기 위해, 확장 가능한 babel.extractors 엔트리 포인트를 노출합니다. 그리고 별도의 템플릿 언어인 Jinja는 해당 템플릿 엔진을 쓸 때 국제화도 대응할 수 있도록, babel.extractors 엔트리 포인트에 Jinja 언어를 해석하는 jinja2.ext.babel_extract를 주입합니다.저는 같은 개념을 활용하여, flake8-import-order가 flake8_import_order.styles라는 엔트리 포인트를 노출하게 하는 패치를 제출했고, 다행히도 업스트림에 받아들여졌습니다.flake8-import-order를 런타임에 확장할 수 있는 구조가 됐으니, flake8-import-order 위에서 스포카의 import 사용 가이드를 구현하는 것은 어렵지 않은 작업이었습니다. 어차피 스포카의 파이썬 코딩 스타일은 대부분 PEP 8을 그대로 따르고 있었고, 따라서 flake8-import-order에 이미 존재하는 스타일 구현에서 몇 부분만 덮어씌우는 것으로 충분했기 때문입니다.위와 같은 장광설 끝에, 그래서 이번에 소개하려고 한 스포카의 파이썬 import 린트 도구는 flake8-import-order-spoqa입니다. 만든지 보름이 지난 뒤에 소개하는 것은, flake8-import-order에 제출한 패치가 포함된 0.12가 PyPI에 릴리스될 때까지 기다려야 했기 때문입니다.사용법은 어렵지 않습니다. pip로 flake8-import-order-spoqa를 설치한 뒤에, flake8 설정에 다음 옵션을 추가하면 됩니다.[flake8]import-order-style = spoqa#스포카 #개발 #개발자 #개발팀 #개발팁 #꿀팁 #인사이트
조회수 9076

왜 SQLite 에서 Realm 으로 옮겼는가?

SQLite 와 Realm잔디 앱은 2015년 중반부터 앱 내에 Offline Caching 기능이 포함되면서 본격적으로 Local-Databae 를 사용하기 시작했습니다.당시에 Realm 과 SQLite 를 검토하는 과정에서 다음과 같은 사유로 Realm 을 포기하였습니다.1.0 이 아직 되지 않은 미성숙된 상태의 라이브러리사용 사례에서 리포팅되는 버그들 (CPU 지원 등)Data 의 상속을 지원하지 않는 문제Robolectric 미지원 (안드로이드 팀 당시 테스트 프레임웍은 Robolectric 이었으며 현재 Android Test Support Library 입니다.)위의 문제로 인해 SQLite 를 선택하였고 여러 SQLite-ORM Library 를 검토한 후 ORMLite 를 선택하였습니다.누구보다 가볍고 빠르게2016년 6월경 앱의 핵심 데이터에 대해 개선작업이 되면서 그에 따라 기존의 Cache Data 로직도 많은 부분이 변경되었습니다. 그에 따라 실시간성으로 DB 를 대상으로 Read-Write 동작이 발생하게 되었습니다. Locking 등에 대한 처리가 되면서 성능에 대한 이슈가 계속적으로 발생할 수 밖에 없었습니다.간헐적인 성능 이슈는 사용자에게 나쁜 UX 로 다가갈 수 있기 때문에 다음과 같은 병목지점들에 대해 성능 향상을 꾀하였습니다.서버와의 통신 향상비지니스 로직 개선내부 DB 로직 향상서버와의 통신 향상병목 지점이 되는 것으로 판단되는 API 를 찾아 원인을 분석하여 개선요청을 서버팀에서 개선할 수 있도록 하였습니다.비지니스 로직 개선불필요한 객체 생성, 비동기로 처리해도 되는 동작들에 대해서는 로직 수정, 최소한의 검증 후에만 앱 실행, 네트워크 동작 최소화, 캐싱 활용 등 다양한 전략을 시도하였습니다.내부 DB 로직 향상SQLite 를 대상으로 빈번한 쿼리 작업을 최소한으로 하기 위해 2~3개의 쿼리로 이루어진 부분에 대해서 최소한의 쿼리만으로 동작하도록 여러 시도를 하였습니다.ORMLite 의 한계점ORMLite 를 대상으로 여러가지 시도를 하였습니다. 쿼리를 최소한으로 하고 1:N, N:M 동작에 대해서 로직 중간에 Query 가 발생하지 않도록 애초에 Join Query 를 하도록 하는 등 여러가지 전략을 시도하였으나 궁극적으로 ORMLite 자체에 대한 성능을 개선하는 것은 불가능하다는 결론이 도출하였습니다.여러 시도를 하였으나 고작 10~20% 정도의 성능향상밖에 없었으며 이는 사용자 관점에서 여전히 느릴 수 있다고 느끼기 충분한 수준이었습니다. 기존에 목표했던 100ms 이하의 쿼리를 기대하기엔 어려운 상황이었습니다.그래서 GreenDAO, Requery 라이브러리를 검토하였습니다.GreenDAO 의 문제점GreenDAO 를 검토하는 과정에서 겪은 가장 큰 문제점은 실제 Object 코드에 GreendDAO 코드가 생성이 붙으면서 유지보수에 큰 걸림돌이 될 수 있다는 것이 예상되었습니다.Requery 의 문제점성능면에서 ORMLite 에 비해서 큰 개선을 가져오지 못했습니다. Requery 는 JPA 를 가장 잘 채용한 것으로 알려져 있지만 그렇다고 SQLite 자체의 성능을 극적으로 개선했다고 보기엔 어려운 부분들이 있었습니다.SQLite vs RealmSQLite 가 가진 자체적인 성능 이슈를 SQLite 기반 라이브러리 범위안에서는 개선할 수 없다는 결론에 도달하였습니다.검토 방법 : 기존의 Object 를 대상으로 ORMLite 와 Realm 을 대상으로 성능을 검토합니다.데이터는 1:N / 1:1 관계가 되어 있는 여러 Object 의 집합으로 구성되어 있다.Database 에서 데이터를 가져올 때는 Eager Loading 방식으로 택한다.Write : 20회, Read : 20회 를 수행했고 그에 대한 평균 성능을 비교한다. SQLiteRealm성능 향상Write4039ms1142ms3.5xRead6010ms2450ms2.5x(Realm 의 벤치마크 정보와 너무 상이하여 재테스트한 결과 수정하였습니다.)위의 비교차트에서 봤듯이 Realm 은 무시무시한 성능이 입증되었습니다.도입 검토시에 Realm 버전은 2.0 이었기 때문에 충분히 신뢰할 수 있을 만큼 성숙되었다고 판단하고 최종적으로 도입을 결정하였습니다.Realm 도입 과정에서 문제점Realm 을 도입한다고 해서 여전히 잠재적인 문제가 해결된 것은 아니었습니다.파악된 다음 문제를 해결 해야 했습니다.Primitive 타입에 대해 Collection 저장을 지원하지 않는다.RealmObject 에 대한 호출 Thread 를 유지해야 한다.상속을 지원하지 않는다.Primitive 타입에 대한 Collection 관리를 해결하기이 문제는 ORMLite 에서 이미 겪었기 때문에 의외로 쉽게 구할 수 있었습니다. long, int 등에 대한 Wrapper 를 만들고 Json Convert 등의 과정에서 Post Processing 과정에서 Wrapper 로 데이터를 이관하도록 처리하였습니다.// example class Data extends RealmObject { private transient List refs; private List refIds; } class RealmLong extends RealmObject { private long value; } RealmObject 에 대한 호출 Thread 분리Realm 은 Object 에 대해 query 후 객체를 받는다 하더라도 실제로 객체 내 데이터르 접근할 때는 다시 Query 로 접근하기 때문에 실제로 Object 전체에 대해서 Eager Loading 방식으로 접근해야 합니다.Jandi 는 싱글톤 객체를 통해 데이터베이스에 접근하며, Background Thread 에서 진행하고 UI Thread 에서 객체 내 변수에 접근해서 UI 에 그리는 작업이 빈번하기 때문에 Thread 독립을 반드시 해야했습니다.Realm 에서는 Eager-Loading 을 지원하고 있습니다. Realm.copyFromObject() 를 사용하면 Return 값이 Eager-Loading 된 Object 가 반환됩니다.단, Realm 의 가장 큰 특징이로 보는 ZeroCopy 를 포기하는 것이기 때문에 신중하게 생각해야 합니다.// example public Chat getChat(long chatId) { return execute((realm) -> { Chat it = realm.where(Chat.class) .equalTo("id", chatId) .findFirst(); if (it != null) { return realm.copyFromRealm(it); } else { return null; } }); } 상속을 지원하지 않는다.가장 큰 문제였는데 해결방법을 찾을 수 없어 결국 상속을 포기하고 모든 Data 를 1개의 Object 에 표현하기로 하였습니다.위의 3가지 문제를 이렇게 해결해서 안드로이드팀에서는 1차적으로 도입을 완료하였습니다.결론현재까지 Realm 전환에 있어서 성공적인 도입으로 판단되어 차후에 다른 데이터에 대해서도 하나씩 DB 이전을 할 예정입니다.Realm 은 이제 충분히 신뢰할 수 있을만큼 성숙되었다고 생각이며 Realm 에서 처음부터 강조하던 성능또한 믿기 어려울 정도로 빨라졌습니다. 더 빠른 Mobile Database 를 원하신다면 Realm 을 적극 추천합니다.#토스랩 #잔디 #JANDI #개발 #개발환경 #업무환경
조회수 2825

리디북스 웹뷰어의 이어보기를 개발하며

최근 리디북스에서는 판타지 연재물을 웹에서 바로 볼 수 있는 기능을 새롭게 선보였습니다.기존에는 별도의 앱을 설치하고 다운로드하는 과정을 거쳐야 했기에 연재물을 보는 사용성이 좋지 않았습니다만, 브라우저에서 바로 볼 수 있는 “웹뷰어” 기능을 제공함으로써 사용성을 높일 수 있었습니다.그리고 여기에 사용성을 더하기 위해 추가된 것이 이어보기 기능입니다. 짧아도 100화 이상, 길게는 1000화가 넘는 연재물에서 다음 화로의 매끄러운 연결은 매우 중요합니다. 혹은 잠시 읽기를 중단했다가 다시 돌아왔을 때, 어디까지 보고 있었는지를 빠르게 알려준다면 호흡을 이어서 작품에 더욱 몰입할 수 있을 것입니다.이어보기가 구현된 모습리디북스에 로그인되어 있다면, 이곳에서 확인하실 수 있습니다.이번 글은 이어보기 기능에 대한 개발 후기입니다. 요구 사항에 따라 여러 저장소 솔루션을 비교해 보았으며 최종적으로 Couchbase를 선택한 이유와 간단한 벤치마크 결과, 그리고 겪었던 문제를 공유합니다.요구 사항기획된 내용을 요약하니 아래와 같습니다.연재물의 가장 마지막에 읽은 화를 알 수 있다.보았던 모든 연재물에서 가장 마지막에 읽은 연재물을 알 수 있다.사용자가 본 모든 연재물 목록을 확인할 수 있다.이를 개발자 용어로 다시 풀어보면 아래와 같습니다.연재물을 읽을 때마다 연재물 ID와 화(episode) 정보를 기록한다.보았던 연재물을 최신순으로 정렬하여 가져온다.선택된 연재물의 마지막으로 읽은 화를 가져온다.목록에서 특정 연재물을 삭제한다.이어보기는 가장 마지막에 읽은 연재물을 기억하기 위해 작품을 열 때마다 해당 정보를 기록해야 합니다. 그런데 수십 화를 연달아서 보는 연재물의 특성상 내가 어디까지 읽었는지를 조회하는 것(read)보다 내가 읽은 연재물을 기록하는 것(write)이 더 많을 것으로 판단했습니다. 즉, 읽기보다 쓰기가 더 많을 것으로 예상했습니다.NoSQL을 쓰자대부분의 연산이 쓰기(write)와 관련된 이상, 어떤 저장공간을 사용할 것인지가 주된 관심사였습니다.특히 RDBMS와 NoSQL 사이에서 어떤 것을 사용할지 많은 고민과 테스트를 했고, 결국 아래와 같은 이유로 NoSQL을 사용하는 것이 적합하다고 판단했습니다.현재 사용 중인 MariaDB를 그대로 사용한다면 마스터에 부담을 줄 수 있다.별도로 MariaDB를 구성하더라도 운영 및 쓰기 분산하기가 여전히 어렵다.반면 NoSQL은 RDBMS 대비 확장(Scale out)이 간편하므로 운영에 대한 부담이 적다.단순 Key-Value 보관 용도면 충분하다.이어보기 데이터는 독립적인 성격을 가지고 있어서 다른 사용자 데이터와 JOIN을 할 필요가 없다.이어보기 데이터는 크리티컬한 트랜잭션이 필요하지 않다.MongoDB vs. Couchbase데이터를 영속적으로 유지해야 한다는 요구 사항을 충족하기 위해, Redis 등의 메모리만 사용하는 NoSQL은 제외했습니다. 물론 디스크에 기록할 수 있지만, 성능이 급감하기 때문에 실용적이지 못 합니다. 또한, 메모리 사이즈에 기반을 두기 때문에 Scale up 비용이 크고, 서비스 확장시 Scale out 빈도가 높습니다.그래서 MongoDB와 Couchbase를 비교 대상으로 했습니다. 둘 다 도큐먼트 기반의 NoSQL이고 확장이 용이합니다. 과거에는 MongoDB가 Write lock 사용에 있어서 문제점이 있었지만, 최근 버전에서는 문제가 되지 않습니다.[1] 둘 다 기업용 서비스 및 충분한 부가 기능들을 제공하므로 선택하기 어려웠지만, 최종적으로 아래와 같은 이유로 Couchbase(CE)를 선택했습니다.1. 이미 사내에서 다른 서비스에 사용되고 있습니다.가장 중요한 요인이었습니다. 더 좋은 솔루션이 있더라도 어디까지나 서버 스택을 늘리는 것 이상의 효용이 있는지를 따져보아야 합니다. 이미 사용하고 있는 솔루션이 있다면, 검증이 되었을 뿐만 아니라 개발 및 운영 경험도 활용할 수 있습니다.2. 이어보기는 복잡한 쿼리(Query)가 필요 없습니다.이어보기에서 사용할 쿼리는 간단하기 때문에 Couchbase의 뷰(View)만으로 충분했습니다.Couchbase, 실제 성능은 어떨까?테스트를 하기 전 우리가 어떤 식으로 사용할 것인지 정리해야 합니다. 애플리케이션 액세스 패턴이나 동시성 문제, 데이터 구조화 등을 파악하고 그에 맞는 테스트를 진행해야 합니다. 이번 이어보기는 쓰기 연산이 보다 많기 때문에 이로 인한 뷰의 인덱싱(Indexing)에 초점을 맞추고 테스트를 진행했습니다.성능을 위협하는 요소들View IndexingCouchbase는 MapReduce를 이용하여 뷰를 제공합니다. MapReduce는 일반적으로 리소스를 많이 소모하는 동작입니다. 그래서 Couchbase는 버킷의 새로 갱신된 데이터만 인덱싱하는 Incremental MapReduce라는 기법을 적용해서 리소스 소모를 줄였다고 합니다.[2] 하지만 해당 작업으로 인한 부하는 여전히 발생합니다.Auto CompactionCouchbase는 데이터와 인덱스를 디스크에 데이터를 저장할 때 파일에 추가하기(Append) 모드로만 쓰기를 수행합니다.[3] 그리고 오래되고 불필요한 데이터들은 추후 한꺼번에 정리하는데, 이는 디스크 쓰기 성능을 최대화하기 위함입니다.그런데 이렇게 추가만 하게 되면 오래된 정보들은 파일의 앞에 쌓이게 됩니다. 그리고 사용하지 않게 된 데이터도 남아있습니다. 이를 주기적으로 정리해서 최적화하는 작업을 Auto Compaction이라고 합니다. 뷰의 인덱스는 디스크에 존재하기 때문에 디스크 작업이 있으면 인덱싱에 영향을 미치게 됩니다.성능 테스트Couchbase는 기본적으로 5,000ms마다 Index를 업데이트합니다.[2] 그리고 데이터를 비동기적으로 응답합니다. 비동기는 응답속도를 빠르게 하지만, 데이터 불일치가 발생할 수 있습니다. 데이터 불일치가 신경 쓰이고 이 시간이 길다고 생각되면, stale 옵션을 지정해서 뷰의 인덱스를 업데이트할 수 있습니다.이어보기는 뷰가 간단하기 때문에 응답시간에 큰 문제가 없을 것으로 예상하고 stale 옵션을 꺼두었습니다. 이 옵션은 뷰를 조회했을 때 버킷의 변경사항에 따라 뷰를 인덱싱하고 데이터를 응답합니다. 하지만 예상한 것과 같이 실제로도 응답시간이 짧은지 확인할 필요가 있습니다. 그래서 다음과 같이 테스트를 진행했습니다.테스트 환경은 아래와 같이 2-tier로 준비하고 요청을 늘려가면서 RPS를 측정했습니다.서버 구성OS: Ubuntu 14.04Application: Couchbase Server (CE) 3.1.3클라이언트 구성클라이언트 1개에서 50개의 세션으로 요청10만 사용자 가정책은 1만개의 책중 랜덤으로 선택됨요청의 70%는 책 읽기(Bucket Write)요청의 30%는 연재물의 마지막에 읽은 책 가져오기(View Read)그래프 분석성능 테스트 주요 지표RPS : Response Per SecondSP : Saturation PointBuckle zone : 시스템 과부하로 인해 내부 자원이 서로 경쟁상태나 적체 상태가 심해지기 때문에 최대 처리량보다 더 떨어지는 경우가 발생함성능테스트 결과그래프를 보면 요청이 늘어남에 따라 RPS가 선형으로 증가하지만, SP인 8,000 RPS에 도달하고 나서 Buckle zone에서 7,000 RPS로 수렴하고 있습니다. 물론 1개의 클라이언트에서 세션을 생성해서 테스트를 진행했기 때문에 서버의 성능 부족이 아닌 클라이언트의 병목 현상이 원인일 수 있습니다. 또한 JMeter나 다른 부하 테스트 툴을 사용하지 않고 간략하게 만든 테스트 툴을 사용하였기 때문에 수치가 부정확할 수 있습니다. 그러나 어디에서 병목이 있었든 현재 이 이상의 성능이 필요하지 않기 때문에 테스트 결과에 만족할 수 있었습니다.이어보기 배포 후모바일 브라우저 캐시 문제이어보기 기능을 배포하자마자 당일 저녁 이슈 하나를 접수했습니다. 아이패드와 PC를 번갈아 이용할 경우 이어보기 데이터가 맞지 않다는 것이었습니다.데이터를 쌓을 때 모든 이력을 기록하지는 않았지만, 다행히도 Couchbase에 이용기기와 시간은 기록하였기 때문에 이를 바탕으로 디버깅을 할 수 있었습니다. (서비스 초기라 할지라도 최대한 많은 이력을 남기는 것이 중요함을 다시 느꼈습니다)원인은 아이패드의 멀티태스킹으로 인한 캐시 소멸이었습니다. 아이패드 브라우저의 캐시가 소멸되면서 마지막으로 열어두었던 페이지가 강제적으로 리로딩되었고, 이때 의도치 않게 마지막 위치 정보가 덮어씌워진 것입니다.이 문제는 기술적으로 해결이 쉽지 않아 결국 기획을 수정하게 되었습니다. 사용자가 해당 책을 읽었다고 판단하는 기준이 “페이지를 열어본 즉시”였다면, 이를 “페이지를 열고 수 초 이상을 유지”하는 것으로 기준을 변경하였습니다. 물론 근본적인 해결책은 아니었지만, 실제 사용에는 지장이 없는 합리적인 해결책이라고 생각합니다.Key 구조의 변경 및 동시성 문제Couchbase는 높은 성능을 위해 메타데이터(Key + @)를 모두 메모리에 적재하는 특징이 있어서, Document 하나가 평균 350Byte를 차지하고 있었습니다. 따라서 현재 상태로 1000만개의 데이터를 저장할 경우 최소 3.5G의 메모리를, 2개의 사본(Replica)를 유지할 경우 약 10.5G의 메모리를 사용하게 될 것으로 예상되었고 이는 큰 부담으로 다가왔습니다.처음에는 단순히 “사용자ID_연재물ID” 형태의 Key를 사용하였지만, 보다 빠르게 증가할 것으로 예상되는 것은 사용자보다 연재물 이었으므로 아래와 같이 Key값을 변경하여 메모리 사용량을 크게 줄였습니다.// U_id : S_id 조합을 사용하면 Key가 엄청 많아진다. // 그래서 사용자당 Key를 100개로 제한하도록 한다. Count = 100 Key = '사용자ID' + ('연재물ID' % Count) 그런데 이렇게 Key 구조를 변경하였더니, 간단한 업데이트 동작임에도 불구하고 정상적으로 수행되지 않는 경우가 빈번하게 발생하였습니다. 이유는 낙관적 동시성(Optimistic concurrency) 모델의 특징 때문이었는데, Couchbase는 명시적인 잠금 이외에도 “Check and Set(CAS)”이라는 기능을 제공하고 있었습니다.공식 문서의 예제를 참고하여 아래와 같이 로직을 수정한 뒤로는 다행히도 동시성 문제가 아직까지 발생하지 않고 있습니다.boolean updateUsingCas(key, value) {  for (tryCount = 0; tryCount < MAX>    orgValue, cas = getValueAndCas(key)           // Update the original value.     // newValue = ... if setValueWithCas(key, newValue, cas)      return SUCCESS sleep(0.1) // 부하를 줄이기 위해  }  return FAIL } 맺으며동작하는 서비스에 새로운 기능을 추가한다는 것은 어려운 일입니다. 특히 새로운 데이터 스토리지를 필요로 하는 일이라면 더더욱 어렵다고 생각합니다. 그리고 그럴 때일수록 설계에 많은 시간을 들여야 한다는 것을 느꼈습니다. 설계 초기에는 RDBMS의 샤딩까지 고려하였지만, 요구 사항을 구체화할수록 단순 Key-Value로도 같은 문제를 해결할 수 있음을 깨달았기 때문입니다.또한, 서비스 개발에 있어서 어려운 문제를 마주했을 때 기술적으로만 접근할 것이 아니라 고객이 정말 원하는 것이 무엇인지를 고민하여 기획적으로 해결하는 능력도 중요하다는 것을 실감하였습니다.마지막으로 Couchbase는 현재로서도 꽤 좋고 앞으로도 많은 발전이 기대되는 NoSQL입니다. 도입을 고민하시던 분들께 조금이라도 도움이 되었기를 바랍니다.참고자료[1] MongoDB - Concurrency[2] Couchbase - Views Operations[3] Couchbase - File write#리디북스 #개발 #개발자 #서버개발 #서비스개발 #고객중심 #기능개발 #Couchbase #인사이트 #개발후기
조회수 1048

컴공생의 AI 스쿨 필기 노트 ⑥인공신경망

인공지능, 머신러닝, 딥러닝이번 6주차 AI 스쿨에서는 딥러닝의 가장 기초적인 부분을 배웠어요. 인공지능과 머신러닝, 그리고 딥러닝을 많이 들어보긴 했는데 이 셋의 차이는 무엇일까요?인공지능이라는 개념은 1956년 미국 다트머스 대학에 있던 존 매카시 교수가 개최한 다트머스 회의에서 처음 등장했고 최근 몇 년 사이 폭발적으로 성장하고 있는 중이에요. 1956년 당시 인공지능의 선구자들이 꿈꾼 것은 최종적으로 '인간의 지능과 유사한 특성을 가진 복잡한 컴퓨터'를 제작하는 것이었죠. 이렇듯 인간의 감각, 사고력을 지닌 채 인간처럼 생각하는 것을 인공지능이라고 해요.인공지능은 위 세 개념 중 가장 큰 개념이에요. 머신러닝은 일반적으로 사람들이 이야기하는 인공지능, 즉 머신러닝에 기반한 인공지능을 말하는데요. 인공지능을 구현하는 구체적인 접근 방식이라고 할 수 있어요.머신러닝에는 linear regression, logistic regression 등의 여러 알고리즘이 있는데요.  그중 학습에 사용되는 모델을 딥러닝이라고 해요. 즉 딥러닝은 완전한 머신러닝을 실현하는 기능이라고 볼 수 있어요. 이러한 딥러닝의 등장으로 인해 머신러닝의 실용성은 강화됐고 인공지능의 영역은 확장됐다고 해요.인공 신경망(Neural Network)오늘 수업의 핵심인 인공 신경망(Neural Network)은 어떻게 만들어졌을까요?뉴런의 구조이것은 우리 몸에 존재하는 신경세포인 뉴런이에요. 뉴런은 전기적인 신호를 전달하는 특이한 세포인데 뇌는 뉴런의 집합체라고 할 수 있어요. 뉴런은 수상 돌기(dendrites, input)에서 신호를 받아들이고 축색 돌기(axon terminals, output)에서 신호를 전송해요. 신호가 전달되기 위해서는 일정 기준(임곗값 : threshold) 이상의 전기 신호가 존재해야 해요. 이 신호들의 전달을 통해서 정보를 전송하고 저장해요.이런 신경세포로 이뤄진 신경망 시스템을 위의 그림처럼 표현할 수 있어요. 이처럼 인공신경망은 사람 몸속의 신경들을 모방해서 만든 시스템이에요.위의 식처럼 뉴런을 수학적으로 표현할 수 있는데요. 입력 값들(X)에 가중치를 두어(W) 값 (f(x))을 구하고 그 값과 임계치와의 관계를 활성함수(active function)*로 판단하여 결괏값을 출력하게 돼요.( * 활성함수는 인공신경망의 개별 뉴런에 들어오는 입력신호의 총합을 출력 신호로 변환하는 함수로 비선형 함수(non-linear function)를 씁니다.**)이때 활성함수는 뉴런에서 임곗값을 넘었을 때만 출력하는 부분을 표현한 것으로 sigmoid 함수, Relu 함수 등 여러 방식이 있어요.인공 신경망의 구조인공 신경망 구조는 위의 그림처럼 나타낼 수 있어요. 인공 신경망 구조는 입력층(input layer), 은닉층(hidden layer), 출력층(output layer)으로 이루어져 있어요. 위의 그림은 그 구조에 의해 3-layer Neural Network 또는 2-hidden-layer Neural Network라 부를 수 있는데요. 3-layer Neural Network는 3개의 층을 가지는 인공신경망이라는 뜻이고, 위 그림에서는 은닉층1, 은닉층2, 출력층이 해당되겠죠. 인공 신경망에 입력층과 출력층은 항상 존재하기 때문에 은닉층의 개수만을 고려하여 부르기도 해요. 위 그림에서는 은닉층이 2개 있기 때문에 2-hidden-layer Neural Network라고 부를 수 있어요. 전파(Propagation)이번에는 실제로 학습하는 과정인 인공신경망의 알고리즘에 대해 알아볼게요. 순전파(Forward Propagation)와 역전파(Backward Propagation)가 있어요.순전파는 입력값에서 출력값으로 가중치를 업데이트를 하고 활성화 함수를 통해서 결괏값을 가져오는 것을 말해요. 인공신경망이 설계된 정방향(input → hidden → output)으로 데이터가 흘러가기 때문에 순전파라고 해요. 말 그대로 입력값을 앞쪽으로 보낸다고 생각하면 돼요.역전파는 출력값을 통해서 역으로 입력값 방향으로 오차를 다시 보내며 가중치를 재 업데이트하는 것이에요. 출력값에서 계산된 오차에 가중치를 사용해 바로 이전 층의 뉴런들이 얼마나 오차에 영향을 미쳤는지 계산해요. 결과에 영향을 많이 미친 뉴런일수록 더 많은 오차를 돌려줘요.개념을 코드에 적용하기NumPy로 구현된 Neural Network(이하 NN)의 작동 방법을 살펴볼게요. NN은 총 2개의 레이어로 이루어져 있어요. 이번 과제에서는 입력 x가 들어왔을 때, 레이블에 따라 예측치가 1로 수렴하는지 알 수 있는 인공신경망을 구현하는 것이 목적이에요.Neural Network다음 코드는 simpleNueralNet() 클래스를 나타내는 코드예요. simpleNueralNet()은 두 개의 레이어로 구성된 NN이에요.N, D_in, H, D_out = 64, 1000, 100, 10- N은 batch size, 즉 한 번에 처리할 수 있는 데이터 사이즈를 말해요. - D_in은 입력값 차원에 쓰이는 값으로 1000을 할당해요.- H는 은닉층 차원에 쓰이는 값으로 100을 할당해요.- D_out은 출력값 차원에 쓰이는 값으로 10을 할당해요.아래 코드를 통해서 랜덤 입력과 출력 데이터를 만들어요.x = np.zeros((N, D_in))     #1  x.fill(0.025)                         #2y = np.ones((N, D_out))   #31. np.zeros() 함수를 사용하여 (64, 1000)의 차원을 갖는 0인 행렬을 만들어요.2. fill() 함수를 통해 x 안의 모든 0을 0.025로 바꿔요.3. np.zeros() 함수를 사용해 (64, 10)의 차원을 갖는 0인 행렬을 만들어요.아래는 랜덤 값을 갖는 가중치(weight)들을 초기화하는 코드예요. w1은 1000, 100 차원의 랜덤 값을 갖는 행렬로, w2는 100, 10차원의 랜덤 값을 갖는 행렬로 만들어요.w1 = np.random.randn(D_in, H)   w2 = np.random.randn(H, D_out)learning_rate는 학습 속도를 의미해요. 아래는 단계별로 움직이는 학습 속도를 1e-6으로 정의하는 코드예요.learning_rate = 1e-6이제 5000번의 순전파를 할 거예요.h = x.dot(w1)     h_relu = relu(h)  y_pred = h_relu.dot(w2)h는 은닉층에 전달할 값이에요. x와 w1을 행렬곱한 값을 가져요.활성 함수 relu에 h를 넣어서 계산해요.y_pred는 예상되는 출력값이에요. relu로 계산된 h_relu와 가중치 w2를 행렬곱한 값이에요.아래는 순전파로 얻은 y_pred에서 진짜 y를 뺀 값을 제곱한 것의 합을 구해 손실 값(loss)을 구하는 코드예요. print(loss) 코드로 손실을 확인할 수 있어요.loss = np.square(y_pred - y).sum()순전파 후 역전파를 이용해 손실에 대한 가중치 w1과 w2의 gradients를 계산하여 update 할 거예요.grad_y_pred = 2.0 * (y_pred - y)              #1grad_w2 = h_relu.T.dot(grad_y_pred)    #2grad_h_relu = grad_y_pred.dot(w2.T)    #3grad_h = grad_h_relu.copy()                    #4grad_h[h < 0>grad_w1 = x.T.dot(grad_h)                         #61. 순전파로 얻은 y_pred에서 진짜 y값을 뺀 값에 2.0을 곱하여 grad_y_pred를 구해요.2. grad_w2는 순전파에서 y_pred = h_relu.dot(w2) 식을 사용했으므로  h_relu.T.dot(grad_y_pred) 로 구해요. h_relu가 반대로 곱해지기 때문에 T를 이용하여 shape을 바꿔줘야 해요.3. grad_h_relu는 방금 위에서 사용한 y_pred = h_relu.dot(w2)을 이용하여 grad_y_pred.dot(w2.T) 로 구해요. 이번에는 w2 shape의 반대를 grad_y_pred에 곱해줘야 해요.4. 순전파에서 h_relu = relu(h)였는데요. 역전파에선 grad_h와 grad_h_relu가 같기 때문에 copy() 함수로 그대로 복사해요!5. 0보다 작은 h는 0으로 만들어요.6. 가중치 w1의 값인 grad_w1은 순전파의 h = x.dot(w1)와 반대로 x.T.doT(grad_h) 곱해요. 역전파는 순전파의 식에서 이항한다고 생각하면 조금 더 쉽게 이해할 수 있을 것 같아요. 이항한 값은 .T를 붙여서 표현한다고 생각하면 될 것 같아요.아래는 가중치를 재업데이트하는 코드예요.w1 -= learning_rate * grad_w1 w2 -= learning_rate * grad_w2 과제1을 통하여 NN을 알아보았는데요. 복잡하지만 순전파와 역전파를 알고 있다면 많이 어렵지는 않은 것 같아요. 과제 2는 정확도를 95% 이상으로 만들어보는 과제인데 여러 가지 방법을 동원해서 풀어보는데 생각보다 쉽지가 않아요. ^^;이번 수업시간에 배운 딥러닝의 기초인 신경망은 굉장히 중요한 개념이라고 해요. 신경망을 기반으로 한 딥러닝을 강화하여 안면인식을 가능하게 하거나 저장된 데이터를 정확하게 인식하고 분류할 수 있는 기기들도 만들어지고 있어요. 이처럼 AI는 점진적으로 활용 범위가 넓어지고 있기 때문에 이 수업을 통해 쌓은 AI 지식을 마음껏 뽐낼 수 있는 날이 왔으면 좋겠어요!** 왜 활성함수로 비선형 함수를 쓸까요?선형함수인 h(x)=cx를 활성함수로 사용한 3-layer 네트워크를 생각해봐요. 이를 식으로 나타내면 y(x) = h(h(h(x)))가 되는데요.  이는 y(x) = c3x와 같습니다.  이렇게 활성함수로 선형함수를 사용하면 은닉층을 사용하는 이점이 없어요.* 이 글은 AI스쿨 - 인공지능 R&D 실무자 양성과정 6주차 수업에 대해 수강생 최유진님이 작성하신 수업 후기입니다.
조회수 1823

소프트웨어 개발자에게 성공이란...

소프트웨어 개발자들이 생각하는 ‘성공’이라는 단어와 키워드에는 어떤 것들의 의미를 포함하고 있을까? 한편으로는 단편적이고 획일적인 ‘성공’이라는 단어에 너무 많은 개발자들이 매몰되어 있는 것 아닌가 하는 생각을 해본다. 필자 스스로 실무경력 20년을 넘겨서 소프트웨어 개발을 하고 있는 경험을 바탕으로 주변의 성공한 개발자들에 대해서 혼자 생각해 보았다.일반적으로 의미의 ‘성공’이라는 것이 무엇을 의미하는 것인가에 대한 정의는 이번 칼럼의 말미에서 이야기하도록 하자. 정말 많은지 모를 대한민국에서 성공한 개발회사나 개발된 서비스들을 살펴보는 것부터 시작을 하는 것이 정답인지는 필자도 잘 모르겠다. 성공적인 서비스나 소프트웨어, 프로그램은 세상에 선보인다는 것. 그러한 것을 만들어낸 순수한 아이디어나 원천기술로 무장한 기술로 축적되었고, 그 아이디어를  뛰어넘어, 새로운 기술이라고 할 수 있는 것을 보유한 제품이나 상품들이 얼마나 되는지에 대해서부터 냉정하게 필자는 잘 모르겠다라고 먼저 인지하고 넘어가자. 아니, 다시 말하자면, 냉정하게 국내에서 그런 것을 본적이 별로 없는  듯하다.더욱더 삐딱하게 이야기하자면, 국내에서 성공한 개발 서비스들은 대부분 아류작이거나 남의 아이디어를 도용한 제품과 서비스들이 대부분이 아닌가라고 생각한다. 심지어는 특정 솔루션 시장은 오픈소스를 그대로 제품에 반영해 두고서는 자신의 제품인 것처럼 위장하는 사례까지 보이고 있으니, 과연 대한민국 소프트웨어 시장은 과연 얼마나 ‘성공’이라는 키워드를 그대로 사용해도 되는지에 대해서 매우 의문시된다.(물론, 필자의 삐딱한 시선에서만 그렇게 보일지도 모른다.)대한민국의 소프트웨어 시장에서 1위를 지키고 있다고 하는 서비스와 제품들이 되려면 어떻게 해야 하는가?. 삐딱하게 이야기하자면, 오로지, 대한민국에서 성공한 개발회사나 개발자가 되려면, 창의적인 아이디어나, 독특한 아이디어로 무장하는 승부수를 던지기 보다는, 해외의 서비스 중에 알차고, 괜찮은 것들에 대해서 관심을 가지는 것이 중요하다고 생각한다. ( 그래서, 영어공부를 잘해야 하는지도 모르겠다. )필자가, 대기업과 신규사업기획을 할 때에 작업하는 내용을 보고서는 경악을 금치 못했던 경험을 한적이 있다. 정말 상당한 컨설팅 금액( 수십억을 넘긴 비용 )을 지불해서, 대기업이 유명한 컨설팅업체를 통해서 신규사업에 대한 기획과 아이디어에 대한 컨설팅을 받는 것에 전문가의 한 사람의 참여했었다. 그런데, 그 중요한 작업의 모티브는 해외에서 이미 성공적으로 안착한 서비스에 대한 분석과, 한국에서의 서비스 시에 벌어질 일에 대해서 예측을 하는 일을 하고 있었다는 점이다. 새로운 아이디어가 아니라는 점이다.물론, 성공한 서비스를 도입해서, 로컬 화한다는 것 또한 매우 어려운 일이라고 생각하지만, 대부분의 새로운 기획이나 신규 서비스에 대한 작업들의 대부분을 이런 식으로 진행한다는 이야기를 들었을 때에 받은 충격은 정말 놀라운 경험이었다, 물론, 지나고 나서 생각해보니, 그렇게 놀랄만한 경험도 아니었는지 모르겠다. 대부분의 대기업들이 이런 식으로 한다는 이야기를 듣고 더 놀라기는 했지만. 물론, 이렇게 로컬화 한다는 것 자체도 대단한 도전이고 어려운 점이라는 것은 인정한다고 하지만, 이런 로컬화와 아류작에 대해서 비판적인 시야를 가진 필자의 생각은 그렇다.성공한 서비스들은 대부분 아류작들이다?냉정하게 국내에서 성공한 대부분의 서비스들은 아류작들이고, 복제본들이고, 독창적인 아이디어보다는 해외 서비스를 대부분 국내에 안착한 서비스라고 생각한다. 심지어 독창적인 mp3 플레이어마저도, 아이팟의 생태계가 한층 더 발전적인 시장을 창출했으니, 국내에서 만들어진 디지털적인 요소들 중에 독창적인 것이 얼마나 있는가?필자는 생각한다. 예술에 있어서 복제와 창작의 차이는 매우 크다는 것을. 물론, 소프트웨어 개발이 이런 예술에 비견될 정도의 가치를 부여해서 그런 것 만은 아니다. 소프트웨어 개발은 아이디어와 구현하고자 하는 추진력과 열정이 결합되어져서 만들어지는 최고의 가치 구현을 위한 세계이기 때문에 그렇게 생각할 뿐이다.필자가 좋아하는 만화 중에 ‘맛의 달인’이라는 만화에 나온 표현을 그대로 옮기자면 다음과 같은 장면이 나온다. 프랑스의 유명한 요리를 그대로 일본에서 구현하지만, 그 요리에 대한 평가는 ‘프랑스의 요리를 그대로 구현한 요리이다’. ‘매우 아름답지만 최저의 요리’라는 평가를 받는다. 그러한 최저의 요리라는 평가를 받은 이유는 ‘로컬화 한다는 것은 실정에 맞게 고치고, 연구 개발한 맛이라면 완벽하겠지만. 너무도 프랑스 요리와 똑같이 만든 것은 처절한 아류라는 점이다. 지금 먹은 요리에는 프랑스 요리사의 모습이 그대로 남아있다는 점. 원형이 프랑스의 것을 그대로 답습했다는 것.오리지널을 복사했다는 냉정한 평가는 정말 명확하다. 요즘 가장 국내에서 최근에 성공한 서비스를 이야기한다면, 카카오톡과 애니팡을 예로 들 수 있겠다. 다른 사람들은 어떻게 평가할지 모르지만, 정말 대단한 성공을 가진 것은 사실이다. 하지만, 둘 다 원형을 그대로 복사했을 뿐, 새로운 것은 아무것도 없다는 점이다. 아니, 오히려. 기존의 원형을 대한민국의 안 좋은 통신사의 서비스와 결합한 케이스라고 평가를 해야 정확하지 않을까 한다. 원형을 오히려 퇴보시킨 서비스라고 평가하고 싶다.카카오톡은 WatsApp을 그대로 복제했다. 대표적으로 등록되어진 전화번호로 연계하는 원형의 아이디어를 그대로 받아들였다. 하지만, 카카오톡의 새로운 신규 비즈니스 모델인 게임센터는 자체적인 생태계를 만들어서 통제하려 하는 기존의 통신사의 방식과 그다지 차이가 없다고 보인다. 뭐, 돈을 벌어야 하는 기업의 입장을 반대하는 것이 아니다. 단지, 필자의 삐딱한 시선으로는 진보를 위한 선택이 아니라, 퇴보를 위한 선택이었다는 점이 불편할 뿐이다.애니팡도 마찬가지이다. 기존의 게임방식을 그대로 복제했다. 그리고, ‘하트’라는 이름으로 무분별한 ‘스팸’을 활성화해서, 기존 통신사들이 SMS에서 얻어들이는 대량 SMS 발송을 통한 이익을, 그대로 실현한 점이다.물론, 카카오톡이나 애니팡의 ‘이익 실현 구조’는 매우 성공적으로 국내에 론칭한 것은 사실이고, 이러한 구조로 ‘돈’을 벌어야 한다는 점이 매우 안타까울 뿐이다. 개인적으로는 ‘국내’에서는 어느 정도 ‘돈을 버는 성공은’할 수 있지만, 해외에서까지 성공적으로 론칭할 것인지는 조금 의심스럽다. ( 어차피, ‘돈’을 벌면 성공이라는 관점으로는 매우 대성공이다. )넥슨의 카트라이더와 마리오 카드와 같이 일일이 나열하기에는 너무도 많은 사례들이 있어서 굳이 더 나열하지 않겠다.다만. 정말 중요한 것은 복사보다는 진짜가 더 좋다는 점이다. 가령, 오리지널이 존재하는 영역이나 예술과 같은 고부가가치의 영역에서는 ‘화가나 작가가 다른 사람의 작품을 흉내내면  웃음거리밖에 되지 않는다’는 점을 이야기하고 싶다. 필자 개인적으로는 ‘그런 웃음거리를 통한 수익실현’을 그렇게 높게 평가하고 싶지 않기 때문이다.대표적으로 통신사는 ‘스팸’과 ‘보이스 피싱’을 해결하지 못하는가? 에 대해서 필자는 그렇게 생각한다. ‘대량 SMS수입’을 포기하지 못하고, ‘전화번호를 통한 대량 통화의 수익’을 포기하지 못하는 구조적인 문제 때문에 그렇다고 생각한다.과거에 문제가 된 iOS6로 업데이트가 되면서 SKT 아이폰4S에서 발생한 전화번호 호출의 문제, ‘112 신고가 안 되는 아이폰’이라는 기사와 사건에 대한 문제의 근본적인 원인은 SKT가 국제표준 방식을 따르지 않아서 발생한 문제라는 것을 모르는 사람들이 정말 많다. 이 문제를 더 파고들어가면, 부당한 SMS수입을 얻고 있는 국내 통신사들의 부도덕한 점도 드러난다. 2003년 이후 3G 서비스(WCDMA)가 도입되었지만, 문자 메시지 국제표준이 기존의 80 byte에서 140 byte로 늘어났지만, 정작 통신사들은 국제표준규격을 지키지 않으면서 연간 수백억의 이익을 부당하게 얻어냈다. 다만. 아이폰4s 출시 당시 KT는 140바이트를 맞추었지만, SKT는 아직도 80 byte였다는 점을 예로 들고 싶다.국제표준을 따르거나, 해외의 서비스가 ‘돈’이 되는 것에는 빠르지만, ‘돈’이 안 되는 기준에는 미온적이고, 대처가 느린 것에 대해서는 참으로 훌룡(?)한 성공적인 방법이라고 평가를 굳이 필자와 같은 주변 사람이 할 필요가 있을까 한다. 그런 훌륭한 평가는 비싼 컨설팅 비용을 지불한 뛰어난 전문가들이 할 것이기 때문에...내 주변에 성공한 개발자와 성공한 벤처 사업가...성공한 개발자. 고급 승용차를 몰고, 출근하는 개발자의 모습을 본다면, 성공한 개발자의 향기를 느낄 수 있을까? 물론, 일반적으로 그럴 수 있다고 생각한다.자본주의 사회에서 ‘돈’은 그 사람을 평가하는 가장 기본적인 ‘수단’이기 때문이다. 성공하지 못한 필자는 아니지만, 필자 주변에는 고급 승용차인 BMW나 벤츠를 직접 몰고 다니는 성공한 개발자들이 여럿 있다. 그리고, 상당히 많다. 사업을 하는 사람으로부터, 프리랜서인 사람까지 매우 다양하다.분명, 그들은, 자신만의 서비스와 제품을 실현하였고, 시장에서도 안정적인 자신만의 브랜드를 확립하였고, 후배들로 존경을 받고 있으며, 직원들에게 비전과 꿈을 주고 있으며, 새로운 기술과 시장에 대해서 언제나 도전하고 있는 사람들이 있다.그들은 충분히 ‘성공’한 사람들이다.‘복제’와 ‘아류작’이 아니더라도. 독특한 자신들만의 서비스와 제품을 구현하여 성공한 개발자들이 분명 존재한다.그들의 성공요인을 주변의 사람으로서 살펴본다면, 몇 가지의 요인이 있다고 정의할 수 있다. 그것들을 필자의 주관적인 생각으로 정리해보면, 크게 4가지 정도로 정리할 수 있다고 본다.하나. 그들은 뛰어난 개발자는 아니었다.그들은 아주 탁월한 능력을 소유한 개발자들은 아니었다는 점이다. 그리고, 아주 뛰어난 학벌을 가진 개발자들도 아니었다. 개발자 동호회에서 만난 친구도 있고, 직장생활이나 사회생활에서 만난 사람도 있었지만. 그들은 아주 탁월한 재능을 지녔거나, 엄청난 코딩능력, 뛰어난 직관을 지닌 사람만은 아니었다.순수한 개발 능력만 놓고 본다면, 오히려, 뒤처지는 개발자들이었는지도 모른다. 하지만, 뛰어난 개발자들이나 아이디어를 가진 사람들과 친하게 지냈으며, 그들의 도움을 자연스럽게 얻어내는 소통의 달인은 아니었지만, 개발자 커뮤니티에 매우 즐겁게 활동을 하던 사람들이었다.둘. 그들은 우직하지만, 묵묵하게 자신의 상품과 아이디어를 다듬었다.그들은 하나의 아이디어가 실현되는 것을 쉽게 포기하지 않았다. 사업을 하기 전에는 그 아이디어를 실현하기 위해서 애썼고, 속한 회사가 아이디어에 대해서 낮은 평가를 하는 것에 대해서도 크게 실망하지 않았다. 오히려, 반대를 해도 해당 서비스와 제품, 기술에 대한 애정이 정말 높았으며, 그것을 실현하려고 매우 애썼다.처음에는 언제나 소프트웨어는 단순한 것부터 시작한다.그 단순한 것을 꾸준하게 다듬고, 소프트웨어에서 제품으로 다듬어서 시장에서 가치를 인정받을 수 있도록 수년 이상을 투자하고 노력해야만 얻어진다. 그것은 스티브 잡스도 똑같았다. iOS는 하루 이틀 만에 나온 소프트웨어가 아니기 때문이다.심지어, 몇 년 동안 밥을 굶더라도, 자신이 생각하는 가치를 실현하기 위해서 포기하지 않고 도전했던 우직한 도전이 오히려 성공을 만들어 내었다. 분명, 훌륭한 소프트웨어는 뛰어난 기술로 만들어지는 것만은 아니다는 것을 요 근래에서야 필자도 느낀다.필요한 가치가 적정한 가격에 구현되어진 것이 정말 필요하다는 점이다. 뛰어난 기술이 뛰어난 제품을 만드는 것이 아니라, 뛰어난 제품이 뛰어난 기술을 만든다는 것이다. 그것이 사용자들로 하여금, 또 다른 가치를 얻을 수 있는 기능을 제공한다는 것에 대해서 굳이 설명하지 않더라도, 그들은 그 아이디어와 생각을 실현하기 위해서 자신만의 길을 걸었다.정말 우직할 정도로... 필자 주변의 그들은, 몇 년을 일 년에 몇백만 원을 벌더라도, 그 꿈을 포기하지 않았다.셋. 시장과 세상의 시선을 그렇게 두려워하지 않았다. 자신의 ‘가치’와 ‘비전’을 실현했다.자신의 아이디어와 자신의 서비스, 제품을 지키기 위해서 약간의 주변 사람들에게 욕을  얻어먹는 것을  두려워하지 않는다. 필자가 아는 어떤 기업은 시장에서는 냉혈안이라는 말도 듣고, 불법 복제된 제품에 대해서는 가차 없는 소송도 불사하는 어떤 기업을 알고 있다. 하지만, 그 회사와 그 사장에 대해서 필자는 비난하지 않는다. 왜냐하면, 그는 기업 내부의 직원들에게는 절대 급여를 밀리지 않고, 야근을 시키지 않는 최고의 사장이었기 때문이다.시장과 타인에게는 가차 없지만, 자신이 생각한 비전을 실현한 회사를 만들기 위해서 언제나 최선을 다하는 사람이었을 뿐이다. 그리고, 자기 것을 지키기 위해서 애를 썼고, 직원들과의 거리도 언제나 적절하게 유지했다. 냉정하게 기업과 사업이라는 것은 자선사업이 아니라는 것을 잘 알고 있었다. 충분하게 돈을 벌고, 외제 승용차를 사장은 타고 다니지만 ( 외제 승용차를 타는 것도, 대한민국은 간단하다. 법인세를 충분하게 낼 정도로 수익이 생기면, 그 수익으로 차를 리스해서 타면 간단하다는 대한민국의 세법 구조 때문이다. ), 모든 직원들에게 그 이익을 100% 나누어주지는 않는다. 직원은 직원일 뿐이니까.그들은 회사의 재정이 힘들어지면 소속된 직원을 힘들기 전에 내보낼 줄도 알고, 필요하다면... 해고도 그리 어렵지 않게 결정하는 사람도 있다, 영업기밀을  들고나간 직원과 소송도 불사했다. 차라리, 친구와 따로 술을  마실지언정, 직원들과의 ‘관계’는 냉정하고 쿨한 관계를 유지했다. (물론, 그렇지만. 인간관계가 깨어지는 것을 매우 괴로워하는 사람들이다. 다만, 아래 직원들에게 속시원히 이야기를 못할 뿐이다. )넷. 필요한 기술자나 기술은 기필코 얻으려 노력했다.그들은 자신이 부족한 점을 잘 이해하고 있었다. 부족한 것을 오히려, 더 널리, 많이 이야기를 하였다. 그리고, 그것을 커버하기 위해서 매우 많은 노력을 한다. 다 잘하고자 하는 팔방미인이 되는 것이 아니라, 자신이 부족한 점을, 자신이 가장 잘하는 것으로 커버하려 애쓴 것이다. 전문적인 기술을 소유한 사람에게 도움 요청하는 것을 부끄러워하지 않고, 도와준 사람에게 충분한 대우나 접대를 잊지 않았다. 그래서, 그들이 도와달라고 하면, 주변의 전문가들이 아낌없이 그를 도와준다.그 이외에서 그들은 그렇게 ‘성실’하게 일하는 친구들은 아니었다. 실제, 사장이었던 그들이 직원의 입장으로 회사를 다닐 때에는 근태 문제로 지적을 받은 친구들도 꽤 많다는 점이다. 아마도, 사업이나 자신이 좋아하는 일을 하는 것과, 어떤 일이 주어진 상태에서 일을 하는 것은 분명 다른 지도 모르겠다. 직원일 때에 불성실하지만, 자신의 일을 할 때에 성실한 것은 전혀 상관관계가 없어 보인다. 한편으로는 ‘사장’이나 ‘자신의 일’을 하는 사람의 경우에는 특별하게 ‘근무시간’이라는 것 자체는 큰 의미가 없다는 점이 더 정답일 것이다. 하여간, 그들은 성공한 개발자들이고, 성공한 기업인이 되어 있었다. 자신만의 제품이나 서비스를 만들면 자연스럽게 ‘사장’이 되어버리는 것이 소프트웨어 업계의 현실인 듯하다.그렇다면, 대한민국에서 ‘성공’이란 ‘돈’을 의미하는가?강남의 최고급 아파트와 외제 승용차가 성공을 의미할까?자신의 뛰어난 기술력으로 커뮤니티에서 인정받고, 유명해진 명예를 얻는 것이 성공을 의미할까? 다른 사회현상을 생각하면서 다시 한번 비교해보자.요즘 개발자들도 오디션 프로에 영향을 받은 듯하다. 요즘 연예계 지망자들이나 배우나, 가수를 꿈꾸는 친구들이 선배나 멘토들에게 묻는 것이 언제나 똑같다고 한다.그것은 ‘빠르게 성공’하고 ‘빠르게 명예’를 얻는 방법이 무엇이냐 묻는 것이다.어렵고 복잡하고, 길게 걸리는 방법은 무시하고, 오디션 프로에서 1등을 해서, 빠르게 성공하는 방법만을 생각한다고 한다.물론, 그 방법도 있을 것이다.소프트웨어의 세계에도 똑같은 방법이 있다. 대표적인 방법이 유명대학을 가서, S 멤버쉽이 되고, 대기업에 입사해서 경력을 쌓은 다음, 해외의 서비스를 적당하게 분석하다가, 성공적으로 론칭한 서비스를 재빠르게 국내에 도입해서 성공에 이르게 하는 방법이 아마도 가장 빠른 방법일 수 있겠다.물론, 이 방법으로 ‘성공’을 쟁취하려 하는 개발자라고 하더라도. 비난하지 않는다.분명, 그 길은 대다수 ‘성공’이라고 부른다. 하지만, 그 길을 선택하고 집중하는 것 또한 매우 어렵고 힘든 길이다. 선택한다고 얻을 수 있는 길도 아니다.가령, 이 글을 읽는 독자가 학생이라면. 가장 먼저 명문대학을 가는 것부터 시작해야 할 테니, 당장, 이 내용을 덮어버리고, 국영수를 공부하는 것에 몰두해야 하기 때문이다.사실, 가장 넓게 알려진 성공으로 가는 길은 가장 가기 어려운 길인지도 모른다. 경쟁이란 정말 어렵고 힘들 것이라는 것을 잊지 말자.본론으로 다시 돌아와 보자. 개발자로서 '성공'이란 무엇을 의미하는가? 아니, 개발자로서 비전을  갖는다는 것은 무엇을 의미하는가?  원천적으로 개발자의 삶이란 어떻게 살아야 하나요라고 묻는다면,이 문제는 정말 어렵고, 사람마다 다르기 때문에 최선을 다하는 것이 정답이라라는 교과서적인 답변만 늘어놔야 하는지도 모르겠다.이점에 대해서는 이제는 폐간했지만 오랫동안 개발자들의 벗이 되었던 마이크로소프트웨어 잡지에 대해서 원망을  슬쩍해보자.그것은, 나에게 ‘정말 대단히 큰 재미’를 선사했다는 것이 나에게 가장 처음 다가온 충격이었는지도 모른다. 처음에 가진 꿈은 그냥, ‘소프트웨어 개발’을 통해서 삶을 영유할 수 있는 것만으로 나는 행복했다는 점이다. 그래서, 이 소프트웨어의 세계로 진입하게 된 마이크로소프트웨어에 대해서 원망을 해야 하는지도 모르겠다.하지만 필자는 소프트웨어로써 ‘개발자로서 성공’을 하기 위해서, 이 직업과 삶을 선택한 것이 아니라, ‘개발자로 살기 위해서’이 삶을 선택한 것이었다. 나이를 먹고, 무언가를 목표로 살아온 경험을  되돌아본다면, ‘돈’과 ‘명예’를 선택하지 않았을 때에, 오히려, ‘돈’과 ‘명예’를 얻지 않았는가 하다. 오히려, ‘돈’을 선택하던 시기에 ‘돈’을 더 많이 잃어버린 경험도 가지게 되었다.이제는 주변을  되돌아보면, 필자는 꽤 넓은 스펙트럼을 가지게 되었다는 것을 느끼게 된다. 한때는 고인이 되셨지만 대통령이셨던 분부터, 수천억을 소유한 재벌 총수, 의료재단과 대학법인을 소유하신 분, 병원의 원장님들을 비롯한 분들을 비롯하여, 출판계, 영화계, 물론. 다수의 소프트웨어 개발자들까지. 매우 넓은 사람 관계를 만들어본 것 같다.그중에 소프트웨어 개발자들은 참 착하고 바보스러운 사람들이 많은 것 같지만, 한편으로는 너무도 욕심이 많은 사람들이 존재하는 참, 신기한 동네이다.그리고, 여러 계층을 경험해보니. 모든 계층은 똑같이 피라미드 구조를 가지고 있다는 점이다. 대부분 다 똑같았다. 하층의 사람들은 싼 가격에 노동력과 지식을 제공하고, 상위 레벨에서는 적절한 대우 이상과 재미있고 신기한 일들을 많이 한다는 점이다. 이 부분은 어느 계층이나 똑같다.대표적으로 출판일을 경험했을 때에 자신의 이름이 들어간 편집장이 되는 사람과, 그것을 목표로 기획자로 일하는 직원의 급여 수준이나 처우, 대우는 정말 최고급 아키텍트와 SI 개발자를 비교하는 것 이상으로 그 상대 감은 소프트웨어 개발세 상의 것 이상으로 매우 컸다.행복한 개발자라고 한다면, ‘개발이 정말 재미있고’, ‘개발도 잘하고’, ‘소프트웨어 개발 피라미드의 상층부의 일’을 하고 있다는 사람이 있다면. 그 사람은 정말 행복할 것이다. 뭐, 그런 사람은 이 글을 읽고 있지도 않을 것이다.그러나, 개발이 재미있지 않거나, 개발을 뛰어나게 잘하지도 못하고, 소프트웨어 개발 피라미드의 하층부에서 일하고 있다면, 어떻게 생존해야 하는 가에 대해서 정말 심각하게 고민해야 한다.이 글을 읽는 독자가 이제 개발자의 길을 시작한 사람이라면 고민해라, 소프트웨어 개발을 비롯한 모든 전문적인 직업들은 새로운 것을 배우고, 익히고, 소모하면서 계속 변화되는 것을 즐길 줄 알아야 재미있는 직업이다. 그런 것이 아니라면, 정말 힘들고, 피곤하고 어려운 것이 전문직과 같은 직업이다. 만일 그런 것이 힘들다면 다른 일을 알아보는 것이 현명하다.소프트웨어 개발자들과 가장 비슷하게 일하는 웹디자이너들의 푸념이 있다.‘낮은 급여에 야근은 허구한 날, 거기에. 불투명한 미래’에 대한 그들의 이야기를 들으면서, 흔히 소프트웨어 개발자들은 그 질문에 답변한다. ‘너희들은 모니터라도 크지’라고. 대부분의 프로젝트들은 ‘분석’에 의해서 ‘일정’을 만들지 않고, ‘일정’을 통해서, ‘품질’을 선택한다고 봐야 한다.‘정말 하고 싶은 것이 무엇인가?’개발자들에게 물어보면, 대부분 당황하는 경우가 많다. 이것은 개발자이기 때문에 답변을 못하는 것이 아니라, 자신의 비전이나 꿈에 대해서 명쾌하게 정의하지 못하고 있기 때문이다. 주변의 초보 개발자들에게 이야기하고 싶은 점은...가끔은 수필집이나 여행기, 그리고. 다른 사람의 생각과 꿈에 대한 글을 많이 읽어보라고 권하는 것이다. 그러면, 그 비전과 꿈에 대해서 이야기해달라는 사람들이 꽤나 있고는 하다.문제는 그 비전은 누가 정해주는 것이 아니라, 자신이 생각하거나, 자신이 발견하는 것이 옳지 않냐고 다시 이야기를 해준다. 물론, 이렇게 이야기하는 사람도 있다.‘저는 이번 프로젝트에서 인정을 받아서, 다음 프로젝트를 수행할 때에는 팀장이 되고 싶어요!’라고 이야기할 수 있다. 하지만, 이런 ‘단기적인 비전’을 말하는 것은 아니다. 이런 ‘단기적인 비전’만을 따라가다 보면, 냉정하게 수단만 중요시 여기게 되고, 목적 자체를 잃어버린 인생의 방랑자가 될 가능성이 매우 크다.내가 생각하는 ‘성공’이란 과연 무엇인가?또 하나는, 그 ‘성공’의 목표를 너무 작게 가져도 문제이고, 너무 커도 문제라는 점이지만, 그래도, ‘꿈’과 ‘목표’가 있다는 것 자체가 재미있고, 신기하지 아니한가?‘성공은 자신이 정한 것을 이루는 것’을 의미한다고.그럼 ‘꿈’을 어떻게 정의하나요?1. 10년, 20년, 30년 후의 자신의 모습을 상상해보고 정의해봐라.2. 현재 내가 좋아하는 모든 것들을 적어봐라.3. 내가 가장 잘하고 가장 인정받는 것을 적어봐라.보통은 이렇게 끄적거리다 보면, 무언가가 조금은 구체적인 비전이 나올 수도 있지만, 아무렇지도 않은 것이 나올 수 있다. 하지만, 일단, 끄적이기 시작했다면, 다음번에는 좀 더 잘할 수 있다는 것이 중요하다. 가장 중요한 것은 ‘내가 비전에 대해서 생각하기 시작했다’는 점이다. 일단 작심 3일이라도 중요한 결정이다. 그것은, ‘결정’을 하고 ‘결심’을 하기 시작했다는 것이기 때문이다.일단, ‘써야 한다’. ‘생각은 생각일 뿐이다’주변의 개발자들이 가장 잘 못쓰는 말 중의 하나가 ‘머릿속에 다 있다’라는 말이고, ‘글로 쓰기에 너무 어려운 이야기’이다라는 이야기가 가장 잘못된 것이라는 것을 잘 모르는 경우가 많다.‘머릿속에 다 있다’라는 이야기는 한번 생각은 해봤으나, 결론을 내리지 못하였다는 이야기로 들리고, ‘글로 쓰기 어렵다는 이야기’는 그만큼 정리가 안되고, 그 일에 대해서 잘 모른다는 이야기와 똑같다.10년 20년 특정 도메인에서 일한 베테랑이라고 하는 개발자와 일을 할 때에, 자신이 하는 일은 너무도 복잡하여, 설계도나 다이어그램, 순서도, 타이밍 차트 등을 그릴 수 없다는 사람들이 있다.그들과 이야기하고, 그 업무를 다이어그램과 설계도로 만들어 주어도, 그들은 그것 말고, 설명이 안 되는 그 무언가가 있다고 이야기를 한다. 물론, 필자는 그때에 이렇게  이야기해준다.‘만일 그러한 것이 존재한다면. 그것은 당신만이 생각하는 경험이나 당신이 소중하게 생각하는 가치인지 모른다. 하지만, 그것은 어떤 지식이 되기에 매우 부족한 것일 수 있다. 지식은 설명하기 쉽고, 이해하기 쉬운 것이 지식이다. 설명하기 어려운 경험은 정규화되거나 전달되어지기 매우 어렵다’더 쉽게 이야기하면. ‘쉽게 설명하거나 글자로 남기지 못한다면, 당신은 그것에 대해서 잘 알고 있지 못한 것입니다’비전이나 목표 잡기가 너무 어려워요?!그렇다면, 당장 휴일에 컴퓨터를 내버려두고, 아이폰이나 패드와 같은 스마트하다고 우기는 디지털기기를 집안에 던져두고 여행을 떠나는 것이 현명한 방법이겠다. 그리고, 다른 매체를 들여다보고, 개발자 이외의 사람들을 만나서 이야기해보라라고 권유해야 하는 것이 맞을  듯하다.생각 이상으로 소프트웨어 개발자의 세계는 정말 좁다. 그리고, 단편적인 지식들과 단편적인 경험들만이 존재하는 세상인지도 모른다. 그래서, 소프트웨어 개발자들은 ‘관심의 폭을 넓히고,’ ‘자신을 확장’하는 것이 결론적으로는 더 뛰어난 개발자가 된다는 것을 나중에야 깨달을 것이다. 마지막으로 이야기한 한다면, 소프트웨어 개발자에게 ‘성공’이란 일단... 전혀 해보지 않았던 것을 도전해보는 것, 그리고. 삶은 소프트웨어 개발처럼 버전을 나누어서 설명하기 어렵다는 것을 이해하고. 무언가 계속 새로운 것에 도전한다는 것이 진정한 ‘성공’ 아닌가 한다.#와탭랩스 #와탭 #개발자 #개발 #프로그래머 #성공 #성공한개발자
조회수 880

프로그래밍에는 왜 창의성이 필요하다고 할까요?

왜 프로그래밍에는 창의성이 필요하다고 할까요? 실제로 프로그래밍을 하다 보면 복잡한 문법을 이해하고, 암호 같은 에러를 차분히 해결해야 하니, 오히려 수학적이며 논리적인 사고가 더 필요해 보입니다. 그런데도 프로그래밍이 창의적이어야 하는 이유는 하나의 프로그램을 만드는 답이 여럿이기 때문입니다.답이 하나여도 가르치기 어려운데, 다양한 방법을 어떻게 가르쳐야 하는 걸까요? 또, 기상천외한 학생들의 코드를 보며 이해하고 교육하는 것이 얼마나 긴 시간이 필요하며 어려운 일인가요? 어디서부터 해결해나가야 할지 막막합니다.Elice 리서치 팀에서 하는 일 중 하나는 학생들의 수많은 코드 중 비슷한 타입들을 추려내는 것입니다. 코드를 몇 가지 타입으로 추려내고 나면, 선생님은 학생 하나하나의 코드를 보고 교육하는 것이 아니라, 비슷한 형태의 코드를 작성한 학생 그룹 전체에게 적절한 피드백을 줄 수 있습니다. 이렇게 그룹 전체에게 피드백을 준다면 선생님은 같은 시간에 더 많은 학생을 교육할 수 있을 것입니다.그럼 이제, 비슷한 코드를 어떻게 찾아내서 분류할지 이전 연구를 보며 알아봅시다. (현기증이 날 수 있으며, 다 이해할 수 없어도 괜찮으니 걱정하지 마세요!)지프의 법칙과 숙제 제출 패턴자연어 처리(Natural Language Processing;NLP)를 배울 때 자주 거론되는 사람이 있습니다. 바로 미국의 언어학자인 조지 킹슬리 지프George Kingsley Zipf인데, 이 사람이 만든 지프의 법칙은 자연적으로 일어나거나 생성되는 특정 정보들이 일정하게 나타내는 경향을 나타낸 것입니다. 지프는 영어로 된 텍스트를 분석하던 도중, 자주 쓰이는 단어를 순서대로 나열하면 각 단어의 빈도는 그 단어의 출현 순위에 반비례함을 찾아냈습니다. 영어에서 가장 많이 사용되는 단어 1~3위가 “the”, “of”, “and” 인데, “the”는 “of”의 약 두 배, “and”의 약 세 배의 빈도를 보입니다.이것을 수학적으로 표현하면, 일정 크기 이상의 영어 말뭉치(corpus)에 들어 있는 단어들의 개수를 전부 세서 그 단어들을 가장 많이 쓰이는 것부터 순위를 1위부터 나열했을 때, 특정 단어의 순위가 k 라면 (즉 전체에서 k번째로 많이 쓰인 단어라면) 그 단어가 말뭉치에서 쓰인 개수는 1/k에 비례한다는 것입니다. 이것을 그래프로 그려보면 다음과 같습니다. 재미있는 사실은, 여기에서 x축과 y축에 log를 씌워 보면 (이것을 log-log scale로 변환한다고 합니다.) 다음과 같은 직선 형태로 변환된다는 것입니다.이것이 도대체 숙제 제출과 무슨 관계가 있길래 이렇게 장황한 설명을 한 것일까요? 위에서 나온 지프의 법칙을 기억하시나요? 학생이 낸 숙제를 채점하다 보면 꽤 많은 학생이 비슷한 방식으로 숙제를 푸는데, 제출된 풀이 방식들을 비슷한 것끼리 묶어 분석해 보니, 이것 또한 지프의 법칙을 따른다는 것이 발견되었습니다. 예를 들어 가장 인기 있었던 풀이 방식으로 100명이 숙제를 제출했다면, 두 번째로 인기 있는 풀이 방식으로는 약 50명이 숙제를 제출했다는 뜻입니다.여기서 우리가 찾아낼 수 있는 인사이트는 무엇일까요? 첫째, 학생들의 숙제들을 비슷한 것끼리 묶을 수 있다면, 그리고 이 분류를 컴퓨터로 자동으로 할 수 있다면 조교가 채점하거나 코멘트를 할 때 써야 할 시간이 상당히 줄어들 것입니다. 둘째, 방법 서너 개에 대해서만 어떻게 채점할지 혹은 어떻게 코멘트할지에 대해 준비를 해놓으면, 그걸로 숙제 대부분을 채점/코멘트할 수 있을 것입니다. 대다수의 숙제는 몇 가지 인기 있는 풀이방식으로 만들어졌을 것이기 때문입니다.그러면 이제 다음 문제는, ‘비슷한 풀이 방식으로 푼 프로그램 코드’를 어떻게 찾아낼 것인가? 를 고민해봅니다. MIT의 Elena Glassman은 이에 대한 해법으로 Overcode를 제시했습니다.Overcode뉴스 기사나 책, 블로그 글 등 자연어로 이루어진 텍스트 데이터를 분석하고, 여기에 어떤 주제가 들어있는지 밝혀내는 연구는 많이 진행 됐습니다. 이를 위한 머신러닝 알고리즘 중 하나가 토픽 모델, Topic model 입니다(토픽 모델에 대해서는 다른 글에서 자세히 다룰 예정입니다). 그러나 토픽 모델링을 프로그래밍 문제에 실제로 적용하기는 쉽지 않습니다. 코드에 사용되는 문법이나 키워드가 자연어와 1:1로 매칭되지 않기 때문에, 기존에 자연어에서 사용되던 모델을 그대로 사용할 수 없기 때문입니다. 가령, 슬쩍 보면 무척 달라 보이는 아래 두 파이썬 코드는 사실 완전히 같게 동작합니다. 이 두 코드를 (사람들이 일상생활에서 사용하는) 자연어를 분석하는 모델로 분석한다면 제대로 된 결과를 낼 수 없는 건 당연합니다.def fibonacci(): parents, babies = (1, 1) while babies < 100 xss=removed>fibonacci()def fib(parents, babies): ‘’’ parents = 1 babies = 1 ‘’’ while True: print ‘This generation has {0} babies’.format(babies) parents = babies # set parents as babies babies = parents + babies # recursively add number of babies if babies >= 100: break fib(1, 1)Elena Glassman이 제시한 Overcode의 목적은 비슷한 로직으로 만들어진 프로그래밍 코드들을 모으는 것입니다. 이제 Overode가 어떻게 작동하는지 간단하게 소개하도록 하겠습니다. 가장 먼저 수행되어야 하는 것은 서로 다른 형식으로 쓰인 소스 코드들을 정리하는 것입니다. 소스코드 정리에는 주석 제거, 줄 및 공백/들여쓰기를 일정하게 맞추는 작업 등이 포함됩니다.Image from Overcode하지만 이 작업만으로는 충분하지 않습니다. 거의 같아 보이는 코드도 실제로 프로그램을 실행하기 전까지는 같은지 알 수 없고, 꽤 달라 보이는 코드도 실제로는 완전히 같게 동작할 수 있기 때문입니다 (여기서 같게 동작한다 함은, 결과를 같게 내는 것 이상으로 결과를 내는 중간과정이 완전히 같다는 것을 의미합니다). 다시 위로 돌아가, fibonacci() 함수와 fib(parents, babies) 함수를 살펴봅시다. 위 두 코드는 기존의 자연어 처리 기법에 따르면 완전히 다른 프로그램일 것입니다. 변수명이 달라서가 가장 큰 이유일 텐데, 사실 컴퓨터의 입장에서 변수는 어떤 값을 할당하는 공간에 불과하며, 그 공간에 어떤 이름을 붙이느냐는 중요하지 않습니다. 코드를 작성하는 것이 사람이기 때문에 공간에 편하게 이름을 붙이는 것뿐입니다. 서로 다른 프로그램에서 어떤 변수가 서로 같은 역할을 하는지, 컴퓨터가 알아내려면 어떻게 해야 할까요? (컴퓨터는 창의적이지 않습니다!)Image from OvercodeElena가 제시한 방법은 프로그램을 실행하면서 변수의 값이 어떻게 바뀌는지를 추적한 것입니다. 아래 두 코드를 보고, 한번 머릿속으로 프로그램을 실행해 봅시다. 학생 B의 코드는 for문으로 5의 3승을 계산했고, 학생 C의 코드는 while문으로 5의 3승을 계산한 것입니다. 학생 B의 코드가 실행됨에 따라 r이라는 변수가 어떻게 변하는지, 학생 C의 코드에서 result가 어떻게 변하는지 확인해보면 둘 다 1 → 5 → 25 → 125 의 값을 가지게 됩니다. 그렇다면 컴퓨터는 이렇게 판단할 수 있습니다. “B의 코드에서의 변수 r과 C의 코드에서의 result가 완전히 같은 방식으로 변하니, 같은 의미로 사용된 것이다.”Image from Overcode이제 같은 의미를 가지는 변수들을 알아냈다면, 컴퓨터는 쉽게 가장 “흔한” 이름으로 변수의 이름을 바꿔치기 합니다. 그러면 처음에 서로 다르게 보였던 코드들도 이제 같아질 것입니다.물론 이것이 다는 아닙니다. 예를 들어, 간단한 테스트 케이스들을 통해 결과를 비교함으로써 변수를 분석하기 전에 먼저 거르는 방법, 너무 흔한 변수들을 처리하는 방법 (예를 들어 완전히 다르게 동작하는 코드들에서도 반복문에서 사용되는 인덱싱 변수들은 같이 변화할 것입니다), 한 변수가 다른 의미론적으로 두 번 사용되는 경우 처리하는 방법… 등이 논문에는 더욱 자세히 적혀있습니다. 궁금한 독자들은 한번 논문을 읽어보도록 합시다.남은 문제들Elena가 제시한 방법은 위에서 보여준 예제와 같은 간단한 코드에서 꽤 잘 동작합니다. 예를 들어, 다음과 같은 문제들이 있습니다.a의 b승을 구해서 리턴하는 프로그램N번째 피보나치 숫자를 리턴하는 프로그램다항식의 미분 결과를 리턴하는 프로그램하지만 대학교에서 1학년만 넘어가더라도 이런 간단한 프로그램 과제는 내지 않습니다. 예를 들어 Elice에서 교육 중인 기초 프로그래밍/ 프로그래밍 유치원 수업을 듣는 학생들은 매우 많은 실습문제를 풉니다. 여기에서 푸는 과제들은 초반 몇 주가 지나면 이 정도의 간단한 프로그래밍 수준을 뛰어넘기 때문에, 코드가 꽤 길어지고 다양성이 생기게 되는데 이런 경우 이 방법은 잘 동작하지 않습니다.또 다른 문제는, 이 방법이 “동작하는” 코드에서만 작동한다는 것입니다. 예를 들어, 수강생들이 아직 기초 문법을 배우고 있다면? 제대로 실행도 되지 않는 코드를 만들었을 때, 비슷한 실수를 한 사람들끼리 묶어주고 싶다면? 아쉽게도 Elena가 제시한 방법은 이렇게 에러가 나는 코드에서는 동작하지 않습니다. 코드가 실행되지 않는다면 변수의 값의 변화를 추적할 수 없기 때문입니다.마치며이번 포스트에서는 학생의 제출 코드를 비슷한 것끼리 묶는(Clustering하는) 방법에 대해 간단하게 살펴 보았습니다. 학생이 낸 비슷한 답안을 모아주는 솔루션은 수학 문제 같은 단답식 문제, 혹은 영어 에세이같은 자연어에 대해서는 이미 상용화가 되어 있습니다. 영어 에세이의 경우 여러분들이 가장 친숙할 만한 상용화된 솔루션은 아마 copy detector일 것입니다.하지만 프로그래밍 코드의 클러스터링은 연구가 계속 진행되고 있습니다. 앞서 말했듯 코드에서 한 글자 한 글자가 가지는 의미가 자연어에서 가지는 알파벳과는 완전히 다르기 때문이기도 하고, 정말 실행을 해 보기 전까지는 어떻게 동작하는지 예측하는 것이 매우 어렵기 때문이기도 합니다. Elice 리서치 팀에서도 프로그래밍 코드에 대한 분석을 자동으로 수행하는 머신러닝 연구를 수행하고 있습니다. 이러한 기술을 통해 선생님이나 조교가 학생을 더욱 효율적으로 지도하고, 컴퓨터의 도움으로 지도에 아낀 시간을 한 단계 더 개인화된 도움을 주도록 하는 것이 Elice의 목표 중 하나 입니다.글쓴이김수인: KAIST 전산학부 박사과정 / Research Lead, Elice김재원: KAIST 전산학부 박사과정 / The Lead, Elice배휘동: KAIST 전산학부 박사과정 / Frontend Lead, Elice#엘리스 #코딩교육 #교육기업 #기업문화 #조직문화 #서비스소개
조회수 3122

코딩, 어떤 언어로 시작하지?

경영학과 학생 윤수는 요즘 주변에서 이런 말을 자주 듣는다."앞으로는 코딩을 모르면 문맹이다.""4차 산업혁명 시대에 대비해야 한다.""소프트웨어가 세상을 잡아먹고 있다."정확히 뭔 소리인지는 모르겠지만 일단 프로그래밍을 배우기로 결심한다. 그런데 '프로그래밍 언어'라는 게 또 뭐가 이렇게 많은지... 어떤 걸로 시작해야 할지 도무지 감이 안 잡힌다.그래서 공대생 친구들에게 물어본다. 친구 1: "일단 가장 기본인 C부터 배워."친구 2: "한국에서 제일 많이 쓰는 자바부터 배워."친구 3: "파이썬이 배우기 쉬워."친구 4: "요즘은 자바스크립트가 대세지."누가 정답일까? 사실 이 중에 "틀린" 사람은 없다. 각자 관심 분야와 목적이 다르기 때문이다. 만약 다음 달에 아이폰 어플을 개발해야 한다면 어쩔 수 없이 곧장 스위프트를 배워야 한다. 내일모레까지 사이트 레이아웃을 완성해야 한다면 더 물을 것도 없이 그냥 HTML과 CSS를 시작하면 된다. 그러나 일반적으로 첫 프로그래밍 언어를 추천하라면 내 톱 초이스는 단연 파이썬, 그다음은 HTML/CSS + 자바스크립트일 것이다. 이 3개의 기준으로 평가하였다:1. 배우기에 얼마나 어려운 언어인가?2. 이 언어에 대한 수요가 얼마나 있는가?3. 나는 프로그래밍으로 뭘 하고 싶은가?*우연히 보게 된 CSDojo라는 유튜브 채널에서 너무 훌륭하게 정리해줘서 참고하였다.1. 배우기에 얼마나 어려운 언어인가?나는 고등학교 때 C를 독학하는 것으로 프로그래밍에 입문했다가 금방 질려서 그만두었다. 창업에 관심이 생겨 다시 시작했는데 이번에는 파이썬으로 배워보았다. 그제야 흥미를 느꼈고, 프로그래밍이 마냥 어렵기만 한 게 아니라는 걸 깨달았다.어떤 차이가 있는 걸까?파이썬은 C보다 쓰기 쉽다. C로 수백 줄을 써야 하는 프로그램을 파이썬 몇십 줄로 쓸 수 있다. 파이썬 코드 몇 줄이면 쓸모 있고 흥미로운 결과물을 만들어낼 수 있다는 뜻이다. "Life is short, use Python"이라는 말이 있을 정도다. 물론 파이썬이 무조건적으로 C보다 좋은 건 아니다. 파이썬 프로그램은 C 프로그램보다 느리기 때문에 특정 업무에는 적합하지 않다. 하지만 그런 건 지금 신경 쓸 필요가 없다. 첫 프로그래밍 언어로 "컴퓨터적인 사고력"을 익히고 나면 새로운 언어를 배우는 것은 어렵지 않기 때문에, 일단은 배우기 쉬운 언어로 시작해라.비교적 배우기 쉬운 언어:    - Python    - Ruby    - JavaScript2. 이 언어에 대한 수요가 얼마나 있는가?시장에서 필요로 하는 언어를 배우는 게 좋다. 세계에서 가장 큰 웹사이트들은 어떤 기술을 사용하는지 살펴보자:출저: 위키피디아위 테이블에는 미국의 웹 서비스들만 정리되어 있다. 지역과 직군에 따라 요구하는 언어가 다르기 때문에 로켓펀치, 더팀스, 위시켓, 링크드인, 인디드, 사람인, 잡코리아 등의 구인/구직 사이트에서 직접 살펴보는 걸 추천한다.인기가 많은 언어일수록 커뮤니티가 크기 때문에, 도움을 받을 수 있는 자료들이 많고 가져다 쓸 수 있는 코드가 많다는 장점도 있다. 세계 최대 규모의 프로그래밍 커뮤니티인 스택오버플로우의 언어 점유율을 참고해보자.출저: 스택오버플로우이 중에서 HTML/CSS(웹 레이아웃), SQL(데이터베이스), Bash/Shell(Unix)은 아주 특수한 경우에 쓰이는 언어이기 때문에 제외하고 보자. 수요가 높은 언어:    - JavaScript    - Java    - Python3. 나는 프로그래밍으로 뭘 하고 싶은가?분야별로 자주 사용되는 언어가 있다. 간단하게 정리하자면:1. 데이터 과학, 공학 => Python, R, MATLAB2. 웹 프런트엔드 => HTML/CSS + JavaScript3. 웹 백엔드 (서버) => Python, Ruby, JavaScript, Java, Go, C, C++, PHP 등4. 아이폰 어플 => Objective-C, Swift (이제는 거의 Swift로 넘어갔다)5. 안드로이드 어플 => Java, Kotlin (슬슬 Kotlin으로 넘어가고 있다)6. 게임 개발 => C#, C++7. 임베디드 시스템 => C, C++결론: 왜 파이썬, 자바스크립트인가?앞서 이야기했듯 당장 급히 배워야 하는 언어가 있으면 그 언어를 배우면 된다. 교수님이 연구실에서 다음 주부터 C언어를 쓴다고 하면, 뭐 어쩌겠나? 그냥 당장 C를 배우는 수밖에. 하지만 조금 더 여유롭게, 제대로 프로그래밍을 배우고 싶다면 이 포스트에 나와 있는 세 가지 기준을 고려해서 결정하는 걸 추천한다. 배우기 쉬운 언어로는 파이썬, 루비, 자바스크립트를 선정했고, 수요가 높은 언어로는 자바스크립트, 자바, 파이썬을 선정했다. 두 기준에 모두 부합하는 언어는 파이썬과 자바스크립트이다. 이 중 무엇을 택할지는 3번 기준으로 결정하면 된다. 데이터 분석에 관심 있으면 파이썬부터, 웹 개발에 관심 있으면 자바스크립트부터 시작하면 된다. 참고로 자바스크립트를 하기 위해서는 기본적으로 HTML과 CSS를 알아야 한다!데이터 과학과 웹 개발 둘 다 관심 없으면 자바스크립트보다는 파이썬으로 시작하는 걸 추천한다. 개인적인 의견이지만 초보자 입장에서 파이썬 언어가 자바스크립트보다 깔끔하다고 생각하기 때문이다. 또한 HTML과 CSS를 미리 배워야 하는 수고를 덜 수 있다.어디서 배우지?온라인으로 프로그래밍을 가르치는 사이트가 굉장히 많다. 해외에는 Codecademy, Treehouse, Coursera, MIT OpenCourseWare 등이 있고 한국에는 인프런, 엘리스, 코드잇, 생활코딩 등이 있다. 국내외 서비스를 통틀어서 가장 추천하는 곳은 코드잇이다. 영어로 된 수업이 당연히 더 좋을 것이라 생각한다면 큰 오산이다. Codecademy나 Treehouse는 쉽고 재미있지만 막상 수업을 다 들어도 직접 무언가를 할 수 있겠다는 생각이 들지 않는다. 반면 Coursera나 MIT OpenCourseWare는 대학 수업과 흡사하기 때문에 지루하고 어려워서 이수율이 5% 정도밖에 되지 않는다. 코드잇은 내용의 깊이와 재미를 모두 잡았다. 심도 있는 내용을 난해하지 않고 간결하게 풀어내어 졸업률이 60%나 된다. 코드잇 수업 안 들은 사람은 있어도 하나만 들은 사람은 없다는 말이 있을 정도인데, 수강 후기를 보면 정말 수강생들의 애정이 드러난다. 무료로 샘플을 들어볼 수 있으니 일단 한 번 해보도록.Python으로 배우는 프로그래밍 기초 수업, HTML/CSS로 배우는 웹 퍼블리싱 수업, JavaScript로 배우는 인터랙티브 웹 수업을 모두 들으면 자신감을 갖고 프로그래밍 커뮤니티에 입문할 수 있을 것이다.이제 어떤 프로그래밍 언어를 어디서 배워야 하는지 알았으니, 주저 말고 시작해보길 바란다!#코드잇#코딩교육 #개발자양성 #교육기업 #인사이트 #경험공유
조회수 5192

"캘린더앱은 돈이 되지 않아요"

지난 2년 내내 투자자 미팅에서 귀에 박히도록 들었던 소리."캘린더앱은 돈이 되지 않아요."맞다. 캘린더앱은 돈이 되지 않는다.지난 몇 년간 다수의 회사들이 출시했던 화제의 캘린더 앱들의 말로를 함께 살펴보자.  1,000만 달러를 투자받은 캘린더앱 - Tempo지평만 열고 2015년에 인수 후 종료.  모두에게 사랑받던 캘린더앱 - SunriseMS가 1억 달러(1천억 원)에 인수를 해 화제가 된 후1년 만에 또 종료(2016년).뭐 바다 건너 이야기는 너무 멀게 느껴질 수 있으니, 국내의 사정을 살펴보자.참고로 아래 4개의 서비스 모두 종료 관련 공식 보도자료를 내지는 않았기에 가볍게 블로그나 커뮤니티를 통해서만 확인이 가능하다(그조차도 없는 서비스는 출시 정보로 대체했다).2015년 9월 다음카카오(현 카카오), 다음캘린더 서비스 종료.2017년 6월, SKT 썸데이 캘린더 종료(2016년 출시, 2017년 종료).2018년 12월, 네이버 타르트 종료.(네이버의 경우 오랫동안 유지 중인 '네이버 캘린더'가 있긴 하지만 사실 신규 '일정 관리 앱'을 실험적으로 출시했었다)위 3개 서비스는 다소 생소할 수 있지만 아래 쏠캘린더는 대부분 한번 정도 들어본 적 있으리라 생각한다.위 서비스들 중 가장 많은 사용자를 확보했던 쏠캘린더도 결국 2016년 가을 종료. (쏠캘린더는 다음과 카카오 합병 전 카카오에서 출시된 서비스라 다음캘린더와 쏠캘린더는 다른 서비스였다)위의 4개, 아니 3개 회사가 캘린더 서비스를 종료하게 된 이유는 각기 다를것이고, 공식 보도자료는 없지만 업계 관계자 및 당사자 분들이 남겨놓은 몇몇 자료들을 통해 소소하게나마 내막을 엿볼 수 있었다.다음캘린더 서비스 개발 비하인드 스토리SKT 모바일앱은 왜 거의 다 '단명'할까 네이버 타르트 - 연구 종료 일지결국 그렇게 국내 현 캘린더 시장은 구글 캘린더, (기존)네이버 캘린더, iOS 기본 캘린더, 삼성 / LG 등 안드로이드 내장 캘린더, 4개 캘린더가 4등분하고 있으며 그 외에도 다양한 커스터마이즈 캘린더와 아웃룩이 작은 포션을 차지하고 있다(물론 어디까지나 국내의 이야기로 나라마다 상황은 다르다).커스터마이즈 캘린더를 쓰는 대부분은 구글 캘린더 또는 iOS 기본 캘린더 서버를 연동해서 사용하기에 사실상 자체 캘린더 서버를 운영하는 기업은 구글과 네이버, 그리고 애플뿐이다. 그런데 또 iOS 캘린더 유저의 상당수는 구글 캘린더를 연동해서 쓰기에 여러모로 얽히고설키고 복잡한 시장이다. 아 원래 하려던 얘기로 돌아와서, 여하튼 카카오와 SKT가 시도하다 접었고 네이버, 구글, 애플이 꽉 잡고 있는 이 시장에,2017년 대학생 5명이 또 하나의 캘린더 기반 서비스를 들고 뛰어들었다.(그렇다. 그 얘기 하나 하려고 이렇게 글이 길어졌다.)이름하야 '받아보는 캘린더 - 린더'. 때는 바야흐로 2017년 1월, 졸업을 앞둔 대학생 5명이 학교 강의실에 모여 창업 아이템을 구상하던 그 시절, 공동창업자 중 한 명이 '일정'을 아이템으로 서비스를 만들어보자고 의견을 던졌다.당시 그는 몇 주 전 교내 '캠퍼스 CEO'라는 창업 수업에서 '일정 관리 및 추천' 기능을 가진 서비스 기획서를 과제로 제출했던 상황이었고 팀의 리더였던 나는 그 제안을 듣고 허탈하게 웃으며 "그런 건 구글이나 네이버가 하는 겁니다"라고 단칼에 거절했다(원래 형 동생이었던 우리 팀은 팀빌딩 시점부터 존댓말을 썼다).비록 나 또한 학생이었지만 다수의 공모전, 해커톤, 회사 근무를 통해 서비스를 출시해본 경험이 있었고 서비스의 기획, 개발, 출시, 마케팅, 운영까지 이어지는 프로세스를 몇 번 정도 겪어본 입장에서 또 하나의 '캘린더' 앱을 출시하는 건 미친짓이라고 생각했다(솔직히 이제와서 말하자면 아직 뭘 몰라서 그냥 하는 말이겠거니 했다).그런데 당시 그가 했던 말 한마디가 우리를 움직였다."그러니까 우리가 해야죠"그의 논리는 이러했다."구글이나 네이버가 할 정도의 아이템이니까 시장이 큰 건 이미 증명이 됐고, 근성과 패기, 실행력으로 그들을 이기면 되는 거 아닙니까? 그게 스타트업 아니에요?"그때 말렸어야 했다.그때 설득되지 말았어야 했다.그때는 몰랐다.'일정'이라는 분야를 기반으로 사업을 기획하고, 운영하고, 확장한다는 것이 이렇게 외롭고 힘든 일이 될 줄은.  앞서 언급한 바와 같이 해외 사례라고는 하나 같이 다 종료된 서비스밖에 없었고 국내 시장은 해외의 그 사례들을 몇 년 후 따라가다 종료되는 수준에서 그쳤다.그래서 우리는 판을 새로 짜기로 했다.우리가 만들고자 한 서비스는 캘린더를 기반으로 하거나, 캘린더처럼 생겼는데, 캘린더 앱은 아니어야 했다.캘린더의 메인 기능인 일정을 '입력'하거나 '수정'하는 기능은 다 빼고, 사이드 기능 중 하나인 '구독'을 핵심으로 뒀다.캘린더도 문제였지만 이미 포화된 앱 시장도 문제였다. 새로운 앱들이 하루에도 수십 개씩 출시된지도 모른 채 사람들의 기억 속에서 잊혀지고 있던 상황이었다.단순히 앱을 통해 돌파구를 찾기보다는, 다양한 판로를 찾아보기로 했다.몇 번의 시행착오를 거쳐,2017년 하반기 즈음 우리가 앞으로 가져가야 할 방향성이 명확해지기 시작했다.카카오, 네이버, SKT 같은 회사의 기라성 같은 업계 선배들이 몇십억을 쓰고도 캘린더 서비스를 종료할 수밖에 없었던 데는 분명 이유가 있었다.우리의 전략은 치밀해야 했고, 2017년 말 아래와 같은 3개년 로드맵을 구상하게 되었다.일정 구독 서비스 린더 - 3개년 로드맵(2017.12)(로드맵에 대한 자세한 내용은 https://brunch.co.kr/@five0203/33 에서 확인할 수 있다)위 로드맵을 바탕으로 지난해 하반기 출시된 모바일앱, 즉 관심 일정 구독 플랫폼:린더의 다운로드 수는 40만, MAU는 18만을 돌파했고 지금도 가파르게 상승하고 있다.  한 달에 린더를 통해 일정을 확인하는 횟수(PV)는 700만 건이 넘었고 린더 내 링크를 통해 웹사이트로 이동하는 전환 횟수는 하루 1만 건을 넘어서고 있다.지난 30일 간 약 10여 건의 광고 및 제휴 문의가 있었고 그중 몇몇은 실행으로 옮겨졌다.린더의 장점은 그동안 광고로만 인식되어오던 이벤트 정보들이 '유용한 정보'로 전달된다는 것이다.누군가에게는 광고인 일정이, 누군가에게는 정보가 될 수 있다는 이유로 린더는 사용자에게 '광고 없는 앱'으로 인식되고 있다.물론 광고의 비중이 올라갈수록 네이티브 광고마저도 거부감을 일으킬 수 있기에, 우리는 일정을 모아 놓치지 않도록 도와주는 최초의 목적을 지속적으로 잊지 말아야 한다.  광고 플랫폼 기업 DMC미디어가 발표한 '2018 DMC리포트 종합 보고서'에 의하면 광고를 의도치 않게 실수로 클릭한 사용자는 28.9%에 그치며, 사용자 10명 중 7명은 노출되는 광고에 관심 및 의도를 가지고 클릭하는 것으로 조사되었습니다.문자, 페이스북, 카톡 플러스 친구 등 기존 채널에 대한 피로도가 높아지고 있는 현시점에서 린더가 경쟁력을 가지게 된 이유는 캘린더 유형의 정보 전달이 현재까지 '유용한 정보'라는 인식이 강하기 때문이라 볼 수 있습니다.위에서 언급한 바와 같이 이미 다양한 유형의 수익모델을 준비 중인 린더이지만 보다 장기적 관점에서 서비스 가치를 보존하기 위해 노력해야만 하며, 서비스 수익화에 대한 사용자의 거부감을 '너무 빠르게' 증가시키지 않아야만 사용자 이탈을 사전에 방지할 수 있습니다.이는 우리가 발생시키고자 하는 수익의 총합이 사용자에게 전달되는 가치의 총합을 섣부르게 넘어서는 안된다는 것을 의미합니다.- 19년 3월 주주서한 중 -아직 우리의 목표 MAU에는 한참 미치지 못한 현 상황에서도 밀려드는 광고 제의를 보며, 팀을 최소한으로 유지하고 서비스 운영 비용을 낮춘다면 향후 서비스의 지속과 생존, 즉 ROI를 맞추어 나가는 것은 어렵지 않을 것 같다는 확신이 생겼다(물론 ROI를 맞추는 것과 BEP를 맞추는 것은 차원이 다른 얘기라 BEP를 달성하신 모든 회사를 진심으로 존경합니다).하지만 성장하지 않고 머무르는 조직은 도태하는 조직이기에, 우리 팀은 앞으로도 여러 무모한 시도를 멈추지 않을 계획이다.  "캘린더앱은 돈이 되지 않아요" 공식적인 투자 라운딩을 3주 전 처음으로 시작하게 됐는데, 작년까지만 해도 귀에 박히게 들리던 이 이야기를 올해는 단 한 번도 듣지 못했다. 애초에 중요한 건 돈이 되는 게 아니었다. 사람들에게 필요한 서비스를 만들고, 그를 통해 새로운 가치를 창출하는 것. 그게 우리가 해야 할 일이었다.다수의 불편함을 소수의 기술력을 통해 해결하며, 그것을 지속&확대하기 위해 수익을 만든다.돈은 수단이지 목적이 아니다.긴 글을 마치기에 앞서 우리의 시작을 잊지 않기 위해, 2017년에 남겼던 감성 페북글 하나와 최근에 진행된 린더의 기업 협업 사례 하나를 남겨본다.2017년 7월(법인설립 1달 후, 기보 대출 받은지 일주일 후), SKT 썸데이 캘린더, 여름 문자 서비스 종료 소회그로부터 약 1년 후인 2018년 10월, SKT NUGU 스피커 x 린더 - 데이터 협업 진행
조회수 1056

[인공지능 in IT] 구글이 말하는 인공지능의 혁신성

지난 2018년 5월 8일부터 5월 10일까지 3일간, 미국 샌프란시스코에서 '구글 I/O 2018(Google Input/Ouput 2018)'이 열렸다. 구글 I/O는 매년 구글이 혁신적인 제품을 선보이는 행사로, 구글의 신제품과 신기술을 가장 먼저 접할 수 있는 자리다. 필자는 지난 몇 년간 구글IO를 지켜봤지만, 개인적으로 이번만큼 신선한 충격을 받지는 못했던 것 같다.< 구글 I/O 2018, 출처: 구글, 제공: 스켈터랩스 >구글 선다 피차이(Sundar Pichai) CEO는 올해 구글 듀플렉스(Duplex)라는 음성 기술을 시연했다. 구글 듀플렉스는 시연을 통해 미용실과 레스토랑에 스케줄을 예약하며, "Mm-hmm"이나 "Aha"라고 자연스러운 대화 흐름을 선보여 많은 사람에게 경외 혹은 두려움을 불러 일으켰다. 구글 듀플렉스가 베이퍼웨어(Vaperware, 개발 중이지만 아직 완성되지 않은 또는 완성되지 않을 수 있는 소프트웨어)일 가능성도 있지만, 구글의 인공지능 기술 수준을 전세계에 알리기에 충분한 계기라고 생각한다.< 구글 듀플렉스, 출처: 구글, 제공: 스켈터랩스 >구글IO 2018을 보며 스스로에게 질문을 던졌다. 구글이라는 기술 공룡은 어떻게 혁신의 아이콘이 될 수 있었을까? 먼저 혁신의 사전적 의미를 살펴보면 다음과 같다. '묵은 풍속, 관습, 조직, 방법 따위를 완전히 바꾸어서 새롭게 함.' 여기서 가장 집중할 부분은 '완전히 바꾸어서 새롭게 한다는 것'으로, 대다수의 사람은 짠하고 나타나는 새로운 기술을 떠올릴 것이다. 틀린 말은 아니다. 다만, 조금 다른 관점으로 생각해본다면 기술이라는 결과물을 만들기 위해, 어떠한 방식으로 접근(Approach)했는지도 중요할 것이다.이번 구글IO 2018 중 듀플렉스를 시연하며 선다 피차이 CEO가 던진 질문을 끝으로 짧은 글을 마무리한다."60%의 소상공인들은 온라인 예약 시스템을 가지고 있지 않다. 이를 인공지능이 해결할 수 있지 않을까?"질문만 듣고 판단한다면, 구글 자체가 거대한 인공지능 기술기업이기에 당연히 온라인 예약시스템을 대체하거나 더 요긴하게 사용할 수 있는 인공지능 플랫폼을 만들 것이라고 생각할 것이다. 그러나 구글은 다른 관점에서 접근했다."온라인 예약 시스템이 없다면, 인공지능이 직접 전화를 걸면 된다"고.이호진, 스켈터랩스 마케팅 매니저조원규 전 구글코리아 R&D총괄 사장을 주축으로 구글, 삼성, 카이스트 AI 랩 출신들로 구성된 인공지능 기술 기업 스켈터랩스에서 마케팅을 담당하고 있다#스켈터랩스 #기업문화 #인사이트 #경험공유 #조직문화 #인공지능기업 #기술기업
조회수 1271

EOS Token 생성과 발행, 전송

이번시간에는 배포한 Contract를 통해 Token 발행과 전송을 해보겠습니다. 이를 위한 준비는 아래 2미디엄 글을 참조해주세요EOS Smart Contract 를 위한 준비EOS Smart Contract 배포먼저 저번 시간에 배포한 token 발행 abi 를 확인해 보겠습니다.$ cleos get abi hexlanthenryget abiabi를 확인하다보면 actions 라는 항목에 총 3개의 action이 있음을 확인할 수 있습니다. 이 3개의 name이 실행할 수 있는 action입니다. token발행은 create action을 통해 진행할 수 있습니다.Token 생성$ cleos push action hexlanthenry create '["hexlanthenry", "10000000000.0000 HEX"]' -p hexlanthenrycreate action 실행 결과create action 을 통해 ‘HEX’ 토큰을 100억개 생성했습니다. create 라는 action의 인자는 account_name(hexlanthenry), maximum_supply(10000000000.0000 HEX) 입니다. 즉 첫번째 인자는 토큰의 발행자를 나타내며, 두번째 인자는 토큰의 최대 수량을 나타냅니다.이 인자가 어떻게 들어가는지는 abi 의 struct 를 확인하면 알 수 있습니다.abi의 create structparameter 1 : account_name type— issuerparameter 2 : asset type — maximum_supply+ 저번 강의에서 공지한데로 다음 포스팅에서는 abi가 무엇을 뜻하는지, 이를 통해 어떻게 action을 실행할 수 있는지 알아보도록 하겠습니다.Token 발행생성과 발행 이 2개의 개념이 헷갈릴 수 있습니다. create action을 통한 생성은 최대 발행량을 결정 하는 것이며, issue action 은 토큰을 유통 시키는 것입니다.create : token 생성과 동시에 최대 발행량 결정issue : token 의 유통따라서 issue action을 통해 이전에 생성한 HEX token을 발행해보겠습니다.$ cleos push action hexlanthenry issue '["hexlanthenry", "10000.0000 HEX", "initial issue"]' -p hexlanthenryissue contract 실행 결과issue action 역시 data로 어떤 인자가 들어가는지는 abi를 통해 확인 가능합니다.abi의 issue structparameter 1 : account_name type — toparameter 2 : asset type — quantityparameter 3 : string type — memomemo 는 transfer 가 어떤 목적인지에 대해 설명해주는 인자 입니다. 생략해도 되는 값으로, 원하시면 parameter 개수를 유지하는 선에서 empty string을 넣으시면 됩니다. memo를 어떻게 쓰면 유용한지에 대해서도 다른 포스팅에 담도록 하겠습니다.issue가 잘 실행 되었는지 확인해 보겠습니다.$ cleos get currency balance hexlanthenry hexlanthenry저는 issue 를 4번 수행한 후 balance 를 체크 했기 때문에 총 40000개의 HEX token이 존재하는 것을 확인 할 수 있습니다.hexlanthenry 의 HEX token개수예외사항1create 하지 않은 token을 issue 할 경우해당 symbol 이 존재하지 않음예외사항2생성한 token 수보다 많은 양을 issue 할 경우maximum supply를 초과함Token transfer마지막으로 token을 다른 계정에 전송 해보도록 하겠습니다. 다른계정에 token을 보내야 하기 때문에 계정을 생성하거나 존재하고 있는 계정을 사용하시면 됩니다.아래 명령으로 hexlanthenry 계정이 babylion1234 계정으로 10000개의 HEX 토큰을 보냅니다.$ cleos push action hexlanthenry transfer '["hexlanthenry", "babylion1234", "10000.0000 HEX", "first"]' -p hexlanthenrytransfer 실행결과transfer 시 들어가는 data에 대해서도 abi를 확인해보겠습니다. 다른 action보다 많은 인자를 필요로 합니다. [“hexlanthenry”, “babylion1234”, “10000.0000 HEX”, “first”]abi의 transfer structparameter 1 : account_name type — fromparameter 2 : account_name type — toparameter 3 : asset type — quantityparameter 4 : string type — memo실제로 babylion1234 계정을 확인해 보면, 방금 배포한 HEX token을 보유하고있는 것을 확인할 수 있습니다.babylion1234의 HEX 보유이번 포스팅에서는 token을 생성과 발행 그리고 전송을 다뤄봤습니다. EOS는 Ethereum 과 달리 토큰 발행을 매우 쉽게 진행할 수 있습니다. 이 두 dapp의 차이에 대해서도 포스팅을 하고 싶으나 우선 다음 포스팅에서는 contract 개발의 기초를 다루도록 하겠습니다.감사합니다.#헥슬란트 #HEXLANT #블록체인 #개발자 #개발팀 #기술기업 #기술중심
조회수 444

컴공생의 AI 스쿨 필기 노트 ⑦합성곱 신경망

안녕하세요! 이번 주 수업에서는 합성곱 신경망에 대해서 배웠어요. 제가 읽은 한 기사에 의하면 대장 내시경 검사에도 딥러닝을 이용하면 종양 식별 능력을 더 높일 수 있다고 해요. 딥러닝을 이용한 검사는 전문가 분석을 통한 대장 내시경 검사보다 종양을 9개 더 많이 발견했고 진단 정확도는 96%인 것으로 나타났어요. (원문 링크) 이 대장 내시경에 우리가 배운 CNN(Convolutional Neural Network), 이미지 기반 딥러닝 모델을 사용했다고 하는데요. 이 대장 내시경에 사용된 CNN에 대해 알아볼까요? (Cover image : Photo by Paul Carmona on Unsplash)CNN(Convolutional Neural Network, 합성곱 신경망) CNN(합성곱 신경망)은 Convolution(합성곱)연산을 사용하는 인공신경망의 한 종류에요. 합성곱 신경망은 주로 이미지 데이터를 다루는 문제에서 사용돼요. 쉽게 말해 합성곱 신경망은 이미지의 특징을 추출하고 잘 조합하여 문제를 해결하는데요.  예를 들어 왼쪽 이미지가 고양이인지 컴퓨터가 알아맞히기 위해서 합성곱 신경망은 고양이가 가져야 할 특징을 한 번에 파악하는 것이 아니라 부분부분 판단하여 종합적으로 결론을 내요. 합성곱 신경망은 사진에 고양이의 특징이 기묘하게 분포되어 있어도 정확하게 고양이의 특징을 찾아내는 높은 적응도를 갖고 있어요.이제 합성곱 신경망의 구조에 대해 알아볼까요?CNN의 네트워크 구조1. 합성곱 층 (Convolutional Layer)합성곱은 두 함수 중 하나를 반전하고 이동시켜가며 다른 하나의 함수와 곱한 결과를 적분해나간다는 아주 어려운 뜻을 가지고 있어요. 다음 예시를 보도록 할게요.여기에 2차원 배열 픽셀을 넣으면 X 인지 O 인지 알아내는 합성곱 신경망이 있다고 해봐요.이 합성곱 신경망은 똑바로 된 X와 O를 넣으면 X 인지 O 인지 정확하게 구분하는데,이렇게 크기가 바뀌고 회전되어 모양이 변형된 이미지를 보고도 X 인지 O 인지 정확히 구분할 수 있을까요?합성곱 신경망은 합성곱 신경을 이용하여 이미지의 특징을 매칭 시킨 결과가 같으면 같은 이미지라고 인식해요.‘X’ 이미지의 특징을 추출하면 위와 같은 매트릭스, 합성곱 필터(Convolution filter(=커널))가 나와요. (세 특징을 잘 조합하면 X 형태가 나오죠?)이제 제일 왼쪽의 합성곱 필터를 가지고서 이미지가 X 인지 알아볼게요. 합성곱 필터와 원본 이미지를 비교할 때는 곱셈을 이용해요. 합성곱 필터의 크기만큼 원본 이미지와 차례차례 곱해서 값을 채워나가요.위의 합성곱 정의에서 두 함수를 하나는 이미지, 또 하나는 필터라고 생각하면, 필터를 이동시켜가며 이미지와 곱한 결과를 적분 즉, 덧셈해 나간다는 뜻이 돼요.합성곱 필터의 크기만큼 값을 다 계산한 후, 계산한 원소를 다 더해서 합성곱 필터의 크기만큼 나눈 평균값을 또 다른 새 매트릭스에 채우게 되는데 이를 특징 맵(Feature map)이라고 불러요. 즉, 특징 맵은 기존의 이미지에 필터를 곱한 결과로 각 픽셀에 쓰여있는 값이 클수록 그 특징을 가지고 있다는 뜻이에요.이렇게 원본 이미지와 합성곱 필터의 곱한 결과로 특징 맵이 나왔어요.나머지 두 개의 합성곱 필터와 곱한 결과로 두 개의 특징 맵을 가질 수 있어요.한 개의 합성곱 층(Convolutional layer)에는 여러 개의 합성곱 필터가 있어요. 합성곱 층에서 기존의 이미지와 필터들을 합성곱한 결과, 처음 이미지는 필터 된 이미지(특징 맵)로 쌓이게 돼요.2. 풀링 층(Pooling Layer)풀링은 가로/세로 방향의 공간을 줄이는 연산으로 합성곱 층의 특징을 압축한 특징 맵을 형성해요. 풀링에는 최대 풀링(Max pooling)과 평균 풀링(Average pooling)이 있는데 이미지 인식 분야에서 주로 사용하는 것은 최대 풀링이에요. 그래서 보통 풀링이라고 하면 최대 풀링이라는 의미로 사용한다고 보시면 돼요.위의 예시는 2x2 최대 풀링을 적용한 예시에요. 아까 구한 특징 맵에서 2x2 픽셀에서 가장 큰 원소 값을 새로운 맵을 채워나가는데 이를 활성화 맵(Activation map)이라고 불러요. 최대 풀링을 사용하면 노이즈가 감소하고 속도도 빨라지며 영상의 분별력이 좋아진다고 해요. 마지막 출력 층은 최대 풀링의 모든 뉴런과 연결되어 출력값이 어떤 클래스에 해당하는지 파악되는데 사용돼요.이렇게 CNN을 이용하면 변형된 이미지라고 하더라도 원래 이미지의 특징을 가지고 있다면 정확히 구분할 수 있어요.코드로 연습해보기아래는 간단한 인공신경망 코드예요.Layer 1 - input:1x28x28 , output : 64x28x28 + Activation function - reluLayer 2 - input: 64x28x28 output:1x28x28Layer 3 - input: 1x28x28=784 output:10class MNIST_Net(nn.Module):    def __init__(self):        super(MNIST_Net, self).__init__() # nn.Module 생성자 호출         # an affine operation: y = Wx + b        layers = []        layers.append(nn.Conv2d(1,64,3,1,1))         layers.append(nn.ReLU())         layers.append(nn.Conv2d(64,1,3,1,1))         layers.append(nn.ReLU())         self.main = nn.Sequential(*layers)        self.fc = nn.Linear(28*28, 10)    def forward(self, x):        # x.view함수는 주어진 인자의 크기로 해당 데이터의 크기를 반환합니다. 즉, (Batch_size,1,28,28) --> (Batch_size,28*28)로 변환합니다.        x = self.main(x)        x = x.squeeze().view(-1, 28*28)        x = self.fc(x)  # 10 으로 10개의 Class에 대한 logit 값을 호출합니다.         return x합성곱 인공 신경망의 내용은 정말 배울 것이 많아서 수업 시간 내에 다 배우기가 조금 벅찼지만 다른 인공 신경망에 비해 재밌어서 집중할 수 있었어요. 이제 앞으로 1번의 이론수업만을 남겨두고 있어서 아쉽기도 하고 또 뿌듯하기도 해요. 앞으로 조원들과 함께 프로젝트를 진행하면서 지금까지 배운 이론을 적용해보게 되는데요. 프로젝트 주제를 정하는 것부터 벌써 쉽지가 않아요. 하지만 열심히 프로젝트를 해서 리쿠르팅 데이 때 실력을 뽐낼 수 있다면 좋겠네요!* 이 글은 AI스쿨 - 인공지능 R&D 실무자 양성과정 7회차 수업에 대해 수강생 최유진님이 작성하신 수업 후기입니다.

기업문화 엿볼 때, 더팀스

로그인

/