스토리 홈

인터뷰

피드

뉴스

조회수 1668

HBase 설정 최적화하기 - VCNC Engineering Blog

커플 필수 앱 비트윈은 여러 종류의 오픈 소스를 기반으로 이루어져 있습니다. 그 중 하나는 HBase라는 NoSQL 데이터베이스입니다. VCNC에서는 HBase를 비트윈 서비스의 메인 데이터베이스로써 사용하고 있으며, 또한 데이터 분석을 위한 DW 서버로도 사용하고 있습니다.그동안 두 개의 HBase Cluster 모두 최적화를 위해서 여러 가지 설정을 테스트했고 노하우를 공유해 보고자 합니다. 아랫은 저희가 HBase를 실제로 저희 서비스에 적용하여 운영하면서 최적화한 시스템 구성과 설정들을 정리한 것입니다. HBase를 OLTP/OLAP 목적으로 사용하고자 하는 분들에게 도움이 되었으면 좋겠습니다. 아래 구성을 최적화하기 위해서 했던 오랜 기간의 삽질기는 언젠가 따로 포스팅 하도록 하겠습니다.HBaseHBase는 Google이 2006년에 발표한 BigTable이라는 NoSQL 데이터베이스의 아키텍처를 그대로 따르고 있습니다. HBase는 뛰어난 Horizontal Scalability를 가지는 Distributed DB로써, Column-oriented store model을 가지고 있습니다. 사용량이 늘어남에 따라서 Regionserver만 추가해주면 자연스럽게 Scale-out이 되는 구조를 가지고 있습니다. 또한, Hadoop 특유의 Sequential read/write를 최대한 활용해서 Random access를 줄임으로 Disk를 효율적으로 사용한다는 점을 특징으로 합니다. 이 때문에 HBase는 보통의 RDBMS와는 다르게 Disk IO가 병목이 되기보다는 CPU나 RAM 용량이 병목이 되는 경우가 많습니다.HBase는 많은 회사가 데이터 분석을 하는 데 활용하고 있으며, NHN Line과 Facebook messenger 등의 메신저 서비스에서 Storage로 사용하고 있습니다.시스템 구성저희는 Cloudera에서 제공하는 HBase 0.92.1-cdh4.1.2 release를 사용하고 있으며, Storage layer로 Hadoop 2.0.0-cdh4.1.2를 사용하고 있습니다. 또한, Between의 데이터베이스로 사용하기 위해서 여러 대의 AWS EC2의 m2.4xlarge 인스턴스에 HDFS Datanode / HBase Regionserver를 deploy 하였습니다. 이는 m2.4xlarge의 큰 메모리(68.4GB)를 최대한 활용해서 Disk IO를 회피하고 많은 Cache hit이 나게 하기 위함입니다.또한 Highly-Available를 위해서 Quorum Journaling node를 활용한 Active-standby namenode를 구성했으며, Zookeeper Cluster와 HBase Master도 여러 대로 구성하여 Datastore layer에서 SPOF를 전부 제거하였습니다. HA cluster를 구성하는 과정도 후에 포스팅 하도록 하겠습니다.HDFS 최적화 설정dfs.datanode.handler.countHDFS에서 외부 요청을 처리하는 데 사용할 Thread의 개수를 정하기 위한 설정입니다. 기본값은 3인데 저희는 100으로 해 놓고 사용하고 있습니다.dfs.replicationHDFS 레벨에서 각각의 데이터가 몇 개의 독립된 인스턴스에 복사될 것 인가를 나타내는 값입니다. 저희는 이 값을 기본값인 3으로 해 놓고 있습니다. 이 값을 높이면 Redundancy가 높아져서 데이터 손실에 대해서 더 안전해지지만, Write 속도가 떨어지게 됩니다.dfs.datanode.max.transfer.threads하나의 Datanode에서 동시에 서비스 가능한 block 개수 제한을 나타냅니다.과거에는 dfs.datanode.max.xcievers라는 이름의 설정이었습니다.기본값은 256인데, 저희는 4096으로 바꿨습니다.ipc.server.tcpnodelay / ipc.client.tcpnodelaytcpnodelay 설정입니다. tcp no delay 설정은 TCP/IP network에서 작은 크기의 패킷들을 모아서 보냄으로써 TCP 패킷의 overhead를 절약하고자 하는 Nagle's algorithm을 끄는 것을 의미합니다. 기본으로 두 값이 모두 false로 설정되어 있어 Nagle's algorithm이 활성화되어 있습니다. Latency가 중요한 OLTP 용도로 HBase를 사용하시면 true로 바꿔서 tcpnodelay 설정을 켜는 것이 유리합니다.HBase 최적화 설정hbase.regionserver.handler.countRegionserver에서 외부로부터 오는 요청을 처리하기 위해서 사용할 Thread의 개수를 정의하기 위한 설정입니다. 기본값은 10인데 보통 너무 작은 값입니다. HBase 설정 사이트에서는 너무 큰 값이면 좋지 않다고 얘기하고 있지만, 테스트 결과 m2.4xlarge (26ECU) 에서 200개 Thread까지는 성능 하락이 없는 것으로 나타났습니다. (더 큰 값에 관해서 확인해 보지는 않았습니다.)저희는 이 값을 10에서 100으로 올린 후에 약 2배의 Throughput 향상을 얻을 수 있었습니다.hfile.block.cache.sizeHBase 의 block 들을 cache 하는데 전체 Heap 영역의 얼마를 할당한 것인지를 나타냅니다. 저희 서비스는 Read가 Write보다 훨씬 많아서 (Write가 전체의 약 3%) Cache hit ratio가 전체 성능에 큰 영향을 미칩니다.HBase 에서는 5분에 한 번 log 파일에 LruBlockCache (HBase 의 Read Cache) 가 얼마 만큼의 메모리를 사용하고 있고, Cache hit ratio가 얼마인지 표시를 해줍니다. 이 값을 참조하셔서 최적화에 사용하실 수 있습니다.저희는 이 값을 0.5로 설정해 놓고 사용하고 있습니다. (50%)hbase.regionserver.global.memstore.lowerLimit / hbase.regionserver.global.memstore.upperLimit이 두 개의 설정은 HBase에서 Write 한 값들을 메모리에 캐쉬하고 있는 memstore가 Heap 영역의 얼마만큼을 할당받을지를 나타냅니다. 이 값이 너무 작으면 메모리에 들고 있을 수 있는 Write의 양이 한정되기 때문에 디스크로 잦은 flush가 일어나게 됩니다. 반대로 너무 크면 GC에 문제가 있을 수 있으며 Read Cache로 할당할 수 있는 메모리를 낭비하는 것이기 때문에 좋지 않습니다.lowerLimit와 upperLimit의 두 가지 설정이 있는데, 두 개의 설정이 약간 다른 뜻입니다.만약 memstore 크기의 합이 lowerLimit에 도달하게 되면, Regionserver에서는 memstore들에 대해서 'soft'하게 flush 명령을 내리게 됩니다. 크기가 큰 memstore 부터 디스크에 쓰이게 되며, 이 작업이 일어나는 동안 새로운 Write가 memstore에 쓰일 수 있습니다.하지만 memstore 크기의 합이 upperLimit에 도달하게 되면, Regionserver는 memstore들에 대한 추가적인 Write를 막는 'hard'한 flush 명령을 내리게 됩니다. 즉, 해당 Regionserver이 잠시 동안 Write 요청을 거부하게 되는 것입니다. 보통 lowerLimit에 도달하면 memstore의 크기가 줄어들기 때문에 upperLimit까지 도달하는 경우는 잘 없지만, write-heavy 환경에서 Regionserver가 OOM으로 죽는 경우를 방지하기 위해서 hard limit가 존재하는 것으로 보입니다.hfile.block.cache.size와 hbase.regionserver.global.memstore.upperLimit의 합이 0.8 (80%)를 넘을 수 없게 되어 있습니다. 이는 아마 read cache 와 memstore의 크기의 합이 전체 Heap 영역 중 대부분을 차지해 버리면 HBase의 다른 구성 요소들이 충분한 메모리를 할당받을 수 없기 때문인 듯합니다.저희는 이 두 개의 설정 값을 각각 0.2, 0.3으로 해 놓았습니다. (20%, 30%)ipc.client.tcpnodelay / ipc.server.tcpnodelay / hbase.ipc.client.tcpnodelayHDFS의 tcpnodelay 와 비슷한 설정입니다. 기본값은 전부 false입니다.이 설정을 true로 하기 전에는 Get/Put 99%, 99.9% Latency가 40ms 와 80ms 근처에 모이는 현상을 발견할 수 있었습니다. 전체 요청의 매우 작은 부분이었지만, 평균 Get Latency가 1~2ms 내외이기 때문에 99%, 99.9% tail이 평균 Latency에 큰 영향을 미쳤습니다.이 설정을 전부 true로 바꾼 후에 평균 Latency가 절반으로 하락했습니다.Heap memory / GC 설정저희는 m2.4xlarge가 제공하는 메모리 (68.4GB)의 상당 부분을 HBase의 Read/Write cache에 할당하였습니다. 이는 보통 사용하는 Java Heap 공간보다 훨씬 큰 크기이며 심각한 Stop-the-world GC 문제를 일으킬 수 있기 때문에, 저희는 이 문제를 피하고자 여러 가지 설정을 실험하였습니다.STW GC time을 줄이기 위해서 Concurrent-Mark-and-sweep GC를 사용했습니다.HBase 0.92에서부터 기본값으로 설정된 Memstore-Local Allocation Buffer (MSLAB) 을 사용했습니다. hbase.hregion.memstore.mslab.enabled = true #(default)hbase-env.sh 파일을 다음과 같이 설정했습니다. HBASE_HEAPSIZE = 61440 #(60GB) HBASE_OPTS = "-XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps"GC log를 Python script로 Parsing해서 STW GC 시간을 관찰하고 있습니다. 지금까지 0.2초 이상의 STW GC는 한 번도 발생하지 않았습니다.그 밖에 도움이 될 만한 설정들hbase.hregion.majorcompactionHBase는 하나의 Region에 대해서 여러 개의 StoreFile을 가질 수 있습니다. 그리고 주기적으로 성능 향상을 위해서 이 파일들을 모아서 하나의 더 큰 파일로 합치는 과정을 진행하게 됩니다. 그리고 이 과정은 많은 CPU usage와 Disk IO를 동반합니다. 그리고 이때 반응 속도가 다소 떨어지게 됩니다. 따라서 반응 속도가 중요한 경우에는, 이 Major compaction을 off-peak 시간대를 정해서 manual 하게 진행하시는 것이 좋습니다.저희는 사용자의 수가 상대적으로 적은 새벽 시간대에 crontab 이 실행시키는 script가 돌면서 전체 Region에 대해서 하나하나 Major Compaction이 진행되도록 하였습니다.기본값은 86,400,000 (ms)로 되어 있는데, 이 값을 0으로 바꾸시면 주기적인 Major Compaction이 돌지 않게 할 수 있습니다.hbase.hregion.max.filesizeHBase는 하나의 Region이 크기가 특정 값 이상이 되면 자동으로 2개의 Region으로 split을 시킵니다. Region의 개수가 많지 않을 때는 큰 문제가 없지만, 계속해서 데이터가 쌓이게 되면 필요 이상으로 Region 수가 많아지는 문제를 나을 수 있습니다. Region 수가 너무 많아지면 지나친 Disk IO가 생기는 문제를 비롯한 여러 가지 안 좋은 점이 있을 수 있기 때문에, split 역시 manual 하게 하는 것이 좋습니다. 그렇다고 Table의 Region 수가 너무 적으면 Write 속도가 떨어지거나 Hot Region 문제가 생길 수 있기 때문에 좋지 않습니다.HBase 0.92.1 에서는 기본값이 1073741824(1GB)로 되어 있는데, 저희는 이 값을 10737418240(10GB)로 늘인 후에 manual 하게 split을 하여 Region의 개수를 조정하고 있습니다.hbase.hregion.memstore.block.multipliermemstore의 전체 크기가 multiplier * flush size보다 크면 추가적인 Write를 막고 flush가 끝날때까지 해당 memstore는 block 됩니다.기본값은 2인데, 저희는 8로 늘려놓고 사용하고 있습니다.dfs.datanode.balance.bandwidthPerSec부수적인 설정이지만, HDFS의 Datanode간의 load balancing이 일어나는 속도를 제한하는 설정입니다. 기본값은 1MB/sec로 되어 있지만, 계속해서 Datanode를 추가하거나 제거하는 경우에는 기본값으로는 너무 느릴 때가 있습니다. 저희는 10MB/sec 정도로 늘려서 사용하고 있습니다.dfs.namenode.heartbeat.recheck-intervalHDFS namenode에만 해당되는 설정입니다.Datanode가 응답이 없는 경우에 얼마 후에 Hadoop cluster로부터 제거할 것인지를 나타내는 값입니다.실제로 응답이 없는 Datanode가 떨어져 나가기까지는 10번의 heartbeat가 연속해서 실패하고 2번의 recheck역시 실패해야 합니다. Heartbeat interval이 기본값인 3초라고 하면, 30초 + 2 * recheck-interval 후에 문제가 있는 Datanode가 제거되는 것입니다.기본값이 5분으로 되어 있는데, fail-over가 늦어지기 때문에 사용하기에는 너무 큰 값입니다. 저희는 문제가 있는 Datanode가 1분 후에 떨어져 나갈 수 있도록 이 값을 15,000 (ms) 으로 잡았습니다.Read short-circuitRegionServer가 로컬 Datanode로부터 block을 읽어올 때 Datanode를 통하지 않고 Disk로부터 바로 읽어올 수 있게 하는 설정입니다.데이터의 양이 많아서 Cache hit이 낮아 데이터 대부분을 디스크에서 읽어와야 할 때 효율적입니다. Cache hit에 실패하는 Read의 Throughput이 대략 2배로 좋아지는 것을 확인할 수 있습니다. OLAP용 HBase에는 매우 중요한 설정이 될 수 있습니다.하지만 HBase 0.92.1-cdh4.0.1까지는 일부 Region이 checksum에 실패하면서 Major compaction이 되지 않는 버그가 있었습니다. 현재 이 문제가 해결되었는지 확실하지 않기 때문에 확인되기 전에는 쓰는 것을 추천하지는 않습니다.설정하는 방법은 다음과 같습니다. dfs.client.read.shortcircuit = true #(hdfs-site.xml) dfs.block.local-path-access.user = hbase #(hdfs-site.xml) dfs.datanode.data.dir.perm = 775 #(hdfs-site.xml) dfs.client.read.shortcircuit = true #(hbase-site.xml)Bloom filterBloom filter의 작동방식에 대해 시각적으로 잘 표현된 데모 페이지HBase는 Log-structured-merge tree를 사용하는데, 하나의 Region에 대해서 여러 개의 파일에 서로 다른 version의 값들이 저장되어 있을 수 있습니다. Bloom filter는 이때 모든 파일을 디스크에서 읽어들이지 않고 원하는 값이 저장된 파일만 읽어들일 수 있게 함으로써 Read 속도를 빠르게 만들 수 있습니다.Table 단위로 Bloom filter를 설정해줄 수 있습니다.ROW와 ROWCOL의 두 가지 옵션이 있는데, 전자는 Row key로만 filter를 만드는 것이고, 후자는 Row+Column key로 filter를 만드는 것입니다. Table Schema에 따라 더 적합한 설정이 다를 수 있습니다.저희는 데이터 대부분이 메모리에 Cache 되고 하나의 Region에 대해서 여러 개의 StoreFile이 생기기 전에 compaction을 통해서 하나의 큰 파일로 합치는 작업을 진행하기 때문에, 해당 설정을 사용하지 않고 있습니다.결론지금까지 저희가 비트윈을 운영하면서 얻은 경험을 토대로 HBase 최적화 설정법을 정리하였습니다. 하지만 위의 구성은 어디까지나 비트윈 서비스에 최적화되어 있는 설정이며, HBase의 사용 목적에 따라서 달라질 수 있음을 말씀드리고 싶습니다. 그래서 단순히 설정값을 나열하기보다는 해당 설정이 어떤 기능을 하는 것인지 저희가 아는 한도 내에서 설명드리려고 하였습니다. 위의 글에서 궁금한 점이나 잘못된 부분이 있으면 언제든지 답글로 달아주시길 바랍니다. 감사합니다.
조회수 2228

블로그 운영 방법에서 엿보는 VCNC의 개발문화

VCNC에서 엔지니어링 블로그를 시작하고 벌써 새로운 해를 맞이하였습니다. 그동안 여러 글을 통해 VCNC 개발팀의 이야기를 들려드렸습니다. 이번에는 엔지니어링 블로그 자체를 주제로 글을 적어보고자 합니다. 저희는 워드프레스나 텀블러와 같은 일반적인 블로깅 도구나 서비스를 사용하지 않고 조금은 개발자스럽다고 할 수 있는 특이한 방법으로 엔지니어링 블로그를 운영하고 있습니다. 이 글에서는 VCNC 개발팀이 엔지니어링 블로그를 운영하기 위해 이용하는 방법들을 소개하고자 합니다. 그리고 블로그를 운영하기 위해 방법을 다루는 중간중간에 개발팀의 문화와 일하는 방식들에 대해서도 간략하게나마 이야기해보고자 합니다.블로그에 사용하는 기술들Jekyll: Jekyll은 블로그에 특화된 정적 사이트 생성기입니다. GitHub의 Co-founder 중 한 명인 Tom Preston-Werner가 만들었으며 Ruby로 작성되어 있습니다. Markdown을 이용하여 글을 작성하면 Liquid 템플릿 엔진을 통해 정적인 HTML 파일들을 만들어 줍니다. VCNC 엔지니어링 블로그는 워드프레스같은 블로깅 도구를 사용하지 않고 Jekyll을 사용하고 있습니다.Bootstrap: 블로그 테마는 트위터에서 만든 프론트엔드 프레임워크인 Bootstrap을 이용하여 직접 작성되었습니다. Bootstrap에서 제공하는 다양한 기능들을 가져다 써서 블로그를 쉽게 만들기 위해 이용하였습니다. 덕분에 큰 공을 들이지 않고도 Responsive Web Design을 적용할 수 있었습니다.S3: S3는 AWS에서 제공되는 클라우드 스토리지 서비스로서 높은 가용성을 보장합니다. 일반적으로 파일을 저장하는 데 사용되지만, 정적인 HTML을 업로드하여 사이트를 호스팅하는데 사용할 수도 있습니다. 아마존의 CTO인 Werner Vogels 또한 자신의 블로그를 S3에서 호스팅하고 있습니다. VCNC Engineering Blog도 Jekyll로 만들어진 HTML 파일들을 아마존의 S3에 업로드 하여 운영됩니다. 일단 S3에 올려두면 운영적인 부분에 대한 부담이 많이 사라지기 때문에 S3에 올리기로 하였습니다.CloudFront: 브라우저에서 웹페이지가 보이는 속도를 빠르게 하려고 아마존의 CDN서비스인 CloudFront를 이용합니다. CDN을 이용하면 HTML파일들이 전 세계 곳곳에 있는 Edge 서버에 캐싱 되어 방문자들이 가장 가까운 Edge를 통해 사이트를 로딩하도록 할 수 있습니다. 특히 CloudFront에 한국 Edge가 생긴 이후에는 한국에서의 응답속도가 매우 좋아졌습니다.s3cmd: s3cmd는 S3를 위한 커맨드 라인 도구입니다. 파일들을 업로드하거나 다운로드 받는 등 S3를 위해 다양한 명령어를 제공합니다. 저희는 블로그 글을 s3로 업로드하여 배포하기 위해 s3cmd를 사용합니다. 배포 스크립트를 실행하는 것만으로 s3업로드와 CloudFront invalidation이 자동으로 이루어지므로 배포 비용을 크게 줄일 수 있었습니다.htmlcompressor: 정적 파일들이나 블로그 글 페이지들을 s3에 배포할 때에는 whitespace 등을 제거하기 위해 htmlcompressor를 사용합니다. 또한 Google Closure Compiler를 이용하여 javascript의 길이도 줄이고 있습니다. 실제로 서버가 내려줘야 할 데이터의 크기가 줄어들게 되므로 로딩속도를 조금 더 빠르게 할 수 있습니다.블로그 관리 방법앞서 소개해 드린 기술들 외에도 블로그 글을 관리하기 위해 다소 독특한 방법을 사용합니다. 개발팀의 여러 팀원이 블로그에 올릴 주제를 결정하고 서로의 의견을 교환하기 위해 여러 가지 도구를 이용하는데 이를 소개하고자 합니다. 이 도구들은 개발팀이 일할 때에도 활용되고 있습니다.글감 관리를 위해 JIRA를 사용하다.JIRA는 Atlassian에서 만든 이슈 관리 및 프로젝트 관리 도구입니다. VCNC 개발팀에서는 비트윈과 관련된 다양한 프로젝트들의 이슈 관리를 위해 JIRA를 적극적으로 활용하고 있습니다. 제품에 대한 요구사항이 생기면 일단 백로그에 넣어 두고, 3주에 한 번씩 있는 스프린트 회의에서 요구사항에 대한 우선순위를 결정합니다. 그 후 개발자가 직접 개발 기간을 산정한 후에, 스프린트에 포함할지를 결정합니다. 이렇게 개발팀이 개발에 집중할 수 있는 환경을 가질 수 있도록 하며, 제품의 전체적인 방향성을 잃지 않고 모두가 같은 방향을 향해 달릴 수 있도록 하고 있습니다.VCNC 개발팀이 스프린트에 등록된 이슈를 얼마나 빨리 해결해 나가고 있는지 보여주는 JIRA의 차트.조금만 생각해보시면 어느 부분이 스프린트의 시작이고 어느 부분이 끝 부분인지 아실 수 있습니다.위와 같은 프로젝트 관리를 위한 일반적인 용도 외에도 엔지니어링 블로그 글 관리를 위해 JIRA를 사용하고 있습니다. JIRA에 엔지니어링 블로그 글감을 위한 프로젝트를 만들어 두고 블로그 글에 대한 아이디어가 생각나면 이슈로 등록할 수 있게 하고 있습니다. 누구나 글감 이슈를 등록할 수 있으며 필요한 경우에는 다른 사람에게 글감 이슈를 할당할 수도 있습니다. 일단 글감이 등록되면 엔지니어링 블로그에 쓰면 좋을지 어떤 내용이 포함되면 좋을지 댓글을 통해 토론하기도 합니다. 글을 작성하기 시작하면 해당 이슈를 진행 중으로 바꾸고, 리뷰 후, 글이 발행되면 이슈를 해결한 것으로 표시하는 식으로 JIRA를 이용합니다. 누구나 글감을 제안할 수 있게 하고, 이에 대해 팀원들과 토론을 하여 더 좋은 글을 쓸 수 있도록 돕기 위해 JIRA를 활용하고 있습니다.JIRA에 등록된 블로그 글 주제들 중 아직 쓰여지지 않은 것들을 보여주는 이슈들.아직 제안 단계인 것도 있지만, 많은 주제들이 블로그 글로 발행되길 기다리고 있습니다.글 리뷰를 위해 Pull-request를 이용하다.Stash는 Attlassian에서 만든 Git저장소 관리 도구입니다. GitHub Enterprise와 유사한 기능들을 제공합니다. Jekyll로 블로그를 운영하는 경우 이미지를 제외한 대부분 콘텐츠는 평문(Plain text)으로 관리 할 수 있게 됩니다. 따라서 VCNC 개발팀이 가장 자주 사용하는 도구 중 하나인 Git을 이용하면 별다른 시스템의 도움 없이도 모든 변경 내역과 누가 변경을 했는지 이력을 완벽하게 보존할 수 있습니다. 저희는 이런 이유로 Git을 이용하여 작성된 글에 대한 변경 이력을 관리하고 있습니다.또한 Stash에서는 GitHub와 같은 Pull request 기능을 제공합니다. Pull request는 자신이 작성한 코드를 다른 사람에게 리뷰하고 메인 브랜치에 머지해 달라고 요청할 수 있는 기능입니다. 저희는 Pull request를 활용하여 상호간 코드 리뷰를 하고 있습니다. 코드 리뷰를 통해 실수를 줄이고 개발자 간 의견 교환을 통해 더 좋은 코드를 작성하며 서로 간 코드에 대해 더 잘 이해하도록 노력하고 있습니다. 새로운 개발자가 코드를 상세히 모른다 해도 좀 더 적극적으로 코드를 짤 수 있고, 업무에 더 빨리 적응하는데에도 도움이 됩니다.어떤 블로그 글에 대해 리뷰를 하면서 코멘트로 의견을 교환하고 있습니다.코드 리뷰 또한 비슷한 방법을 통해 이루어지고 있습니다.업무상 코드 리뷰 뿐만 아니라 새로운 블로그 글을 리뷰하기 위해 Pull request를 활용하고 있습니다. 어떤 개발자가 글을 작성하기 위해서 가장 먼저 하는 것은 블로그를 관리하는 Git 리포지터리에서 새로운 브랜치를 따는 것입니다. 해당 브랜치에서 글을 작성하고 작성한 후에는 새로운 글 내용을 push한 후 master 브랜치로 Pull request를 날립니다. 이때 리뷰어로 등록된 사람과 그 외 개발자들은 내용에 대한 의견이나 첨삭을 댓글로 달 수 있습니다. 충분한 리뷰를 통해 발행이 확정된 글은 블로그 관리자에 의해 master 브랜치에 머지 되고 비로소 발행 준비가 끝납니다.스크립트를 통한 블로그 글 발행 자동화와 보안준비가 끝난 새로운 블로그 글을 발행하기 위해서는 일련의 작업이 필요합니다. Jekyll을 이용해 정적 파일들을 만든 후, htmlcompressor 통해 정적 파일들을 압축해야 합니다. 이렇게 압축된 정적 파일들을 S3에 업로드 하고, CloudFront에 Invalidation 요청을 날리고, 구글 웹 마스터 도구에 핑을 날립니다. 이런 과정들을 s3cmd와 Rakefile을 이용하여 스크립트를 실행하는 것만으로 자동으로 이루어지도록 하였습니다. VCNC 개발팀은 여러 가지 업무 들을 자동화시키기 위해 노력하고 있습니다.또한, s3에 사용하는 AWS Credential은 IAM을 이용하여 블로그를 호스팅하는 s3 버킷과 CloudFront에 대한 접근 권한만 있는 키를 발급하여 사용하고 있습니다. 비트윈은 특히 커플들이 사용하는 서비스라 보안에 민감합니다. 실제 비트윈을 개발하는데에도 보안에 많은 신경을 쓰고 있으며, 이런 점은 엔지니어링 블로그 운영하는데에도 묻어나오고 있습니다.맺음말VCNC 개발팀은 엔지니어링 블로그를 관리하고 운영하기 위해 다소 독특한 방법을 사용합니다. 이 방법은 개발팀이 일하는 방법과 문화에서 큰 영향을 받았습니다. JIRA를 통한 이슈 관리 및 스프린트, Pull request를 이용한 상호간 코드 리뷰 등은 이제 VCNC 개발팀의 문화에 녹아들어 가장 효율적으로 일할 수 있는 방법이 되었습니다. 개발팀을 꾸려나가면서 여러가지 시행 착오를 겪어 왔지만, 시행 착오에 대한 반성과 여러가지 개선 시도를 통해 계속해서 더 좋은 방법을 찾아나가며 지금과 같은 개발 문화가 만들어졌습니다. 그동안 그래 왔듯이 앞으로 더 많은 개선을 통해 꾸준히 좋은 방법을 찾아 나갈 것입니다.네 그렇습니다. 결론은 저희와 함께 고민하면서 더 좋은 개발문화를 만들어나갈 개발자를 구하고 있다는 것입니다.저희는 언제나 타다 및 비트윈 서비스를 함께 만들며 기술적인 문제를 함께 풀어나갈 능력있는 개발자를 모시고 있습니다. 언제든 부담없이 [email protected]로 이메일을 주시기 바랍니다!
조회수 2478

사운들리 백엔드 이야기

사운들리는 '귀에 들리지 않는 소리'를 이용해서 컨텐츠를 전달할 수 있는 SaaS 플랫폼을 서비스하고 있습니다.제품의 구성요소는,음파를 송신할 수 있는 송신단음파를 모바일에서 수신할 수 있는 Android, iOS SDK그리고 컨텐츠를 제공하고 데이터를 수집, 분석하는 백엔드로 구성되어 있습니다.오늘은 구성 요소중 백엔드에 대해서 이야기 해보도록 하겠습니다.<그림 1. 사운들리 솔루션 구성도>사운들리의 인프라는 모두가 잘 아시는 아마존 웹 서비스를 이용하고 있으며, 크게 컨텐츠를 제공하는 API서버 부분, 로그를 수집, 분석하는 부분, 그리고 컨텐츠를 관리하는 CMS 부분으로 이루어져 있습니다.소프트웨어 스택Java : 현재 사운들리의 일부 시스템을 제외하고는 전부 자바로 작성되어 있습니다. Node.js로 시작하여 PHP를 거쳐 지금의 자바 기반의 시스템으로 구성하게 되었습니다. 다양한 사람들이 개발을 해오면서 각자 가장 잘할 수 있고, 빠르게 구현할 수 있는 언어로 개발되어 가다 현재의 자바로 통일되어 구성되게 되었습니다.Spring : API서버는 HTTP 기반의 REST API를 이용해 컨텐츠를 전달하고 있으며 스프링 프레임워크를 이용해 개발되었습니다. 이외에도 일부 분석에 스프링 배치를 사용하고 스프링을 편리하게 사용할 수 있게해주는 스프링 부트도 이용하고 있습니다.gRPC : 분산되어있는 서버들끼리 이기종 언어간 통신을 하기 위해서 Protocol Buffers 기반의 gRPC를 이용하고 있으며 서버들의 모니터링하는 서버와 에이전트들 사이의 통신 목적으로 사용합니다.Flume : 분산된 서버들에서 로그를 수집하는 역할을 합니다. 수집된 로그는 파일로 저장하며 실시간으로 볼수 있도록 엘라스틱서치에 같이 저장하고 있습니다. SDK에서 전송되는 로그 또한 웹서버의 엑세스 로그를 플럼 에이전트가 수집하는 방식으로 비동기로 처리하고 있습니다.ElasticSearch : 수집된 로그들을 실시간으로 확인하기 위해서 사용되며 Kibana를 이용해 시각화하고 있습니다.Angular.js : CMS의 프론트엔드는 Angular.js + Bootstrap을 이용해 개발되었으며, Bower를 이용한 라이브러리 관리, Grunt를 이용한 빌드 관리를 하고 있습니다.소프트웨어 개발/운영GIT : 소스코드는 git로 관리하며 Git-Flow를 이용한 브랜치 정책을 수립하여 가져가고 있고 저장소로는 깃허브를 이용합니다.Quality Practice : QA단계에서 제품을 테스트하기 전 개발자들은 QA 프로세스에 맞게 다음 3가지 기준으로 소스 코드의 품질을 관리합니다.코딩 컨벤션 : 사운들리 내부 코딩 컨벤션에 맞게 개발되었는지 확인합니다. Checkstyle의 규칙을 정의 및 자동화합니다.테스트 코드 : 단위 테스트 코드를 작성하며 테스트 결과는 모두 통과되어야 합니다.테스트 커버리지 : 단위 테스트 코드가 작성된 커버리지를 계산하며 현재 60%를 목표로 진행하고 있습니다.젠킨스 : 소스코드 저장소에 변동이 일어나면 젠킨스가 소스코드를 빌드하고 위에서 언급한 세가지에 대한 리포트를 작성합니다.소나큐브 : 무료 오픈소스로 코드 정적 분석을 해주며 및 QA 리포트를 같이 볼 수 있습니다.슬랙 : 인력이 적은 저희 팀도 슬랙을 적극적으로 개발/운영에서 사용하고 있습니다.팀 커뮤니케이션 : 팀원들 간의 의사사통을 위한 주요 수단으로 모든 팀원이 함께 사용하고 있습니다.분석 리포트 : 젠킨스나 배치를 통해 분석된 데이터들은 분석이 끝난 지표들은 슬랙으로 결과를 전송하여 모든 팀원이 볼 수 있도록 공유하고 있습니다.서버 모니터링 : 서버들의 이상 징후 감지나 배치 오류등을 슬랙을 통해 담당자에게 전송하여 조치할 수 있도록 합니다.애플리케이션 및 서버 모니터링 : 애플리케이션의 모니터링은 Naver에서 오픈소스로 공개한 핀포인트를 사용하고 있고, 서버 상태 모니터링을 위해 자체 개발한 모니터링 시스템을 사용하고 있습니다. 모니터링 데이터 수집을 하는 에이전트와 전체 시스템의 데이터를 관장 하는 서버간에는 gRPC를 이용하여 상태 체크를 합니다. 서버의 상태에 문제가 있을 때에는 slack을 통해 담당자들에게 알람을 주도록 시스템 설계를 하였습니다.개발 문화개발자들은 각각 개발을 할때 정해진 정책에 맞춰 브랜치를 만들어 개발합니다.각각 개발된 소스들은 저장소인 깃허브에 푸시된 후 깃허브의 댓글 기능을 이용하거나 오프라인을 통해 코드 리뷰를 진행합니다.리뷰가 끝난 후 합쳐진 소스는 QP 활동을 통해 분석이 됩니다.빌드가 실패할 경우 커피를 사야합니다 ^^ (커피를 얻어 먹으려는 것이 아닌 소스코드를 푸시하기 전 잘 확인하자는 취지입니다) AWSEC2 : 사운들리의 대부분의 구성 요소인 API서버와 로그 수집, 분석 서버, 엘라스틱서치, 플럼, CMS등이 모두 EC2에 구축되어 있습니다.RDS : 컨텐츠의 주 저장소로 데이터베이스 관리의 용이성을 고려하여 RDS의 Multi-AZ에 배포하여 Active-Standby로 구성되어 있으며 이 데이터들은 레디스와 로컬 캐시를 이용하여 API서버에서 활용하고 있습니다.S3 : 컨텐츠에 포함된 각종 정적 데이터들이 저장되며 수집된 로그들도 저장하여 보관됩니다. EMR : 로그 수집서버를 통해 S3에 저장된 로그들은 EMR을 이용해서 분석됩니다.Beanstalk : 개발 서버의 배포에 사용됩니다. 최근 IntelliJ의 플러그인이 업데이트 되면서 IntelliJ 15버전을 지원하게 되므로써 로컬에서 개발하고 개발 서버에 배포까지 편리하게 하고 있습니다. VPC : 인터넷이 필요 없는 서버들은 VPC 내부 private-zone에 배포 및 ELB를 통해 외부에서 접근하도록 구성되어 있습니다.<그림 2. AWS 배포 구성도>이상으로 사운들리에서 사용하고 있는 백엔드 소프트웨어들을 소개해 보았습니다. 적은 인력으로 빠르게 사업을 진행하는 스타트업에서는 비즈니스에 집중할 수 있도록 도와주는 다양한 툴이나 오픈소스를 이용하여 많은 도움을 받을 수 있는 것 같습니다. 또한 코드를 잘 작성하여 에러를 줄이는 것도 필요하지만 여유가 많지 않으면 최소한 제품의 에러에 빠르게 대응할 수 있도록 하는 방법도 필요한 것 같습니다.#사운들리 #개발 #개발자 #문제해결 #프레임워크 #스킬스택 #스택 #인사이트
조회수 1438

[인공지능 in IT] 서로 다른 우리, 대화할 수 있을까?

설연휴 동안 그간 못 봤던 밀린 TV 프로그램들을 맘껏 즐기며 여유로운 시간을 보냈다. 그 중에서도 여러 분야의 전문가를 초빙해 특강을 해주는 tvN의 '어쩌다 어른'을 보기 시작했다. 몇 년 전 언어인문학을 주제로 한 조승연 작가님편을 보니 새삼 현재 대한민국이 처한 현실을 피부로 느끼게 되더라.< tvN>강연에서 가장 심도있게 다룬 부분은 대한민국 영어교육의 현실이다. 초등학교부터 영어 수업을 듣고, 심지어 말도 제대로 떼기 전인 유아기부터 영어를 주입시키는 것이 어느새 자연스러운 일이 되어버렸다. 하지만, 10년, 20년 이상 영어 교육을 받았는데도 막상 영어로 문서 작업을 하거나, 외국인이 길을 물어보면 식은땀을 흘리는 이유는 무엇일까? 어째서 한국에서는 영어를 제대로 하려는 노력보다, 영어를 아는 노력을 하고 있는 것일까?재미있는 사실은 우리만 영어를 배우려고 애먹는 것이 아니다. 미국인이 한국어를 배울 때에도 비슷한 현상을 겪는다. 강연 중 'FSI(The Foreign Service Institute)'에서 미국인들이 다른 나라 언어를 얼마나 공부해야 소통할 수 있는지에 대한 연구 자료를 공개했다. 언어별 Level 1부터 Level 5까지 다섯 가지 난이도로 구분 되어있고, 이에 따른 총 필요시간으로 구성되어 있는 연구에서, 한국어는 일본어, 중국어와 함께 소통하기 까지 총 2,200시간을 공부해야 하는 Level 5군에 속해 있었다.즉, 전세계 7,000여 개가 넘는 언어 중 한국어는 영어와 문장구조가 완전히 다르기 때문에, 24시간 내내 공부해도 90일 넘게 공부해야 한다는 것. 이렇듯 모국어가 아닌 다른 언어를 배우기 위해서는 어마어마한 시간과 노력이 필요하다. 만약, 단순히 언어를 알기 위해 배우는 것보다, 소통하기 위해 배운다면 흔히들 말하는 'ROI(Return on Investment)'를 더 높일 수 있자 않을까.출처: 동아일보소통을 위한 언어 학습은 비단 사람에게만 해당되는 것이 아니다. 기계와 사람의 소통 역시 요즘과 같은 인공지능 시대에서는 빼놓을 수 없는 부분이다. 몇 년 전부터 업계에서는 '챗봇(Chatbot)' 열풍이 불고있다. 챗봇은 대화(Chat)와 로봇(Robot) 두 단어를 합친 신조어로서, 각종 앱이나 웹을 기반으로 문자를 통해 사용자의 의도를 파악해 대화할 수 있는 인공지능 기계다. 여기에는 '자연어 처리(Natural Language Processing, NLP)', '자연어 이해(Natural Language Understanding, NLU)', '머신러닝(Machine Learning)' 등 수많은 기술이 접목되어 발전 중이다. 현재 챗봇은 나날이 진화하며, 텍스트를 텍스트로만 처리하는 것을 넘어, '음성으로 변환(Text-To-Speech, TTS)'시키거나, '음성을 텍스트로 변환(Speech-To-Text)'시키는 등 다양성에 있어 점점 넓은 범위에 적용되고 있는 추세다.< 출처: Understanding Natural Language Understanding, Bill MacCartney >글로벌 챗봇 시장은 매년 큰 폭으로 성장하고 있는 추세이며, 여러 사업 분야에 걸쳐 사용되고 있다. 북미의 시장조사기관 'Credence Research' 조사에 따르면, 글로벌 챗봇 시장은 2015년부터 2023년까지 연평균 35% 성장할 것으로 예상된다. IT솔루션 기업 'MindBowser'가 조사한 결과, 95%의 기업이 챗봇 활용성에 대해 긍정적인 반응을 보였으며, 고객응대(93%)부터, 마케팅(61%), 상품 주문(47%), 소셜 미디어(32%) 등 사업 분야에서 활용되는 용도 역시 다양한 것으로 밝혀졌다.챗봇은 어떠한 프로세스를 통해 실제로 작동하는지 살펴보기 위해서 사내 엔지니어의 도움을 받았다. 스켈터랩스에서 대화형 인공지능 프로젝트팀에 있는 정태형 엔지니어가 메신저를 통한 간단한 시범 사례를 스크린샷으로 찍어 보여주었다.< 인공지능 메신저 사례, 출처: 스켈터랩스 >여행지를 자동으로 추천해주는 엡에 적용할 수 있는 챗봇과의 대화다. 사용자가 "여행을 가고 싶다"고 말하자 자동으로 '카이트봇'이 반응하고, 여행 기간과 테마를 물어본다. 여기서 사용자가 "여행 기간"을 말하자 챗봇은 자동으로 '3월'과 '7일'을 인식, 이전 질문에서 대답하지 않은 테마에 대해 질문한다. 이렇게 사용자와 챗봇 사이에서 대화를 자연스럽게 주고 받을 수 있는 것은 대화의 구성 요소 중 '의도(Intent)', '개체(Entity)', '맥락(Context)'이 중요한 역할을 한다. 이를 간단히 살펴보도록 하자.의도(Intent)는 사용자가 어떠한 의도로 대화를 하는지를 의미한다. 위 스크린샷의 경우, 여행을 가는 것'이 의도라 할 수 있다. 예를 들어, "여행 가고 싶어"가 아닌 "여행 가볼까?"로 입력하더라도 - 미리 여행을 가는 것에 대한 자연어 기반 패턴이 'Intent Classifier'에 입력되어 있는 상태라면 - 이를 '사용자가 여행을 가고 싶구나'라는 의도로 이해할 수 있는 것이다.개체(Entity)는 사용자의 의도 중에서 실체가 될 수 있는 변수를 말한다. 개체는 사용자가 입력한 문장에서 특정한 변수가 달라질 때 사용된다. 위 스크린샷의 경우, '3월 3일', '해변', '일주일' 등과 같이 주로 명사 형태로 구성된 문장에 들어가는 구성 요소를 말한다.문맥(Context)은 이전 대화를 자연스럽게 이어갈 수 있도록 처리할 수 있는 기능이다. 예를 들어, 사용자가 챗봇에게 "가수 빅뱅의 프로필을 검색해달라"고 요청했다. 그리고 빅뱅의 노래를 듣기 위해 "거짓말 틀어 줘"라고 명령하면, 기존에 빅뱅이라는 가수에 대해 대화하고 있던 문맥을 인식해 God의 거짓말이 아닌 빅뱅의 거짓말을 재생하는 것이다.이 외에도 챗봇에는 '말뭉치(Utterance)', '시나리오(Scenario)', '슬롯채우기(Slot Filling)' 등 다양한 구성요소를 통해 대화를 이어나갈 수 있다. 물론, 아직 100% 인간과 대화하는 기술까지 이르지는 못했다. 하지만, 우문현답하지 않고 사용자 의도를 정확하게 파악하는 수준에 이르러 생활에 편의성을 제공하고 있다.한국어의 경우 언어의 난이도 때문에 국내 기업은 물론 많은 글로벌 IT 기업도 아직 완벽한 수준에 도달하지 못했다. '잘 한다'라는 말만 하더라도 '훌륭하게 하다', '만족할 만하다', '자주 하다' 등의 긍정적인 표현이 있는가 하면, '잘 하는 짓이다' 등의 부정적인 표현인 경우도 흔하기 때문이다. 결국 챗봇도 기계이기 때문에, 여러가지 문장과 상황을 학습시켜 한국어 성능을 향상시켜야만 한다.다시 '어쩌다 어른'으로 돌아가보자. 강연을 마무리할 즈음 조승연 작가는 이렇게 말한다."영어도 결국 언어의 한 종류, 영어를 쓰는 사람들도 우리와 같은 사람, 우리처럼 희로애락을 느끼는 인간입니다. 기계와 얘기하기 위해 법칙에 맞춰 말해야 하는 것이 아니라 그 사람과 감정을 통하게 해주는 어떤 도구입니다."여전히 우리는 챗봇이라는 기계와 소통한다기 보다, 일방적으로 질문을 던지고, 챗봇은 미리 입력되어 있는 규칙 안에서만 답한다. 학습을 통해 수많은 데이터가 축적된다 하더라도, 아직까지 언어를 통해 전달되는 인간의 감정을 완벽히 이해하기에는 부족한 것이 사실이다. 과연 기계가 '법칙'에 맞춰서 말해야 하는 것 이상을 넘어서는 순간이 올까? 우리는 그 순간을 찾아 지금도 노력하고 있는지 모른다.이호진, 스켈터랩스 마케팅 매니저조원규 전 구글코리아 R&D총괄 사장을 주축으로 구글, 삼성, 카이스트 AI 랩 출신들로 구성된 인공지능 기술 기업 스켈터랩스에서 마케팅을 담당하고 있다#스켈터랩스 #기업문화 #인사이트 #경험공유 #조직문화 #인공지능기업 #기술기업
조회수 2175

CSS animation으로 프로토타이핑하기

들어가며Framer, Flinto, Origami, Invision. 많은 프로토타이핑 도구가 존재합니다. 디자인에 활력을 불어넣고 개발팀과의 커뮤니케이션을 위해 필수라고 하는 프로토타이핑. 어떻게 하기는 해야겠는 데 어려운 도구나 코드르 공부하기엔 시간이 없고, 막상 열심히 공부하면 새로운 버전이 나오고, 더 좋은 도구가 나오고. 이런 경험을 많이 하셨을 겁니다. 프로토타이핑 도구로 멋지고 완결된 시나리오를 가진 결과물을 만들 수도 있습니다. 하지만 우리에게 당장 필요한 것은 지금 당장 떠오르는 아이디어를 보여줄 수 있는 아이콘의 간단한 모션, 쓱 움직이는 화면 전환 같은 것이 아닐까요? 오늘 배워서 바로 쓸 수 있는 CSS animation으로 하는 간단한 프로토타이핑 방법을 소개합니다.https://codepen.io/yunkimoon/embed/preview/BZEYgY?default-tabs=css,result&embed-version=2&height=600&host=https://codepen.io&referrer=https://blog.stibee.com/media/c7c8adfdea76b3b98829ecce41fee7d7?postId=e5bb1630afb5&slug-hash=BZEYgY<iframe data-width="800" data-height="600" width="700" height="525" data-src="/media/c7c8adfdea76b3b98829ecce41fee7d7?postId=e5bb1630afb5" data-media-id="c7c8adfdea76b3b98829ecce41fee7d7" data-thumbnail="https://i.embed.ly/1/image?url=https://s3-us-west-2.amazonaws.com/i.cdpn.io/1370087.BZEYgY.small.f06b1cb1-09d2-4285-b8b5-eb8f5b9cea7a.png&key=a19fcc184b9711e1b4764040d3dc5c07" class="progressiveMedia-iframe js-progressiveMedia-iframe" allowfullscreen="" frameborder="0" src="https://blog.stibee.com/media/c7c8adfdea76b3b98829ecce41fee7d7?postId=e5bb1630afb5" style="display: block; position: absolute; margin: auto; max-width: 100%; box-sizing: border-box; transform: translateZ(0px); top: 0px; left: 0px; width: 700px; height: 525px;">어디서, playground코딩을 공부하려면 텍스트 에디터도 설치해야 하고, 각종 패키지도 설치해야 합니다. 또한, 결과물이 담길 파일도 생성해야 하고, 여러 파일이 연결되니까 폴더 구조도 고민해야 하죠. 이런 고민을 하다 보면 시작조차 하기 싫어집니다. 그래서 브라우저에서 바로 작성하고 확인하고 공유할 수 있는 온라인 코딩 플레이 그라운드가 있습니다. 대표적으로 jsbin과 codepen이 있습니다. 그냥 해당 서비스에서 가서 각 섹션(html 또는 css)에 맞게 코드를 입력하기만 하면 됩니다. 우리는 html과 css섹션만 사용할 예정입니다. js와 같은 다른 섹션은 최소화(minimize)해주세요.codepen.io어떻게 시작할까html에 내용을 담고, css에 디자인(스타일)을 담을 겁니다. 당장 직접 작성하기는 어려우니 예제(https://codepen.io/yunkimoon/pen/BZEYgY)의 html과 css코드를 그대로 복사합니다. 코드의 주석(회색글씨)을 확인해 봅니다. 요약하면 아래와 같습니다.가장 바깥의 파란 배경 상자이미지와 그걸 담고 있는 상자파란 배경 상자에 hover(마우스 오버 이벤트)를 하면,left 포지션을 2%에서 80%로 변경여기서 중요한 건 .box상자에 설정된 transition이라는 속성입니다. transition은 딱딱한 움직임을 부드럽게 해줍니다. 여기서는 position left를 2%에서 80%로 부드럽게 바꿔주었습니다. 위치뿐만 아니라 색상(color, background), 크기(width, height)도 자연스럽게 바꿔주는 속성입니다. “all 3s”라는 값을 가지고 있는데 “모든 변경사항에 대해 3초 동안 움직여라”라는 의미입니다.꼭 알아야할 3가지css 애니메이션의 맛을 잠깐 보았습니다. transition을 통해 부드러운 움직임을 줄 수 있습니다. 하지만 더 복잡하고 멋진 움직임을 위해서는 많은 속성들을 이해하고 응용할 수 있어야 합니다. 하지만 모든 속성을 다 알아볼 수는 없으므로 가장 중요한 3가지를 알아보도록 하겠습니다. 미리 살펴본 transition과 transform, keyframe(s) 입니다.1. transition위에서 살펴본 것처럼 대상의 위치, 크기, 색상 등에 부드러운 움직임을 줍니다.2. transform대상의 위치, 크기, 방향 등을 상대적으로 변경합니다. 예제를 통해 알아보겠습니다.<iframe data-width="800" data-height="600" width="700" height="525" data-src="/media/43617ca3eab01b6f86f50b25a362c5a1?postId=e5bb1630afb5" data-media-id="43617ca3eab01b6f86f50b25a362c5a1" data-thumbnail="https://i.embed.ly/1/image?url=https://s3-us-west-2.amazonaws.com/i.cdpn.io/1370087.BZErpP.small.5ebe332d-41b1-4a16-8253-6e2df7b347d0.png&key=a19fcc184b9711e1b4764040d3dc5c07" class="progressiveMedia-iframe js-progressiveMedia-iframe" allowfullscreen="" frameborder="0" src="https://blog.stibee.com/media/43617ca3eab01b6f86f50b25a362c5a1?postId=e5bb1630afb5" style="display: block; position: absolute; margin: auto; max-width: 100%; box-sizing: border-box; transform: translateZ(0px); top: 0px; left: 0px; width: 700px; height: 525px;">2.1. rotate대상에 각도 값을 설정합니다. 즉, 주어진 값만큼 회전합니다. 첫 번째 예제와 조금 다른 부분은 :hover { }에 작성된 내용입니다. transform:rotate(360deg)에서 rotate는 회전을 뜻하고, 360deg는 각도입니다. 즉, 360도(한 바퀴)만큼 회전하라는 의미입니다. 미리 transition이 걸려있었기 때문에 부드럽게 회전하는 모습을 볼 수 있습니다.2.2. translate대상의 이동 값을 설정합니다. 주어진 값만큼 이동합니다. 값은 좌푯값으로 x축, y축 값을 나눠서 줍니다. transform: translate(100px, 100px)에서 translate는 이동을 뜻하고, 이후에 나오는 값은 순서대로 x축의 이동값, y축의 이동 값입니다. 그런데 y축 이동 값이면 위로 올라가야 할 것 같은데, 그림은 아래로 이동합니다. 그 이유는 스크린에서 좌측 위가 기준점이기 때문입니다.2.3. scale대상의 크기를 설정합니다. 즉, 주어진 값만큼 늘어나거나 줄어듭니다. 값은 가로 값, 세로 값을 차례로 줍니다. transform:scale(1.5, 2)에서 scale은 크기를 뜻하고, 1.5와 2는 각각 가로값, 세로값을 뜻합니다. 가로는 1.5배가 늘어나고 세로는 2배가 늘어납니다. 그래서 그림은 세로로 긴 비율로 보입니다.이제 우리는 css만으로 대상의 위치, 크기, 회전 애니메이션을 줄 수 있습니다 :)3. keyframes마우스 오버 액션에 대한 애니메이션을 보아왔습니다. 이렇게 사용자의 특정 반응(마우스 오버)이 없어도 자동으로 움직이도록 할 수는 없을까요? 앞의 두 예제보다 조금 복잡하지만 keyframes를 사용하면 가능합니다. keyframes는 미리 움직임을 지정해두고, 대상에 해당 애니메이션의 속성을 부여하는 방식으로 작성됩니다. 예제를 확인해 보겠습니다.<iframe data-width="800" data-height="600" width="700" height="525" data-src="/media/fc6ef62f3a79def6442479e60dcba75d?postId=e5bb1630afb5" data-media-id="fc6ef62f3a79def6442479e60dcba75d" data-thumbnail="https://i.embed.ly/1/image?url=https://s3-us-west-2.amazonaws.com/i.cdpn.io/1370087.vZMRdd.small.22bea369-dda5-4454-9f16-f5ad68f9b292.png&key=a19fcc184b9711e1b4764040d3dc5c07" class="progressiveMedia-iframe js-progressiveMedia-iframe" allowfullscreen="" frameborder="0" src="https://blog.stibee.com/media/fc6ef62f3a79def6442479e60dcba75d?postId=e5bb1630afb5" style="display: block; position: absolute; margin: auto; max-width: 100%; box-sizing: border-box; transform: translateZ(0px); top: 0px; left: 0px; width: 700px; height: 525px;">3.1. spin앞서 살펴 본 transform의 rotate를 미리 애니메이션을 만들어 놓고 대상에 animation이라는 속성을 설정했습니다.@keyframes spin 처름 spin이라는 애니메이션을 설정합니다. 그 안에는 from과 to가 있는데 각각 시작과 끝을 뜻합니다. 즉, 시작할 때는 회전이 0(rotate(0deg))이고 끝날 때는 회전이 360도(rotate(360deg))입니다.대상과 keyframes를 연결할 때는 대상에 animation: spin 8s infinite linear;와같이 애니메이션 속성을 줍니다. spin은 keyframes의 이름, 8s는 8초 동안, infinite는 무한 반복을 뜻합니다. 여기서 linear는 easing을 나타내는데, 우선은 조금 딱딱한 애니메이션이라고 해둡시다.3.2. leftAndRighttransform의 translate를 활용해서 우측으로 이동했다 돌아오는 애니메이션을 반복시키는 예제입니다. from과 to대신 조금 상세한 타임라인을 가지고 있습니다. 0%, 50%, 100%는 타임라인을 구성하는 속성들로 전체 애니메이션 시간 동안 해당하는 타이밍에 맞게 속성이 변경됩니다. 역시 infinite 속성이 있어 계속 반복되고 있습니다. 그리고 마지막에 linear대신 ease라는 속성을 넣어서 조금 부드러운 움직임 표현했습니다.3.3. hideAndShow앞서 다루지 않은 opacity(투명도)를 활용했습니다. 1이 100%이고 0은 보이지 않는 상태입니다. 1 → 0 → 1을 반복하며 보였다 안 보였다 하는 애니메이션을 보여줍니다.이제 우리는 css만으로 대상의 위치, 크기, 회전 애니메이션 반복적으로 사용할 수 있게 되었습니다. 그리고 무한 반복 애니메이션도 만들 수 있습니다.마무리 예제<iframe data-width="800" data-height="600" width="700" height="525" data-src="/media/f95d4317209e7a3488242568bbdcd5a3?postId=e5bb1630afb5" data-media-id="f95d4317209e7a3488242568bbdcd5a3" data-thumbnail="https://i.embed.ly/1/image?url=https://s3-us-west-2.amazonaws.com/i.cdpn.io/1370087.OgeMEY.small.ab075079-b3bb-443e-a11e-d707c5a6a198.png&key=a19fcc184b9711e1b4764040d3dc5c07" class="progressiveMedia-iframe js-progressiveMedia-iframe" allowfullscreen="" frameborder="0" src="https://blog.stibee.com/media/f95d4317209e7a3488242568bbdcd5a3?postId=e5bb1630afb5" style="display: block; position: absolute; margin: auto; max-width: 100%; box-sizing: border-box; transform: translateZ(0px); top: 0px; left: 0px; width: 700px; height: 525px;">앞서 살펴본 예제들을 활용한 마무리 예제를 만들어 보았습니다. 앞서 공부한 내용을 바탕으로 소스를 분석해 보시기 바랍니다. 각 버튼에는 transiton으로 부드러운 hover 전환 효과를 주었고, 녹색의 메시지는 keyframes를 주어 상하로 계속 움직이도록 했습니다. frame에 마우스가 올라가면 메시지는 프레임 바깥으로 밀려나고 사용자 메뉴가 프레임 안으로 이동하도록 했습니다. 메뉴는 하위 메뉴가 펼쳐지는 인터렉션을 가지고 있습니다.마치며전문 프로토타이핑 도구보다 결과물이 투박하고, 지금 당장 만들 수 있는 장면도 제한적입니다. 자바스크립트 같은 동적 언어가 들어가 있지 않아 표현할 수 있는 화면도 많지 않습니다. 기본적으로 제공되는 템플릿이나 자원이 없으므로 하나하나 html로 코딩하거나 공개 소스를 넣어가면서 만들어야 하는 수고로움도 존재합니다.하지만 실행만 해도 막막한 도구들을 바라보며 “언제 한 번 해보나”하는 생각을 할 시간에 간단히 익혀 한 번이라도 써먹을 수 있다면 그 자체로 의미가 있지 않을까요? 물론 탄탄한 시나리오와 설계를 가지고, 제대로 만든다면 전문 프로토타이핑 도구보다 절대 뒤쳐지지 않을 것입니다. 그리고 우리가 만든 코드들은 커뮤니케이션을 위한 전달용이 아니고 실제로 쓰일 수도 있는 코드라는 점에서도 의미가 있습니다. 간단한 프로토타이핑이라도 지금 시작해 보면 어떨까요?참고https://www.w3schools.com/css/css3_animations.aspttps://www.w3schools.com/css/css3_transitions.asphttps://www.w3schools.com/css/css3_2dtransforms.asphttp://report.stibee.com/2017 by 조은지 디자이너#슬로워크 #스티비 #CSS #퍼블리셔 #개발 #디자인 #인사이트 #꿀팁 #조언
조회수 1074

DevOps 문화 안에서의 APM의 역할 [1] (DevOps+JENNIFER)

 DevOps의 시작언제나 그랬듯이 소프트웨어 개발 트렌드는 계속 변화하고 있다. A부터 Z까지 모든 것을 새롭게 개발했던 것과 달리 아키텍처나 사용하는 용도에 따라 개방형 플랫폼이나 오픈소스 등을 활용하여 원하는 소프트웨어를 쉽게 개발할 수 있게 되었다. 또한 클라우드로 인해 애플리케이션과 서비스 개발에 대한 새로운 패러다임이 나타나고 있다. 기존의 온-프레미스 환경에서는 물리적 서버 준비, 운영체제 설치, 서비스 배포 등에 수많은 시간이 걸렸지만, 클라우드를 활용하면서 단시간에 원하는 자원을 준비하고 배포할 수 있게 되었다.이러한 변화로 개발자의 영역이 좀 더 넓어지는 계기가 되었다. 이는 전통적인 비즈니스 환경에서 개발, 빌드, 테스트, 배포, 운영에 이르는 프로세스를 효율적으로 운용할 수 있게 되어 고객의 요구사항을 빠르게 반영할 수 있게 되었다. 이것이 바로 DevOps의 시작이다. 하지만 다양한 오픈소스의 탄생과 클라우드 환경의 확산 등으로 인해 정말로 새로운 기능에 대한 개발이 빨라졌을까? 그렇다면 이에 따른 문제는 없을까? 개발 프로세스의 병목 구간DevOps의 필수 조건인 테스트 및 배포의 자동화가 이뤄지면 운영 단계에서는 반영된 사항들에 대해 주기적으로 모니터링을 해야 한다. 만약에 반영된 소스코드에 장애를 발생시킬 수 있는 잠재적 버그가 존재한다면 이를 어떻게 운영 단계에서 찾을 수 있을까? 예를 들어 특정 서비스의 피크타임에 부하가 급증한다면 앞서 말한 상황에 대한 버그가 발생할 확률이 상대적으로 높아진다. 하지만 장애의 원인이 될 수 있는 요소는 매우 다양하기 때문에 단순히 트래픽 문제로 속단할 수는 없다.직접 개발한 소프트웨어만의 문제가 아닐 수도 있으며, 제품 개발시 생산성 향상을 위해 도입된 다른 종류의 오픈소스에서 문제가 될 수도 있다. 실은 이런 류의 프로젝트들은 상용 제품이 아니므로 문제가 발생하면 상당히 곤란한 경우가 생기곤 한다. DevOps를 위한 환경이 구성되고, 고객의 요구사항을 빠르게 반영할 수 있는 시스템이 갖춰졌더라도 결국에는 앞서 말한 다양한 종류의 잠재적, 환경적인 문제들로 인해 병목이 발생할 수 있다.  모니터링 단계에서 APM의 역할개발 프로세스의 마지막 관문인 모니터링 단계는 DevOps에서 매우 중요한 역할을 한다. 하지만 안타깝게도 이미 반영된 실제 서비스에서 모니터링을 성공적으로 마치고 피드백 수집 단계로 넘어가기 위해서는 앞서 말했던 장애의 원인을 빠르게 진단해야 한다. 경우에 따라 많은 시간이 소모되기도 하기도 하며, 이는 바로 생산성 저하로 이어진다. 또한 새로운 프로세스 진행을 더욱더 보수적으로 만드는 원인이 된다.DevOps를 완벽하게 실현하기 위해서는 모니터링 단계에서 서비스 배포 이후의 서버에 들어오는 트랜잭션에 대한 상태를 배포 전과 비교할 수 있어야 하며, 응답을 지연시킬만한 요소들을 빠르게 인지할 수 있어야 한다. 그리고 배포된 소스코드로 인해 서비스 장애가 발생하는 상황이 온다면 이를 처리하기 전까지 어떻게든 서비스 장애를 지연시켜야만 한다. 이러한 이유로 DevOps 진영에서는 APM의 역할은 매우 중요한 이슈이다. 우리는 제니퍼를 통해 앞서 말한 기능들을 활용하는 방법에 대해 알아볼 것이다. 모니터링 프로세스모니터링 단계는 아래 그림과 같이 문제의 발견 및 조치, 문제해결시 재배포 단계로 나눌 수 있다.  제니퍼 대시보드를 통해 액티브서비스 상태와 트랜잭션 변화 추이를 모니터링 할 수 있는데, 만약에 새로 배포된 소스코드에 문제가 있다면 처리 중인 액티브서비스가 쌓이게 되고 , 트랜잭션 분포도 차트는 기존에 그려졌던 패턴과 다르게 보여지게 된다.이런 시점에 운영에서는 설정 여부에 따라 이벤트를 발생 시킬 수 있다. E-Mail이나 SMS, Slack과 같은 메신저 등으로 각각의 담당자들에게 서비스 상태를 알려줄 수 있으며, 담당자에게 이벤트 메시지가 전달되었다면 제니퍼를 통해 두가지 조치를 할 수 있게 된다. 먼저 개발자는 스마트 프로파일링 기능을 통해 원인분석을 하고, 운영에서는 서비스가 최악의 상태가 되기 전에 트랜잭션 유입을 차단하여 다른 화면으로 리다이렉트 시켜주는 PLC 기능을 사용할 수 있다.제니퍼에서는 서버에서 하나의 요청에 대한 처리가 끝나면 곧바로 수집되는 데이터를 트랜잭션이라하며, 현재 수행 중인 상태에 대한 실시간 데이터를 액티브서비스라고 정의한다.   모니터링 기준 값 설정서비스를 배포하기 전에 모니터링 단계를 원활하게 수행하기 위해서는 제니퍼 관리 화면에서 몇가지 설정을 해야한다. 먼저 서비스 장애 발생시 이벤트 알림 및 서비스 부하량 제어 설정의 기준이 되는 값인 전체 에이전트의 평균 액티브서비스 개수를 알아야 한다. 하지만 서비스가 운영되는 환경에 따라 기준 값이 너무 다르기 때문에 어느 정도 안정적으로 서비스가 운영되고 있다고 생각하는 시점에 대략적으로 기준 값을 정하면 된다.에이전트란 모니터링 대상 애플리케이션에 기생하여 성능 데이터를 수집하고, 이를 서버로 전송하는 역할을 하는 모듈을 말한다. 참고로 모니터링 대상 애플리케이션은 플랫폼 환경에 따라 차이가 있을 수 있는데, 일반적으로 WAS(Web Application Server)나 웹 서버를 말한다.  액티브서비스는 처리가 완료되지 않은 상태이므로 서비스 장애의 원인분석을 위한 데이터로는 적합하지 않다. 그렇기 때문에 액티브서비스 개수는 기준 값이 될 수 없으며, 개발자는 처리가 완료된 트랜잭션 데이터의 응답시간을 기준 값으로 제니퍼의 프로파일링 관련 설정을 해야 한다. 설정된 값을 기준으로 트랜잭션 분포도 차트에서 가상의 선을 긋고, 그 선 위에 있는 트랜잭션을 대상으로 스마트 프로파일링 기능을 수행할 수 있다.  본문에서는 모니터링 단계에서 직면하게 되는 문제점과 이를 해결하기 위한 APM의 역할과 필요성 대한 이야기를 했다. 다음 편에서는 본격적으로 제니퍼를 활용하여 모니터링 프로세스를 어떻게 수행하는지에 대해 알아볼 것이다.2편에서 계속...
조회수 4389

Flask로 만들어 보는 WSGI 어플리케이션

안녕하세요. 스포카 크리에이터팀 문성원입니다. 오늘은 WSGI(Web Server Gateway Interface)어플리케이션을 직접 작성해보고, 또 이런 작성을 보다 쉽게 도와주는 프레임워크 중 하나인 Flask에 대해서 알아보겠습니다.WSGIWSGI에 대해 기억이 가물하신 분들을 위해 지난 글의 일부를 잠깐 다시 살펴보죠.이 경우 uwsgi는 일종의 어플리케이션 컨테이너(Application Container)로 동작하게 됩니다. 적재한 어플리케이션을 실행만 시켜주는 역할이죠. 이러한 uwsgi에 적재할 어플리케이션(스포카 서버)에는 일종의 규격이 존재하는데, 이걸 WSGI라고 합니다.(정확히는 WSGI에 의해 정의된 어플리케이션을 돌릴 수 있게 설계된 컨테이너가 uwsgi라고 봐야겠지만요.) WSGI는 Python 표준(PEP-333)으로 HTTP를 통해 요청을 받아 응답하는 어플리케이션에 대한 명세로 이러한 명세를 만족시키는 클래스나 함수, (__call__을 통해 부를 수 있는)객체를 WSGI 어플리케이션이라고 합니다.글로는 감이 잘 안오신다구요? 그럼 코드를 보면서 같이 살펴봅시다. (모든 코드는 Python 2.7에서 테스트 되었습니다.)Hello World!def app(environ, start_response):    response_body = 'Hello World!'    status = '200 OK'    response_headers = [('Content-Type', 'text/plain'),                         ('Content-Length', str(len(response_body)))]    start_response(status, response_headers)        return [response_body]view rawgistfile1.py hosted with ❤ by GitHubapp은 일반적인 Python 함수지만, 동시에 WSGI 어플리케이션이기도 합니다. environ과 start_response를 받는 함수기 때문이죠.(PEP-333) 사실은 꼭 함수일 필요도 없습니다. 다음은 위의 app과 동일한 동작을 하는 WSGI 어플리케이션입니다.class App(object):    def __init__(self, environ, start_response):        self.environ = environ        self.start_response = start_response    def __iter__(self):        status = '200 OK'        response_body = "Hello World!"        response_headers = [('Content-Type', 'text/plain'),                            ('Content-Length', str(len(response_body)))]        self.start_response(status, response_headers)        yield response_bodyview rawgistfile1.py hosted with ❤ by GitHubApp는 Python 클래스(Class)로 environ과 start_response를 멤버 변수로 가지는데, 여기에는 약간의 트릭이 있습니다. 생성자(Constructor)인 App를 함수처럼 사용하게 하여 리턴되는 결과(실제로는 생성자를 통해 생성된 객체겠죠.)가 \_\_iter\_\_를 구현한 순회 가능한(Iterable) 값이 되게 하는 것이죠. (덤으로 이 객체는 발생자(Generator)를 돌려주게 됩니다.)그럼 이제 이 코드들을 실행하려면 어떻게 해야할까요? 그러려면 먼저 WSGI 규격에 맞게 어플리케이션을 실행시켜 줄 서버를 작성해야합니다. 하지만 다행히도 Python 2.5부터 제공되는 wsgiref.simple_server를 이용하면 간단히 테스트 해 볼 수 있습니다.(서버를 직접 작성하는 부분에 대해선 나중에 다루도록 하겠습니다.)from wsgiref.simple_server import make_serverhttpd = make_server('', 8000, app)httpd.serve_forever()view rawgistfile1.py hosted with ❤ by GitHub위 코드를 실행시킨 후에(당연히 app이나 App도 만들어져 있어야겠죠?) 웹 브라우져를 통해 localhost:8000으로 접속하면 작성한 어플리케이션의 동작을 확인할 수 있습니다.environ과 start_response테스트도 해봤으니 코드를 조금만 더 자세히 살펴봅시다. 함수 버젼의 app이나 클래스 버젼의 App모두 공통적으로 environ과 start\_response를 인자로 받아 요청을 처리하는 것을 확인할 수 있습니다. (당연한 이야기겠지만, 반드시 이름이 environ이나 start\_response일 필요는 없습니다만 편의상 이후 계속 environ과 start_response로 표기하겠습니다.)하나씩 살펴보자면, environ은 Python 딕셔너리(dictionary)로 HTTP 요청을 처리하는데 필요한 정보가 저장되어있습니다. HTTP 요청에 대한 정보는 물론, 운영체제(OS)나 WSGI 서버의 설정 등도 정의되어있지요. 다음 코드는 이러한 environ의 내용을 응답으로 주게끔 수정한 WSGI어플리케이션입니다.def dump_environ_app(environ, start_response):    response_body = "\n".join(["{0}: {1}".format(k, environ[k]) for k in environ.keys()])    status = '200 OK'    response_headers = [('Content-Type', 'text/plain'),                         ('Content-Length', str(len(response_body)))]    start_response(status, response_headers)        return [response_body]view rawgistfile1.py hosted with ❤ by GitHublocalhost:8000에 각종 쿼리 스트링(Query String)을 붙이거나, 브라우져를 바꿔가면서 확인해보면 출력되는 값이 바뀌는 것을 확인하실 수 있습니다.그럼 이제 start\_response를 한번 볼까요. start\_response는 일종의 콜백(Callback)으로 인터페이스는 다음과 같습니다. start_response(status, response_headers, exc_info=None) 실제 서버에서 어플리케이션으로부터 응답(Response)의 상태(Status)와 헤더(Header), 그리고 예외(Exception)의 유무를 확인받아 실행하게 되는데, status와 response_headers는 HTTP 응답 명세에 근거하여 작성하게 됩니다.Middleware지금까지 우리는 어떻게 WSGI 어플리케이션을 작성하는지에 대해 살펴봤습니다. 요청을 받아 처리하는 HTTP의 기본 기능에 충실한 어플리케이션이었죠. 그런데 일반적으로 우리가 작성하는 웹 어플리케이션에서 주로 다루게 되는 쿠키(Cookie), 세션(Session)에 대해서는 어떻게 처리해야 좋을까요? WSGI 명세에는 이러한 내용을 직접적으로 다루고 있지 않습니다. WSGI 자체는 서버나 프레임워크 자체가 아니라 서버가 어플리케이션과 통신하는 명세를 다루고 있기 때문이죠. 따라서 이러한 기능은 작성자가 직접 이를 구현해야 합니다. 그런데 이런 구현을 어플리케이션을 작성할때마다 하는건 너무 번거로운 일입니다. 그것보다는 이미 작성한 어플리케이션을 확장하는 것이 간단하겠지요. 이러한 확장을 위해 필요한 것이 WSGI 미들웨어(Middleware)입니다.미들웨어는 어플리케이션을 처리하기 전후의 처리나 environ의 추가등을 통해 작성된 어플리케이션을 확장할 수 있습니다. 다음은 쿼리 스트링의 \_\_method\_\_에 따라 HTTP 메소드(Method)를 임의로 변경하는 처리를 도와주는 간단한 미들웨어입니다.from werkzeug import url_decodeclass MethodRewriteMiddleware(object):    """        app = MethodRewriteMiddleware(app)    """    def __init__(self, app, input_name = '__method__'):        self.app = app        self.input_name = input_name    def __call__(self, environ, start_response):        if self.input_name in environ.get('QUERY_STRING', ''):            args = url_decode(environ['QUERY_STRING'])            method = args.get(self.input_name)            if method:                method = method.encode('ascii', 'replace')                environ['REQUEST_METHOD'] = method        return self.app(environ, start_response)view rawgistfile1.py hosted with ❤ by GitHubMethodRewriteMiddleware는 \_\_call\_\_를 통해 app을 대체하게 됩니다. (데코레이터(Decorator)가 생각나셨다면 정확한 이해십니다.)Flask미들웨어를 통해 어플리케이션을 확장하는 방법까지 알아봤습니다. 그러나 이것만 가지고 웹 어플리케이션을 만들기에는 아직 귀찮은 부분이 많이 남아있습니다. 각종 파라미터를 처리하기 위해서는 environ를 일일히 뒤져야하며, 요청에 대한 응답으로 전달할 HTML도 일일히 문자열로 적어야하죠. 이런 여러가지 불편함을 해결하기 위해 알아볼 것이 WSGI 마이크로프레임워크를 자처하는 Flask입니다. Flask는 WSGI 라이브러리인 Werkzeug를 만들기도 한 Armin Ronacher가 만든 프레임워크로 “마이크로”라는 수식어에 어울리게 아주 핵심적인 부분만을 구현하고 있지만, 유연하게 확장이 가능하게 설계된 것이 특징입니다.다시 한번 Hello World!우선 Flask를 시스템에 설치해야하는데, pip가 설치되어있다면 pip install flask로 설치 가능합니다.(환경에 따라 루트(root)권한이 필요할 수도 있습니다.) easy_install의 경우도 마찬가지로 easy\_install flask로 설치 가능합니다.설치가 완료되었으면 다음과 같이 아주 간단한 어플리케이션을 작성해봅시다.from flask import Flaskapp = Flask(__name__)@app.route("/")def hello():    return "Hello World!"if __name__ == "__main__":    app.run()view rawgistfile1.py hosted with ❤ by GitHubFlask(정확히는 Werkzeug)는 테스트를 위해 간단한 WSGI 서버를 자체 내장하고 있기 때문에 app.run을 통해 어플리케이션을 직접 실행할 수 있습니다.Route이번에 작성한 Flask 어플리케이션에는 이전까지 보지 못하던 개념이 들어 있습니다. app.route가 바로 그것인데요. 이 메서드는 URL 규칙을 받아 해당하는 규칙의 URL로 요청이 들어온 경우 등록한 함수를 실행하게끔 설정합니다. 위의 Hello World! 예제 같은 경우엔 “/”가 해당되겠지요. 또한 이런 규칙을 URL로 부터 변수도 넘겨 받을 수 있습니다.# http://flask.pocoo.org/docs/api/#[email protected]('/')def index():    [email protected]('/')def show_user(username):    [email protected]('/post/')def show_post(post_id):    passview rawgistfile1.py hosted with ❤ by GitHub이렇게 URL을 통해 처리할 핸들러를 찾는 것을 일반적으로 URL 라우팅(Routing)이라고 합니다. 이런 URL 라우팅에서 중요한 기능 중 하나가 핸들러에서 해당하는 URL을 생성하는 기능인데, Flask는 이를 url_for 메서드를 통해 지원합니다[email protected]('/')def index():    return ""@app.route('/')def show_user(username):    return [email protected]('/post/')def show_post(post_id):    return str(post_id)from flask import [email protected]("/routes")def routes():    return "".join([            url_for("index"),            url_for("show_user", username="longfin"),            url_for("show_post", post_id=3)            ])view rawgistfile1.py hosted with ❤ by GitHub보다 자세한 사항은 API 문서를 참고하실 수 있습니다.Template여태까지 우리는 요청에 대한 응답으로 단순한 문자열을 사용했습니다. 하지만 일반적인 웹 어플리케이션의 응답은 대부분이 그것보다 훨씬 복잡하지요. 이를 보다 쉽게 작성할 수 있게끔 도와주는 것이 바로 Flask의 템플릿(Template)입니다. Flask는 기본 템플릿 엔진으로 (역시 Armin Ronacher가 작성한)Jinja2를 사용합니다.기본적으로 템플릿엔진은 별도의 규칙(여기서는 Jinja2)에 맞게 작성된 템플릿 파일을 읽어 환경(Context)에 맞게 적용한 결과물을 돌려주는데 이 과정을 Flask에서는 render_template()가 담당하고 있습니다. 다음 코드는 hello.html이라는 템플릿 파일을 읽어서 이름을 적용한 뒤에 돌려주는 코드입니다.# from http://flask.pocoo.org/docs/quickstart/#rendering-templatesfrom flask import [email protected]('/hello/')@app.route('/hello/')def hello(name=None):    return render_template('hello.html', name=name)view rawgistfile1.py hosted with ❤ by GitHub쉽게 작성할 수 있게 도와준다고 해도, 템플릿 역시 나름의 학습을 필요로 합니다. 자세한 사항은 Jinja2의 API 문서를 참고하시기 바랍니다.RequestHTTP 요청을 다루기 위해서 때로는 environ의 내용은 너무 원시적일때가 있습니다. HTML 폼(Form)으로부터 입력받는 값이 좋은 예인데요. Flask에서는 request라는 객체(역시 Werkzeug에서 가져다가쓰는 거지만요)를 통해 이를 보다 다루기 쉽게 해줍니다. 다음은 HTML 폼으로부터 입력받은 message라는 값을 뒤집어서 출력하는 코드입니다.from flask import [email protected]("/reverse")def reverse():    message = request.values["message"]    return "".join(reversed(message))view rawgistfile1.py hosted with ❤ by GitHubSession로그인등으로 대표되는 요청간의 상태를 유지해야하는 처리에 흔히 세션(Session)을 사용하실 겁니다. Flask에서는 session객체를 지원합니다.# from http://flask.pocoo.org/docs/quickstart/#sessionsfrom flask import Flask, session, redirect, url_for, escape, requestapp = Flask(__name__)@app.route('/')def index():    if 'username' in session:        return 'Logged in as %s' % escape(session['username'])    return 'You are not logged in'@app.route('/login', methods=['GET', 'POST'])def login():    if request.method == 'POST':        session['username'] = request.form['username']        return redirect(url_for('index'))    return '''        <form action="" method="post">           <input type=text name=username>           <input type=submit value=Login>        </form>    '''@app.route('/logout')def logout():    # remove the username from the session if its there    session.pop('username', None)    return redirect(url_for('index'))# set the secret key.  keep this really secret:app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'view rawgistfile1.py hosted with ❤ by GitHubFlask는 기본적으로 시큐어 쿠키(Secure Cookie)를 통해 세션을 구현하므로 길이에 제한이 있습니다. 때문에 파일이나 DB기반의 세션을 구현하려면 Beaker와 같은 프레임워크를 통한 확장이 필요합니다.(하지만 이 또한 매우 쉽습니다.)#스포카 #개발 #개발자 #개발팀 #인사이트 #기술스택 #꿀팁 #Flask
조회수 5223

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

지난 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 린더 - 데이터 협업 진행
조회수 876

[Tech Blog] Keep Principles in Mind

원칙(Principle)은 중요합니다. “난 원칙대로 살지 않겠어!” 라고 외치고 싶더라도, 원칙이 있고 원칙을 충분히 이해하고 있지 않다면 그저 사춘기 소년/소녀의 이유 없는 반항 정도로 밖에 들리지 않을테니까요. 사실 대부분의 이런 경우 원칙 보다는 “규칙(Rule)대로 살지 않겠다”에 가깝지만, 여기에서는 그냥 넘어가도록 하죠. 소프트웨어 개발에도 다양한 원칙들이 존재합니다. 학부 수업에서 잠깐 들었거나 이런 저런 글들을 읽다가 접해 봤을 이런 원칙들은 실제 서비스를 만들면서 바쁘게 기능을 추가하고 버그를 수정 하느라 어느새 기억 속에서 잊혀지곤 하죠. 정신없이 기능을 구현하다가 문득 코드를 돌아봤을 때 ‘이게 왜 여기에 있지’ 라는 의문이 든다면 한 번쯤 원칙을 되새겨 보라는 신호가 아닐까요? 이 글에서는 Clean Architecture 와 Clean Code 등의 저자로 유명한 Uncle Bob(Robert C. Martin)이 얘기하는 S.O.L.I.D Principles 에 대해 얘기해 보려고 합니다. SOLID 원칙은 밥 아저씨가 2000년도 자신의 논문 Design Principle and Design Patterns 에서 OOD(Object-Oriented Design)를 위해서 제안한 5가지 원칙의 앞 글자만 떼서 붙여졌습니다. Object-Oriented Design 을 대상으로 제안된 원칙이지만 Agile 개발 등의 개발 방법론 핵심 철학에도 적용될 수 있는 개념들 입니다. S.O.L.I.D Principles Single Responsibility Principle Class 는 오직 한 가지의 책임이 주어져야 하고, 오직 한 가지 이유에서만 변경되어야 합니다. 보고서를 편집하고 출력하는 모듈에 대해서 생각해 볼까요. 해당 모듈은 두 가지의 이유로 변경될 가능성이 있습니다. 보고서의 내용이 바뀌었을 때도 변경되어야 하고, 보고서의 형식이 바뀌었을 때도 변경되어야 합니다. 편집 과정 때문에 모듈을 변경하다 보면 해당 변경 사항이 출력 부분에도 영향을 미칠 가능성이 상당히 높습니다. 이 경우 내용을 편집하는 모듈(i.e 내용을 담당하는 모듈)과 출력하는 모듈(i.e 형식을 담당하는 모듈) 두 가지로 나뉘어야 합니다. “할 수 있다고 해서 해야 한다는 뜻은 아닙니다.” Open / Closed Principle Class, Module, Function 등의 소프트웨어 구성 요소는 확장(extension)에 대해 열려 있어야 하며, 변경(modification)에 대해 닫혀 있어야 합니다. 어떤 모듈이 Data Structure 에 필드를 추가하거나 함수를 추가하는 등 확장이 가능하다면 그 모듈은 확장에 대해 열려 있다고 표현합니다. 반면에 어떤 모듈이 수정 없이 다른 모듈에 의해 사용될 수 있다면 그 모듈은 닫혀 있다고 표현합니다.  public class CreditCard {     private int cardType;       public int getCardType() { return cardType; }       public void setCardType(int cardType) { this.cardType = cardType; }          public double getDiscount(double monthlyCost){          if (cardType == 1) {              return monthlyCost * 0.02;          } else {              return monthlyCost * 0.01;          }     } }  위 CreditCard class 에 새로운 카드 타입을 추가하려고 하면 getDiscount 함수를 변경할 수 밖에 없습니다. 이 경우 Open/Closed Principle 을 위반된다고 볼 수 있습니다. “코트를 입기 위해서 개복 수술을 할 필요는 없으니까요.” Liskov Substitution Principle 프로그램 상의 Object 들은 프로그램의 정확성을 해치지 않으면서 하위 타입의 Instance 로 변경 가능해야 합니다. 하위 타입 함수 인자의 반공변성(Contravariance), 하위 타입 함수 반환 타입의 공변성(Covariance), 상위 타입의 예외를 상속하지 않는 추가적인 예외 발생 금지 등의 요구 사항이 있습니다. OOP 에서 상속 개념을 배울 때 이해를 돕기 위해 주어진 몇 가지 예시들이 있었을텐데, 우습게도 우리가 생각하기에 타당한 상속에 관한 예시들 중 의외로 원칙을 위배하는 경우가 많습니다. Liskov Substitution Principle 을 위반하는 대표적인 예시는 정사각형과 직사각형입니다. 정사각형은 직사각형의 일종이니 Square가 Rectangle을 상속받는 것이 충분이 타당한 것으로 보입니다. 정말 그럴까요? Rectangle 의 넓이를 구하는 함수의 테스트를 구성해 봅시다.  Rectangle rect = new Rectangle(); rect.setWidth(10); rect.setHeight(20); assertEquals(200, rect.getArea());  여기에 new Rectangle() 대신에 new Square()가 rect 에 할당되면 어떻게 될까요? 넓이는 400 을 반환하기 때문에 테스트는 실패하겠죠. 정사각형이 직사각형을 상속 받으면 Liskov Subsitution Principle 을 위반한다고 볼 수 있습니다. 상속은 문제를 해결하는데 있어서 상당히 유혹적인 방법입니다. 하지만 상당히 많은 경우에 상속을 오용할 가능성이 높습니다. “오리처럼 생기고 오리처럼 꽥꽥 거리더라도, 배터리가 필요하다면 오리가 아닙니다.” Interface Segregation Principle 많은 것을 아우르고 일반적으로 사용 가능한 하나의 interface 보다 특정 클라이언트를 위한 여러 개의 interface 가 낫습니다. Xerox는 Stapling(프린터기가!?), Fax 등의 다양한 기능이 포함된 신규 프린터 소프트웨어를 개발 도중, 더이상 개발이 불가능할 정도로 프로그램이 번잡 해졌다는 것을 인정하고 밥 아저씨에게 도움을 요청합니다. 문제는 Job Class 하나가 모든 기능을 다 구현하고 있다는데 있었습니다. 이 비대한 Class 는 Client 입장에서 사용되지도 않을 모든 함수를 알 수 있게 구성 되어 있었죠. 이 문제에 대해 밥 아저씨는 Interface Segregation Principle 을 적용하여 각 Client 입장에서 사용해야 하는 함수 만을 가지고 있는 각 interface 들을 따로 만들었습니다. 그리고는 다음에 나올 Principle 인 Dependency Inversion Principle 을 통해서 해당 기능을 구현하게 함으로써 문제를 해결했습니다. Dependency Inversion Principle “추상화에 의존해야지, 구체화에 의존하면 안됩니다.” 상위 계층의 모듈은 하위 계층의 구현이 아니라 추상화에 의존해야 합니다. 상위 계층이 하위 계층의 구현에 의존하던 전통적인 의존 관계를 역전 시킴으로써 상위 계층이 하위 계층의 구현으로부터 독립되게 할 수 있습니다. 예를 들어 Dependency Injection 은 이 원칙을 따르는 방법 중 하나 입니다. Conclusion 세상에 나쁜 프로그램은 있습니다. 당장 눈에 보이는 기능이 똑같다고 같은 프로그램인 것은 아닙니다. 생각보다 많은 코드들이 ‘그 곳에 넣을 수 있기 때문에’, ‘그 곳에 넣어도 돌아가기 때문에’ 깊은 고민 없이 그 곳에 정착합니다. 당장 좀 더 빠르게 기능을 추가해서 주변 사람들의 박수를 받을 수도 있습니다. 허나 이것들이 쌓이면 더이상 손댈 수 없는 코드가 되고, 문제를 느끼고는 Refactoring을 하자고 다짐하고, 모두 엎은 다음 또 다시 같은 코드를 만들게 되겠죠. 쉬운 코드가 가장 만들기 어려운 코드이고, 그런 좋은 코드는 좋은 원칙으로 부터 나옵니다. 변화에 적응할 수 있는 프로그램, 의도가 쉽게 읽히는 프로그램, 문제 발생 가능성이 적은 프로그램, 쉽게 확장할 수 있는 프로그램 등 좋은 프로그램을 만드는 것은 우리가 실제로 목표하는 것을 달성하기 위해서 정말 중요합니다. 이는 그저 경험이나, Tweak 만으로 이루어지지 않습니다. 다양한 신규 기술들과 Framework 들을 두루 섭렵하면서 활동 반경을 넓히고 경험을 쌓았다면, 가끔은 잠시 서서 원칙에 대해 되돌아 보는 것은 어떨까요?   *버즈빌에서 활기찬 개발자를 채용 중입니다. (전문연구요원 포함)작가소개 Whale, Chief Architect “Keep calm and dream on.”
조회수 1834

성장하는 PHP와 환대받지 못하는 개발자

https://kinsta.com/blog/php-7-2/ PHP v7.2 릴리즈최근(2017년 11월 30일)에 PHP  7.2 버전이 릴리즈 되었습니다.(다운로드 바로가기) PHP는 1995년에 만들어진 오래된 언어지만 여전히 많은 웹사이트들이 PHP로 만들어지고 있습니다. 특히 버전7로 넘어오면서 퍼포먼스가 비약적으로 좋아졌다는 평을 듣고 있습니다. 이번 7.2 버전에서는 아래와 같이 보안성강화와 프로그래밍 기능 향상을 제공하고 있습니다. (개선목록 바로가기)PHP 7.2.0 comes with numerous improvements and new features such as  Convert numeric keys in object/array castsCounting of non-countable objectsObject typehintHashContext as ObjectArgon2 in password hashImprove TLS constants to sane valuesMcrypt extension removedNew sodium extensionPHP로 만들어진 많은 사이트2017년 GitHub 통계를 보면 PHP는 GitHub에서 사용되는 337개의 언어들중에서 Top 5에 들어가는 매우 대중적인 언어입니다.https://octoverse.github.com/ WordPress, Drupal, Zoomla 와 같은 웹 기반의 오픈소스 컨텐츠 관리 시스템은 모두 PHP로 만들어 졌습니다. 그리고테크크런치(TechCrunch), 펩시 리프레시(Pepsi Refresh), 코메디닷컴(Comedy.com) 같은 기업들은 WordPress로 만들어진 사이트를 적극 활용하고 있기도 합니다. 다만 아쉬운 점은 아직도 5버전을 사용하여 개발한 사이트들이 많이 있다는 점입니다.https://kinsta.com/blog/php-7-2/환대받지 못하는 PHP 개발자PHP는 탁월한 접근성으로 인해 생각지도 못한 문제가 발생합니다. PHP가 누구나 사용할 수 있을 정도로 쉬운 구조이다보니 우리나라의 갑-을-병-정 으로 내려가는 SI 구조에서 저렴한 인력으로 구분되기 시작합니다. PHP 고급 개발자가 고급 대우를 못받게 되는 상황이 발생하는 것입니다. 또한 엔터프라이즈 개발에서 제외되다 보니 PHP 개발자는 점점 대규모 시스템 설계 경험이 적어지고 결국 중소규모의 서비스 개발에만 참여하게 되었습니다. 하지만 PHP도 충분히 대규모 서비스 개발이 가능한 언어이며 PHP The Right Way 와 같이 PHP를 잘 사용할 수 있는 방법들을 정리한 사이트를 보면 PHP의 저력을 확인할 수 있습니다.PHP 개발자를 위한 서비스 관리 도구PHP 개발에 있어서 아쉬운 부분이 있다면 개발 이후 운영에 관련된 부분입니다. 많은 국내 PHP 사이트들이 개발 이후 성능 분석이 되지 않은 상태에서 운영되고 있습니다. Java로 만들어진 엔터프라이즈 서비스들은 오픈 시점과 운영 과정에서많은 노력을 들여서 서비스 최적화 작업을 진행하는데 반해서, PHP로 개발된 서비스들은 사용자가 많아지더라도 튜닝 작업을 진행하는 경우가 거의 없습니다. 아쉬운 점은 이로 인해 PHP의 성능이 떨어진다는 오해가 발생하기도 한다는 것입니다.일반적으로 평균 응답시간을 계산하여 서비스의 상태를 파악하기도 하지만 하루 1만명이 들어오는 사이트에 100명이 10초 이상의 응답시간을 경험하더라도 나머지 인원이 0.1초의 응답시간을 갖는다면 서비스의 평균 응답시간은 0.2초 이내로 나오게 됩니다. 이런 고객의 장애를 해결하기 위해서는 사용하는 성능 분석 서비스가 이전까지는 솔루션으로만 제공되었기 때문에 고가이며 설치도 어려웠지만 최근에 서비스로 제공되기 시작하면서 비용도 저렴해지고 설치도 매우 쉬워졌습니다. 해외에서는 몇 년전부터 많은 PHP 개발자들이 모니터링 서비스인 뉴렐릭(https://newrellic.com)이나 앱다이나믹스(https://appdynamics.com)의 서비스를 통해 PHP 분석/모니터링 서비스를 사용하고 있습니다. 이런 서비스들은 당연히 한국에서도 사용이 가능합니다.https://newrelic.com/php국내 모니터링 서비스 중에서는 와탭(https://whatap.io)이 최근 PHP를 지원하고 있습니다. 어플리케이션의 성능을 분석하고 튜닝한 사이트와 안한 사이트의 성능 차이가 날수 있기 때문에 PHP로 만들어진 서비스의 운영 및 업데이트 작업을 진행하는 개발자 분들은 뉴렐릭이나 앱다이나믹스 또는 와탭을 사용하여 운영중인 서비스의 성능을 확인해 보시길 권하고 싶습니다. 대부분의 PHP 성능 모니터링 서비스는 트라이얼 기간을 제공해 주기 때문에 일정기간 무료로 서비스 사용이 가능합니다. 몇일간 성능을 분석하고 모니터링 한다면 서비스 운영 방식에 대한 인사이트도 얻을 수 있습니다. https://coderseye.com/best-php-frameworks-for-web-developers/PHP 성능 모니터링 서비스로 할수 있는 것들PHP 성능 모니터링 서비스는 정확히 표현하면 고객의 트랜잭션을 추적하는 서비스입니다. 서비스를 사용하는 모든 고객의 트랜잭션을 추적하여 서비스의 성능을 알아내는 방식입니다. 이런 어플리케이션 성능 모니터링 서비스는 대규모 서비스를 체계적으로 운영하는 위한 필수 도구입니다. 최근 서비스 형태로 제공되는 성능 모니터링 서비스들은 기존 운영자 위주의 기능에서 벗어나서 개발자와 운영자가 함께 참여하는 DevOps 환경에 맞는 기능을 제공하고 있습니다. 서비스를 운영하는 과정에서 응답시간의 상황을 실시간으로 확인할 수 있으며 문제가 발생한 쿼리를 빠르게 찾을 수 있도록 도와줍니다. 트랜젝션의 에러도 당연히 알수 있으며 문제가 발생한 메소드도 알수 있습니다. 코드상의 서비스 구조뿐만 아니라 실제 트랜잭션의 흐름을 알수 있기 때문에 서비스의 동작 구조도 함께 공유해가며 서비스를 발전시킬 수 있도록 도와줍니다. 결론PHP는 정말 빠르게 발전하고 있는 언어중에 하나입니다. 우리가 정보를 주고 받는 많은 서비스들이 PHP로 만들어 지고 있으며 언어의 구조도 모던하게 변화하고 있습니다. 특히 빠르게 변화하는 스타트업에서 사랑받는 언어이며 세계적으로도 많은 이들의 사랑을 받고 있는 언어입니다. 한편 PHP는 소규모에서만 적용한다는 인식과 함께 PHP로 시작했음에도 규모가 커지면서 서비스를 Java로 변경하는 경우에는 아쉬움이 남습니다. 하지만 PHP가 지속적으로 발전하고 있고 더 좋은 방향으로 나아가는 과정에서 더 좋은 PHP 개발자들이 나오기 시작할 거라 생각합니다. 그리고 뉴렐릭(https://newrelic.com)이나 앱다이나믹스(https://appdynamics.com) 아니면 와탭(https://whatap.io)과 같은 성능 분석 도구를 사용하여 PHP로 만든 서비스의 효율을 높이고 운영 관리를 체계화해 나간다면 국내에서도 페이스북과 같이 PHP로 개발하여 대규모로 서비스볼수 있을거라 생각합니다. http://php.net/archive/2017.php#와탭랩스 #개발자 #개발팀 #인사이트 #경험공유 #일지 #PHP
조회수 6117

개발자 직군 파헤치기 1 | 프론트(Front), 백(Back), 풀스택(Full-Stack) 개발자

수많은 개발자 직군들개발자가 되기 위해서는 프로그래밍 언어만 배운다고 끝나는 것이 아닙니다. 자신이 배운 언어를 가지고 어떤 개발자가 될지 고민도 해야합니다. 실제로, 많은 분들이 내가 어떤 분야의 개발자가 되야 할지 고민을 많이 합니다. 그런데 이 고민에 앞서 어떤 개발자의 종류가 있고 직군이 있는지를 살펴보아야 합니다. 그래서 이번에 준비한 연재는 개발자 직군 파헤치기 시리즈입니다. 우리가 개발의 한 직군이라고 부를 수 있는 것들 중 관심이 많이 가는 직군들을 위주로 알아볼 것입니다. 일하는 분야에 대한 직군(게임 개발자)에 대한 이야기도 할 것이고, 지금 이야기할 프론트-엔드, 백-엔드처럼 개발의 영역에 대한 이야기도 할 것입니다. 다양한 관점에서 개발자의 영역들을 살펴볼 것입니다. 자, 그럼 지금부터 시작해 보죠!(※이 글은 유다시티 3Web Dev Careers Decoded: Front-End vs Back-End vs Full Stack을 번역한 것입니다.Front, Back and Full Stack우리가 매일같이 인터넷을 사용하는 과정을 떠올려봅시다. 새 브라우저 탭을 열고 URL을 입력 한 다음 Enter 키를 누르면 그 즉시 사이트가 로딩이 됩니다. 깔끔한 레이아웃, 잘 구성된 페이지, 그리고 화려한 시각적 효과들은 때로 감탄을 자아내죠.순식간에 일어난 이 모든 경험을 담당하는 사람들이 바로 웹 개발자들입니다.2018 년 4 월 현재 인터넷에 있는 페이지의 수는 45 억개가 넘습니다.  지금 이 순간에도 그 수는 계속 늘어나고 있습니다. 누군가 안정적인 직업을 찾고 싶다면 웹 사이트의 코딩, 설계, 분석 및 유지 관리를 담당하는 사람들, 곧 웹 개발자들을 찾아야 할 것입니다.웹 사이트는 이제 모든 비즈니스가 경쟁력을 유지하는 데 중요한 구성 요소입니다. 웹 개발의 트렌드와개발의 패러다임이 거의 매 시즌마다 바뀌는 상황에서, 개발자에 대한 수요는 부족함이 없습니다.그러나 웹 개발자의 범위는 매우 넓기 때문에 정확히 어떤 종류의 웹 개발자 채용 공고를 찾아보아야 하고, 그러한 개발자가 되기 위해 무슨 교육을 받아야 하는지를 판단하기는 쉽지 않습니다.  만약 구직 사이트를 둘러 보거나 온라인 강좌를 알아본 경험이 있다면, 프론트엔드, 백엔드, 그리고 풀스택 개발자라는 용어를 한번쯤은 들어보았을 것입니다.HTML, 자바 스크립트 또는 약간의 파이썬을 사용해 본 적이 있지만, 막상 개발자 직군에 대해서는 막막했다면 이 글이 매우 유용할 것입니다. Photo by Annie Spratt on UnsplashFront-End Developer프론트엔드는 웹사이트 중 사용자가 직접 상호작용을 하게 되는 부분입니다. 글꼴 부터 색상, 드롭 다운 메뉴 및 슬라이더에 이르기까지 인터넷에서 보게 되는 모든 것들은 브라우저의 제어를 받는 HTML, CSS 및 JavaScript의 조합입니다.SKILLS AND TOOLS프런트엔드 개발자는 웹 사이트에서 사용자가 직접 경험하는 부분과 그 경험의 아키텍처를 담당합니다. 이를 위해 프론트엔드 개발자는 HTML, CSS, Javascript 활용에 능숙해야합니다. 언어를 잘 다루는 것 외에도 프런트 엔드 개발자는 사용자의 도구에 따라 유연한 방식으로 컨텐츠를 보여줄 수 있게 하는 Bootstrap, Foundation, Backbone, AngularJS, EmberJS와 같은 프레임워크에 익숙해야합니다. 또한 jQuery, LESS와 같은 라이브러리를 사용할 수 있다면 더욱 유용하고 효율적인 코드를 작성할 수 있게됩니다. 프론트엔드 개발자를 채용할 때에는 Ajax 사용 경험을 요구하는 경우도 많습니다. 백그라운드에서 서버 데이터를 가져와 페이지를 동적으로 만드는 Javascript를 활용하는 데 있어서 Ajax는 보편적으로 사용되는 기술이기 때문입니다.프런트 엔드 개발자는 백엔드 개발자가 만든 집의내부 디자인을 담당합니다.프론트엔드 개발자는 이러한 기술을 사용하면서도, 목업(mockup) 혹은 와이어프레임(wireframe)의 개발에서 전달의 단계까지 디자이너 또는 사용자 경험 분석가와 긴밀히 협력합니다. 실력 있는 프론트엔드 개발자는 사용자 경험에서의 문제를 정확하게 발견하고, 디자인을 수정에 관한 조언과 문제 해결을 위한 코드를 제공합니다. 또한 목표와 필요, 기회들을 정확히 이해하고 수행하기 위해서는 다른 팀들과 유연하게 협력하는 능력이 중요합니다. 이처럼 프론트엔드 개발자의 작업은 여러 영역에 대한 책임을 동시에 감당하는 일이면서도 그만큼의 보람이 따라오는 것이기도 합니다. 8 년차 프론트엔드 개발자 인 Mikey Ilagan은 아래와 같은 이야기를 합니다.저는 기술적인 사람이면서도 시각적인 사람입니다.그래서 저는 자연스럽게 목업과 코드를 동시에 다루며 사람들이디지털 플랫폼과 상호작용하는 방식을 만들어 낼 수 있게 되었습니다.-Mikey Ilagan-종합해보자면, 프론트엔드 개발자는 백엔드 개발자가 만든 집의 내부 설계를 담당합니다. 집을 장식하는취향과 스타일은 집주인이 결정합니다. Apptix의 제품 마케팅 디렉터인 Greg Matranga는 "프론트엔드에서 작업하는 개발자는 자신의 창의성을 실질적으로 작업에 반영할 수 있기 때문에 때로는 자신이 하는 일에 대해 더욱 흥분한다"며 자신이 관리하는 프론트엔드 및 백엔드 개발자 팀 모두에게 말하기도 했습니다.HOW IT TRANSLATES지금 이 블로그에서 보고있는 모든 것은 프론트엔드 개발자의 손을 타지 않은 곳이 없습니다. 물론 로고와 그래픽은 디자이너가 만들고, 사진은 자신 작가가 찍었으며, 텍스트는 지금 글을 쓰고 있는 제가 작성합니다. 그러나 이 모든 조각들을 모아 웹으로 만들고, 각 페이지마다 사용자가 경험할 것을 설계한 것은 프론트엔드 개발자입니다.Photo by Lee Campbell on UnsplashBack-End Developer프론트엔드에서 일어나는 일을 이해했다면, 그것만으로는 웹사이트가 완성되지 않는 다는 것 역시 이해했을 것입니다. 그렇다면 프론트엔드 자체를 가능하게 만드는 것은 무엇일까? 데이터는 어디에 저장되는 것일까? 바로 백엔드입니다. 웹 사이트의 백엔드는 서버, 응용 프로그램 및 데이터베이스로 구성됩니다. 백 엔드 개발자는 이러한 구성요소들이 작동할 수 있게하는 기술을 만들고 유지하는 일을 합니다. 이러한 작업을 통해 비로소 사용자에게 보여지는 측면이 존재할 수 있게 됩니다.SKILLS AND TOOLS서버, 응용 프로그램, 데이터베이스가 서로 통신 할 수 있도록 만들기 위해 백엔드 개발자는 PHP, Ruby, Python, Java, .Net과 같은 서버 측 언어를 활용하여 응용 프로그램을 만듭니다. 또한 데이터를 검색, 저장 또는 변경하고 이를 프론트엔드 코드로 사용자에게 다시 제공하기 위해서는 MySQL, Oracle 및 SQL Server를 사용합니다. 백엔드 개발자에 관한 채용 공고는 그 외에도 1) Zend, Symfony 및 CakePHP와 같은 PHP 프레임 워크에 대한 경험, 2) SVN, CVS 또는 Git과 같은 버전 제어 소프트웨어 사용 경험, 3) 개발 및 배포 시스템으로서의 Linux 사용 경험을 요구하는 경우가 있습니다.백엔드 개발자는 이러한 도구를 사용하여 깔끔하고 모듈화가 가능한 코드로 웹 응용 프로그램을 만듭니다. 그러나 이와 같이 코드를 작성하기 전에 백엔드 개발자는 비즈니스 이해 관계자와 소통하면서 구체적인 요청 사항을 파악해야 합니다. 그런 다음 이를 기술적 내용으로 변환하여 기술 설계를 위한 가장 효과적이고 효율적인 솔루션을 제시할 수 있어야 합니다.나는 데이터를 다루는 것을 좋아하기 때문에항상 백엔드 개발을 선호 해 왔습니다.-JP Toto-오랫동안 백 엔드 개발자였던 JP Toto는 현재 와일 비트의 소프트웨어 개발자입니다. 그는 "최근 공개 및 비공개 API는 모바일, 웹 사이트를 포함한 여러 시스템간에 데이터를 교환하는 데 필수적인 부분이되었으며, 사람들이 유용하다고 생각하는 API를 만드는 것은 그에게 큰 만족감을 주는 일 중에 하나"라고 말한다.HOW IT TRANSLATES여러분이 코드스테이츠의 웹사이트를 찾아 들어오는 과정을 봅시다.  웹사이트의 서버는 여러분의 컴퓨터 또는 모바일로 정보를 보내고, 그 정보는 코드스테이츠 소개가 담긴 페이지로 보여집니다. 이 프로세스는 백엔드 개발자의 작업 결과입니다. 또한 회원가입을 할 때 저장되는 개인정보, 그리고 로그인을 할 때마다 각 계정의 정보가 불러와지는 과정 역시 백엔드 개발자 덕분입니다.Full Stack Developer프론트엔드 개발과 백엔드 개발 간에는 흑백 구분이 없는 경우가 종종 있습니다. 프론트엔드 개발자는 종종 추가 백엔드 기술을 습득해야하며 그 반대의 경우도 있습니다. 개발자는 여러 분야를 넘나들어야 할 때가 많아 종종 제너럴리스트가 되어야 합니다.  풀스택 개발자라는 역할은 7년 전 페이스북의 엔지니어링 부서에서 대중화되었습니다. 풀스택 개발자라는 호칭은 프론트엔드와 백엔드 모두에서 교차적으로 작업 할 수 있는 역할을 지칭하는 것에서 시작했습니다. 말 그대로 풀패키지(full package)를 제공하는 개발자라는 뜻입니다.서버와 클라이언트 측 모두에서 작업할 있는 전문성은더 많은 기회를 열어줍니다.-Federico Ulfo-Grovo의 풀스택 개발자인 Federico Ulfo는 이를 음식에 비유에 이야기합니다. "요리와 베이킹 중에 하나를 잘할 수는 있습니다. 그러나 두 가지를 모두 마스터하는 데에는 시간과 경험이 필요합니다. 마스터 한다는 것은 단지 레시피를 따라서 만드는 것을 말하는 게 아닙니다. 그건 누구든지 할 수 있습니다. 마스터 한다는 것은 직접 재료를 고르고 자신의 레시피로 훌륭한 음식을 만들어내는 것입니다."Photo by freestocks.org on UnsplashSKILLS AND TOOLS풀스택 개발자는 백엔드 개발자와 마찬가지로 웹 프로그래밍의 서버 측에서 작업하지만, 이와 동시에 사용자 측에서 콘텐츠가 보여지는 방법에 관해 프론트엔드의 언어로 능숙하게 소통할 수 있습니다. 아래의 이미지는 풀스택 개발이 얼마나 복잡해지고 있는지를 체감하게 해줍니다. 몇년 전까지만 해도 3-4가지의 기술의 종합으로 표현될 수 있었던 풀스택은 현재 7개의 기술이 종합된 형태로 훨씬 복잡해졌음을 알 수 있습니다.출처: Techrunch출처: Techrunch구체적인 기술의 종류는 프로젝트나 클라이언트에 따라 달라질 수 있지만, 풀스택 개발자는 기술의 종류와 상관없이 Linux 서버의 설정과 구성, 서버 측 API 작성, 클라이언트 측 JavaScript, 디자인을 맡는 CSS 등 웹이 작동하는 모든 차원에 있어서 해박해야합니다.풀스택 개발자는 이러한 기술들을 사용하여 클라이언트 측과 서버 측이 담당할 영역을 즉각적으로 구분해내고, 다양한 솔루션들의 장단점을 명확히할 수 있어야 합니다. HOW IT TRANSLATES풀스택 개발자는 로딩 시간부터 레이아웃, 그리고 사용자와의 상호작용성과 구조적 토대에 이르기까지이 게시물이 주는 경험의 전체적인 흐름을 책임집니다.The Bottom Line웹 개발에는 많은 면모가 있습니다. 그러나 당신이 어떠한 개발자가 되고 싶든지 디테일에 주의를 기울이는 능력, 빠르게 학습할 수있는 능력, 문제를 효율적으로 해결하는 능력, 그리고 커뮤니케이션 능력은 당신을 돋보이게 만들것입니다. 다행히 웹 개발 분야에서 경력을 쌓기 위해 이보다 더 좋은 시기는 없습니다. 웹 개발자의 고용은 2014 년에서 2024 년까지 10 년 동안 27 % 증가 할 것으로 예상되며 이는 모든 직종의 평균보다 빠릅니다. 지금까지 Front, Back, Full Stack 개발자에 대해서 알아보았습니다.다음 포스팅은 개발의 한 축을 담당하고 있기는 하지만 일반 개발 분와야는 다른 '게임 개발자'에 대해서 알아보도록 하겠습니다.
조회수 834

[Buzzvil Culture] Strategy Talk for Engineer Hiring : How we hire engineers

 버즈빌에서는 전사 차원에서 고민하고 있는 회사의 현안과 전략적 방향성에 대해 모두와 함께 공유하고 의견을 나눈다는 취지 하에 한 달에 한 번 Strategy Talk을 진행하고 있습니다. Strategy Talk의 주제는 매 달의 화두와 고민에 맞게 진행되고 있는데요. 지난 번에 버즈빌 블로그를 통해 소개드렸던 Machine Learning(AI) 부터 프로덕트 로드맵, 시장 동향, 그리고 회사의 비전과 미션 등 다양한 주제로 진행되고 있습니다. 이번 달, Strategy Talk은 ‘버즈빌의 Engineer Hiring Strategy’ 라는 주제로 진행되었습니다. 이번 세션은 버즈빌의 Product side를 총괄하고 있는 Young의 주도하에 진행되었는데요. 세션을 통하여 왜 버즈빌이 더 많은 엔지니어가 필요한지에 대한 배경부터 어떤 방법들을 통해 채용을 해 나갈 것인지, 나아가 버즈빌이 어떤 모습으로 변해갈 것인지에 대한 내용을 공유하고 함께 논의하는 시간을 가졌습니다.새로운 개발자들을 대규모 채용하는 것이 어떤 의미가 있을까요? 기본적으로 새로운 사업을 만들어가며 공격적으로 성장하고 현재 리소스의 한계 때문에 진행하지 못하고 있는 기존 Product의 개선 작업들을 진행 하기 위해서는 당연히 충분한 개발자들이 합류하는 것이 필요합니다. 뿐만아니라 다양한 경험을 가진 더 많은 개발자를 채용하는 것은 ‘버즈빌의 개발문화’와도 큰 연관이 있습니다. 버즈빌은 좋은 개발문화를 가지고 있기로 유명합니다. 수평 / 자율 / 성장 삼박자가 고루 갖추어진 환경이라고 할 수 있는데요. 개발팀의 개발자들 모두가 동등한 Software Engineer로 일하고 있고 그만큼 개발 과정에서 의견 교환이 자유롭게 일어납니다. 누군가의 일방적인 지시가 아닌 모두가 최적이라고 합의할 수 있는 방향으로 개발을 진행해 나가고 있습니다. 뿐만아니라 개발 과정에서 각각의 엔지니어가 본인의 업무를 맡아 주도적으로 처리해 나가며 자신이 맡은 이슈에 대해 주인의식을 가지고 일하고 있습니다. 따라서 특정 개발 방향이 주어져서 틀에 박힌 개발을 해야한다거나 다른 사람의 눈치를 보면서 맞춰가는 개발을 해야하는 건 버즈빌의 개발문화와는 거리가 멀다고 할 수 있습니다. 그리고 개인의 성장을 위해 여러가지 지원을 하고 있는데요. 업무를 진행하는 과정중에 필요하다면 AWS의 다양한 서비스를 포함한 여러가지 툴들을 자유롭게 사용해 볼 수 있습니다. 외부에서 열리는 세미나 / 강연등에 참여하는 것을 독려하며 회사에서 관련비용을 지원하기도 합니다. 이러한 개발문화를 가지고 있기에 버즈빌은 개발자들이 자신의 역량을 100% 발휘할 수 있고 새로운 것들을 배워가며 성장해 나가기에는 최적의 조건을 가지고 있다고 할 수 있습니다. (버즈빌에 개발문화에 대한 보다 자세한 내용은 여기를 참고해 주세요!)이러한 버즈빌의 개발 문화를 유지하고 더 나아가 발전시켜 나가기 위해서도 다양한 경험을 가진 많은 엔지니어들이 합류하는 것이 긍정적인 영향을 미치리라 생각합니다. 지금도 내부적으로 개발자들이 돌아가면서 기술 관련 세미나를 진행하면서 서로의 노하우와 새로운 기술에 대한 논의들을 하고는 있지만 더 많은 개발자들이 합류 하면서 이런 기회 들을 더욱 확장해 나갈 수 있음은 물론 관심사가 맞는 개발자들 끼리 모여 관련 주제로 스터디 모임을 진행한다거나 새로운 사업모델 발굴을 위해서 버즈빌의 자원들을 활용하여 새로운 프로젝트들도 진행해 볼 수 있을 것입니다.

기업문화 엿볼 때, 더팀스

로그인

/