스토리 홈

인터뷰

피드

뉴스

조회수 8382

AWS Lambda에서 메모리 설정값과 CPU 파워의 관계

안녕하세요. 데이블 백엔드 개발팀 최형주입니다.이번에 말씀드릴 내용은 서버 없는 컴퓨팅(Serverless Computing)의 널리 사용되는 AWS(Amazon Web Service)의 Lambda에 대한 내용입니다. AWS Lambda는 메모리 설정값에 따라 CPU 파워가 결정되는데, 그 메모리 설정값에 따라 CPU 파워가 어떻게 변화하는지에 대한 실험 내용을 설명하겠습니다. 처음에 AWS Lambda가 무엇인지 간략하게 소개를 하고 왜 이번 실험을 하게 되는지 배경 설명을 드릴 것입니다. 그다음 메모리 설정값에 따른 CPU 파워는 어떻게 결정되는지를 규명하고 마지막으로 이번 포스트를 간략히 요약겠습니다.목차1. AWS Lambda란?2. 실험배경3. 메모리 설정값과 CPU 파워의 관계4. 요약AWS Lambda란?AWS Lamba의 웹사이트AWS Lambda는 이벤트에 응답하여 코드를 실행하고 자동으로 기본 컴퓨팅 리소스를 관리하는 서버 없는 컴퓨팅 서비스입니다. 즉 코드를 업로드 하기만 하면 높은 가용성과 확장성을 보장하는 Lambda 플랫폼에서 코드를 실행합니다.AWS Lambda를 사용의 장점은 서버관리 불필요(Serverless), 지속적인 조정(Scaling), 밀리 초 단위의 측정 및 과금(Demand-based Pricing)입니다. 즉 서버를 프로비저닝(Provisioning)하거나 관리할 필요 없이 AWS Lambda에서 코드를 자동으로 실행하기 때문에 코드를 작성하고 AWS Lambda에 업로드하기만 하면 됩니다. 또한, 각 트리거에 대한 응답으로 코드를 실행하여 애플리케이션을 자동으로 확장하거나 축소합니다. 즉 코드는 병렬로 실행되고 각 트리거는 개별적으로 처리되어 정확히 워크로드(Workload) 규모에 맞게 조정됩니다. 과금 방식은 100밀리 초 단위로 코드가 실행되는 시간 및 코드가 트리거 되는 회수를 기준으로 요금이 부과됩니다. 코드가 실행되지 않을 때는 요금이 부과되지 않습니다.실험 배경AWS Lambda의 과금은 요청 요금과 컴퓨팅 요금의 합으로 계산됩니다. 요청 요금은 Lambda 함수를 호출한 총 요청 수에 대해 요금을 부과하고, 컴퓨팅 요금은 사용자가 업로드한 코드를 실행한 시간을 계산하여 100ms당 요금을 부과합니다. 컴퓨팅 요금은 사용자가 설정한 메모리 크기에 선형 비례하여 다르게 부과됩니다. 예를 들어 128MB 메모리에서는 100ms당 0.000000208$이고 256MB는 128MB의 약 두 배인 0.000000417$입니다. 그리고 512MB에서는 256MB의 두 배인 0.000000834$입니다. 또한, 더 큰 메모리를 사용할수록 더 큰 CPU 파워를 제공합니다.가장 큰 메모리 설정값을 사용하면 좋겠지만, 비용적인 측면을 고려해볼 때 사용자 입장에서의 사용 목적은 AWS Lambda로부터 최소한의 요금으로 최대한의 계산 효율을 뽑아내는 것입니다. 이 목적을 달성하기 위해서는 Lambda 함수를 실행할 때 메모리의 크기와 CPU의 파워(코어 수, 연산능력)를 명확하게 규명할 수 있어야 합니다. 메모리 크기는 사용자가 설정할 수 있습니다. 하지만 아쉽게도 아마존에서는 CPU 용량은 설정한 메모리 크기에 비례하여 결정된다고만 설명되어 있고 어느 정도의 성능을 가졌는지 명시하지 않고 있습니다.하지만 데이블의 백엔드 개발팀에서, 실험을 통하여 AWS Lambda에서 메모리 설정값에 따라 CPU 파워가 어떻게 변하는지 규명해냈습니다. 이제 그것을 이 포스팅을 통해 설명해 드리고자합니다.메모리 설정값과 CPU 파워의 관계"설정한 메모리 크기와 CPU 파워는 지수적 감쇠 관계(Exponential Decay)를 보인다"앞서 "CPU 파워는 메모리 설정한 값에 비례하여 증가한다”라고 했습니다. "그러면 어느 정도로 어떻게 비례하는가?”, “당연히 선형관계 아닌가?"라는 질문이 자연스럽게 나올 것입니다. 저희는 이 질문에 대답하기 위해 각 메모리 설정값별로 100만 번의 덧셈연산을 하여 각 설정 별 처리시간을 계산해 보았습니다. 다음 [그림 1]은 100만 번의 덧셈 연산을 했을 때 처리시간을 나타낸 그래프입니다. X축은 할당한 메모리의 크기를 나타내고 Y축은 처리시간을 초 단위로 측정한 것입니다. 보시는 바와 같이 처리시간은 메모리 크기에 따라 지수적으로 감소함을 알 수 있었습니다. 그러므로 AWS Lambda에서는 설정한 메모리 크기와 CPU 파워는 지수적 감쇠 관계(Exponential Decay)를 보인다고 결론을 내릴 수 있습니다. 예를 들면 현재 설정한 메모리보다 2배 높은 CPU 파워를 사용하고 싶으면 2배로 큰 메모리 용량을 설정해야 합니다.[그림 1] 메모리 설정값에 따른 처리시간필요로 하는 메모리 크기와 사용하는 응용에 따라 다르겠지만, 일반적으로 메모리의 크기에 상관없이 사용하는 비용이 거의 같다고 얘기할 수 있습니다. [그림 2]는 앞서 100만 번 덧셈 연산을 1만 번 호출했을 때의 각 메모리 설정값 별 요금을 나타낸 것입니다. X축은 설정한 메모리 크기이고 Y축은 각 메모리 설정값 별 요금입니다. 보시는 바와 같이 분포가 급격히 변하지 않고 대체로 균일한 것을 알 수 있습니다.[그림 2] 메모리 설정값에 따른 요금하지만 프로그램의 실행 시간은 단순히 CPU 파워로만으로 처리 시간이 결정되지 않기 때문에 다양한 요인을 검토해야 합니다. 알고리즘의 시간복잡도, 메모리의 크기와 접근 횟수, 네트워크 비용 등 다양한 것들이 처리 시간에 영향을 미치기 때문에 단순히 메모리 설정값을 늘려서 사용하는 방법은 옳지 못합니다. 그러므로 위 자료를 참고 용도로만 사용하셔서 하고자 하는 목적에 맞게 가장 최적의 메모리 설정값을 설정하시면 됩니다.요약AWS Lambda는 대표적인 서버 없는 컴퓨팅 서비스입니다. AWS Lambda에서 뛰어난 가성비를 얻고자 할 때는 각 설정값에 따라 제공하는 자원을 예측할 수 있어야 합니다. 여러 설정값 중 가장 성능에 큰 영향을 미치는 것은 사용하고자 하는 메모리 크기인데 이 크기에 따라 CPU 파워가 결정됩니다. 하지만 각 메모리 설정값에 따른 CPU 파워 정보를 아마존에서 제공해 주지 않고 있으므로 실험을 통해서 확인하였습니다. 실험 결과 설정한 메모리 크기와 CPU 파워는 지수적 감쇠 관계(Exponential Decay)를 규명했습니다. 이 규명은 단순한 프로그램에서만 확인한 것이기 때문에 최고의 효율을 가지는 AWS Lambda를 사용하기 위해서는 그 밖의 다양한 것들을 고려하여 설정해야 합니다.  기타머신 성능 및 정보- 사용하는 CPU는 Intel(R) Xeon(R) CPU E5-2666 v3 @ 2.90GHz, 코어의 개수는 2개, 그리고 캐시의 크기는 25600 KB 임(사용하는 Microcode는 바뀔 수 있음)- 메모리는 약 3.67GB를 가짐실험에 사용한 Lambda 함수import osimport multiprocessingimport timeimport subprocessdef lambda_handler(event, context):mem_bytes = os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES')mem_gib = mem_bytes/(1024.**3)num_cores = multiprocessing.cpu_count()#start_time = time.time()print subprocess.check_output ('vmstat -s', shell=True)sum = 0for i in range(1000000):sum += iif sum 000 == 0:print subprocess.check_output ('vmstat -s', shell=True)print subprocess.check_output ('vmstat -s', shell=True)hostname = subprocess.check_output ('hostname', shell=True)cpuinfo = subprocess.check_output ('cat /proc/cpuinfo', shell=True)meminfo = subprocess.check_output('cat /proc/meminfo', shell = True)print hostnameprint '--------------------------------------------------------------\n\n'print 'CPU Information'print cpuinfoprint '--------------------------------------------------------------\n\n'print 'Memory Information'print meminfoprint '\n\n\n\n'참고 자료https://aws.amazon.com/ko/lambda/details/#데이블 #개발 #개발자 #인사이트 #꿀팁 #AWS #조언
조회수 847

비트윈의 HBase 스키마 해부 - VCNC Engineering Blog

비트윈에서는 HBase를 메인 데이터베이스로 이용하고 있습니다. 유저 및 커플에 대한 정보와 커플들이 주고받은 메시지, 업로드한 사진 정보, 메모, 기념일, 캘린더 등 서비스에서 만들어지는 다양한 데이터를 HBase에 저장합니다. HBase는 일반적인 NoSQL과 마찬가지로 스키마를 미리 정의하지 않습니다. 대신 주어진 API를 이용해 데이터를 넣기만 하면 그대로 저장되는 성질을 가지고 있습니다. 이런 점은 데이터의 구조가 바뀔 때 별다른 스키마 변경이 필요 없다는 등의 장점으로 설명되곤 하지만, 개발을 쉽게 하기 위해서는 데이터를 저장하는데 어느 정도의 규칙이 필요합니다. 이 글에서는 비트윈이 데이터를 어떤 구조로 HBase에 저장하고 있는지에 대해서 이야기해 보고자 합니다.비트윈에서 HBase에 데이터를 저장하는 방법Thrift를 이용해 데이터 저장: Apache Thrift는 자체적으로 정의된 문법을 통해 데이터 구조를 정의하고 이를 직렬화/역직렬화 시킬 수 있는 기능을 제공합니다. 비트윈에서는 서버와 클라이언트가 통신하기 위해 Thrift를 이용할 뿐만 아니라 HBase에 저장할 데이터를 정의하고 데이터 저장 시 직렬화를 위해 Thrift를 이용합니다.하나의 Row에 여러 Column을 트리 형태로 저장: HBase는 Column-Oriented NoSQL로 분류되며 하나의 Row에 많은 수의 Column을 저장할 수 있습니다. 비트윈에서는 Column Qualifier를 잘 정의하여 한 Row에 여러 Column을 논리적으로 트리 형태로 저장하고 있습니다.추상화된 라이브러리를 통해 데이터에 접근: 비트윈에서는 HBase 클라이언트 라이브러리를 직접 사용하는 것이 아니라 이를 래핑한 Datastore라는 라이브러리를 구현하여 이를 이용해 HBase의 데이터에 접근합니다. GAE의 Datastore와 인터페이스가 유사하며 실제 저장된 데이터들을 부모-자식 관계로 접근할 수 있게 해줍니다.트랜잭션을 걸고 데이터에 접근: HBase는 일반적인 NoSQL과 마찬가지로 트랜잭션을 제공하지 않지만 비트윈에서는 자체적으로 제작한 트랜잭션 라이브러리인 Haeinsa를 이용하여 Multi-Row ACID 트랜잭션을 걸고 있습니다. Haeinsa 덕분에 성능 하락 없이도 데이터 무결성을 유지하고 있습니다.Secondary Index를 직접 구현: HBase에서는 데이터를 Row Key와 Column Qualifier를 사전식 순서(lexicographical order)로 정렬하여 저장하며 정렬 순서대로 Scan을 하거나 바로 임의 접근할 수 있습니다. 하지만 비트윈의 어떤 데이터들은 하나의 Key로 정렬되는 것으로는 충분하지 않고 Secondary Index가 필요한 경우가 있는데, HBase는 이런 기능을 제공하지 않고 있습니다. 비트윈에서는 Datastore 라이브러리에 구현한 Trigger을 이용하여 매우 간단한 형태의 Secondary Index를 만들었습니다.비트윈 HBase 데이터 구조 해부페이스북의 메시징 시스템에 관해 소개된 글이나, GAE의 Datastore에 저장되는 구조를 설명한 글을 통해 HBase에 어떤 구조로 데이터를 저장할지 아이디어를 얻을 수 있습니다. 비트윈에서는 이 글과는 약간 다른 방법으로 HBase에 데이터를 저장합니다. 이에 대해 자세히 알아보겠습니다.전반적인 구조비트윈에서는 데이터를 종류별로 테이블에 나누어 저장하고 있습니다. 커플과 관련된 정보는 커플 테이블에, 유저에 대한 정보는 유저 테이블에 나누어 저장합니다.각 객체와 관련된 정보는 각각의 HBase 테이블에 저장됩니다.또한, 관련된 데이터를 하나의 Row에 모아 저장합니다. 특정 커플과 관련된 사진, 메모, 사진과 메모에 달린 댓글, 기념일 등의 데이터는 해당 커플과 관련된 하나의 Row에 저장됩니다. Haeinsa를 위한 Lock Column Family를 제외하면, 데이터를 저장하기 위한 용도로는 단 하나의 Column Family만 만들어 사용하고 있습니다.각 객체의 정보와 자식 객체들은 같은 Row에 저장됩니다.또한, 데이터는 기본적으로 하나의 Column Family에 저장됩니다.이렇게 한 테이블에 같은 종류의 데이터를 모아 저장하게 되면 Region Split하는 것이 쉬워집니다. HBase는 특정 테이블을 연속된 Row들의 집합인 Region으로 나누고 이 Region들을 여러 Region 서버에 할당하는 방식으로 부하를 분산합니다. 테이블을 Region으로 나눌 때 각 Region이 받는 부하를 고려해야 하므로 각 Row가 받는 부하가 전체적으로 공평해야 Region Split 정책을 세우기가 쉽습니다. 비트윈의 경우 커플과 관련된 데이터인 사진이나 메모를 올리는 것보다는 유저와 관련된 데이터인 메시지를 추가하는 트래픽이 훨씬 많은데, 한 테이블에 커플 Row와 유저 Row가 섞여 있다면 각 Row가 받는 부하가 천차만별이 되어 Region Split 정책을 세우기가 복잡해집니다. RegionSplitPolicy를 구현하여 Region Split 정책을 잘 정의한다면 가능은 하지만 좀 더 쉬운 방법을 택했습니다.또한, 한 Row에 관련된 정보를 모아서 저장하면 성능상 이점이 있습니다. 기본적으로 한 커플에 대한 데이터들은 하나의 클라이언트 요청을 처리하는 동안 함께 접근되는 경우가 많습니다. HBase는 같은 Row에 대한 연산을 묶어 한 번에 실행시킬 수 있으므로 이 점을 잘 이용하면 성능상 이득을 얻을 수 있습니다. 비트윈의 데이터 구조처럼 특정 Row에 수많은 Column이 저장되고 같은 Row의 Column들에 함께 접근하는 경우가 많도록 설계되어 있다면 성능 향상을 기대할 수 있습니다. 특히 Haeinsa는 한 트랜잭션에 같은 Row에 대한 연산은 커밋시 한 번의 RPC로 묶어 처리하므로 RPC에 드는 비용을 최소화합니다. 실제 비트윈에서 가장 많이 일어나는 연산인 메시지 추가 연산은 그냥 HBase API를 이용하여 구현하는 것보다 Haeinsa Transaction API를 이용해 구현하는 것이 오히려 성능이 좋습니다.Column Qualifier의 구조비트윈은 커플들이 올린 사진 정보들을 저장하며, 또 사진들에 달리는 댓글 정보들도 저장합니다. 한 커플을 Root라고 생각하고 커플 밑에 달린 사진들을 커플의 자식 데이터, 또 사진 밑에 달린 댓글들을 사진의 자식 데이터라고 생각한다면, 비트윈의 데이터들을 논리적으로 트리 형태로 생각할 수 있습니다. 비트윈 개발팀은 Column Qualifier를 잘 정의하여 실제로 HBase에 저장할 때에도 데이터가 트리 형태로 저장되도록 설계하였습니다. 이렇게 트리 형태로 저장하기 위한 Key구조에 대해 자세히 알아보겠습니다.Column Qualifier를 설계할 때 성능을 위해 몇 가지 사항들을 고려해야 합니다. HBase에서는 한 Row에 여러 Column이 들어갈 수 있으며 Column들은 Column Qualifier로 정렬되어 저장됩니다. ColumnRangeFilter를 이용하면 Column에 대해 정렬 순서로 Scan연산이 가능합니다. 이 때 원하는 데이터를 순서대로 읽어야 하는 경우가 있는데 이를 위해 Scan시, 최대한 Sequential Read를 할 수 있도록 설계해야 합니다. 또한, HBase에서 데이터를 읽어올 때, 실제로 데이터를 읽어오는 단위인 Block에 대해 캐시를 하는데 이를 Block Cache라고 합니다. 실제로 같이 접근하는 경우가 빈번한 데이터들이 최대한 근접한 곳에 저장되도록 설계해야 Block Cache의 도움을 받을 수 있습니다.비트윈에서는 특정 커플의 사진이나 이벤트를 가져오는 등의 특정 타입으로 자식 데이터를 Scan해야하는 경우가 많습니다. 따라서 특정 타입의 데이터를 연속하게 저장하여 최대한 Sequential Read가 일어나도록 해야 합니다. 이 때문에 Column Qualifier가 가리키는 데이터의 타입을 맨 앞에 배치하여 같은 타입의 자식 데이터들끼리 연속하여 저장되도록 하였습니다. 만약 가리키는 데이터의 타입과 아이디가 Parent 정보 이후에 붙게 되면 사진 사이사이에 각 사진의 댓글 데이터가 끼어 저장됩니다. 이렇게 되면 사진들에 대한 데이터를 Scan시, 중간중간 저장된 댓글 데이터들 때문에 완벽한 Sequential Read가 일어나지 않게 되어 비효율적입니다.이렇게 특정 타입의 자식들을 연속하게 모아 저장하는 묶음을 컬렉션이라고 합니다. 컬렉션에는 컬렉션에 저장된 자식들의 개수나 새로운 자식을 추가할 때 발급할 아이디 등을 저장하는 Metadata가 있습니다. 이 Metadata도 특정 Column에 저장되므로 Metadata를 위한 Column Qualifier가 존재합니다. 이를 위해 Column Qualifier에는 Column Qualifier가 자칭하는 데이터가 Metadata인지 표현하는 필드가 있는데, 특이하게도 메타데이터임을 나타내는 값이 1이 아니라 0입니다. 이는 Metadata가 컬렉션의 맨 앞쪽에 위치하도록 하기 위함입니다. 컬렉션을 읽을 때 보통 맨 앞에서부터 읽는 경우가 많고, 동시에 Metadata에도 접근하는 경우가 많은데, 이 데이터가 인접하게 저장되어 있도록 하여 Block Cache 적중이 최대한 일어나도록 한 것입니다.Datastore 인터페이스비트윈에서는 이와 같은 데이터 구조에 접근하기 위해 Datastore라는 라이브러리를 구현하여 이를 이용하고 있습니다. HBase API를 그대로 이용하는 것보다 좀 더 쉽게 데이터에 접근할 수 있습니다. GAE의 Datastore와 같은 이름인데, 실제 인터페이스도 매우 유사합니다. 이 라이브러리의 인터페이스에 대해 간단히 알아보겠습니다.Key는 Datastore에서 HBase에 저장된 특정 데이터를 지칭하기 위한 클래스입니다. 논리적으로 트리 형태로 저장된 데이터 구조를 위해 부모 자식 관계를 이용하여 만들어 집니다.Key parentKey = new Key(MType.T_RELATIONSHIP, relId); Key photoKey = new Key(parentKey, MType.T_PHOTO, photoId); // 특정 커플 밑에 달린 사진에 대한 키 Datastore는 Key를 이용해 Row Key와 Column Qualifier를 만들어 낼 수 있습니다. Datastore는 이 정보를 바탕으로 HBase에 새로운 데이터를 저장하거나 저장된 데이터에 접근할 수 있는 메서드를 제공합니다. 아래 코드에서 MUser 클래스는 Thrift로 정의하여 자동 생성된 클래스이며, Datastore에서는 이 객체를 직렬화 하여 HBase에 저장합니다.MUser user = new MUser(); user.setNickname("Alice"); user.setGender(Gender.FEMALE); user.setStatus("Hello World!"); Key userKey = new Key(MType.T_USER, userId); getDatastore().put(userKey, user); user = getDatastore().get(userKey); getDatastore().delete(userKey); 또한, Datastore는 Key를 범위로 하여 Scan연산이 할 수 있도록 인터페이스를 제공합니다. Java에서 제공하는 Try-with-resource문을 이용하여 ResultScanner를 반드시 닫을 수 있도록 하고 있습니다. 내부적으로 일단 특정 크기만큼 배치로 가져오고 더 필요한 경우 더 가져오는 식으로 구현되어 있습니다.try (CloseableIterable> entries = getDatastore().subSibling(fromKey, fromInclusive, toKey, toInclusive)) { for (KeyValue entry : entries) { // do something } } Secondary Index 구현 방법HBase는 데이터를 Row Key나 Column Qualifier로 정렬하여 저장합니다. 이 순서로만 Sequential Read를 할 수 있으며 Key값을 통해 특정 데이터를 바로 임의 접근할 수 있습니다. 비트윈에서는 특정 달에 해당하는 이벤트들을 읽어오거나 특정 날짜의 사진들의 리스트를 조회하는 등 id 순서가 아니라 특정 값을 가지는 데이터를 순서대로 접근해야 하는 경우가 있습니다. 이럴 때에도 효율적으로 데이터에 접근하기 위해서는 id로 정렬된 것 외에 특정 값으로 데이터를 정렬할 수 있어야 합니다. 하지만 HBase에서는 이와 같은 Secondary Index 같은 기능을 제공하지 않습니다. 비트윈 개발팀은 이에 굴하지 않고 Secondary Index를 간단한 방법으로 구현하여 사용하고 있습니다.구현을 간단히 하기 위해 Secondary Index를 다른 데이터들과 마찬가지로 특정 타입의 데이터로 취급하여 구현하였습니다. 따라서 Index에 대해서도 Column Qualifier가 발급되며, 이때, Index에 해당하는 id를 잘 정의하여 원하는 순서의 Index를 만듭니다. 이런 식으로 원하는 순서로 데이터를 정렬하여 저장할 수 있으며 이 인덱스를 통해 특정 필드의 값의 순서대로 데이터를 조회하거나 특정 값을 가지는 데이터에 바로 임의 접근할 수 있습니다. 또한, Index에 실제 데이터를 그대로 복사하여 저장하여 Clustered Index처럼 동작하도록 하거나, Reference만 저장하여 Non-Clustered Index와 같이 동작하게 할 수도 있습니다. Datastore 라이브러리에는 특정 데이터가 추가, 삭제, 수정할 때 특정 코드를 실행할 수 있도록 Trigger 기능이 구현되어 있는데, 이를 통해 Index를 업데이트합니다. 데이터의 변경하는 연산과 Index를 업데이트하는 연산이 하나의 Haeinsa 트랜잭션을 통해 원자적으로 일어나므로 데이터의 무결성이 보장됩니다.못다 한 이야기각 테이블의 특정 Row의 Column들에 대한 Column Qualifier외에도 Row에 대한 Row Key를 정의 해야 합니다. 비트윈에서는 각 Row가 표현하는 Root객체에 대한 아이디를 그대로 Row Key로 이용합니다. 새로운 Root객체가 추가될 때 발급되는 아이디는 랜덤하게 생성하여 객체가 여러 Region 서버에 잘 분산될 수 있도록 하였습니다. 만약 Row Key를 연속하게 발급한다면 특정 Region 서버로 연산이 몰리게 되어 성능 확장에 어려움이 생길 수 있습니다.데이터를 저장할 때 Thrift를 이용하고 있는데, Thrift 때문에 생기는 문제가 있습니다. 비트윈에서 서버를 업데이트할 때 서비스 중지 시간을 최소화하기 위해 롤링 업데이트를 합니다. Thrift 객체에 새로운 필드가 생기는 경우, 롤링 업데이트 중간에는 일부 서버에만 새로운 Thift가 적용되어 있을 수 있습니다. 업데이트된 서버가 새로운 필드에 값을 넣어 저장했는데, 아직 업데이트가 안 된 서버가 이 데이터를 읽은 후 데이터를 다시 저장한다면 새로운 필드에 저장된 값이 사라지게 됩니다. Google Protocol Buffer의 경우, 다시 직렬화 할 때 정의되지 않은 필드도 처리해주기 때문에 문제가 없지만, Thrift의 경우에는 그렇지 않습니다. 비트윈에서는 새로운 Thrift를 적용한 과거 버전의 서버를 먼저 배포한 후, 업데이트된 서버를 다시 롤링 업데이트를 하는 식으로 이 문제를 해결하고 있습니다.
조회수 863

AWS IoT Core 활용하기

이 포스팅에 실린 실습은 AWS CLI가 설치되어 있고, AWS credentials이 설정되어 있는 상태에서 진행했습니다. 서버와 하드웨어 사이의 TCP 연결을 구현하지 않고 AWS IoT를 이용해 MQTT 프로토콜로 데이터를 송수신하는 환경을 구성해보겠습니다. 진행을 위해 AWS IoT와 NodeJS가 필요합니다.1.AWS IoT Core로 접속해 사물을 생성합니다. 테스트로 1개만 사용할 것이므로 “단일 AWS IoT 사물”로 등록합니다.2.‘인증서 없이 사물 생성’을 클릭합니다. 인증서는 사물 등록 후에 생성할 예정입니다.3.사물이 정상적으로 등록되었는지 확인합니다.4.루트 CA 인증서를 생성합니다. 4-1.개인키를 생성하기 전, openssl 설정 파일을 추가해 아래 내용으로 저장합니다. 아래와 같이 진행하는 이유는 basicConstraints = true로 설정하기 위해서입니다.4-2.개인키를 생성합니다.openssl genrsa -out rootCA.key 2048 4-3.루트 인증서를 생성합니다.openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem -config rootCA_openssl.conf -extensions v3_ca 5.인증서를 생성합니다. 5-1.AWS IoT 등록 코드를 확인합니다.aws iot —region=ap-northeast-1 get-registration-code 5-2.개인키를 생성합니다.openssl genrsa -out verificationCert.key 2048 5-3.CSR을 생성합니다. 앞서 5-1에서 확인한 등록코드를 Common Name 항목에 입력합니다.openssl req -new -key verificationCert.key -out verificationCert.csr 5-4.인증서를 생성합니다.openssl x509 -req -in verificationCert.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out verificationCert.pem -days 500 -sha256 5-5.CA 인증서와 개인 인증서 파일들을 확인합니다.5-6.AWS에 인증서를 등록합니다.aws iot register-ca-certificate —ca-certificate file://rootCA.pem —verification-cert file://verificationCert.pem —region=ap-northeast-2 5-7.AWS에 인증서를 활성화합니다.aws iot update-ca-certificate --certificate-id 인증서 등록 후 응답으로 오는 certificateId 값 --new-status ACTIVE --region=ap-northeast-2 예)aws iot update-ca-certificate —certificate-id AAAAAABDADFDF1ABADFDFDFDF### —new-status ACTIVE —region=ap-northeast-2 5-8.AWS에 인증서 자동 등록 활성화를 켭니다.6.AWS 콘솔에 접속해 CA 인증서 등록을 확인합니다.7.AWS 콘솔에서 인증서를 생성합니다.7-1.원클릭 인증서 생성을 클릭합니다.7-2.활성화를 클릭하면 완료됩니다.8.인증서와 사물을 연결합니다.9.상호 작용 탭에서 디바이스를 연결합니다.10.환경에 맞게 선택하여 다운로드합니다.11.압축을 해제해 srart.sh를 실행하고, 연결 대기합니다.12.AWS IoT 테스트 접속 후, topic 1으로 메시지를 게시합니다.13.터미널을 확인합니다.이것으로 AWS IoT 로컬 환경이 구성되었습니다. AWS IoT를 사용하면 서버와 하드웨어를 제어하는 클라이언트 간 통신을 쉽게 하도록 다양한 구성을 할 수 있습니다. 모든 포맷은 JSON 포맷으로 송수신하며, MQTT(Message Queueing Telemetry Transport) 방식이라 양방향 통신을 쉽게 처리하고 전송할 수 있을 겁니다.참고자세한 MQTT - Publish/Subscribe 모델은 여기를 클릭하세요.글장현준 팀장 | R&D 개발3팀janghj@brandi.co.kr브랜디, 오직 예쁜 옷만
조회수 2388

코드 커버리지 80% 넘긴 썰

첫번재 코드를 짜기까지2015년 1월이었던 것으로 기억해. 당시 전 회사에서 테스트를 정착시키기 위해서 노력을 하고 있었는데, 사실 잘 되지 않았어. 그래서 혼자 ‘Testing Goat’를 따르며 공부를 하고 있었어. 그때 8퍼센트 이효진 대표와 연락이 닿았고, 초기 개발을 좀 도와 달라는 요청을 받았어. 옳다구나! 실전에 적용해 볼 수 있겠다 생각이 들어서 도와주기로 했지이것이 8퍼센트의 첫번째 commit간단한 기능을 가지고 있어서, TDD를 하면서 unit test와 functional test를 붙여서 전달해줬지. 책에 있는 내용을 열심히 활용해서 코드를 짜긴 했지만, 테스트 코드와 함께 결과물을 전달해서 스스로 뿌듯해했어. 물론 그때까지만 해도 내가 8퍼센트 들어갈 거라고는 생각도 하지 못했지. (사람의 인생이란 참)2015년 PyCon에서 발표테스트 없이 코드를 짜다가, 테스트와 함께 개발을 하다 보니 이게 너무 좋은 거야. 그래서 발표를 해야겠다는 생각을 했어. 그래서 아래 꼭지들을 내용으로 발표를 했어. ㅇ 테스트가 왜 필요할까요? 어떤 테스트가 필요할까요?ㅇ 좋은 테스트란 무엇인가요?ㅇ unittest 소개 및 활용ㅇ 테스트 관련 툴 소개ㅇ 내가 하고 있는 테스팅 과정 소개발표를 준비하면서 팀 단위에서 이런 것들을 제대로 한번 해보면 좋겠다는 생각을 했어. 내가 돌아왔다2015년 11월에 8퍼센트에 CTO로 조인을 하게 되었어. 처음으로 CTO로 일을 하게 된 것이었으니까, 이런저런 꿈에 부풀었지. 그중 하나가 ‘테스팅을 제대로 한번 해보자’라는 생각이었어. 코드를 살펴보니까 뭔가 내가 처음에 작성해서 넘긴 후에도 테스트 코드가 추가된 흔적은 있는데 제대로 동작하고 있는 것 같진 않더라고. 일단 기존에 있던 테스트들을 정리했어. 동작해야 하는 것 들을 정리하고, 필요 없는 것들을 지웠지. 그리고는 git push hook 에 테스팅을 추가했어. unittest가 돌지 않으면 push를 하지 못하도록 해버렸어.당시에는 bitbucket을 쓰고 있기도 했고 특별히 CI툴을 붙이지 않은 상태였어서,  기록이 남아 있지 않더라. 하지만 당시의 코드 커버리지가 한 20% 정도였을 것 같아. 그 뒤로 PR을 통해 코드 리뷰를 할 때에는 테스트가 짜여 있지 않은 경우에는 관련된 테스트를 추가해 달라고 요청을 했어. 하지만 구성원들이 테스트를 편하게 짜게 될 때까지는 꽤 시간이 걸렸어. 특히 unittest.mock, freezegun , fixture 등을 사용해서 테스트 상황을 잘 구성하는 것에 익숙해지는 것에 시간이 걸렸던 것 같아. Travis 의 도입 2016년 1월에 github으로 갈아타면서 travis를 도입했어. 기존에는 push을 할 때마다 전체 테스트를 돌리도록 했었는데, 테스트의 양이 늘어나면서 push의 시간이 오래 걸리는 문제가 있었어. 그래서 travis에서 테스트를 돌리도록 했어. 이제는 테스트가 안 돌아도 push 까지는 할 수 있는데 PR merge는 할 수 없는 상태가 된 거지. 그 이후에는 flake8을 돌려서 스타일 체크를 시작했어. 그래 생각난다. 개발팀에서 하루 날 잡아서 PEP8에 맞춰서 코드들을 수정했어. 그렇게 한 이후에도 수정할 것들이 많이 남아 있어서 모듈 단위로 수정을 하면서 해당 모듈을 추가로 검사할 수 있도록 travis와 commit hook에 추가해 나갔어. 결국 다 정리되긴 하더라. 그리고는 주요 브랜치에 대한 빌드를 깨뜨린 사람이 음료수를 쏘는 규칙을 만들었어. (주요 브랜치가 깨진다는 것은 로컬 환경과 travis 모두에서 테스트를 생략했다는 이야기거든)지금은 github flow  라서 develop branch 는 없어FactoryBoy의 사용테스트가 점점 늘어나서 한 1500개 정도가 되었어. 점점 모델도 많아지게 되면서 fixture로 테스트 데이터를 관리하는데 한계가 왔어. 예를 들면 신용평가를 한번 하면 데이터가 200여개가 쌓이는데, 신용평가 모델에 대한 테스트를 하려면 그것들을 다 fixture로 만들어야 했어. 그래서 개발팀의 한 분(누군지 기억은 안나는데 고마워요)이 FactoryBoy를 추천해 주셨고, 쓰기로 했지. 지금까지 만들어졌던 fixture 들을 모두 factory 기반으로 옮기는 것도 간단하지는 않았어. 하지만 새롭게 만드는 것부터 적용하고 과거 테스트들을 고칠 때마다 조금씩 조금씩 수정을 했더니, 다 고쳐지긴 하더라고. 그 이후로는 새롭게 모델을 만들 때에는 항상 관련된 TestFactory를 함께 만들어 주게 되었어.테스트 커버리지 측정도구 도입이걸 처음에 왜 붙였는지는 잘 모르겠어. 사실 그전까지는 테스트 커버리지를 재미로 측정해 본 적은 있었지만 꾸준히 측정을 해야겠다는 생각을 해보진 못했었거든. 그런데 이 수치가 측정이 되기 시작되면서부터는 많은 것들이 바뀌었어. 처음 측정 했을 때가 63.59%바뀐 게 무엇이냐고 하면, PR에서 '공식적인 잔소리'가 가능해졌어. 이게 테스트를 작성하다 보면 자괴감이 들 때가 있거든. 내가 봤을 때 너무나 자명한 것에 대한 테스트를 작성할 때야. 그런데 이 테스트라는 것이 지금의 내 기준으로 보면 안 되고, 다른 누군가 그리고 혹은 미래의 나를 기준으로 바라봐야 하거든. 그래서 자괴감을 느낄 시간에 그냥 짜야해. 근데 우리가 사람인지라 가끔 나태해 지거든. 나태해 지면...뭐. 나라고 예외는 없지UI 테스트에 대한 좌절처음에 테스트를 시작했을 때에는 selenium을 이용해서 UI에 대한 functional test가 있었어. 그리고 꽤 오랫동안 유지가 되었었지. 그 이후에는 멀티플랫폼에 대한 테스트를 하기 위해서 sauce labs를 통해서 firefox, IE, mobile browser 에 대한 테스트도 자동으로 진행했었어. 그런데 이 테스트는 한번 동작시키는데 시간이 너무 오래 걸리다 보니 로컬 환경에서 테스트가 쉽지 않더라. 그래서 CI환경에서만 테스트를 돌리게 했어. 그랬더니 수정하고 다시 CI에서의 테스트를 위해 push 해야 하고 또 기다리게 되더라고. 이런 어려움 때문에 중단했다, 재개했다, 중단했다, 재개했다를 몇 번 반복한 이후에 지금은 작성하고 있지 않아. 우리 팀의 프런트엔드를 이전 작업이 어느정도 되고 나면, UI 테스트를 꼭 다시 시도해 볼 생각이야.80%의 공약70%가 넘고 나니까 전체 테스트 커버리지를 올리는 것이 쉽지 않았어. 그래서 개발팀에 공약을 하나 걸었지.그날이 금방 올것 같지는 않았어그랬더니 사람들이 코드를 지우기 시작하더라고... 물론 사용되지 않는 코드를 말이야. 그리고 아예 브랜치 이름을 "80percent"라고 만들더니 예전에 테스트 코드를 작성하지 않던 시절의 코드까지 테스트를 붙이기 시작했어. 보이니? 그래프 마지막, 사람들의 욕망이?사실 80%가 특별한 의미가 있는 숫자는 아니야. 그냥 100줄의 코드에서 80줄의 코드가 테스트가 되고 있다는 것이지. 그래도 우리가 2년 동안 테스트를 중요하게 생각하고, 열심히 노력해 온 결과라고 생각하면 좀 뿌듯해. 달성흠. 나는 약속을 중요하게 생각하는 사람이야. 그리고 우리 팀원들은 나보다 더 약속을 중요하게 생각한다는 것을 알게 되었어.  아. 그리고 위 사진에 디자이너 두 분이 있어. 디자이너 분들도 commit 한 코드가 있으니 점심을 먹을 자격이 충분하지. 암암. 그렇지.이렇게 해서 80%를 달성하기까지의 과정을 적어 봤어. 짧은 글에 적혔지만 사실 2년의 시간이 걸렸고 아마 팀원들의 몇천 시간이 들어간 일일 거야. 모두들 고마워~끝!사람들을 낚아 보기 위해서 글 제목을 "~썰"로 지었다가, 평소에 잘 쓰지 않는 스타일의 쓰기 글이 되어 버렸다. 글의 남은 부분에서는 80%를 달성하고 나니 어떤 점이 좋은지 앞으로는 어떤 부분을 잘 하고 싶은지를 추가로 적어 보겠다.테스트를 작성하니까 무엇이 좋은가?테스트를 작성하게 되면 코드리뷰가 더 쉬워진다. 코드를 읽다가 잘 이해가 되지 않으면 테스트 코드를 살펴본다. 작성된 코드는 어떻게 사용되는가? 작성된 코드는 어떤 기능인가? 작성된 코드에서 주의해야 하는 점은 무엇인가? 를 효과적으로 알 수 있다.코드 수정에 자신감이 생긴다. 내가 오래전에 짠 코드, 다른 팀원들이 짠 코드는 수정하기가 무섭다. 특히 우리 회사와 같이 대부분의 코드 수정이 실제 돈의 흐름에 영향을 주는 경우는 더욱 무섭다. 하지만 테스트가 있으면 자신감이 생긴다. (그렇다고 안 무서운 것은 아니다.) 특히 시스템이 복잡해질수록 정적 분석 혹은 QA로 특정 코드에 대한 수정의 영향을 파악하기가 어렵다. 자동화된 테스트 외의 답은 없다고 생각한다. 11월에는 작성한 코드 보다 삭제한 코드가 더 많다. 이렇게 리팩토링이 가능하다.이제 수정하지 못하는 코드는 오래된 코드, 작성자가 퇴사한 코드가 아니라 테스트가 없는 코드가 되었다.테스트가 정착되기까지 키가 된 것은 무엇이었나?자동화를 통한 강제였다고 생각한다. 첫 번째 시점은 git hook을 사용한 시점이었다. commit을 할 때 flake8 체크를 하고 push를 할 때 테스트를 돌려주었다. 사람들은 스타일을 맞추지 않으면 commit을 할 수 없게 되었고, 기존의 테스트를 깨뜨리게 되면 코드를 push 할 수 없게 되었다. 두 번째 시점은 CI툴의 도입이었다. 내가 작성한 코드는 테스트를 통과했지만 maste에 있는 코드와 merge가 된 것을 기준으로 테스팅을 할 수 있게 되었다. 세 번째 시점은 테스트 커버리지 측정이었다. 신규로 작성되는 코드들이 우리가 원하는 수준의 테스트 커버리지를 만족시키는지 확인할 수 있었다. 자동화되지 않은 상태에서 매번 개발자에게 "테스트가 깨졌어요", "테스트를 추가해 주세요.", "여기는 코딩 스타일이 맞지 않아요."라고 말하는 것은 피곤한 일이기도 하고, 장기적으로 보면 동작하지 않는다. 자동화 외의 방법은 없고, 이 자동화된 방법은 새롭게 입사한 사람들이 테스팅에 손쉽게 적응하도록 한다. 앞으로의 테스팅에 대해사실 커버리지가 테스팅의 전부는 아니다. 커버리지만 올리는 의미 없는 테스트도 작성할 수 있다. 하지만 기본적으로는 python이 런타임 시에 다양한 에러를 발생시키기 때문에 어느 정도 이상의 커버리지 테스트는 필수라고 생각한다. 앞으로 주요한 모듈에서는 커버리지를 90% 이상을 맞추고 나머지 영역에 대해서는 80% 이상을 유지할 생각이다. 그리고 테스트의 질은 코드 리뷰로 해결해야 하겠다. 지금 unittest 가 약 3500개 정도 작성되어 있는 상태이다. 이 테스트를 동작시키는데 로컬에서는 약 3분 정도 CI환경에서는 10분 정도가 걸린다. 이 테스트를 기다리는 시간 동안 생산적인 일을 크게 하지 못하는 경향이 있어서 이 시간을 줄이기 위한 노력을 해야 한다. 마지막으로는 프런트엔드에 대한 테스트를 추가해야겠다. 글을 마치며이 글은 나의 눈에서 바라본 것을 기준으로 적었기에 내가 다 한 것처럼 느껴진다. 하지만 전혀 그렇지 않다. 이 모든 작업은 나 혼자 한 것이 아니라 우리 팀이 한 것이다. 더 나은 개발을 목표로 함께 달리고 있는 팀원분들께 감사를 전한다. #8퍼센트 #에잇퍼센트 #개발 #개발팀 #삽질 #팀워크 #팀플레이 #성장 #성과
조회수 2875

GUI가이드라인 정의와 목적

S/W 개발자가 디자인대로 화면을 구현할 때, 어떻게 디자인 요소 위치를 잡아야 하는지 정확한 정보가 필요합니다. 이런 정보는 GUI 디자이너가 포토샵과 같은 디자인 툴을 사용하여 개발자가 사용 가능한 형태로 사이즈 정보와 리소스를 만들어 전달하는 작업을 GUI 가이드라인 제작 작업이라 합니다.GUI 가이드 문서 상에는 화면상에 표현되는 모든 GUI 요소들의 정보가 표시가 됩니다. 화면상의 위치 X/Y 좌표값, 디자인 요소의 폭/높이 사이즈 정보, 이미지 파일 리소스명, 폰트 타입, 폰트 크기 등 다양한 그래픽 요소의 정보를 정확하게 수치화 하여 기재한 것입니다.가이드 문서의 양식은 딱 정해진 틀은 없지만, 소위 대기업의 경우 표준 템플릿을 이용합니다. 단말 하나에 탑재되는 앱 별로 수십 벌의 문서를 제작하여 관리해 왔습니다. 현재 과도기적인 단계라 스케치(.sketch) 파일과 가이드라인 문서를 함께 운영하는 곳도 있을 정도입니다.기존에 GUI 가이드 문서 제작을 위해서는 아래와 같은 일련의 순서로 작업을 하였습니다.디자인 시안 작업 > 디자인 시안 확정 > 개발 가능성 리뷰 > 최종 수정 >GUI 가이드라인 문서 제작 & 이미지 파일 리소스 작업이 중에서 가이드 문서 제작 과정을 초점에 두고 살펴보면, GUI 디자이너가 직접 이미지를 자르고 위치와 크기 정보를 확인하여, 파워포인트 문서로 정보를 입력하는 일련에 단순 노가다를 반복적으로 진행하게 됩니다.대부분의 에이전시 신입 디자이너들이 중국집 요리사 탱크트리와 유사하게 최소 2년 정도 GUI 가이드라인 작업을 하고 난 뒤에 시안 디자인 작업을 참여할 수 있는 구조였습니다. 크리에이티브를 위해 디자인 작업에 시간을 일주일 중 3일을 쓰고, 4일은 가이드를 쳐야 할 정도의 노력과 시간이 드는 노동 집약적 작업이었습니다.이렇듯 GUI 가이드라인 문서 제작은 모든 디자인 요소 정보들을 일일이 확인한 후, 파워포인트로 옮겨 적어야 하는 야근의 헬게이트를 열어주는 대표적인 업무였습니다.디자인 완료 후 개발자에게 “디자인을 이렇게 구현해 주세요.” 라고 말하면 얼마나 쉽나요? 근래에는 야근의 대부분을 차지하는 이러한 업무들로부터 스케치 툴이 많은 디자이너를 구해준 셈입니다.업무의 프로세스상 디자이너가 가이드라인 문서와 이미지 리소스 파일들을 넘겨줘야 개발자들이 개발진행을 할 수 있기에 디자이너들은 타이트한 데드라인에 쫓기듯 업무할 수 밖에 없었습니다.이러다 보니, GUI 가이드라인 문서 제작 중 휴먼에러(크기 정보 오타, 이미지 파일 누락 등)로 개발자가 작업하던 도중 디자이너에게 가이드라인 문서 업데이트 요청을 해오는 경우가 매우 빈번했습니다. 또한, 대규모 프로젝트 일수록 가이드라인 문서, 이미지 리소스 파일, PSD 디자인 파일 등 관리해야 할 대상이 많아서 개발자와 디자이너 사이의 커뮤니케이션 빈도수도 잦아지고 많은 비용이 필요했습니다.비단 3년 전만해도 GUI 디자인을 개발자가 구현하기 위해 필요한 정보를 수천 페이지나 되는 파워포인트 문서로 전달했지만, 요즘은 스케치를 활용한 제플린이나 심플리 등과 같은 가이드 정보를 제공해주는 여러 서비스를 이용하여 가이드 문서 제작은 거의 하지 않고 있습니다. 조만간 가이드 문서가 완전히 사라지는 날이 오지 않을까 싶습니다.그 끝에 크래커나인이 일조하는 날이 오기를 바라며 글을 마칩니다.#에이치나인 #디자이너 #개발자 #협업툴 #크래커나인 #솔루션기업
조회수 1092

Single Layer Perceptron

Single Layer Perceptron이번 포스팅에서는 모든 인공신경망의 기초가 되는 perceptron의 개념에 대해서 배워보고, 이를 이용한 단층 퍼셉트론 구조를 구현해보도록 하겠습니다.퍼셉트론은 여러분이 고등학교 과학시간에 한 번쯤은 들어보았을 인간의 신경망, 뉴런으로부터 고안되었습니다. 퍼셉트론은 여러 개의 신호를 입력받으면, 하나의 신호를 출력합니다. 이 때 퍼셉트론이 출력하는 신호는 전달 혹은 차단이라는 1 또는 0의 값을 갖게됩니다. 직관적인 예시를 들어보도록 하죠. 여러분이 매달 초 용돈, 아르바이트비를 받거나(1) 받지 않는다(0)고 가정해보겠습니다. 여러분의 통장에 입금된 이 두 가지 수익을 input(입력) 신호라고 합니다. 이 때 여러분은 두 개의 수익이 합쳐진 통장 잔고를 확인하고 전부터 갖고 싶던 옷을 살지(1) 혹은 사지 않을지(0)를 결정합니다. 이렇게 여러분이 내리는 결정이 output(출력) 신호가 되는 것입니다.하지만 여러분의 의사결정은 이것보다는 복잡할 것입니다. 용돈은 거의 생활비로만 사용하고, 아르바이트비를 주로 취미생활에 사용한다고 가정해보죠. 그럼 여러분이 옷을 살지 여부를 결정할 때에는 아르바이트비가 들어왔는지가 좀더 중요할 것입니다. 따라서 우리는 각 input(입력) 신호를 그대로 사용하지 않고, 각각에 가중치(weight)를 주어 output(출력) 신호를 결정하게 됩니다. 이것을 도식으로 나타내면 다음과 같습니다. 이처럼 input에 weight가 곱해진 형태가 정해진(혹은 학습된) 임계치를 넘을 경우 1을 출력하고 그렇지 않을 경우 0을 출력하게 하는 것이 퍼셉트론의 동작 원리입니다. 정말 간단하죠! 이는 아래 수식과 같습니다.하지만 임계치를 그때그때 바꿔주는 것은 조금 직관적이지 않습니다(저만 그런가요). 그래서 우리는 아래 형태로 식을 바꾸게 되며, 이 때 추가된 b를 bias 혹은 절편이라고 말합니다. 위 식은 여러분이 중고등학교 수학 수업을 잘 들었다면 굉장히 익숙한 형태일 것입니다. 바로 2차원 좌표축을 그리고 직선을 그었을 때, 그 직선을 기준으로 나뉘는 두 개의 공간을 표현한 식입니다. 역시 말보다는 그림이 이해하기 쉬울테니, 아래에 그림을 그려보도록 하겠습니다.위처럼 공간을 올곧은 직선으로 나누는 것을 선형으로 나눴다고 말합니다. 하지만 직선만으로 공간을 나누는 것은 유연하지 않습니다. 위와 같은 방식으로는 OR, AND, NAND 문제는 해결할 수 있지만, XOR 문제는 해결할 수 없습니다. 이와 같은 문제를 해결하기 위해서는 층을 하나 더 쌓고, 공간을 단순한 선형이 아닌 곡선으로 분리해내어 좀더 유연한 적용이 가능해져야합니다.(사실 XOR은 선형만으로도 층을 하나 더 쌓으면 해결이 가능합니다). 이에 따라 multi layer perceptron(MLP) 의 개념이 등장하고, activation function(활성함수) 의 개념이 등장하게 됩니다. 후에 활성함수의 개념을 배우게 되면, 지금 배운 단순 퍼셉트론은 활성함수로 계단함수를 가진 것과 동일하다는 것을 알게 되실겁니다.정리단층 퍼셉트론은 모든 딥러닝 공부의 시작이다.단층 퍼셉트론은 입력 신호를 받으면 임계치에 따라 0 또는 1의 값을 출력한다.이러한 단층 퍼셉트론은 결국 공간을 선형으로 잘라서 구분하는 것과 동일하다.
조회수 1566

PyCon2017 첫번째날 후기

아침에 느지막이 일어났다. 어제 회사일로 피곤하기도 했지만 왠지 컨디션이 좋은 상태로 발표를 하러 가야지!라는 생각 때문에 깼던 잠을 다시 청했던것 같다. 일어나 아침식사를 하고 아이 둘과 와이프를 두고 집을 나섰다. 작년 파이콘에는 참가해서 티셔츠만 받고 아이들과 함께 그 옆에 있는 유아교육전을 갔었기에 이번에는 한참 전부터 와이프에게 양해를 구해둔 터였다.코엑스에 도착해서 파이콘 행사장으로 가까이 가면 갈수록 백팩을 메고, 면바지를 입고, 영어 글자가 쓰인 티셔츠를 입은 사람의 비율이 높아지는 것으로 보아 내가 제대로 찾아가고 있구나 라는 생각이 들었다.늦게 왔더니 한산하다.지난번에는 입구에서 에코백과 가방을 나눠줬던 것 같은데 이번에는 2층에서 나눠준다고 한다. 1층이 아무래도 복잡해지니 그런 것 같기도 하고, 2층에서 열리는 이벤트들에도 좀 더 관심을 가져줬으면 하는 것 같기도 하다. 우선 스피커 옷을 받고 싶어서 (솔직히 입고 다니고 싶어서) 2층에 있는 스피커방에 들어갔다.허락 받지 않고 사진찍기가 좀 그래서 옆방을 찍었다첫 번째 키노트는 놓쳤지만 두 번째 키노트는 꼭 듣고 싶었기에 간단히 인사만 하고 티셔츠를 들고 나왔다. (외국에서 오신 연사분과 영어로 대화를 나누고 있어서 자리를 피한것은 아니다.) 나가는 길에 보니 영코더(초등학교 5학년 부터 고등학생 까지 파이썬 교육을 하는 프로그램)을 진행하고 있었다. 의미있는 시도를 하고 있다는 생각이 들었다.이 친구들 2년 뒤에 나보다 잘할지도 모른다.키노트 발표장에 갔더니 아웃사이더님이 뒤에 서 게셨다. 지난 파이콘 때 뵙고 이번에 다시 뵈었으니 파이콘이 사람들을 이어주는 역할을 하는구나 싶었다.키노트에서는 현우 님의 노잼, 빅잼 발표 분석 이야기를 들을 수 있었다. 그리고 발표를 통해 괜히 이것저것 알려줘야만 할 것 같아 발표가 부담스러워지는 것 같다는 이야기를 들었다. 나 또한 뭔가 하나라도 지식을 전달해야 한다는 압박감을 느끼고 있었던 터라 현우 님의 키노트 발표를 듣고 나니 좀 더 오늘을 즐겨야겠다는 생각이 들었다.오늘은 재미있었습니다!현우님 키노트를 듣고 같은 시간(1시)에 발표를 하시는 경업님과 이한님 그리고 내일 발표이신 대명님, 파이콘 준비위원회를 하고 계신 연태님과 함께 식사를 하러 갔다. 가는 길에 두숟갈 스터디를 함께 하고 계신 현주님과 희진 님도 함께했다. 사실 이번에는 발표자도 티켓을 사야 한다고 해서 조금 삐져 있었는데 양일 점심 쿠폰을 주신다고 해서 삐진 마음이 눈 녹듯이 사라졌다.부담 부담식사를 하고 발표를 할 101방으로 들어가 봤다. 아직 아무도 없는 방이라 그런지 괜히 긴장감이 더 생기는 느낌이다. 발표 자료를 열어 처음부터 끝까지를 한번 넘겨 보고 다시 닫았다. 처음에는 가장 첫 발표라 불만이었는데 생각해보니 발표를 빨리 마치고 즐기는 게 훨씬 좋겠다는 생각이 들었다. 발표 자료를 다듬을까 하다가 집중이 되지 않아 밖으로 나갔다. “열린 공간” 현황판에 충동적으로 포스트잇을 하나 붙이고 왔다. 어차피 발표는 나중에 온라인으로도 볼 수 있으니까 사람들과 이야기를 나눠 봐야 겠다 싶었다. (내 발표에는 사람이 많이 왔으면 하면서도, 다른 사람의 발표는 온라인으로 보겠다는 이기적인 생각이라니..)진짜 궁금하긴 합니다다시 발표장으로 돌아왔다. 왠지 모르는 분들은 괜찮은데 아는 분들이 발표장에 와 계시니 괜히 더 불안하다. 다른 분들은 발표자료에 짤방도 많이 넣으셨던데.. 나는 짤방도 없는 노잼 발표인데.. 어찌해야 하나. 하지만 시간은 다가오고 발표를 시작했다.얼굴이 반짝 반짝리허설을 할 때 22분 정도 시간이 걸렸던 터라 조금 당겨서 진행을 했더니 발표를 거의 20분에 맞춰서 끝냈다. 그 뒤에 몇몇 분이 오셔서 질문을 해주셨다. 어리버리 대답을 한 것 같다. 여하튼 내 발표를 찾아오신 분들께 도움이 되었기를. 그리고 앞으로 좀 더 정확한 계산을 하시기를.대단히 발표 준비를 많이 하지도 못하면서 마음에 부담만 쌓아두고 있는 상황이었는데, 발표가 끝나니 아주 홀가분한 마음이 되었다. 발표장을 나가서 이제 부스를 돌아보기 시작했다. 매해 참여해 주고 계신 스마트스터디도 보이고 (정말 안 받고 싶은 ‘기술부채’도 받고 말았다.) 쿠팡, 레진 등 친숙한 회사들이 많이 보였다. 내년에는 우리 회사도 돈을 많이 벌어 여기에 부스를 내고 재미있는 이벤트를 하면 좋겠다는 생각이 들었다.부스를 돌아다니다가 이제 파이콘의 명물이 된 내 이름 찾기를 시작했다. 이름을 찾기가 쉽지가 않다. 매년 참여자가 늘어나서 올해는 거의 2000명에 다다른다고 하니 파이썬 커뮤니티의 성장이 놀랍다. 10년 전에 파이썬을 쓸 때에는 그리고 첫 번째 한국 파이콘이 열릴 때만 해도 꽤 마이너 한 느낌이었는데, 이제 주류가 된 것 같아 내 마음이 다 뿌듯하다. (그리고 내 밥줄이 이어질 수 있는 것 같아 역시 기쁘다)어디 한번 찾아보시라다음으로는 박영우님의 "Django admin site를 커스텀하여 적극적으로 활용하기” 발표를 들으러 갔다. (짧은 발표를 좋아한다.) 알고 있었던 것도 있었지만 커스텀이 가능한지 몰랐던 것들도 있어서 몇 개의 기능들을 킵해 두었다. 역시 컨퍼런스에 오면 내게 필요한 ‘새로운 것’에 대한 실마리를 주워가는 재미가 있다.익숙하다고 생각했지만 모르는것이 많다4시가 되어 OST(Open Space Talk)를 하기로 한 208B 방으로 조금 일찍 갔다. 주제가 뭐였는지는 잘 모르겠는데 주식 투자, Tensor Flow, 비트코인, 머신러닝 등등의 이야기들이 오가고 있었다. 4시가 되어 내가 정한 주제에 대해 관심 있는 사람들이 모였다. 괜히 모일 사람도 없는데 큰방을 잡은 것이 아닐까 하고 생각하고 있었는데, 생각보다 많은 분들이 오셨다.각 회사들이 어떤 도구를 사용하는지 설문조사도 해보고, 또 어떤 개발 방법론을 사용하는지, 코드 리뷰, QA는 어떻게 하고 있는지에 대한 이야기를 나눴다. 다양한 회사에서 다양한 일을 하는 사람들이 모여 있다 보니 생각보다 꽤 재미있게 논의가 진행되었다. 사실 내가 뭔가 말을 많이 해야 할 줄 알았는데, 이야기하고 싶은 분들이 많이 있어서 진행을 하는 역할만 하면 되었다. 마지막으로는 “우리 회사에서 잘 사용하고 있어서 다른 회사에도 추천해 주고 싶은 것”을 주제로 몇 가지 추천을 받은 것도 재미가 있었다.열심히 오간 대화를 적어두긴 했다5시에 OST를 마치고는 바로 집으로 돌아왔다. 오늘 저녁에 아이들을 잘 돌보고 집 청소도 열심히 해두어야 내일 파이콘에 참여할 수 있기 때문이다. 기대된다. 내일의 파이콘도.그리고 정말 감사드린다. 파이콘을 준비해주시고 운영해주고 계신 많은 분들께.#8퍼센트 #에잇퍼센트 #개발자 #개발 #파이썬 #Python #파이콘 #Pycon #이벤트참여 #참여후기 #후기
조회수 5000

AWS Instance Scheduler Bot 적용기

이 포스팅은 총 2부로 이어지며 현재는 2부입니다.1부 : AWS 비용 얼마까지 줄여봤니?2부 : AWS Instance Scheduler Bot 적용기1부에서 AWS 비용을 절감하기 위한 Instance Scheduler에 대한 소개를 하였습니다. 2부에서는 Instance Scheduler의 설정을 손쉽게 변경하기 위한 Bot을 적용한 사례에 대해서 소개합니다.Bot의 필요성Instance Scheduler의 설정을 변경하기 위해서는 정보를 담고 있는 Dynamo DB 의 데이터를 변경해야 합니다. AWS Console을 이용하여 직접 수정할 수도 있지만 여전히 불편하고 느립니다. 더군다나 이를 이용하는 사용자가 DB Table의 구조와 AWS Console 사용법을 알고 있어야 하고 비 개발자라면 더 쉽지 않은 문제입니다. 하지만 Bot을 이용하면 사용자는 어려운 DB Query나 구조를 알아야 할 필요도 없고 손쉽게 채팅 메시지를 통해 Bot에게 질의하고 처리 결과를 응답받을 수 있습니다.Outgoing WebhookJANDI에서는 Incoming Webhook과 반대되는 개념으로 Outgoing Webhook을 제공합니다. 특정 키워드로 시작하는 메시지가 있을 경우 내용을 설정된 URL Endpoint에 POST로 Webhook을 보내줍니다. Webhook을 수신한 곳에서는 일련의 처리 후 메시지 데이터 형식을 맞춰 응답하게 되면 채팅창에 메시지를 표시하게 됩니다. 이를 통해 다른 외부 시스템과 연동할 수 있습니다.POST Data예를 들어 날씨 키워드로 Outgoing Webhook을 생성했다면 /날씨 메시지가 시작될 때 다음과 같은 데이터가 Webhook으로 발송됩니다.{ "token": "YE1ronbbuoZkq7h3J5KMI4Tn", "teamName": "Toss Lab, Inc.", "roomName": "토스랩 코리아", "writerName": "Gloria", "text": "/날씨 서울", "keyword": "날씨", "createdAt": "2017-07-19T14:49:11.266Z" } token을 이용하여 요청의 유효성 체크를 할 수 있고 text를 적절히 파싱 하여 요청에 부합하는 처리를 할 수 있습니다.ResponsePOST Data를 적절히 처리 후 결과를 채팅창에 응답 메시지를 표시하고 싶다면 아래와 같은 JSON Data를 Response body에 넣어주면 됩니다.{ "body" : "서울의 현재 날씨", "connectColor" : "#FAC11B", "connectInfo" : [{ "title" : "온도", "description" : "최고:28.00, 최저:24.00, 현재: 24.30" }, { "title": "날씨", "description": "흐리고 비" }] } 이를 이용하여 Instance Scheduler에도 적용해봤습니다.Schedule BotSchedule Bot은 Instance Scheduler의 Lambda 함수에 함께 포함되어 작동하며 스케쥴 조회 / 예외 설정, 서버 강제 시작/중지, 서버 상태 조회 등의 기능을 수행합니다.API Gateway와 Lambda 함수를 연결하여 Endpoint URL을 생성하고 Outgoing Webhook URL로 설정하여 Webhook으로 Lambda 함수가 실행될 수 있도록 하였습니다. Lambda 함수는 Cloudwatch를 통해서 실행되면 Scheduler가 작동되고 API Gateway를 통해 실행되면 Schedule Bot이 작동됩니다.Schedule Bot 명령어Schedule Bot은 다음과 같은 명령어를 수행합니다./서버 help : 도움말 /서버 [스케쥴명] status : 현재 서버 상태 조회 /서버 [스케쥴명] info : 오늘의 스케쥴 조회 /서버 [스케쥴명] info [YYYY-MM-DD] : 특정일 스케쥴 조회 /서버 [스케쥴명] exception info : 오늘의 스케쥴 예외 조회 /서버 [스케쥴명] exception info [YYYY-MM-DD] : 특정일 스케쥴 예외 조회 /서버 [스케쥴명] exception set [YYYY-MM-DD] [start|stop] [h:m] : 예외 설정 /서버 [스케쥴명] exception del [YYYY-MM-DD] [start|stop] : 예외 삭제 /서버 [스케쥴명] force_start : 서버 강제 실행 /서버 [스케쥴명] force_stop : 서버 강제 중지 Schedule Bot 작동 화면Schedule Bot은 서버병이라는 컨셉으로 인격화(?)에 힘썼습니다.스케쥴 정보 조회서버 상태 조회서버 강제 시작/중지명령어 오류마무리AWS 기반의 서비스를 운영하는 스타트업이라면 더욱더 현실적으로 부딪히는 비용 문제에 대해서 저희가 고민한 내용과 솔루션에 대해서 공유하였습니다.아직 적용기간이 길지 않아 절감비용에 대해 수치적인 데이터를 언급하기는 힘들지만 많은 금액이 절감될 거라 예상하고 있습니다.저희와 같은 고민을 하고 있다면 Instance Scheduler를 적극 권장합니다.#토스랩 #잔디 #JANDI #개발 #개발자 #AWS #도입후기 #일지 #인사이트 #경험공유
조회수 1211

'구루급' 개발자란...

'구루'라는 단어는 이제 '수준급'을 넘어선 분들에게 부여되는 의미 있는 호칭이다. 특히, 개발자 사회에서는 비공식적으로 '구루급'이라고 불리는 개발자들이 있다. 이 정의에 대해서 누가 명확하게 옳다고 이야기할 수 있는 것은 아니다.다만, 30년 동안 소프트웨어 개발자로 살아오면서 만난 수많은 개발자들과 해외 유수의 개발자들과 만나고 소통하면서 느낀 개인적인 경험을 바탕으로 '구루급'에 대해서 정의를 해보겠다.매우 당연하게 이 정의는 전적으로 객관화된 것이 아닌, 매우 주관적인 기준이다.보통, '구루'급 개발자라고 불리는 분들을 보면, 오픈소스로 한 획을 그었거나, 그의 뜻을 따르는 후배들이 많거나, 특정 분야의 경험이 매우 풍부한 분들을 대상으로 이야기한다.다만, 이 기준에 '돈'을 많이 벌었거나, 특정 제품이나 게임, 서비스를 잘 만들었다는 식의 기준은 들어가는 것은 일부 논외로 하겠다. 이것은 전적으로 개인적인 기준이다. 이런 분들은 '구루급'개발자가 되기보다는, 산업적이거나 경제적으로 크게 성공한 기준이 더 높기 때문이며, 금전적으로 성공한 분들이 '후배'들에게 개발자로서의 영향력을 주는 것이 사실상 어렵기도 하거니와, 이미 비즈니스의 단계로 넘어간 분들이기 때문에 '구루급'개발자라고 이야기하기에는 모호하다고 개인적으로 이야기한다.그렇다면, 내가 생각하는 구루급 개발자의 최소한의 필요조건을 나열해 보자. 전적으로 개인적인 기준이니 너무 주관적이라고 비판하지 마시기를... 그 이유는 정말 주관적이기 때문이다.하나. 하나의 소프트웨어나 도메인을 10년 이상 장기간 개발 및 연구하고 있는가?둘. 자신만의 개발 문화에 대한 철학과 그 기준을 가지고 실행하고 있는가?셋. 자신이 소유하거나 만들어낸 개발 도구나 방법, 기술에 대해서 후배 개발자들에게 전파하고 있는가?넷. 후배 개발자들에게 존경받는 개발자로서의 기본적인 성품을 가지고 있는가?다섯. 후배 개발자들에게 자신의 롤을 양보하거나, 팀과 조직을 위해서 자신의 자리를 포기할 줄 아는가?여섯. 자신의 먹을거리를 위해서 비용을 싸게 부르지 않고, 후배들도 대우를 받을 수 있도록 너무 싸게 일하지 않아야 한다는 것을 실천하는가?제가 생각하는 '구루급'개발자의 조건입니다.분명, 이렇게 활동하는 '구루급'개발자들이 주변에 존재하고 있으며, 이를 위해서 개발자의 처우에 대해서 노력하기도 하고, 불합리한 경영자들과 논쟁을 벌이기도 합니다. 자신의 개인적인 이익만을 위해서 움직이지도 않는 그들이야말로 '구루급'개발자 아닐까요?그리고.대부분의 구루급개발자들은 충분한 대우와 보수를 받고 일하고 있습니다.그것이, 후배 개발자들의 처우와 미래를 위해서 매우 필요하다고 생각하고 있기 때문이죠.저는 '구루급'개발자를 그렇게 생각합니다.ps.최고의 개발자, 슈퍼개발자 등에 대한 호칭도 있을 수 있습니다. 제가 생각하는 '구루'급 개발자는 후배들에게 존경을 받고, 후배들의 처우나 개발자들의 미래에 대해서도 고민하고 실천하는 분들에 대해서 정의해 본것입니다.
조회수 3797

코드리뷰, 이렇게 하고 있습니다.

토스랩 안드로이드팀이 코드리뷰 하는 방법실리콘밸리 이야기 - 코드리뷰는 어떻게 하나요? 를 보고 토스랩이 코드리뷰 하는 프로세스와 방법에 대해서 공유해드리고자 합니다.왜 코드리뷰를 하게 되었나요?토스랩에 안드로이드가 팀 단위로 꾸려진 것은 5월 전후였습니다. 그 전에는 1인 개발 체제를 가지고 있었습니다. 갑작스럽게 인원이 많아지면서 코드스타일, 구조의 일관성 등이 계속적으로 깨지게 되고 이에 따라 제품의 안정성도 급격히 떨어지는 사태가 발생하였습니다.이에 내부적으로 제품의 품질을 강화하기 위한 대책들이 강구되었는데 그 중에 하나가 코드리뷰였습니다.코드리뷰를 위한 프로세스는 토스랩 웹 개발팀의 프로세스를 참고하여 안드로이드 개발 팀원의 내부 의견을 반영하여 진행되었습니다.1. 언제 코드리뷰를 요청하나요?안드로이드팀은 코드리뷰 요청에 대해 별도의 제약을 두지 않았습니다. 언제든지 코드리뷰 시스템이 코드리뷰를 요청할 수 있습니다. 다만 코드 리뷰가 시작되는 시점이 조금 다릅니다.모든 개발자가 코드리뷰를 각자의 업무(Task)가 완료되면 코드리뷰 시스템에 코드리뷰를 요청하고 이를 각 개발자가 언제든지 확인할 수 있도록 하고 있습니다.코드리뷰의 시작은 3. 그럼 코드리뷰는 언제 하나요? 에서 확인해보록 하겠습니다.2. 어떻게 요청하나요코드리뷰는 내가 아닌 다른 사람이 코드를 읽어야 하므로 어떤 목적에서 작업 된 코드인지를 미리 할 수 있어야 빠르게 코드리뷰를 할 수 있습니다. 최대한 자유롭게 하되 아래와 같은 형식을 지키도록 하고 있습니다.TitleFeature/Bug-fix 건인지 알 수 있도록 합니다.어떤 목적인지 간략하게 적도록 합니다.어떤 이슈와 연결된 건인지 알 수 있도록 합니다.Description어떤 로직을 추가/수정했는지를 작성합니다.어떻게 추가/수정했는지를 작성합니다ex)Title - [fix] 소켓 API 버전 처리 (JND-3986) Description@Version 커스텀 어노테이션 추가Version 없는 Event 에 Version 필드 추가, @Version어노테이션 부여SocketObject -> EventObject 로 파싱하는 로직 공통 메소드로 분리파싱 후 바로 반환하지 않고 Version Valid 로직 추가class JandiSocketServiceModel { T getObject(Object, T) // 파싱 공통 메소드 boolean validVersion(Object) // version 확인 } Java Reflection 사용.위와 같이 작성함으로써 이 이슈는 소켓 API 버전에 대한 버그 수정건으로 JND-3986 이라는 이슈와 연관된 것임을 알 수 있습니다. 상세 내용으로는 @Version 이 JandiSocketServiceModel의 getOject 와 validVersion 메소드와 연관되어 있음을 알 수 있도록 기술하였습니다.코드리뷰를 상세하게 쓰는 것은 리뷰어들이 코드리뷰를 효율적으로 하기 위함이기 때문에 리뷰할 부분을 빨리 확인 할 수 있게 적도록 하도 있습니다.3. 그럼 코드리뷰는 언제 하나요?실리콘 밸리의 큰 회사들 (구글, 페이스북 등)은 코드리뷰가 요청이 오면 업무의 최우선순위로 조정되어 즉시 응답하도록 하는 것이 원칙입니다. (지금 당장 하든지 아니면 언제부터 할 것인지를 피드백을 반드시 줘야 한다고 들었습니다.)하지만 스타트업은 일반적으로 개발해야 할 것들이 훨씬 더 많고 코드리뷰가 아니더라도 일이 산더미인 경우가 많습니다. 저희 토스랩이라고 이를 크게 벗어나지 않기 때문에 안드로이드팀은 별도로 코드리뷰하는 프로세스를 정의하였습니다.월~수 : feature/bug-fix 개발이 업무의 최우선 순위이다.목, 금 : 코드리뷰가 업무의 최우선 순위이며 코드리뷰 대상은 목요일 출근 전까지 리뷰 요청을 한 건을 대상으로 한다.이는 개발자들끼리 코드리뷰의 중요성을 이해하지만, 이것이 개발 건보다 더 큰 업무 비중을 차지하게 되면 개발 속도나 의욕을 저해할 수 있기 때문에 최대한 분리하여 해당 건에만 집중하기 위해 룰을 정하였습니다.업무에 따라서 편차는 있지만, 대개의 코드리뷰는 금요일에 모두 완료를 하고 있으며 긍정적 피드백이 나올때까지 코드를 변경해야만 완료가 됩니다.4. 무엇을 리뷰하나요?개발자 개인의 성향과 개발건의 성격에 따라 그때마다 다른 모습을 보여줍니다.성능 개선 개발 : 시간복잡도신규 feature 개발 : 잠재적인 오류에 대한 검출리팩토링 : 테스트코드나 구조에 대한 물음신규 기술 도입 : 해당 기술의 로직과 그에 대한 물음기타 : 변수명과 같은 코드 컨벤션을 하기도 합니다. 전체적인 흐름을 이해하기 위해 실제 빌드를 해서 동작을 시켜보고 이해하기도 합니다.기본적인 사항들은 CI 품질도구 리포팅 기능을 이용하기 때문에 주로 큰 그림에서의 코드리뷰를 하는 편입니다.5. 코드리뷰 코멘트는 어떻게 작성하나요?OO 보다는 XX 가 더 나은 것 같아요.XX 는 OO 부분을 참고해서 이용하면 되요.OO 는 XX 에 의해서 문제되지 않을까요?XX 를 하려다가 OO 로 했는데 어떻게 생각하세요?위와 같이 가급적이면 상대방을 공격하지 않는 느낌을 주도록 하며 단순히 문제를 이슈업하기 보다는 대안을 제시하는 방법을 주로 하고 있습니다. 코드리뷰는 서로의 코드에서 이해할 수 없는 부분을 찾고 문제가 될 수 있는 부분을 미리 찾아내는 자리인만큼 문제의 검출과 해결에 주안을 두고 진행합니다.6. 코드리뷰가 끝나면 어떻게 하나요?서로가 이해할 수 있을 만큼 리뷰가 진행되면 코드는 그때서야 개발용 브랜치에 통합을 합니다. 최소 1명의 피드백도 진행되지 않은 코드는 통합하지 않는 것이 원칙으로 하며 통합되어야 하는 건이 코드리뷰가 진행되지 않으면 늦어도 월요일 아침에 긴급히 진행해 줄 것을 환기시킵니다.7. 긴급히 코드리뷰해야 하는 건은 어떻게 하나요?긴급히 해야하는 건은 그만큼 사안이 중요하다고 생각하기 때문에 리뷰를 요청하는 즉시 진행을 하도록 합니다. 다만 해당 건이 즉시 반영해야 할만큼 중요한지를 서로간의 의논해서 진행하도록 합니다.총평안드로이드팀이 코드리뷰를 최초 시작한 것은 6월초입니다. 브랜치를 통합하기 전 개발 완료된 건에 대한 코드리뷰가 처음이었기 때문에 자리를 잡는데는 2달여 시간이 흐른 다음이었습니다. 초기에는 실수로 코드리뷰를 생략한다던가, 어떻게 코멘트를 남겨야할지에 대해서 조심스럽다던가 하는 시행착오를 겪어서 지금은 개발 건에 따라 20건이 넘는 의견이 남겨질 정도로 활발하게 의견을 교류하고 통합을 거칩니다.코드리뷰에 생소한 사람은 대개 나의 작업물을 누군가에게 검토 받는다는 느낌에 거부감을 가지기 마련입니다. 하지만 더 큰 그림에서 본다면 코드리뷰는 코드의 안정성을 서로 다른 관점에서 검토하는 것이기 때문에 코드의 신뢰성이 더욱 커지는 과정입니다. 그러기에 이에 대한 이해 없이 진행하는 코드리뷰는 금방 유명무실해지기 때문에 모두의 이해를 가진 다음에 진행 할 것을 추천합니다.제품의 안정성을 신경써야 하는 시점에 QA 강화와 같은 외부의 요인만을 찾는 것보다 내부에서 좀 더 개선 할 수 있는 요인을 찾는 것도 하나의 방법입니다. 토스랩에서는 다양한 품질 검증 과정에서 코드리뷰를 매우 중시하고 있습니다. 모든 팀이 각자만의 스타일대로 코드리뷰를 진행하고 있습니다.모든 개발자분들이 코드리뷰에 열린 자세로 올바른 코드리뷰를 진행하기를 바랍니다.#토스랩 #잔디 #JANDI #개발 #개발팀 #개발자 #개발환경 #업무환경 #코드리뷰 #인사이트 #조언
조회수 1183

레진 기술 블로그 - 모두를 위한 설계. 레진 웹 접근성 가이드라인.

레진엔터테인먼트는 글로벌(한국, 일본, 미국) 서비스를 운영하고 있기에 다양한 사람들의 재능과 욕구에 관심이 있습니다. 우리는 웹 접근성에 관심을 기울여 조금 특별한 욕구를 가진 사람들의 문제를 해결하려고 합니다. 소수의 특별한 욕구는 모두의 욕구와 연결되어 있다고 생각하기 때문입니다.조금 특별한 욕구를 가진 사람WHO는 세계 인구의 15%에 해당하는 사람들이 장애가 있는 것으로 파악하고 있습니다. 그리고 보건복지부 장애인 실태조사에 따르면 후천적 장애 발생률은 90% 수준입니다. 이런 통계에 따르면 한 개인이 일생을 살면서 장애인이 되거나 일시적으로 장애를 체험하게 될 확률은 무려 13.5%나 됩니다.저는 적록 색약입니다. 약한 수준의 장애로 분류할 수 있죠. 채도가 낮은 상태의 적색과 녹색을 쉽게 구별하지 못합니다. 충전 중 적색이었다가 완충이 되면 초록색으로 변하는 LED가 박혀있는 전자제품은 전부 망했으면 개선하면 좋겠어요. 전 세계 남성의 8%가 색약이고, 여성은 0.5%가 색약입니다. 대부분 적록 색약이고 마크 저커버그도 적록 색약입니다. 만화가 이현세 선생님도 적록 색약이고요. 한편 색약인 사람은 빛의 밝고 어두움을 구별하는 능력이 뛰어난 것으로 밝혀져 있어 저격과 관측에 탁월한 능력을 발휘합니다. 숨어있는 저격수 빨리 찾기 게임을 해 보세요. 위장 사진 1, 위장 사진 2, 위장 사진 3. 색약인 사람이 이길 것입니다.전맹 시각장애인은 마우스 포인터와 초점을 볼 수 없으므로 키보드만을 사용해서 웹을 탐색합니다. 키보드와 음성 낭독에 의존하지만, 키보드 기능을 정말 잘 다루죠. 그래서 키보드 접근성 문제를 해결하면 시각장애인뿐만 아니라 키보드를 능숙하게 사용하는 사람들의 사용성이 높아집니다. 소수의 특별한 요구사항을 해결하는 것이 모두를 위한 설계와 연결되어 있습니다.결국, 누구에게나 특별히 다른 측면이 있고 그것을 고려할 때 "모두를 즐겁게 하라!"라는 우리의 좌우명에 한 걸음 더 가까워질 수 있다고 믿습니다.도저히 풀 수 없을 것 같은 숙제웹 접근성을 소개할 때 많이 듣는 질문이 있습니다.장애인이 우리 서비스를 이용해요?매출에 도움이 돼요?시간과 비용이 많이 필요하지 않아요?이 질문에 대한 제 대답은 다음과 같습니다.이용한다면 기쁠 것 같아요.큰 도움은 안 될 거예요.조금은 그렇죠. 하지만 반환이 있어요.레진코믹스와 같이 이미지 기반의 콘텐츠를 서비스하는데 웹 접근성을 준수하려고 노력한다는 것은 무모한 도전에 가깝습니다. 왜냐하면, 현재로서는 전맹 시각장애인 고려가 없고 논의조차 쉽지 않기 때문입니다.하지만 달에 갈 수 없다고 해서 일찌감치 체념할 필요는 없겠지요. 쉬운 문제부터 하나씩 풀어 나아가길 기대합니다. 로켓에 올라탔으니까 금방 갈 수 있지 않을까요?W3C 표준을 우리 언어로W3C에서는 WCAG 2.1이라는 웹 콘텐츠 접근성 지침을 제시하고 있고요. 국내 표준 KWCAG 2.1 또한 있습니다. 국내 표준은 W3C 표준에서 중요도가 높은 항목을 우리 언어로 정리한 것이기 때문에 결국 어떤 지침을 선택해서 따르더라도 괜찮습니다.하지만 표준 문서는 너무 장황하고 전문 용어가 많아 다양한 분야 전문성을 가진 직원들과 함께 보기에는 한계가 있다고 생각했습니다. W3C 표준을 근간으로 하되 비전문가도 15분 정도면 읽고 이해할 수 있을 만큼 정리된 문서가 필요했고 레진 웹 접근성 가이드라인 사내 표준을 제안하고 공개하게 됐습니다.의미를 전달하고 있는 이미지에 대체 텍스트를 제공한다.전경 콘텐츠와 배경은 4.5:1 이상의 명도 대비를 유지한다.화면을 400%까지 확대할 수 있다.키보드만으로 조작할 수 있다.사용할 수 있는 충분한 시간을 제공한다.발작을 유발하는 콘텐츠를 제공하지 않는다.반복되는 콘텐츠 블록을 건너뛸 수 있다.모든 문서의 제목은 고유하고 식별할 수 있다.링크와 버튼 텍스트는 콘텐츠의 목적을 알 수 있다.섹션에는 의미있는 마크업과 헤딩이 있다.문서의 휴먼 랭귀지 속성을 제공한다.문맥 변경은 예측할 수 있다.폼 콘트롤 요소에 설명을 제공한다.실수를 예방하고 정정하는 것을 돕는다.HTML 문법을 준수한다.WCAG 2.1 지침의 1.1.1 항목 예를 들어 볼게요.All non-text content that is presented to the user has a text alternative that serves the equivalent purpose, except for the situations listed below. 사용자에게 제공되는 모든 텍스트 아닌 콘텐츠는 아래 나열된 상황을 제외하고 같은 목적을 수행하는 대체 텍스트를 제공한다.원문 표현보다 아래와 같이 다듬은 표현이 좋다고 보는 것이죠.의미를 전달하고 있는 이미지에 대체 텍스트를 제공한다.물론 사내 지침은 너무 단순하게 표현했기 때문에 지침마다 ‘부연 설명, 관련 예시, 기대 효과, 관련 표준, 평가 도구’ 텍스트와 링크를 간략하게 제공하고 있습니다. 사실상 W3C 표준에 대한 링크 페이지라고 생각해도 괜찮습니다. 사실이 그런걸요.맺음말레진 웹 접근성 가이드라인은 사내 유관 부서 담당자분들께 공유하고 동의를 얻어 사내 지침으로 결정하고 공개할 수 있게 됐습니다. 긍정적으로 검토해 주신 사우님들 감사합니다.레진 웹 접근성 가이드라인은 W3C 표준을 요약한 버전에 불과하므로 누구라도 복제(Fork), 개선 요청(Pull Requests), 문제 제기(Issues)할 수 있습니다."Design for all, amuse everyone!"
조회수 953

Node.js - Event

Event(이후 '이벤트'로 통칭)Node.js(이후 '노드'로 통칭)는 이벤트 기반 비동기 방식으로 작동한다. 그러므로 노드를 잘 다루기 위해서는 이벤트에 대해 이해하여야 한다.노드에서 이벤트를 호출하고 여러 처리를 하기 위해서는 EventEmitter 객체를 상속받아 구현해야 한다.아래 예제 코드를 통해 EventEditter를 상속받은 객체를 가지고 이벤트를 생성하고 호출하는 등 여러 처리하는 법을 살펴보자.* 코드 복사붙여넣기가 필요한 경우 http://madeitwantit.tistory.com/32 에서 가능하다.EventEmitterEventEmitter 클래스는 events 모듈에 의해 정의되고 제공된다.EventEmitter = require('events');위와 같이 EventEmitter를 정의할 수 있다.EventEmitter의 메서드EventEmiter.on('이벤트 이름', '리스너 함수') - 지정한 '이벤트 이름' 이벤트에 '리스너 함수'를 리스너 배열 가장 끝에 추가한다. EventEmiter.once('이벤트 이름', '리스너 함수') - on() 메서드와 기능이 비슷하다. 다만 이 메서드로 등록된 리스너는 일회성으로 한 번 실행된 후 제거된다. EventEmiter.addListener('이벤트 이름', '리스너 함수') - on() 메서드와 같다.EventEmiter.emit('이벤트 이름'[, arg]...) - '이벤트 이름'  이벤트에 등록된 리스너 함수를 등록된 순서에 따라 호출한다. 이벤트가 존재한다면 true, 그 외에는 false를 반환한다.EventEmiter.setMaxListeners(n) - EventEmitter는 디폴트로 최대 리스너 수가 10으로 지정되어 있다. 10보다 더 많은 리스너를 등록할 때 사용한다. Infinity나 0을 지정하면 제한 없이 리스너를 등록할 수 있다.EventEmiter.getMaxListeners() - 현재 EventEmitter에 지정된 최대 리스너 수를 반환한다.EventEmiter.listenerCount('이벤트 이름') - '이벤트 이름'에 등록되어 있는 리스너의 수를 반환한다.EventEmiter.listeners('이벤트 이름') - '이벤트 이름'에 등록되어 있는 리스너 배열의 사본을 반환한다.EventEmiter.removeAllListeners(['이벤트 이름']) - 모든 리스너나 파라미터에 지정한 '이벤트 이름'의 리스너를 제거한다.EventEmiter.removeListeners('이벤트 이름', '리스너 함수') - '이벤트 이름'에 등록되어 있는 특정 '리스너 함수'를 제거한다. 같은 리스너가 여러 개 등록되어 있으면 이 메서드를 여러 번 호출해야 한다.EventEmitter의 이벤트'newListener' - 새로운 이벤트를 등록할 때, 추가될 리스너를 리스너 배열에 추가하기 전에 호출된다. 이벤트에 리스너가 전달되기 위해 이벤트 이름과 추가될 리스너가 전달된다.'removeListener' - 리스너가 제거된 후 호출된다.하단의 예제를 통해 newListener가 호출되는 시점에 대해 살펴보자.                                                              * 코드 복사붙여넣기가 필요한 경우 http://madeitwantit.tistory.com/32 에서 가능하다.참고문헌:모던 웹을 위한 Node.js 프로그래밍 - 윤인성Haruair (http://haruair.com/blog/3396)Node.js Documentation (https://nodejs.org/api)조대협의 블로그 (http://bcho.tistory.com/885)#트레바리 #개발자 #안드로이드 #앱개발 #Node.js #백엔드 #인사이트 #경험공유

기업문화 엿볼 때, 더팀스

로그인

/