스토리 홈

인터뷰

피드

뉴스

조회수 2224

시간을 줄여주는 CodeStar 사용 팁

편집자 주: 함께 보면 좋아요!애플리케이션 개발부터 배포까지, AWS CodeStarOverview: 작성 환경AWS CodeStar를 사용하면 애플리케이션의 서버, 언어 , 형상관리, 배포, 빌드까지 한꺼번에 관리할 수 있습니다. AWS를 사용하는 개발자라면 꼭 필요한 도구이기도 합니다. 이번 글에서는 CodeStar를 초기 설정할 때의 도움이 될 내용들을 소개하겠습니다.-서비스: AWS CodeStar-템플릿: Python Webservice, AWS Lambda목차파라미터 바인딩람다 환경변수 설정람다 레이어 설정xray 모니터링 설정람다 함수명 설정Global 섹션로컬 개발환경에서의 SAM 실행CodeStar 프로젝트 생성 후CodeStar로 프로젝트를 생성하면 소스코드와 배포를 위한 Code 시리즈 리소스들이 함께 만들어집니다. CodeCommit, CodeBuild, CodePipeline 등이 있습니다. 우선 기본으로 구축된 파이프라인부터 살펴보겠습니다.CodeCommit 리포지토리의 마스터 브랜치 코드를 변경하면 CodeBuild와 CloudFormaton 서비스를 통해 빌드, 테스트, 배포를 진행할 수 있게 설정되어 있습니다. 생성된 리포지토리의 template.yml 파일을 이용하면 프로젝트 리소스도 관리할 수 있는데, 특히 template.yml을 통해 CloudFormation으로 관리하는 리소스까지도 관리가 가능합니다.기본으로 생성된 template.yml 파일을 자세히 살펴보겠습니다.AWSTemplateFormatVersion: 2010-09-09 Transform: - AWS::Serverless-2016-10-31 - AWS::CodeStar Parameters: ProjectId: Type: String Description: CodeStar projectId used to associate new resources to team members CodeDeployRole: Type: String Description: IAM role to allow AWS CodeDeploy to manage deployment of AWS Lambda functions Stage: Type: String Description: The name for a project pipeline stage, such as Staging or Prod, for which resources are provisioned and deployed. Default: '' Globals: Function: AutoPublishAlias: live DeploymentPreference: Enabled: true Type: Canary10Percent5Minutes Role: !Ref CodeDeployRole Resources: HelloWorld: Type: AWS::Serverless::Function Properties: Handler: index.handler Runtime: python3.7 Role: Fn::GetAtt: - LambdaExecutionRole - Arn Events: GetEvent: Type: Api Properties: Path: / Method: get PostEvent: Type: Api Properties: Path: / Method: post LambdaExecutionRole: Description: Creating service role in IAM for AWS Lambda Type: AWS::IAM::Role Properties: RoleName: !Sub 'CodeStar-${ProjectId}-Execution${Stage}' AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: [lambda.amazonaws.com] Action: sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole PermissionsBoundary: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/CodeStar_${ProjectId}_PermissionsBoundary' 파라미터 바인딩Parameters 섹션에서는 ProjectId, CodeDeployRole, Stage 등 템플릿에서 사용할 파라미터를 지정할 수 있습니다. yml 파일 안에서는 ${ProjectId} 와 같이 사용할 수 있고, CodePipeline 환경에서 파라미터를 전달할 수 있습니다.CodePipeline → Deploy → GenerateChangeSet → Advanced → Parameter overrides람다 환경변수 설정람다 함수에서 사용할 환경변수를 설정할 수 있습니다. 아래와 같이 람다 환경변수 TZ(timezone)를 지정하면 실행 환경의 표준 시간대 설정이 가능합니다.Resources: HelloWorld: Type: AWS::Serverless::Function Properties: Environment: Variables: TZ: 'Asia/Seoul' 람다 레이어 설정람다 레이어를 적용하면 패키지 관리가 훨씬 편리해집니다. 함수의 패키지 크기가 3MB를 넘지 않으면 콘솔에서 코드를 직접 확인 및 수정할 수 있습니다. 람다 레이어는 zip 파일로 관리되고, /opt 폴더에 압축 해제되며 생성됩니다.람다는 250MB의 제한이 있습니다. 만약 레이어를 사용해 분리하더라도 람다함수패키지와 람다 레이어의 합으로 걸려있으므로 크기 제약에서 벗어날 수는 없습니다.Resources: HelloWorld: Type: AWS::Serverless::Function Properties: Layers: - arn:aws:lambda:{region}:{id}:layer:{layer-name}:{version} xray 모니터링 설정Tracing Property를 이용하면 람다 함수의 Enable active tracing 설정을 할 수 있습니다. CloudFormation 템플릿 메뉴얼엔 TracingConfig로 안내하고 있어도 빌드에 실패하여 확인해보니 SAM 템플릿의 AWS::Serverless::Function 의 스펙에선 Tracing으로 안내되고 있는 걸 볼 수 있었습니다.Resources: HelloWorld: Type: AWS::Serverless::Function Properties: Tracing: Active 람다 함수명 설정람다 함수는 기본적으로 아래와 같은 이름을 부여합니다.awscodestar-{brandi-test(프로젝트명)}-lambda-{HelloWorld(template함수ID)}-{NZ6YXLZ8XD0O(RANDOM_ID)}만약 함수 간의 호출이 필요할 때는 아래와 같이 함수 이름의 지정도 가능합니다.Resources: HelloWorld: Type: AWS::Serverless::Function Properties: FunctionName: !Sub '${ProjectId}-HelloWorld-${Stage}' Global 섹션Global 섹션을 이용하면 리소스마다 동일하게 적용할 항목들을 관리할 수 있습니다.Globals: Function: Runtime: python3.6 Environment: Variables: TZ: 'Asia/Seoul' VpcConfig: SubnetIds: - subnet-a1111111 - subnet-b2222222 SecurityGroupIds: - sg-c2222222 로컬 개발환경에서의 SAM 실행API Gateway 환경 실행sam local start-api 람다 함수 직접 실행echo ‘{}’ | sam local invoke —parameter-values=‘ParameterKey=ProjectId,ParameterValue=brandi-test’ HelloWorld Conclusion지금까지 CodeStar 초기 설정에 도움이 될 내용들을 살펴봤습니다. 강력한 기능들과 함께 업무를 진행한다면 조금이라도 더 나은 개발 환경을 구축할 수 있을 거라 생각합니다.글이상근 실장 | R&D DO실[email protected]브랜디, 오직 예쁜 옷만
조회수 1094

스푼 EX팀의 Chuck을 만나보세요!

스푼을 만드는 사람들 열두 번째 이야기누구라도 '내 주변에도 이런 사람 한 명쯤은 있으면 좋겠다'라고 할법한 그런 사람.핑크색 아이폰이 너무나도 잘 어울리는 남자! 회사에서 보면 좋은 동료 같고, 때론 편한 동네 언니(?) 같이 카페에서 5시간 동안 함께 수다 떨 수 있을 법한 그런 다양한 매력이 있는, 멋진 척을 소개합니다!남자는 턱수염이죠!"제가 처음에 스푼에 입사 전에 물어본 게 있어요. 바로 '수염'을 안 깎아도 되는지에 대한 질문이었어요. 근데 웬걸.. 복장도 자유, 모자 쓰고 오시는 분들도 있고 저의 수염이 막 튀거나, 남다르게 느껴지지 않더라고요. 신선했습니다! 나와 코드가 잘 맞는 곳이구나!라고 생각했죠. 저 수염 기르고 싶거든요."EX 멤버들과 Chuck (오른쪽)듣고 싶은 당신의 스푼 라이프Q. 스푼에 입사하시게 된 계기가 궁금해요"저는 사실 취직을 조금 늦게 한 편인데요. 예전에 첫 직장을 다니다가 몸이 안 좋아져서 조금 오랫동안 쉬었어요. 충분히 쉬고 나서 회복되었을 때, 다시 구직활동을 하려던 차, 스푼에 근무하고 있는 지인이 추천을 해주시더라고요. 사실 그전부터 저는 라이브 스트리밍에 관심이 많은지라  스푼에 대해서 이미 알고 있었고 지인이 스푼을 너무 즐겁게 그리고 열심히 다니시는 모습을 보고 궁금하기도 하고 관심이 생겼었는데, 기회가 닿아서 입사를 하게 되었어요." Q. 척은 어떤 업무를 담당하고 있나요?"저는 사실 처음에 총무 포지션으로 들어왔다가, EX팀 업무도 함께 병행하면서 May의 제안으로 EX팀에서 노무 업무를 맡고 있어요! 예를 들면, 회사 규정을 만드는 업무 있잖아요? 규칙 등 그런 일들을 합니다. 무엇보다 다른 분들을 서포트하는 업무를 많이 하고 있어요."Q.  EX팀에서 나의 존재는?아기 - "EX팀에서 유일한 초보자이니까요!"그래서, 앞으로 배워야 할 것도 많고 열심히 배우려고 노력하고 있답니다. 경험 많은 팀원들께서 잘 이끌어주시고 도와주셔서 열심히 따라가고 있어요.Q. 내가 생각하는 스푼에서 일하는 장점은?"업무에 대해 개개인의 의견을 말할 수 있는 기회가 참 많은 것 같아요. 모든 구성원의 의견을 다 귀담아 들어주려고 노력하는 모습도 멋지고요. 이 부분이 저는 가장 큰 장점이라고 생각해요. 수평적인 조직의 문화의 기초가 되는 부분이라고 생각하거든요"Q. 함께 일하고 싶은 사람은 어떤 사람인가요?제겐 없는 부분을 가진 사람, 차분하고 밸런스가 잡힌 사람과 일하고 싶어요.그 예로, 저희 팀 새로 들어오신 Noah가 계신데요. 면접 때가 굉장히 인상 깊었어요. 면접 때 긴장하셨을 텐데도 불구하고 질문에 대한 답변을 굉장히 차분히, 틀린 부분은 정정하시면서 대답을 해주시더라고요. 그 부분이 굉장히 매력 있고 저와는 다른 부분으로 서로 부족한 부분을 채워줄 수 있을 것 같다고 생각했어요. 팀 내에 다양한 성향과 성격의 사람들이 있으면 그런 부분이 좋을 것 같아요.척이 수집하는 신발들의 '일부분' 사진알고 싶은 Chuck의 이야기Q. 나를 한마디로 표현한다면?오나이 - "사나이의 상반되는 개념이고, 한량이되 한심하지 않은 사람을 말합니다."Q. 법을 공부하셨다고 들었습니다."네, 어릴 땐 제 꿈이 법조인이 되는 거라고 생각했고, 그래서 법학과를 나왔어요. 생각해보면 제가 법을 공부하고 고시 준비를 했던 건 법조인이 되고 싶다는 마음보다는, 법조인이 된다면 제가 얻을 수 있는 것들과 제게 돌아오는 것들이 좋다고 생각했던 것 같아요. 공부는 중학교 때 까진 정말 열심히 했던 것 같은데, 고등학교 땐 잘 안 했던 것 같아요(겸손모드..) 그 당시엔 사실 저는 공부 말고 제가 무엇을 잘하는지 모르겠더라고요. 그래서 열심히 해야 한다고 생각했던 것 같아요"Q. 신발 수집은 언제부터 시작됐나요?"어릴 때부터 신발을 좋아했던 것 같아요. 우리 세대, 제 세대엔 마이클 조던이 전성기였거든요. 그때 뭔가 트렌드였어요. 저는 운동화뿐만 아니라, 부츠도 좋아하고 모든 신발을 좋아하지만 그중 운동화가 가장 많은 것 같아요. 이유는 음.. 모르겠어요.. 그냥 좋아하는 신발을 신고 있다는 그 느낌이 좋아요. 근데 저 생각보다 운동화 몇 켤레 없어요. 한 20켤레 정도 될걸요? 더 어릴 땐 지방까지 내려가서 사고, 줄 서서 사곤 했는데 요즘은 그러진 않아요! 아! 그리고 저 모자도 수집해요. 매년 4월이 되면 모자를 꼭 하나씩 사요. 생일 쿠폰이 나오거든요. 그래서 얼마 전에 또 신상 모자 하나 샀어요"Q. 척의 인싸력은 타고난 건가요?"저요? 저 낮 좀 가리는 편인데요? (실상 전혀 그렇게 보이지 않음. 누구보다도 친근하고, 편함)단지 저는 어색한 상황을 좋아하지 않는 편이에요. 아마 그래서 모두와 편하게 지내려고 하는 게 아닐까 싶어요"Q. 원래부터 Yolo 인생을 살았나요?*Yolo (You live only once) : 미래를 위해 현재를 희생하기보다 현재를 즐기려는 사람"저는 오늘이 행복하지 않으면, 내일도 행복하지 않다고 생각해요. 제 좌우명이 오늘이 행복하면 됐다이거든요. 내가 지금 행복한가?라고 묻는 다면 그건 내가 지금 행복하지 않기에 묻는 질문이라고 생각해요. 원래부터 그랬던 건 아닌 것 같은데, 크게 아프고 나서 변한 것 같아요. 지금은 물론 의학적으로 건강하지만요. 저는 제가 완전한 Yolo족은 아닌 것 같은데.. 제가 다른 분들에겐 그래 보일 수도 있을 것 같네요!"Q. 인터뷰해보시니 어떠셨어요?"기분이 좋았어요. 누군가 저에게 관심을 가져주고, 질문을 해준다는 게 기분 좋은 일이더라고요 :)"(인터뷰에 응해주셔서 감사합니다)Chuck은, 1. 음식을 가리지 않지만, '직화' 요리만 먹지 않습니다 2. 술, 담배를 하지 않습니다.함께 식사를 하게 된다면, 센스 있게 '직화' 요리는 피하고 술과 담배는 권하지 않으면 센스만점 동료가 될 수 있을 것 같아요 :) 팀원들이 척을 한마디로 표현한다면?Go 曰: 마이쿤의 명태 코다리 명태 코다리는 사계절 내내 명태의 참맛을 느낄 수 있다고 합니다,속초 출신인 척이 마이쿤을 위해서 사계절 내내 열심히 일해주세요~May 曰: 냉철한 두뇌와 뜨거운 마음의 소유자 사고는 논리적이고 체계적이지만 행동은 정의롭고 따뜻하거나 가끔 뜨겁기도 함 ㅎㅎKai 曰: 무서운 형 - 가끔 눈살을 찌푸릴 때 화난 거 같이 보여서요..Noah 曰: 고등학교 동창 - 낯설지 않은 친근함이 매력 포인트
조회수 1512

AWS 이사하는 날

오늘 8퍼센트의 AWS 인프라를 일본에서 한국으로 옮겼다. 기술적인 내용은 이사를 리드하신 세바님이 다뤄 주시기로 하셨고, 나는 그냥 오늘을 남겨두려고 한다.(세바님이 8퍼센트 서울살자에 기술적인 내용들을 다뤄주셨다.)올해 초 AWS 서울 리전이 열리면서 도쿄에서 옮겨 가야겠다 라고 생각한 것이 벌써 수개월이 지났다. 작업을 시작하면 얼마나 걸릴지 예상이 잘 되지도 않고, 인프라 전체를 예쁘게 정리해야 한다는 부담 때문에 쉽게 손이 가지 않았다. 하지만 새로 조인하신 세바님이 AWS 이사를 가지 못해 여러 가지 제약이 생기는 답답한 상황을 참지 못하시고 총대를 메셨다. 아마 나보다 좀 더 답답하셨나 보다. :)17시에 다 함께 모여 현재 작업 진행상황과 오늘 이전 계획을 검토한 후 바로 퇴근을 했다. 긴 밤이 되리라 생각해서 조금이라도 잠을 자려고 노력은 했지만 두 아이가 있는 집에서 쉬는 것은 역시 쉽지 않더라. 지하철을 타고 23시 30분에 이모작 근무를 위해 다시 회사에 들어섰다. 이미 몇몇 분이 모여서 오늘 작업에 대한 이야기를 나누고 있었다. 아침에 만나는 것보다 왠지 반갑다. 모두 모여서 파이팅을 외치고 기념사진을 하나 찍고 작업을 시작했다.(웃으면서 시작한 작업을 웃으면서 마칠 수 있을 것인가?)일단 서버 작업 공지를 띄우고 작업을 시작한다. 지난 회사에서는 모든 서비스가 24시간 운영되었어야 했기 때문에 서버 점검 시간을 따로 갖지 못해다. 그래서 큰 서버 업데이트 작업을 할 때마다 시간에 쫓기고, 장애 발생을 실시간으로 해결해 가며 작업을 했었다. 하지만 이번에는 시간을 확보해두고 작업을 하는 것이라 그래도 마음에 좀 여유가 있었다.이전 작업을 하기 위해 각 파트를 담당하는 시니어 개발자들만 있어도 충분한데, 서버 이전을 하는 것이 흔치 않은 경험이기 때문에 주니어들도 가능하면 참여를 요청했다.(꼬꼬마들이 세바님 뒤에 쪼르르 모여서 설명을 듣고 있다)코드를 이해하기에 가장 좋은 방법은 코드를 함께 짜면서 설명을 하는 것이고, 인프라를 이해하기에 가장 좋은 방법은 인프라를 설치하는 과정을 함께 하는 것이다. 하나하나 작업을 해가면서 이런저런 이야기들을 나누었다. 이전을 하는 서버의 역할, 더 나은 아키텍처,  AWS의 역사,  AWS의 여러 가지 서비스의 세부적인 옵션에 대해서도 이야기를 나누었다.  세바님이 꼼꼼하게 준비를 해주신 덕분에 1시 30분이 되니 기본적인 이전 작업이 끝났다. 야식을 먹고 맥주를 한잔 마시고 각각의 기능들에 대한 본격적인 테스트를 시작했다.(야식은 12시 전에는 치킨을 시켜야 하고 12시 후에는 족발을 시켜야 한다)드디어 세바님을 제외한 다른 잉여 인력들이 할 일이 생겼다. 체크리스트에 있는 항목들을 하나씩 테스트 하기 시작한다. 꼼꼼하게 준비를 했지만 역시나 예상하지 못했던 문제들이 드러난다. 다행히 이전 작업을 되돌려야 할 만큼 큰 문제는 아니었기에 적절히 대응을 하고 계속 테스트를 진행했다.어느덧 시간이 흘러 3시가 되었다. http://8percent.kr 의 도메인을 도쿄에 있는 서버에서 서울에 있는 서버로 변경했다. 이제 내부 시스템들을 추가적으로 점검해야 한다. 가능하면 끝까지 확인을 하고 자리를 뜨고 싶었지만 내일 오후 사무실을 지키면서 혹시 모를 장애에 대응을 해 줄 사람이 필요할 것 같아 먼저 퇴근을 했다.집에 돌아오면서 생각해 보니 오늘 내가 한 일이 거의 없었다. 기뻤다. 서버 이전 작업을 내가 해야만 하는 일로 생각하며 계속 들고 있었는데 세바님이 먼저 나서서 이 일을 진행해 주셨다. 중요한 작업 중에 자리를 뜨는데도 전혀 불안함 마음이 들지 않았다.아침에 일어나서 슬랙을 확인했다. 슬랙에 별다른 멘트가 없는 것을 보니 큰 문제는 없나 보다. 야호! 이전된 서버가 정상적으로 운영되고 있는지 확인을 위해 심사팀도 일찍부터 출근해서 테스트를 진행하고 있었다. 회사에 도착해 보니, 나를 제외하고는 모두 밤을 새워 일을 하고 계셨다. 다들 몽롱한 표정이다. 고맙다.하루에도 8시간씩 같이 일하는 동료들이지만 왠지 이렇게 같이 밤을 지새워서 작업을 하고 나면 동지애가 생긴다. 긴 밤을 고생해준 개발팀 멤버들에게 다시 한번 고마운 마음을 전한다. 앞으로도 잘 부탁드려요!(제가 따로 드릴것은 없어서 박수를!)#8퍼센트 #에잇퍼센트 #AWS #서버 #서버이전 #인프라 #개발팀 #팀워크 #조직문화
조회수 2109

Kubernetes에 EBS 볼륨 붙이기

Kubernetes에서 컨테이너에 Persistent Volume을 붙이는 방법은 몇가지 있다. 여기서는 Kafka 서비스를 예로 삼아 주요 접근방법을 간단히 알아본다.Kubernetes v1.4.0를 기준으로 문서를 작성한다.Static말이 Static이지 수동 마운트를 뜻한다. 기본적으로 관리자가 EBS 볼륨을 만들고특정 Pod에 그 볼륨을 붙이는 작업을 한다. Volumes 문서에 나오는대로 하면 간단하다.apiVersion: v1 kind: Service metadata: name: kafka1 labels: app: kafka1 tier: backend spec: ports: # the port that this service should serve on — port: 9092 name: port targetPort: 9092 protocol: TCP selector: app: kafka1 tier: backend — - apiVersion: extensions/v1beta1 kind: Deployment metadata: name: kafka1 spec: replicas: 1 template: metadata: labels: app: kafka1 tier: backend spec: containers: — name: kafka1 image: wurstmeister/kafka imagePullPolicy: Always volumeMounts: — mountPath: “/kafka” name: kafka1volume ports: — containerPort: 9092 volumes: — name: kafka1volume awsElasticBlockStore: volumeID: vol-688d7099 fsType: ext4여기서 핵심은 다음의 두 줄 뿐이다.awsElasticBlockStore: volumeID: vol-688d7099Dynamic수동으로 볼륨을 붙이는 방법은 간단해서 좋다. 하지만 Autoscaling하는 서비스에 넣기에는 아무래도 무리다. 서비스가 뜰 때 요구사항에 맞는 볼륨을 스스로 만들어 붙이는 방법도 있다. Kubernetes Persistent Volumes를 참고해 작업해본다.우선 Kubernetes 생성할 EBS 볼륨의 사양을 정한다.# storages.yaml apiVersion: storage.k8s.io/v1beta1 kind: StorageClass metadata: name: default1a provisioner: kubernetes.io/aws-ebs parameters: type: gp2 zone: ap-northeast-1a iopsPerGB: “10” — - apiVersion: storage.k8s.io/v1beta1 kind: StorageClass metadata: name: default1c provisioner: kubernetes.io/aws-ebs parameters: type: gp2 zone: ap-northeast-1c iopsPerGB: “10”default1a를 선택하면 ap-northeast-1a Availablity Zone에 기가바이트당 IOPS는 10인 General SSD EBS 볼륨을 생성한다. 이제 다시 Kafka의 돌아가면apiVersion: v1 kind: Service metadata: name: kafka1 labels: app: kafka1 tier: backend spec: ports: # the port that this service should serve on — port: 9092 name: port targetPort: 9092 protocol: TCP selector: app: kafka1 tier: backend — - apiVersion: extensions/v1beta1 kind: Deployment metadata: name: kafka1 spec: replicas: 1 template: metadata: labels: app: kafka1 tier: backend spec: containers: — name: kafka1 image: wurstmeister/kafka imagePullPolicy: Always volumeMounts: — mountPath: “/kafka” name: kafka1volume ports: — containerPort: 9092 volumes: — name: kafka1volume persistentVolumeClaim: claimName: kafka1volumeclaim — - kind: PersistentVolumeClaim apiVersion: v1 metadata: name: kafka1volumeclaim annotations: volume.beta.kubernetes.io/storage-class: “default1a” spec: accessModes: — ReadWriteOnce resources: requests: storage: 300Gi이제 awsElasticBlockStore가 아닌 PersistentVolumeClaim을 통해 볼륨을 할당받는다. kafka1volumeclaim은 default1을 기준으로 스토리지 정책을 정하므로Availablity Zone: ap-northeast-1aIOPS: 기가바이트당 10General SSD300Gi 이상인 스토리지를 원한다는 요구사항을 기술한다. 위의 설정은 이러한 스토리지에 부합하는 EBS 볼륨을 생성하여 kafka1 Pod에 할당한다.분석Dynamic은 Autoscaling에는 적합하나 kubectl delete [service] 또는 kubectl delete [deployment] 등의 명령을 수행하여 서비스를 내렸다가 다시 올린 경우에 기존에 쓰던 볼륨을 마운트하지 않고 새 볼륨을 만드는 문제가 있다. 물론 delete를 하지 않고 서비스를 업데이트만 하는 경우에는 볼륨이 유지되지만 이래선 아무래도 문제의 소지가 많다.그래서 또다른 시나리오를 고민해볼 수는 있다. 짧게 설명하자면관리자가 Volumn Pool을 만들어놓고 Autoscaling 서비스가 이 풀 안에서 볼륨을 할당받게 한다. 이러면 앞서 본 두 가지 방식의 장점을 골고루 흡수할 수 있다.flocker 또는 glushterfs 같은 스토리지 관리 서비스를 활용해도 좋다. 하지만 배보다 배꼽이 큰 것 같은 느낌이 들지도 모르겠다.#데일리 #데일리호텔 #개발 #개발자 #개발팀 #인사이트 #꿀팁
조회수 1670

개발자 직군 파헤치기 3 | 블록체인 개발자

이번 포스팅은 블록체인 개발자!2017년 대한민국은 가상화폐의 광풍에 휩싸이게 된다. 남녀노소 가릴 것 없이 많은 사람들이 가상화폐에 투자를 했다. 전 세계에 유례가 없을 정도로 국내 가상화폐 투자 열기는 뜨거웠으며 해외의 가상화폐 투자자들은 국내 투자자들의 움직임에 예의주시하면서 투자할 정도였다.이와 동시에 가상화폐의 기술적 원천이 된 블록체인(Block Chain) 기술에 대한 관심도 증가했다. 제2의 인터넷이 될 거라는 찬사를 받으면서 가상화폐의 부상은 뜨거운 관심의 대상이었다. 정부의 가상화폐 규제가 있었지만 시장에서는 블록체인 기술의 잠재적 가능성에 주목을 하면서 이것을 가지고 어떻게 혁신적인 서비스를 제공할지 고심하고 있다. 이에 따라 일반 개발자는 물론이고 기업에서도 블록체인 개발자에 대한 수요와 관심이 늘고 있다.이러한 관심 때문에 개발자를 꿈꾸는 많은 분들이 블록체인 개발자는 무엇을 하고 어떻게 될 수 있는 것인지 궁금해하고 있다. 그래서 이번 포스팅에서는 블록체인 개발자가 되기 위해서는 어떻게 해야 하는지와 더불어, 블록체인 기술에 대한 전망 그리고 블록체인 개발자의 시장 수요에 대한 글을 써 볼 것이다.*이 글은 블록체인 기술에 대한 자세한 설명은 하지 않고 있습니다.*Photo by Andre Francois on Unsplash미래를 여는 신기술, 블록체인의 전망블록체인 기술이 뜨고 있다고 하지만 도대체 어떤 분야에서 적용될 수 있기에 이렇게 많은 관심을 받고 있는 것일까? '딱 이 분야가 유망합니다'라고 말하기가 어려울 정도로 블록체인은 폭넓은 분야에 걸쳐서 파괴적인 혁신성을 가지고 있다. 그중  몇 가지만 추려서 이야기하고자 한다.1. 금융, 은행블록체인의 기술의 특징은 탈 중앙화, 신뢰성, 보안성이다. 전문가들은 기존의 은행들이 하던 업무를 핀테크 기업들이 혁신적인 서비스와 가격으로 대체할 것으로 예상한다. 블록체인 기술이 가지고 있는 신뢰성과 보안성으로 인해 일반 기업들도 거대 은행이 보유하고 있는 보안성을 획득할 수 있는 것이다. 거래 과정에서 제3자를 거치지 않기 때문에 거래의 속도와 효율성 그리고 경제성이 크게 증가한다.핀테크 스타트업뿐만 아니라 거대 금융권의 은행들이나 기존의 대기업들도 블록체인 기술을 이용한 서비스를 발 빠르게 준비하고 있다. 마스터카드는 블록체인 기술을 통해 즉석 지불 시스템을 개발하고 있다. 또한 글로벌 기업 IBM은 서로 다른 국가에 위치한 금융 기관이 블록체인 기술을 이용해서 결제를 처리할 수 있도록 하는 뱅킹 솔루션을 개발했다.현재 이더리움이 선도하는 스마트 계약도 금융권에서 주목하는 분야다. 스마트 계약은 특정 조건이 충족되면 은행과 같은 제3자를 거치지 않고 계약을 이행하게끔 도와준다. 예를 들어, 납품 기업과 발주 기업이 스마트 계약을 맺었다. 납품 기업이 발주 기업의 창고에 물품을 보내고 물품이 도착을 하면(IOT 센서로 감지된다) 납품 기업은 자동으로 결제 대금을 자동으로 받게 된다.2. 물류위에서 블록체인 기술의 특징 중 신뢰성과 보안성을 언급했다. 정보의 신뢰성과 보안성은 물류 시스템에도 파급력을 미칠 것이다. 많은 전문가들이 블록체인으로 인해 물류 시스템에 혁신적인 변화가 가능하다고 말한다. 블록체인 기술이 어떻게 물류 시스템에 적용될 수 있는지 직접 예시로 살펴보자.영국의 소프트웨어 회사 프로비넌스는 블록체인 기술을 이용해서 소매업자와 식당들이 원래 계약했던 대로 재료가 들어오는지 확인할 수 있게 만들었다. 트래킹(tracking) 기술과 결합하여 만든 이 소프트웨어는 재료가 수확되는 과정부터 최종 소비자가 구매하는 단계까지 꼼꼼히 추적하고 관리한다. 공급망의 모든 단계에서 변경 불가능한 데이터가 블록에 추가된다. 이 소프트웨어를 통해 소비자들은 자신이 무엇을 먹는지, 기업이 불법 조업을 통해 재료를 조달한 것이 아닌지, 이 농작물에 대한 적절한 보상이 농부에게 돌아갔는지, 이 식재료가 유기농이 맞는지 명확하게 확인할 수 있다.한편, 중국의 월마트와 IBM이 협력해 중국에서 유통되는 돼지고기의 유통 전 과정을 블록체인 기술을 활용해 추적을 하기도 했다. 월마트는 더 나아가 농산물 공급망의 모든 단계를 추적하기 위한 프로젝트를 IBM과 진행하고 있다. 또한 영국의 신생기업 에버레저는 블록체인 기술을 이용해 다이아몬드와 같은 고부가 가치 상품들의 원산지 추적과 인증을 IBM 블록체인 기술을 활용하고 있다.3. 디지털 콘텐츠블록체인 기술로 디지털 콘텐츠에 대한 지적 재산권 보호를 더 확실하게 할 수 있다. 기존에는 불법적인 경로로 승인되지 않은 디지털 콘텐츠들이 유포가 됐다. 하지만 블록체인 기술로 온라인 콘텐츠에 대한 저작권, 권한, 결제를 관리할 수 있도록 작업할 수 있다. 블록체인 기술을 통해 콘텐츠 원저자의 증명을 더 쉽게 하고 해당 콘텐츠에 누가 접근을 했는지 추적할 수 있다.또한 항상 이슈가 되어 왔던 뮤지션들의 음반 판매 금액에 대해서도 블록체인 기술이 혁신을 가져다줄 것이다. 기존의 중간 단계의 서비스를 없애고 비용을 절감해서 음반 제작자들에게 더 많은 몫이 돌아갈 수 있다. 위에서 언급한 스마트 계약을 통해 라이선스 이슈의 문제들도 해결할 수 있다.블록체인 개발자, 얼마나 핫해?블록체인 기술에 대한 뜨거운 관심에 힘입어 블록체인 개발자에 대한 수요도 크게 증가하고 있다. 아직은 국내에서 가상화폐에 대한 비즈니스가 주를 이루고 있지만 정부의 정책과 시장의 기대와 맞물려 그 수요는 더욱더 커질 예정이다. 여기 블록체인 개발자의 수요에 대한 기사 있다.기사에 따르면 지난 1분기 취업사이트 잡코리아에 블록체인 키워드로 등록된 채용공고는 총 1500여 건이다. 이는 전년 동기 대비 9배 이상 늘어난 수치라고 한다. 또 잡코리아가 분석한 결과 지난해 하반기부터 암호화폐 개발자 수요가 급증했다고 한다. 지난해 1분기와 비교하면 올해 1분기 등록건수는 9배 이상이며 직전 분기와 비교해도 3배에 달한다.다른 아웃소싱 플랫폼 사이트도 비슷하다. 4만 7천 명의 유저를 보유한 위시캣에 따르면 2014년 8월부터 지난달까지 등록된 암호화폐 관련 프로젝트는 108건이다. 그리고 이 중에 절반인 55번이 올해 1분기에 등록이 되었다고 한다. 개발자 커뮤니티 OKKY에 올라온 구인 글에는 월 급여 900만 원을 제시하고 암호화폐 개발하는 개발자를 찾고 있었다. 또 구인 사이트에 올라온 암호화폐 거래소 프로젝트 중 개발비용이 45일 동안 2억 5천만 원에 이른 사례도 있었다.기사에 나온 것처럼 블록체인 개발자의 수요는 암호화폐에 집중되어 있기는 하지만 빠르게 증가하고 있다. 또 많은 기업들이 암호화폐가 아닌 다른 비즈니스의 모델을 찾으면서 블록체인 서비스를 준비하고 있다. 블록체인 개발자는 말 그대로 요즘 가장 핫하다고 할 수 있다.그래서 블록체인 개발자 되기 위해서는?이렇게 핫한 블록체인 개발자가 되기 위해서는 어떤 기술들을 공부해야 할까? 물론 어떤 분야의 개발자가 된다는 것이 특정 기술을 익힌다고 되는 것은 아니다. 웹 개발자가 된다고 해서 자바스크립트와 HTML, CSS를 익힌다고 되는 것이 아닌 것처럼 말이다. 회사마다 진행하는 프로젝트가 있고 그것에 맞춘 기술 스택들을 익혀야 한다. 하지만, 그럼에도 블록체인 개발에 있어서 주류가 되는 기술들은 있다. 이것들을 공부해 가면서 블록체인 개발자를 준비한다면 한층 더 수월해질 것이다.1.솔리디티(Solidity)솔리디티는 블록체인 플랫폼에서 스마트 계약을 만들기 위한 프로그래밍 언어다. 이더리움의 핵심인 스마트 계약을 만들기 위해서는 솔리디티를 배워야 한다. 솔리디티는 EVM(Ethereum Virtual Machine)에서 돌아가도록 설계되었고, 자바스크립트와 비슷한 문법 구조를 갖고 있다. 자바스크립트를 알고 있다면 배우기가 훨씬 수월할 것이다.블록체인은 다양한 분야가 존재하지만 그중 스마트 계약은 가장 대표적인 혁신 기술이다. 그 스마트 계약 기술을 선도하는 이더리움 프로젝트를 다루기 위해서는 솔리디티를 배우는 것이 필수적이다. 블록체인 개발에도 다양한 기술 스택들이 있겠지만 주류 기술을 배운다고 하면 솔리디티를 배워야 한다.솔리디티를 배우기 위해서는 다양한 방법이 있겠지만, 유데미의 강좌를 들으면서 공부하는 것을 추천한다. 저렴한 가격에 퀄리티 높은 강좌를 들을 수 있다. 자세한 사항은 이곳을 참고하면 된다.2.하이퍼레저(Hyperledger)블록체인이 개념이 퍼블릭 네트워크 기반의 시스템이기는 하지만 누구나 데이터를 볼 수 있기 때문에 기밀문서 관리에는 사용되기 힘들다. 특히 금융권이나 기업 문서 같은 경우는 더더욱 그러하다. 그래서 폐쇄적인 프라이빗 네트워크 내에서 블록체인을 활용할 수 있는 기술이 필요하다.하이퍼레저는 이러한 프라이빗 블록체인을 필요로 하는 기업들의 연합체라고 볼 수 있다. 이 기업들은 컨소시엄을 맺고 프라이빗 블록체인을 더 발전시키려고 다양한 분야에서 협업하고 있다. 하이퍼레저 프로젝트는 리눅스 재단에서 주도하며 금융, 은행, 제조, 기술 등 다양한 분야에 관여한다. 그리고 이 프로젝트는 스마트 계약, 분산 합의 네트워크에 목표를 두고 있다.지금까지 에어버스, 엑센츄어, 바이두, IBM, J.P 모건, 히타치, 삼성 SDS 등 다양한 기업이 하이퍼레저에 포함되어 있다. 그만큼 많은 기업들이 하이퍼레저 프로젝트에 관심을 가지고 있다. 하이퍼레저 역시 유데미의 강좌를 통해서 배울 수 있다. 자세한 사항은 이곳을 참고하면 된다.블록체인 개발자의 첫걸음블록체인 개발자가 되기 위해서는 위의 기술 스택뿐만 아니라 기본적으로 백엔드에 대한 지식과 최소한 암호 기법에 대한 기본 지식이 있어야 한다. 또한, 블록체인의 많은 API 및 SDK가 자바스크립트와 nod.js로 이루어져 있다. 무엇부터 시작해야 할지 모르는 분이라면 자바스크립트부터 시작하면서 첫걸음을 떼는 것을 추천한다.블록체인은 IT 기술의 최전선에 있는 기술이다. 그렇기 때문에 산업 동향을 항상 예의주시하면서 빠르게 움직여야 한다. 기업이 원하는 블록체인 기술 스택을 빠르게 습득하고 그에 맞는 실력을 갖추는 것이 중요하다.지금까지 블록체인 개발자에 대해 알아보았다. 많은 내용들을 다루다 보니 각각에 내용들에 깊이 있게 다루지는 못했다. 그래도 이 글을 통해 블록체인 개발자가 되기 위한 가닥은 잡을 수 있었으면 좋겠다.
조회수 1532

스타일쉐어 커머스 시스템 리빌딩 회고 1

스타일쉐어 스토어 소개스타일쉐어 스토어(이하 커머스)는 2016년 4월 출시되어 지금까지 나날이 성장하고 있습니다. 작년 초, 커머스 시스템을 리빌딩하기로 했고 현재까지 진행 중입니다. 어떤 이유로 리빌딩을 하는지, 어떤 고민을 했는지, 어떻게 진행하고 있는지 몇 자 적어보려 합니다. 이 글은 문제 인식, 목표, 계획에 대한 내용입니다.리빌딩을 결정한 이유커머스 프로젝트를 시작할 당시 커머스 시스템을 경험해본 개발자가 없었습니다. 이 상황에서 새로이 구현하기엔 위험 부담이 크다는 판단을 했습니다. 때문에 커머스 솔루션을 도입했고, 적은 비용으로 커머스 기능을 출시할 수 있었습니다. 거래량이 점점 늘어나면서 솔루션이 감당할 수 있는 한계치를 벗어나자, 예상치 못했던 기술적인 이슈가 발생했습니다. 사내 MD팀, CS팀은 물론, 입점사들과 유저들에게까지 불편한 경험을 주고 있었습니다. 개발팀은 솔루션 유지 보수와 운영 이슈에 집중했지만, 끝이 없는 문제들에 점점 지쳐갔습니다. 개발팀의 퍼포먼스는 저하되고 있었고, 새로운 기능 개발에 집중하지 못하는 상황까지 발생했습니다. 이 시점에서도 거래량과 매출은 꾸준히 늘어났으며, 더 늦기 전에 리빌딩을 진행해야겠다고 판단했습니다.리빌딩의 목표당장 눈앞에 생겨나는 문제들로, 서비스가 해결하고자 하는 본질적인 문제들에 집중하지 못하는 상황입니다. 궁극적으로 이 상황을 개선하고 싶었습니다. 그리고 선택의 기로에 섰을 때 좋은 기준을 제시하기 위해, 언제 끝날지 모르는 리빌딩이 산으로 가는 걸 막기 위해 목표를 몇 가지 세웠습니다.유지보수 및 운영 이슈에 소모되는 개발 리소스 최소화커머스 시스템과 연계되는 기능들을 공격적으로 개발할 수 있도록 함개발 리소스 대비 높은 퍼포먼스를 낼 수 있어야 함튼튼한 커머스 시스템목표 1. 유지보수 및 운영 이슈에 들이는 개발 리소스 최소화기존 솔루션의 큰 레거시는 소모될 개발 리소스의 양과 일정을 예측하기 어렵게 만들었고, 개발자에게도 큰 스트레스를 안겨줬습니다. 서비스의 성장을 방해하는 큰 걸림돌 중 하나이며, 개발팀의 움직임을 느리게 만드는 주된 원인이었습니다. 리빌딩을 완료하더라도 유지보수와 운영 이슈는 끝이 없을 테지만, 더 이상 같은 문제를 반복하고 싶지 않았습니다. 효율적인 개발 리소스 운용을 위해선 가장 신경 써야 하는 부분이라고 생각됩니다.목표 2. 커머스 시스템과 연계되는 기능들을 공격적으로 개발할 수 있도록 함기존 솔루션 레거시가 너무 복잡하여 기능을 추가하거나 개선하기 어려워 반려한 요구사항이 많았습니다. 매력적인 요구사항에도 조심스럽게 대응했습니다. 서비스 성장을 위해 다양한 시도를 해야 하는 상황인데, 기술적인 이유로 진행이 까다롭다고 말하는 게 항상 아쉬웠습니다. 개발팀에서도 좋은 기능을 공격적으로 구현하고 싶으나, 실제로도 작업하기 까다로워 항상 답답했습니다. 어떤 방법이던 괜찮으니 지금보다 훨씬 더 공격적인 기능 구현으로 서비스 성장에 좋은 영향을 주고 싶었습니다.목표 3. 개발 리소스 소모 대비 높은 퍼포먼스를 낼 수 있어야 함스타일쉐어 팀은 기존 서비스 운영과 동시에 항상 새로운 무언가를 찾으려 합니다. 개발팀은 이 움직임에 맞춰 개발 리소스를 효율적으로 운용해야 합니다. 하지만 개발 리소스는 한정적이며, 다양항 상황에 따라 유동적으로 변해 예측하기 어렵습니다. 이런 상황에서 커머스 관련 작업 시, 언제나 평균 이상의 높은 퍼포먼스를 내고 싶었습니다.목표 4. 튼튼한 커머스 시스템커머스 시스템의 장애는 매출에 직접적인 악영향을 줍니다. 어떤 작업을 하더라도 커머스 시스템은 잘 운영되어야 합니다. 높은 가용성은 개발팀의 숙명이며, 공격적인 기능 개발에도 높은 가용성을 유지하려면 더욱 신경 써야 합니다.모두 꿈에 가까운 목표들입니다. 이 목표들에 조금이라도 더 가까이 다가갈 수 있도록 노력한다면 보다 좋은 결과를 얻을 수 있을 거라 생각했습니다.현실 반영과 계획당연하게도 현실적인 부분을 생각해야 했습니다. 이미 예정된 작업들이 많아 리빌딩에 필요한 개발 리소스를 확보하기 어려웠고, 개발 성공 여부 또한 불확실해 팀원들을 설득하기 어려웠습니다. 유지보수와 운영 이슈는 끝이 없었고, 회사 방향에 따라 추가 기능 개발과 개선 작업을 진행해야 했습니다. 이 상황을 고려해 리빌딩을 성공적으로 진행할 수 있도록 계획을 세워나갔습니다.개발 리소스에 여유가 생길 때까지 서브 프로젝트로 진행기존 커머스 시스템과 리빌딩된 시스템을 동시에 운영할 수 있어야 함적절한 단위로 서비스를 나눠 안전하고 효율적으로 개발 진행계획 1. 개발 리소스에 여유가 생길 때까지 서브 프로젝트로 진행다들 리빌딩이 필요하다고 느꼈지만, 선뜻 진행하기엔 큰 부담이었습니다. 시간이 흘러 여유가 생길 때 리빌딩을 진행해도 되지만, 그땐 너무 늦을 것 같았습니다. 최대한 빨리 작업을 시작하고 싶었고, 그러기 위해선 서브 프로젝트 수준으로 진행하는 게 제일 빠른 방법이라 생각했습니다.계획 2. 기존 커머스 시스템과 연동되어 동시에 운영할 수 있도록 함리빌딩의 완료 시점을 예측하기 어려웠습니다. 때문에 기존 커머스 시스템을 운영하며 리빌딩을 진행해야만 했습니다. 그리고 리빌딩된 시스템은 점진적으로 기존 커머스 시스템을 교체해 나가야 하므로, 두 시스템이 서로 연동되어야 했습니다. 또한 리빌딩된 시스템이 잘 동작할지에 대한 확신이 없어, 언제나 후퇴 계획을 세워야 했습니다. 이런 이유로 기존 커머스 시스템의 DB와 스키마를 그대로 사용하고, 두 시스템의 로직이 서로에게 문제가 되지 않도록 조심스럽게 개발하기로 했습니다.계획 3. 적절한 단위로 서비스를 나눠 안전하고 효율적으로 개발 진행커져가는 개발팀과 복잡해져 가는 커머스 시스템을 생각하면 요즘 자주 들리는 마이크로 서비스 구조(이하 MSA)를 도입해도 되지 않을까 싶었습니다. 솔직히 이런저런 이유보다, 재미 때문에 도입해보고 싶었습니다. 처음 도입하는 구조라 조심스러웠지만, 적절한 단위로 서비스를 나눈다면 충분히 좋은 효율을 낼 수 있을 것이라 생각되었습니다. 재미와 만족은 덤이고요. 서비스를 나누는 기준은 2가지로 잡았습니다.개발 안정성/개발 속도 둘 중 어느 것에 집중해야 하는가?서비스를 사용하는 주체는 누구인가?—개발 안정성/개발 속도 둘 중 어느 것에 집중해야 하는가?개발 안정성과 개발 속도에 대해 생각한 이유는 시스템 안정성과 작업 퍼포먼스 모두 잡고 싶은 마음 때문이었습니다. MSA는 서비스 별로 다른 언어를 사용해도 괜찮다는 장점이 있습니다. 덕분에 상황 별로 각기 다른 언어를 사용할 수 있고, 이를 통해 개발 안정성 혹은 개발 속도에 잘 집중할 수 있을 것이라 기대했습니다. 나중에 기술 스택을 설명하면서 얘기를 하겠지만, 개발 안정성을 추구해야 하는 부분은 java8로, 개발 속도를 추구해야 하는 부분은 node나 python으로 구현됩니다.서비스를 사용하는 주체는 누구인가?서비스를 어떤 기준으로 나눌지 고민이 많았습니다. 처음엔 상품 관리, 주문 관리, 출고 관리 등 DB 테이블에 가까운 기준으로 나누려고 했으나, 서버 운영이 큰 부담으로 다가올 것 같다는 의견 때문에 다른 기준을 세워야 했습니다. 서비스를 사용하는 주체 별로 나누면 어떨까라는 말이 나왔고, 이 기준이라면 큰 부담이 없을 것 같았습니다. 서비스를 사용하는 주체는 유저, 관리자, 입점사, 다른 서비스 이 4가지라고 정의했고, 이에 따라 서비스를 구성했습니다.—앞서 말한 두 기준으로 나눴을 때에 대한 예시입니다.유저 커머스 서비스 (node 혹은 python)관리자 커머스 서비스 (node 혹은 python)입점사 커머스 서비스 (node 혹은 python)커머스 핵심 기능 서비스 (java8)위 두 기준 말고도 서비스 운영에 큰 부담이 없다면 상황에 맞춰 다른 기준을 세워 서비스를 나누기도 했습니다.이 고민이 끝난 후, 현실적으로 실행 가능한 계획이 나온 것 같아 만족스러웠습니다. 이 계획을 토대로 아키텍처를 구성하고 개발을 진행했습니다.마무리어떤 문제 때문에 리빌딩을 결정했고, 어떤 목표와 계획을 세웠는지 주저리주저리 적어봤습니다. 앞에서 말했듯이 리빌딩은 아직 진행 중입니다. 현재 정식 일감으로 진행되고 있고, 상황에 맞게 계획을 다시 세워 조금씩 목표에 다가가고 있습니다. 처음엔 3부로 계획했지만, 아직 리빌딩 중이란 걸 까먹고 있었나 봅니다. 이 프로젝트가 완료되기 전까진 회고록으로써 글을 계속 쓸 것 같습니다. 앞으로 풀어야 할 문제들이 많으니 하소연할 것들도 많을 거고요. 아무쪼록 다음 편에선 시스템 구성도와 기술 스택에 대해서 한번 이야기해보려 합니다.스타일쉐어 개발팀의 고민과 생각들이 부디 도움이 되었길 빕니다. :)#스타일쉐어 #개발팀 #리빌딩 #인사이트 #조언
조회수 2438

A/B Testing 도구인 Optimizely 사용법

웹 서비스를 운영하다 보면 준비하는 과정에서 정말 많은 고민이 오갑니다. 컨텐츠의 배치, 헤드 카피, 인터랙티브.. 하지만 어떤 요소가 조금 더 사용자의 반응을 이끌어내는지 정확히 알 수 없습니다. 이런 부분들을 ‘직감’이나 ‘경험’으로 막연하게 자기 자신과 타인에게 주장하고 있지는 않나요?그렇다면 두 가지 혹은 그 이상의 시안들을 직접 시험대에 올려 각각 더 좋은 것을 선택하는 것은 어떨까요?A/B 테스팅에 관련한 유명한 일화가 하나 있습니다. 1497년, Vasco da gama는 최초로 유럽에서 아프리카 남부를 거쳐 인도까지 항해한 인물입니다. 그가 인도를 발견하고 귀항했을 때 160명의 원정대원 중 100명이 괴혈병으로 사망하는 사건이 있었습니다. 그만큼 괴혈병은 항해하는 선원들의 공포 대상이었죠. 그로부터 약 300년 뒤, 영국의 의사인 James Lind는 괴혈병의 치료법을 알기 위해 실험군을 나누어 각각 다른 음식으로 실험을 진행했습니다.실험은 다음과 같습니다. 괴혈병에 걸린 12명의 선원을 선정하여 그 중 10명에게는 보통 음식을 주고, 두 사람에게는 매일 라임 과즙을 마시게 하였습니다. 6일 후 라임 과즙을 마신 선원 두 명만이 괴혈병에 완벽히 치료된 모습을 보였습니다. James Lind가 실험하기 전에는 단순히 ‘감귤류 과일이 괴혈병에 좋다.’, ‘괴혈병으로 죽어가는 찰나에 잡초를 먹고 다시 살아났다.’ 라는 이야기만이 난무했었고 직접적인 치료법을 제시한 사람은 James Lind가 최초였습니다. 비타민C가 발견된 것이 1928년임을 고려하면, 이 당시에는 비타민C 이라는 개념이 없었기 때문에 James Lind의 실험은 후에 많은 선원의 목숨을 괴혈병으로부터 지켜주는 사례가 됩니다.괴혈병이 해적보다 더 무서웠던 대항해시대에 보통 음식(A)과 라임(B)을 이용해 선원들을 모두 구했던 영국 해군의 현명한 대처법에서 우리의 웹 서비스를 더욱 더 활성화 시키는 지혜를 얻어야 합니다.Optimizely?Optimizely는 웹서비스를 운영하면서 A/B Testing 수행을 원하시는 분들에게 적합한 서비스입니다. Optimizely를 사용하기 전에 A/B 테스팅에 대한 정보가 필요하다면 A/B 테스팅에 관련한 JC Kim님의 글( A/B Testing에 대한 기초적인 정보들 )을 먼저 읽어보시는 것을 추천합니다.Optimizely는 단순히 A/B 테스트의 진행과 그 통계 결과만 제공하는 것이 아니라, 테스트를 진행하는 동안의 모든 준비 과정에서 사용자들에게 도움을 주고 있습니다. 오늘은 그 Optimizely의 핵심 기능 및 활용법에 대하여 알아보겠습니다. Optimizely는 유료 서비스이지만 30일 동안의 Free Trial을 제공해주므로 그 기간 동안 충분히 이 서비스의 모든 것을 체험할 수 있습니다.Optimizely는 세계적인 대형 기업들이 이용하는 서비스로, 이들은 이미 Optimizely를 통해 각각 컨텐츠들에 대한 사이트 접속자들의 반응을 체크하고 있습니다. 대표적인 회사로 Starbucks, Salesforce, MTV, The Walt Disney Company, ABC 등이 있습니다.그렇다면 왜 많은 기업들이 A/B Testing에 집중하고 있고, Optimizely를 이용하는 걸까요?더 정확한 데이터를 추출하려는 노력.메일링 리스트를 수집하는 등의 폼 입력/전송을 하는 비율을 구하는 경우, 혹은 메인 페이지에서 다른 세부페이지로 이동하는 이용자 비율을 나타내기 위해 목표(Goal)을 나타냅니다. 목표한 골에 A 버전(기존안/Original) 이용자가 더 많이 들어갔는지, B 버전(새로 작성한 안/Variation)이 효과적이었는지를 테스트 할 수 있습니다.이처럼 Goal에 도달하는 행위를 ‘Conversion’이라 표현합니다. 방문자 수 대비 Conversions 수치를 비교한 Conversion rate를 비교하면 A/B 시안 중에 더 효과적인 결과를 수치와 그래프, 특히 “기준을 이길 수 있는 확률”(Chance to beat baseline)을 철저하게 계산해 결과를 명확하게 진단할 수 있습니다. 말 그대로 Goal과 Conversion Rate 수치로 사용자가 승자를 판단하는 것이 아니라, 수치공식을 통해 B 버전이 기존안(A버전)을 확실하게 이겼는지 아닌지를 파악해줍니다.더 자세히 알고싶은 부분은 해당 값을 구하는 통계공식이 있는 링크를 참고해주세요.정말 쉬운 실험요소 변경.Optimizely를 이용하면 여러분이 복잡한 CSS나 Javascript 기술이 없어도 쉽게 A/B 테스팅을 진행할 수 있습니다. Optimizely에서는 실험군의 요소를 마우스 클릭 몇 번으로 손쉽게 바꿀 수 있습니다. 가령 B 버전에 A 버전과 다른 문서 배치를 하거나 배경화면, 이미지, 폰트, 버튼 속의 문구 등도 별도의 코딩 절차 없이 Optimizely 실험페이지 내에서 변경할 수 있다는 말이죠. 또한 실시간으로 CSS를 변경하여 적용하거나 Javascript도 적용할 수 있습니다. 마치 ‘나모 웹 에디터’ 나 ‘드림위버’ 같은 인터페이스로 파워포인트 내의 요소를 다루듯 쉽게 바꿀 수 있습니다.위치와 크기를 Drag & Drop 으로 쉽게 움직이게 할 수 있습니다.웹사이트에 적용된 이미지 또한 로컬에 있는 파일 혹은 웹에 있는 이미지로 대체할 수 있습니다.텍스트도 곧바로 변경할 수 있고 HTML을 직접 대체해서 끼워 넣을 수 있습니다.참 쉽죠?간단한 설치위처럼 변경했던 시험요소들을 저장하려면 복잡하고 긴 코드를 다시 원래 파일에 붙여 넣어야 할까요? 그렇지 않습니다. Optimizely는 변경한 컨텐츠 정보를 간단한 자바스크립트 코드로 ‘Optimize’ 해 주기 때문에 단 몇줄만 추가해주면 원하는 결과가 나옵니다.확장성유명한 아티스트 두 명이 콜라보레이션 하는 상상을 해보죠. 각자의 개성을 살려 새로운 결과물들을 창조해내지요. 물론 그들의 궁합이 잘 맞아야 한다는 전제가 있습니다. 하지만 다행히도 Optimizely와 연동되는 서비스들은 궁합이 잘 맞는 편입니다. Optimizely는 A/B 테스팅에 관한 자료에 집중하고 있기 때문에, 조금 더 디테일한 자료(Analytics, Heatmap)는 욕심내지 않고 기타 많은 서비스와 연동합니다.Optimizely와 연동되는 서비스는 다음과 같습니다.AnalyticsGoogle AnalyticsKISSmetricsMixpanelOmniture SiteCatalystHeatmapClickTaleCrazyegg위 서비스 중 하나라도 이용 중이시라면, Optimizely와 어떤 부분이 연동이 되는 지 살펴보세요.마치며페이지 두 개를 접속자들에게 무작위로 나누어 배포해서 반응을 트래킹하는 기술은 흔할지도 모릅니다. 하지만 Optimizely를, 그리고 연동되는 다양한 서비스들을 이용하면 조금 더 세밀하고 확실한 데이터를 얻을 수 있습니다. 정말로 나의 웹 서비스에 필요한 것이 ‘잡초’인지 ‘레몬’인지 알고 싶다면 지금 당장 시작해보세요.#스포카 #기획 #A/B테스트 #A/BTest #꿀팁 #인사이트 #조언
조회수 2163

[인공지능 in IT] 인공지능 기업에서 하드웨어 엔지니어로 사는 법

인공지능 열풍이 거세게 불면서 이를 개발하는 엔지니어에 대한 수요도 폭발적으로 늘었다. 글로벌 IT의 중심이라 불리던 실리콘밸리를 포함해 중국에서도 막대한 자본을 바탕으로 엔지니어에게 기존 연봉의 2~3배를 제공하는, '인재 쟁탈전'에 돌입했다. 암흑기라 불릴 정도로 이공계 기피현상이 심했던 과거 일은 어느새 기억 속에서 잊혀질만큼 소프트웨어 엔지니어의 위상은 날이 갈수록 높아지고 있다. 심지어 교과 과정에 코딩 교육 의무화를 논의하는 단계다.AI 전문인력이란, 대게 원천기술을 개발하는 소프트웨어 엔지니어나, 학문적인 연구를 하는 리서치 인력을 많이 생각한다. 하지만, 실제로 핵심적인 역할을 담당하는 사람은 하드웨어 엔지니어다. 일반적으로 하드웨어 엔지니어라고 하면 많은 사람들이 납땜을 하고, 모터를 돌리는 등 '기계'를 만지는 엔지니어를 떠올리지만(물론 이 역시 하드웨어 엔지니어가 하는 일 중 하나다), 요즘처럼 인공지능이 적용되지 않은 곳이 없는 세상에서 하드웨어 엔지니어 역할은 그 이상이다.모두의 이해를 돕고, 인공지능 기술을 만드는 회사에서 하드웨어 엔지니어 역할이 얼마나 중요한지 알 수 있도록, 스켈터랩스 사내에서 시니어 하드웨어 엔지니어로 일하고 있는 오혁님과 질의응답 시간을 가졌다.< 스켈터랩스 오혁 하드웨어 엔지니어 >하드웨어 엔지니어로서 주로 하고 있는 일은?사용자가 실제로 만질 수 있는 기기, NVIDIA에서 생산하는 하드웨어 플랫폼과 운영체제(OS) 등을 막론하고, 소프트웨어 알고리즘을 실제 프로덕트로 구현하는 일을 한다. 이런 면에서 보면 소프트웨어 엔지니어링 서포터라고 생각할 수 있다. 하지만, 많은 사람이 더욱 더 심층적으로 인공지능을 연구할 수 있는 이유는 바로 하드웨어의 발전 때문이다.< '구글I/O 2017'에서 차세대 인공지능 전용 칩 'TPU'를 발표하는 모습, 출처: 구글 >예를 들어보자. 프로세서(CPU) 연산속도는 계속 빨라지고 있고, 그래픽 프로세서(GPU)가 프로세서 역할을 일부 담당하고 있으며, 대용량 메모리, 인공지능 가속기 등 모든 면에서 하드웨어 성능이 뒷받침되어야 한다. 하드웨어가 없다면, 소프트웨어 엔지니어가 열심히 만들어도 실제 구현하기가 어렵다. 간단하게 정리하면 하드웨어 엔지니어로서 리서처 역할을 하고, 눈으로 보이는 하드웨어도 만든다.일반인들이 알고 있는 것과 가장 큰 차이가 있다면?일반적으로 하드웨어 엔지니어라고 하면 많은 사람이 빛을 내거나, 모터를 돌리고, 부품을 조립하는 등 물리적인 제품을 만든다고 생각한다. 맞는 말이다. 하지만, 이 모든것을 컨트롤하기 위한 펌웨어, 미들웨어, OS, 디바이스 드라이버 등 소프트웨어가 돌아가기 바로 직전 단계까지, 하드웨어 엔지니어가 담당한다. 또한, 실제 제품 구현도 우리가 맡는다. 때문에, 놀랍게도 하드웨어 엔지니어도 소프트웨어 엔지니어의 전유물이라고 여겨지는 코딩을 많이 한다.< 'GTC 2017'에서 엔비디아 젠슨 황 CEO가 고성능 GPU 아키텍쳐 '볼타'를 발표하고 있다, 출처: 동아일보 >인공지능 붐이 일어나면서 어떤 점이 달라졌는가?인공지능 열풍이 불기 전 하드웨어 엔지니어는 제품을 목적에 맞게 실행하는 역할을 주로 했다. 제품을 구동되기 위해서는 대부분 순차적으로 프로세스를 진행한다. 땜질하고, 코딩하고, 각 부품에 연동하면 완성되는 형태다. 그러나, 지금은 이런 기본적인 프로세스 외에도 기계학습에 대한 알고리즘이나 인공지능 기술 전반에 걸쳐 소프트웨어적인 기술을 이해하지 못하면 절대로 원활하게 제품을 구현할 수 없다. 소프트웨어 엔지니어링을 서포트하는 역할에서 벗어나 인공지능 기술에 들어가는 소프트웨어가 어떻게 구현되는지 이해해야 적합한 제품을 만들 수 있기 때문이다.심지어 이제는 펌웨어를 코딩하는 것도 예전과 많이 달라졌다. 결과물만 놓고 보면, 모터를 돌리는 것은 같을 수 있다. 하지만, 예전에는 로봇 팔을 만들어 무언가를 잡기 위해, A 모터와 B 모터를 순차적으로 돌려서 잡는 것에 그쳤다면, 이제는 기계학습을 적용해 어떤 종류의 컵이라도 스스로 알아서 잡을 수 있도록 제작한다. 하나하나 펌웨어로 낮은 레벨에서 구현하는 것이 아니라, 로봇팔이 잡았을 때 이에 맞는 조건을 제공, 코드 하나로 학습하는 커스터마이징을 적용하는 것이다.< 국산 복강경 로봇수술기기 '레보아이'의 모습, 출처: 동아일보 >인공지능 기업의 하드웨어 엔지니어로서 가장 재미있는 점은?인공지능을 적용하면서 굉장히 재미있는 것을 많이 시도할 수 있다. 아이디어를 내고 무언가를 만들고 싶다면, 최종 제품으로 가는 길에 있어 여러 옵션을 선택할 수 있기 때문이다. 다시 말해 인공지능 소프트웨어를 통해 기존과 다른 방식으로 문제에 접근하고, 이를 해결할 수 있다는 점이다. 비유하자면, 지금까지 손으로 직접 돌리는 드라이버를 사용했다면, 이제는 앞의 부품을 언제든 바꿔낄 수 있는 전동드릴을 사용하고 있다고 보면 된다.반대로 힘든 점은 무엇인가?아무래도 인공지능이 너무 핫하다 보니 계속해서 새로운 기술이 등장한다. 인공지능 업계에서 종사하는 모든 사람들도 마찬가지겠지만, 신기술을 공부하고 연구해야 좋은 제품을 만들 수 있다. 또한, 하드웨어 엔지니어들이 열심히 만든 결과물이 너무나도 빠른 기술 발전속도로 잠시 거쳐가는 것에 불과할까 걱정되기도 한다.그럼에도 앞으로 기대되는 점은 무엇인가?하드웨어 엔지니어로서 세상을 이롭게 하는 제품을 더 많이 제작할 수 있다는 점이다. 인공지능 기술이 발전함에 따라 인간이 못 하는 영역도 조금씩 다가서고 있다.개인적으로는 로봇 쪽에 관심이 많다. 기술 발전속도가 빨라지는 만큼 다양한 제품이 등장해 사람들의 삶에 많은 혜택을 줄 것으로 기대한다. 예를 들면, 청각 장애인을 위해 음성인식을 시각적으로 바꿔주는 제품이나, 거동이 불편한 독거노인을 돕기 위한 기술 등이 있다. 삶을 윤택하게 해주는 기술을 개발하는 것이 점점 더 쉬워지고 있다는 점에서 많이 기대하는 중이다. 어떤 형태가 될 지는 예측할 수 없지만, 지금 단계에서는 소프트웨어든 하드웨어든 커다란 인공지능 플랫폼을 만들고 있다고 생각한다.이호진, 스켈터랩스 마케팅 매니저조원규 전 구글코리아 R&D총괄 사장을 주축으로 구글, 삼성, 카이스트 AI 랩 출신들로 구성된 인공지능 기술 기업 스켈터랩스에서 마케팅을 담당하고 있다#스켈터랩스 #기업문화 #인사이트 #경험공유 #조직문화 #인공지능기업 #기술기업 #하드웨어엔지니어
조회수 2155

레진 기술 블로그 - IntersectionObserver를 이용한 이미지 동적 로딩 기능 개선

구글 크롬 51 버전부터 DOM 엘리먼트의 노출 여부를 비동기로 처리하는 IntersectionObserver API를 사용할 수 있게 되었습니다. 이 기능을 이용하면 이미지의 동적 로딩이나 광고 배너의 노출 측정 등을 효율적으로 사용할 수 있다고 구글 개발자 블로그에서 소개하고 있습니다. 이 글에서는 기존의 이미지 동적 로딩에 대한 문제점을 짚어보고 여러 예제를 통해 IntersectionObserver의 사용 방법을 익혀 기존 기능을 개선할 수 있도록 합니다. 사용한 예제들은 브라우저의 호환성을 고려하지 않고 구글 크롬을 기준으로 작성하였습니다.기존의 이미지 동적 로딩 구현이미지의 개수가 많거나 용량이 큰 페이지를 불러올 경우 쓸데없는 네트워크 비용이 증가하고 이미지를 불러오는 과정에서 서비스 속도에 문제가 발생할 소지가 있어서 이미지가 사용자에게 보일 때만 불러오는 동적 로딩 기능이 필요합니다. IntersectionObserver를 소개하기 전에 먼저 기존 라이브러리들이 이미지 동적 로딩을 어떤 방법으로 구현하고 있는지 간단하게 알아보도록 합니다.엘리먼트 가시성 판단이미지 동적 로딩에서 가장 중요한 코드는 해당 엘리먼트가 현재 화면 내에 보이는지 알아내는 것입니다. 이를 위해 엘리먼트의 크기와 위치 값을 돌려주는 Element.getBoundingClientRect 함수를 사용하는 경우가 많습니다. 아래는 이 함수를 사용한 간단한 구현 예제입니다.function isInViewport(element) { const viewportHeight = document.documentElement.clientHeight; const viewportWidth = document.documentElement.clientWidth; const rect = element.getBoundingClientRect(); if (!rect.width || !rect.height) { return false; } var top = rect.top >= 0 && rect.top < viewportHeight; var bottom = rect.bottom >= 0 && rect.bottom < viewportHeight; var left = rect.left >= 0 && rect.left < viewportWidth; var right = rect.right >= 0 && rect.right < viewportWidth; return (top || bottom) && (left || right); } 이벤트 처리위에서 구현한 isInViewport 함수는 언제 호출해야 할까요? 먼저 문서를 처음 불러왔을 때 호출해야 합니다. 그 후에는 동적 로딩이라는 단어에 맞게 사용자의 동작에 따라 보이지 않던 엘리먼트가 보이게 되는 이벤트를 감지해야 합니다. 마우스나 터치로 스크롤을 통해 문서의 위치가 바뀌거나 브라우저의 크기가 바뀔 수도 있고 모바일 기기의 화면을 돌려서 볼 수도 있습니다. 데스크톱의 경우 scroll, resize 이벤트를, 모바일의 경우 orientationchange 이벤트의 처리를 생각해야 합니다.const images = Array.from(document.querySelectorAll('img')); document.addEventListener('scroll', () => { images.forEach(image => { if (isInViewport(image)) { image.onload = () => images.splice(images.indexOf(image), 1); image.src = 'original_image_path'; } }); }); 간단하게 위 코드와 같이 구현할 수 있습니다. 물론 실제 서비스를 위해서는 수정할 점이 몇 가지 있습니다. 동적 로딩의 대상이 되는 이미지를 구분하기 위해 해당 엘리먼트에만 특정 클래스를 부여하거나 HTML5에서 지원하는 data 속성을 이용하기도 합니다. 스크롤이나 리사이즈 이벤트가 과도하게 발생하는 경우가 많으므로 throttle 또는 debounce 등을 사용해 실행 빈도를 조절할 수도 있습니다. 일부 라이브러리에서는 requestAnimationFrame을 이용해 이벤트 핸들러를 처리하기도 합니다.TADA레진코믹스에서는 이미지 동적 로딩을 위해 서비스 초기에 Unveil 라이브러리를 사용했었습니다. 그러나 적용 후 몇 가지 아쉬움이 있어 따로 TADA 라이브러리를 제작했습니다. 먼저 마크업 구조상 이미지를 태그가 아닌 다른 태그에 배경 이미지로 사용하는 경우를 지원해야 했습니다. 그리고 모바일 웹에 주로 많이 적용하는 수평 스크롤 구역에 대한 처리도 필요했습니다. 문서의 스크롤 이벤트로는 처리가 되지 않기 때문에 특정 엘리먼트를 받아 그 엘리먼트의 스크롤 이벤트 핸들러를 등록할 수 있도록 해야 했습니다. 이를 해결하기 위해 만든 라이브러리를 현재 서비스에 적용 중이지만 이 라이브러리 역시 아래와 같은 문제점들을 가지고 있습니다.</> < id>기존 이미지 동적 로딩의 문제점getBoundingClientRect 함수의 문제점위 코드에서 특정 엘리먼트가 현재 화면 내에 보이는지 검사할 때 사용하던 Element.getBoundingClientRect 함수에는 치명적인 단점이 있습니다. 이 함수를 호출할 때마다 브라우저는 엘리먼트의 크기와 위치값을 최신 정보로 알아오기 위해 문서의 일부 혹은 전체를 다시 그리게 되는 리플로우(reflow) 현상이 발생한다는 점입니다. 호출 횟수가 적을 경우에는 부담이 되지 않지만, 이 함수는 위에서 구현한 것처럼 스크롤이나 리사이즈 이벤트가 발생할 때마다 등록한 모든 엘리먼트를 순환하면서 호출하게 됩니다. 이 코드들이 하나의 메인 스레드에서 실행되기 때문에 스크롤을 할 때마다 실행 속도가 눈에 띄게 느려질 수도 있습니다.외부 도메인 문서를 사용하는 iframe최신 브라우저들은 동일 도메인 정책에 따라 iframe 내의 외부 도메인 문서에서 현재 문서에 접근하지 못 하게 막고 있습니다. 이 제한은 서비스 개발에서 겪게 되는 문제는 아니고 외부 광고 플랫폼 개발자의 입장에서 발생하는 문제입니다. 광고 이미지의 표시나 클릭 이벤트의 처리 등은 iframe 내에서 처리할 수 있지만 광고 이미지를 지연 로딩한다거나 이 광고가 사용자에게 노출이 되었는지 기록하는 등의 기능은 iframe 내에서 불가능합니다. 그래서 광고를 적용하는 서비스 개발자에게 스크립트를 제공하고 서비스 문서 내에 삽입하는 방식으로 처리하고 있습니다. 이러한 외부 광고가 여러 개라면 삽입해야 하는 코드가 늘어날 뿐만 아니라 코드 내에서 스크롤이나 리사이즈 이벤트 등을 각각 사용하기 때문에 위에서 언급한 문제점들이 배가될 수 있습니다.기타 이벤트에 대한 처리대부분의 동적 로딩 라이브러리들은 적용할 엘리먼트에 특정 클래스 또는 data 속성을 부여하면 코드를 추가 작성하지 않더라도 쉽게 사용할 수 있습니다. 하지만 화면에서 보이지 않던 엘리먼트가 갑자기 나타나는 현상은 스크롤이나 리사이즈 이벤트에서만 발생하는 것이 아닙니다. 더보기 버튼을 눌렀을 때 숨겨져 있던 엘리먼트를 노출할 수도 있고 AJAX 호출 후 엘리먼트를 생성한 후 보여줄 수도 있습니다. 이런 경우 일괄적으로 처리하기가 어렵우므로 해당 이벤트가 발생할 때 수동으로 처리하는 수밖에 없습니다.IntersectionObserver위에 나열한 문제들을 효과적으로 처리하기 위해 크롬 51/엣지 15/파이어폭스 55 버전부터 IntersectionObserver를 지원하기 시작합니다. 우리말로 번역하면 교차 감시자 정도가 될 이 기능은 등록한 엘리먼트가 보이는 영역에 나타나거나 사라질 때(용어에 충실하자면 대상 엘리먼트의 영역이 루트 엘리먼트 영역과 교차하기 시작하거나 끝났을 때) 비동기로 이벤트를 발생시켜 줍니다. 기본적인 사용법은 아래와 같습니다.const intersectionObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { // do something observer.unobserve(entry.target); } }); }); intersectionObserver.observe(element); 먼저 IntersectionObserver 생성자에 콜백 함수를 인자로 넘겨주고 생성한 인스턴스의 observe 메소드를 통해 동적으로 처리할 엘리먼트를 등록합니다. 콜백 함수는 IntersectionObserverEntry 객체 목록을 전달받으므로 순환문을 통해 각 엘리먼트에 대한 처리를 완료하고 필요한 경우 unobserve 메소드를 이용해 감시 대상에서 해제할 수 있습니다.IntersectionObserver 예제아래 예제들은 기본적으로 아래 코드를 바탕으로 작성되었습니다. 각 예제들의 최상단에 엘리먼트에 짝을 이룬 표시등을 두었고 콜백 함수가 호출될 때마다 파동 효과를 주었으며 이 때 isIntersecting 속성을 기준으로 표시등을 켜지거나 꺼지게 되어 있습니다.const io = new IntersectionObserver(entries => { entries.forEach(entry => { // isIntersecting 속성으로 해당 엘리먼트가 보이는 지 표시 }); }); Array.from(document.querySelectorAll('.box')).forEach(box => { io.observe(box); }); 스크롤 이벤트를 다루지 않더라도 엘리먼트의 가시성 여부를 isIntersecting 속성을 통해 알 수 있습니다.<iframe class="demo" data-fr-src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/basic-verticalscroll.html" width="600" height="400" frameborder="0">수평 스크롤의 경우에도 overflow 속성이 적용된 컨테이너 엘리먼트의 스크롤 이벤트를 처리하지 않더라도 상관없습니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/basic-horizontalscroll.html" width="600" height="200" frameborder="0">더보기 버튼에 대한 클릭 이벤트를 따로 등록하지 않아도 동작합니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/basic-unfold.html" width="600" height="240" frameborder="0">리사이즈 이벤트 역시 따로 처리할 필요가 없습니다. 새 창을 띄운 후 창 크기를 조절하면서 확인할 수 있습니다.위의 모든 예제들은 <iframe> 태그 안에서 실행되고 있습니다. 이처럼 작성한 코드가 외부에서 실행이 되더라도 IntersectionObserver API는 문제없이 동작합니다.IntersectionObserver 생성자 옵션rootroot 옵션에는 가시성의 판단 기준이 될 HTML 엘리먼트를 지정합니다. observe 메소드로 등록하는 엘리먼트들은 반드시 이 루트 엘리먼트의 자식이어야 합니다. 이 옵션을 지정하지 않을 경우 브라우저 화면에서 현재 보이는 영역인 뷰포트가 기본이 됩니다. 아래 예제에서 알 수 있듯이 루트 엘리먼트를 지정하면 현재 화면과는 상관없이 루트 엘리먼트와 등록한 엘리먼트들의 영역이 교차하는 지 판단하게 됩니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/option-root.html" width="600" height="400" frameborder="0">rootMargin루트 엘리먼트의 마진값을 지정할 수 있습니다. CSS에서 사용하는 형식과 같기 때문에 “10px”, “10px 20px”, “10px 20px 30px 40px” 형태가 모두 가능하며 음수값으로 지정할 수도 있습니다. 기본값은 0이고 루트 엘리먼트를 지정한 상태라면 퍼센트값을 사용할 수도 있습니다. 이 옵션을 이용하면 이미지 동적 로딩에서 해당 엘리먼트가 화면에 나타나기 전에 이미지를 불러오기 시작해 이미지 공백을 줄이는데 유용하게 이용할 수 있겠습니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/option-rootmargin.html" width="600" height="400" frameborder="0">위 예제에서는 root 옵션은 지정하지 않고 rootMargin 옵션을 각각 0, 100px, -100px, 50%로 지정했습니다. 하지만 iframe 내에서 실행을 하게 되면 이 옵션이 정상적으로 동작하지 않습니다. 프로젝트 페이지의 이슈 댓글에는 동일 도메인의 프레임 안에서는 동작하는 것으로 논의되고 있지만 뷰포트에는 해당하지 않거나 버그 또는 아직 크롬에 반영이 되지 않아 보입니다.이 예제는 새 창을 띄워 프레임을 벗어나면 정상적으로 동작합니다. 스크롤을 내리다보면 엘리먼트마다 IntersectionObserver 콜백 함수가 다른 위치에서 호출됨을 알 수 있습니다.thresholdthreshold 옵션은 엘리먼트가 콜백 함수의 호출 시점을 정하는 옵션입니다. 0과 1을 포함한 그 사이의 숫자 또는 숫자 배열을 지정할 수 있는데 이 숫자는 엘리먼트의 전체 영역 중에 현재 보이는 영역의 비율입니다. 이 비율의 경계를 넘나들 때마다 콜백 함수가 호출됩니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/option-threshold-value.html" width="600" height="400" frameborder="0">위 예제에서는 threshold 옵션을 각각 0, 0.5, 1, [0, 1]로 지정했습니다. rootMargin 예제처럼 엘리먼트마다 콜백 함수가 다른 위치에서 호출됩니다. 두 번째와 세 번째 상자는 콜백 호출 시점에 isIntersecting 값이 항상 참이기 때문에 표시등이 정상적으로 표시되지 않습니다. isIntersecting 속성을 기준으로 처리해야 할 작업이 있다면 반드시 threshold 속성에 0을 포함시켜야 정상적으로 동작합니다. threshold 속성은 아래 예제처럼 콜백 함수의 인자로 받는 IntersectionObserverEntry 객체의 intersectionRatio 속성과 같이 사용하기에 유용합니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/option-threshold-ratio.html" width="600" height="400" frameborder="0">위 예제에서는 threshold 옵션을 각각 [0, 1], [0, 0.5, 1], [0, 0.25, 0.5, 0.75, 1]로 지정하고 콜백이 호출되면 intersectionRatio 값을 기준으로 표시등의 배경 투명도를 바꾸도록 했습니다.IntersectionObserver의 활용이미지 동적 로딩지금껏 알아본 IntersectionObserver를 이용해 이미지 동적 로딩을 간단하게 구현해봅니다. 이미지 엘리먼트를 구성할 데이터가 배열로 존재한다고 가정하고 ES6에서 지원하는 템플릿 문자열을 사용해 배열을 순환하면서 이미지 목록을 생성합니다. 그 후 IntersectionObserver를 초기화하고 만들어진 엘리먼트들을 등록합니다. 콜백 함수에서는 엘리먼트가 보이는 상태일 때 이미지를 로딩하고 해당 엘리먼트를 감시 해제합니다. id="comics"> const comics = [ { alias: 'eunsoo', id: 6080299074584576, title: '은수' }, ... ]; const template = comics => ` ${comics.map(comic => ` ${comic.id}"> ${comic.alias}" class="info">${comic.title} `).join('')} `; document.getElementById('comics').innerHTML = template(comics); const io = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (!entry.isIntersecting) { return; } const target = entry.target; const id = target.dataset.id; target.querySelector('.info').style.backgroundImage = `url(https://cdn.lezhin.com/v2/comics/${id}/images/wide?width=600)`; observer.unobserve(target); }); }); Array.from(document.querySelectorAll('.comic')).forEach(el => { io.observe(el); }); 아래 예제를 실행하면서 브라우저의 개발자 도구를 열고 네트워크 탭을 살펴보면 이미지 엘리먼트가 보이기 시작할 때 불러오기 시작하는 것을 확인할 수 있습니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/demo-lazyload.html" width="600" height="400" frameborder="0">무한 스크롤IntersectionObserver 기능을 이용하면 무한 스크롤 역시 쉽게 구현할 수 있습니다. 아래 예제에서는 스크롤의 끝부분에 감시를 할 엘리먼트를 두고 그 엘리먼트가 노출이 될 때마다 콘텐츠를 추가로 불러오도록 작성하였습니다. id="items"> id="sentinel"> const count = 20; let index = 0; function loadItems() { const fragment = document.createDocumentFragment(); for (let i = index + 1; i <= index + count; ++i) { const item = document.createElement('p'); item.classList.add('item'); item.textContent = `#${i}`; fragment.appendChild(item); } document.getElementById('items').appendChild(fragment); index += count; } const io = new IntersectionObserver(entries => { entries.forEach(entry => { if (!entry.isIntersecting) { return; } loadItems(); }); }); io.observe(document.getElementById('sentinel')); loadItems(); 실행 결과를 아래 예제에서 확인할 수 있습니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/demo-infinitescroll.html" width="600" height="400" frameborder="0">마무리IntersectionObserver API는 아직 몇몇 브라우저의 최신 버전에서만 사용할 수 있지만 지원하지 않는 브라우저를 위해 Polyfill을 제공하고 있습니다.IntersectionObserver API는 웹 광고 플랫폼 제공자와 사용자 모두에게도 좋은 소식이라 봅니다. 이 API가 정착된다면 광고 노출 여부를 측정하기가 쉬워지고 서비스에 더해졌던 리소스 낭비를 줄일 수 있을 것이라 생각합니다.레진코믹스는 크롬 브라우저 사용자의 비중이 높은 편이기 때문에 빠른 시일 안에 적용해 볼 예정입니다. 이미지 동적 로딩 기능의 개선과 정주행 기능과 같이 현재 스크롤 이벤트를 과하게 사용하고 있는 코드에 대한 부담을 덜 수 있기를 기대하고 있습니다.참고자료Intersection Observer API SpecificationIntersectionObserver’s Coming into ViewIntersection Observer API
조회수 4836

신입 개발자를 위한 코드의 정석

Overview대학을 수석으로 졸업했지만, 정작 회사에서는 A부터 Z까지 제대로 할 줄 아는 게 없었습니다. 실수를 남발할 때마다 느꼈던 좌절감은 아직도 생생하지만 되돌아보면 그때의 삽질이 소중한 피와 살이 되었지요. 오늘은 헤매고 있는 신입 개발자를 위한 글을 쓰려고 합니다. 신입 개발자, 당신! 내 이야기를 편하게 듣고 가지 않으실래요? 남을 위한 코드, 클-린 코드“너랑 같이 일하는 사람은 어떻게 보라는 거야?” “한 명이 짠 코드인데, 어째 한 사람이 짠 것 같지가 않다..” “이게 네 스타일이냐?” 대학생이었을 땐, 대부분 혼자서 프로젝트를 진행했습니다. 다른 사람이 제 코드를 보는 일도 거의 없어서 띄어쓰기나 들여쓰기 등에 통일이 없었고, 함수의 네이밍도 전혀 고려하지 않았습니다. 이게 나쁜 습관이었다는 걸 입사하고 알게 되었죠. 이 습관을 고치려고 코딩 컨벤션(coding convention)을 지키는 것에 꽤 오랜 시간을 들여야만 했습니다. 우리는 협업을 하는 사람들입니다. 사람들이 더러운 방보다 깨끗한 방을 좋아하는 것처럼, 당신과 협업하는 개발자도 보기 어려운 코드보다 깨끗한 코드를 더 좋아합니다. 클린 코드를 작성하기 위한 세 가지 기본 원칙을 잠시 소개합니다. 클린 코드를 위한 세 가지 기본 원칙 코드를 최초로 작성한 사람이 끝까지 유지보수를 한다는 보장은 없다.이미 잘 정리된 코드는 효율성이 증가한다. 정리할 시간에 코드 한 줄을 더 분석할 수 있으니까!리팩토링은 미루었다가 한꺼번에 하는 것이 아니다. 코드를 작성하는 매순간 함께 하는 활동이다.작은 것 하나부터 습관을 들여보세요. 분명 깔끔하고 보기 좋은 코드를 만드실 수 있을 겁니다. 머지 않아 “남을 위한 코드는 곧 나를 위한 코드”라는 것도 알게 될 거고요. 책의 한 구절이 떠오르네요. “우리는 저자이다. 저자에게는 독자가 있다. 그리고 저자에게는 독자와 잘 소통해야할 책임이 있다.”⌈Clean Code⌋의 저자, Robert C. Martin 설마가 사람 잡는다, 철저한 검증만약 누군가 검증 단계에서 잊지 말아야할 것이 뭔지 묻는다면 이렇게 대답하고 싶습니다. “절대 사용자가 입력한 값을 신뢰하지 말라. 프론트엔드에서도, 백엔드에서도.” 모든 사용자가 각 항목에 맞게 올바른 정보만 입력해준다면 얼마나 좋을까요? 세상에는 다양한 사용자가 있습니다. 너무 바빠서 얼른 회원가입을 해야하는 사용자는 항목을 채우지도 않고 신청 버튼을 누를 수도 있습니다. 영어로 입력해야 하는 항목엔 한글을 입력한 사용자도 있을 겁니다. 이런 휴먼 에러(human error)뿐만 아니라 의도적으로 비정상적인 요청을 시도하는 사용자도 분명 있습니다. 이 때문에 개발자는 기능에 대해 항상 검증해야 합니다. 바로 이렇게요!그런데 프론트엔드에서 유효성 검사를 하면, 백엔드에는 유효한 값만 넘어온다고 보장할 수 없습니다. 자바스크립트는 브라우저 엔진에 따라 다르게 동작할 수도 있습니다. 또 자바스크립트에서 다루는 값들은 크롬의 개발자도구(option + command + i)를 이용하면 얼마든지 값을 변조하거나 검증을 회피할 수 있습니다. 또 불온한 시도가 아니더라도 다양한 예외 케이스들이 존재하기 때문에 백엔드에서도 무조건 검증해야 합니다.페이스북 페이지의 개발자 도구를 열었을 때 노출되는 화면입니다. 얼마나 나쁜 사람들이 많으면 경고화면까지 만들었을까요?누군가 질문할 수도 있겠군요. “프론트엔드의 검증이 의미가 없다면, 백엔드에서만 검증을 해도 되지 않을까요?” 네, 아닙니다.(단호) 많은 양의 일을 한꺼번에 하는게 힘든 것처럼 무분별한 요청이 서버에 쏟아지면 서버도 사람처럼 지치고 말 겁니다. 응답이 느려지는 등의 문제가 생길 수도 있고, 결국 사용자가 불편해질 것입니다. 그러므로 가장 좋은 검증 방식을 3단계로 정리하면 아래와 같습니다. 고수가 되는 검증 방식 3단계프론트엔드에서 먼저 값 검증을 하여 빠른 사용자 경험을 제공한다.백엔드에서 다시 한 번 더 검증을 거쳐 상황에 적절한 응답 코드를 내려준다.프론트엔드는 상황에 맞게 적절한 UX와 메시지를 보낸다. 동작 그만! 정리는 하고 코딩하자!예전에는 요구사항이 있으면 바로 키보드 위에 손부터 올렸습니다만, 그건 좋은 태도가 아니었습니다. 팀장님이 “이 경우엔 어떻게 하지?”라고 질문하면 아무 대답도 하지 못했기 때문이죠. 팀장님은 늘 “항상 먼저 생각하고 코딩하자!“라고 조언하십니다. 맞습니다. 최대한 모든 경우의 수를 머릿속에 정리하고 코딩을 시작해야 합니다. 시간이 없다는 핑계로 무작정 시작하면 분명 문제가 발생합니다. 또 구현할 기능만 몰두하지 말고, ‘이 기능이 다른 기능에 영향을 미칠 수 있을까?’를 고민하면 훨씬 좋은 코드를 만들 수 있을 겁니다. “이런 거 다 생각하고 짜면 도대체 코딩은 언제 하라고?” “얼른 선임 분들에게 코딩하는 내 모습을 보여줘야 하는데!” “당장 코드 안 짜고 있으면 노는 것처럼 보이지 않을까?” 혹시 이런 생각을 하고 계신가요? 나도 그런 생각을 했던 적이 있습니다. 하지만 요구사항을 확실하게 정리한 후, 코드를 짜는 게 더 효율적입니다. (그렇지 않으면.. ‘수정’이란 이름 아래 모든 것을 뒤엎고 처음부터 다시 시작해야할 수도 있습니다.) ‘더 나은 개발자가 되는 8가지 방법(8 Ways to Become a Better Coder)’이란 글에는 이런 내용이 있습니다. “동작하는 코드는 끝이 아니라 시작이다.” 신입 개발자는 종종 요구사항에 따라 동작하는 코드만 짜면 된다고 여길 때가 있습니다. 물론 사회생활에 적응하느라 정신 없는 와중에 그나마 자신의 코드가 요구사항대로 동작하면 무척 뿌듯할 겁니다. 하지만 동작만 한다고 절대 지나치지 말아주세요. 위에서 언급한 것처럼 깨끗한 코드가 되도록 리팩토링을 하고, 검증하고, 동작이 제대로 되는 것인지 의심하면서 꾸준히 노력해야 합니다. 마지막으로 항상 중요하게 생각하는 문장 하나를 남기고 글을 마치겠습니다.“진정으로 훌륭한 프로그래머는 적극적으로 어디가 잘못되었지를 찾는다. 자기가 놓친 결함은 결국 ‘사용자’가 발견하게 된다는 것을 알고 있기 때문이다.” Esther SchindlerConclusion지금까지 다룬 내용은 결국 같은 맥락입니다. 모든 개발조직은 좋은 품질의 소프트웨어를 개발할 줄 아는 개발자, 협업할 줄 아는 개발자를 원합니다. 누군가 “당신은 잘 지키고 있는가”라고 질문한다면, “저 또한 노력하고 있습니다.”라고 답변하고 싶습니다. 같은 자리에 머무르는 개발자가 될 것인지, 부족함을 알고 항상 배우고 나아가는 개발자가 될 것인지는 스스로의 몫이라고 생각합니다. 이 글을 끝까지 읽은 신입 개발자 당신! 같이 노력하지 않으실래요? :-) 참고 Robert C. Martin, 「Clean Code」, 케이엔피북스(2010)Esther Schindler, 8 Ways to Become a Better Corder, New Relic, 2018.03.02.유석문, 「프로그래머 철학을 만나다 - 소프트웨어를 사랑하는 기술」, 로드북(2014)임백준, 「읽기 좋은 코드가 좋은 코드다」, 한빛미디어(2012)팀장들이 꼽은 신입 PHP 개발자가 가급적 빨리 알았으면 하는 것들프론트에서”만” 유효성 검사가 문제인 경우남을 위한 코드 만들기 - 클린코드글김우경 대리 | R&D 개발1팀[email protected]브랜디, 오직 예쁜 옷만#브랜디 #개발문화 #개발팀 #업무환경 #인사이트 #경험공유
조회수 2164

Android Gradle Tips

안드로이드와 GradleAndroid 가 Gradle 을 이용하기 시작한 것도 3년이 다 되어 갑니다. 이제는 많은 유저가 당연히 Gradle 을 Android 기본 개발 환경으로 사용하고 있습니다.하지만 기본 설정으로만 Gradle 을 사용하는 사용자들이 많습니다. 게다가 구글에서 Android Gradle Build DSL 을 끊임없이 변경했기 때문에 많은 사용자들이 이를 이해하기도 전에 변경이 되는 경우가 매우 빈번했습니다.Gradle Dependency 분리하기안드로이드 자동화 툴위 두번의 포스팅을 통해서 TossLab 에서 사용하고 있는 Gradle 에 대해서 소개를 해드렸습니다.오늘은 Android 팀이 사용하는 Custom 설정들에 대해서 정리하도록 하겠습니다.1. 초기화 값 검증 및 설정하기개발자들이나 CI 에서 관리해야하는 속성 값에 대해서는 각각 다르게 설정할 필요가 있습니다.안드로이드 팀은 3개의 추가적인 속성값을 추가하여 사용하고 있습니다.# gradle.properties inhouse_version=2 # 배포/qa 버전의 hofix version 을 관리학 ㅣ위함 report_coverage=false # coverage 측정에 대한 on/off 기능 dev_min_sdk=21 # minSDK 의 개별적인 관리를 위함 위의 3개의 값은 존재 하지 않으면 빌드가 되지 않도록 하는 강제사항으로 만들었으나 새로운 개발자가 입사하게 되었을 때 또는 CI 서버에 실수로 기입하지 못하게 되었을 때 Project Import 나 빌드가 아예 되지 않는 현상이 발생하였기에 초기 값을 설정할 수 있도록 하였습니다.report_coverage 는 5. Android Gradle DSL 에서 buildTypes.debug.testCoverageEnabled 에서 사용되며 이 값은 설정에 따라서 디버그 과정에서 변수값들이 제대로 노출되지 않게 됩니다. report 가 필요한 CI 서버 용으로 만들어진 값입니다.// valid.gradle def checkValidProperties() { println "Properties Valid Checking.........." if (!project.hasProperty("inhouse_version")) { println "set up to gradle.propeties --> inhouse_version = 1 (default)" project.ext.inhouse_version = 1 } if (!project.hasProperty("report_coverage")) { println "set up to gradle.propeties --> report_coverage = false (default)" project.ext.report_coverage = false } if (!project.hasProperty("dev_min_sdk")) { println "set up to gradle.propeties --> dev_min_sdk = 19 (default)" project.ext.dev_min_sdk = 19 } println "Properties Valid Check OK" } checkValidProperties() // ------------------------------- // build.gradle apply from: 'valid.gradle' 위와 같이 설정한 뒤 gradle.properties 에 아무런 값을 설정하지 않고 빌드를 하게 되면 빌드 최초에 다음과 같은 log 를 보실 수 있습니다.================================================================================ Properties Valid Checking.......... set up to gradle.propeties --> inhouse_version = 1 (default) set up to gradle.propeties --> report_coverage = false (default) set up to gradle.propeties --> dev_min_sdk = 19 (default) Properties Valid Check OK ================================================================================ 2. APK Copy 하기QA 팀 전달 또는 스토어 배포시에 Android Studio 의 기본 기능을 이용하지 않고 Gradle Task 를 사용하여 빌드를 하게 되면 /app/build/outputs/apk 에 있는 패키지를 복사하는 것이 여간 귀찮은 작업이 아닐 수 없습니다.그래서 Gradle 에서 기본적으로 제공되는 Copy Task 를 이용하여 APK Copy Task 를 만들었습니다.// apk-copy.gradle android.applicationVariants.all { variant -> // 1. Copy Task 생성 def task = project.tasks.create("copy${variant.name}Apk", Copy) task.from(variant.outputs[0].outputFile) // 2. 바탕화면 Task 로 복사 task.into("${System.properties['user.home']}/Desktop/") // 3. 복사하는 과정에서 APK 이름 변경 def targetName = "jandi-${variant.baseName}-${variant.versionName}.apk" task.rename ".*", targetName task.doFirst { println "copy from ${source.singleFile.name} to $destinationDir" } task.doLast { value -> println "completed to copy : $targetName" } } // --------------- // build.gradle apply from: 'apk-copy.gradle' 위의 Task 는 총 3개의 단계로 구분할 수 있습니다.Copy Task 생성~/Desktop 으로 복사복사 할 때 APK 이름 변경Task 를 정의하는 과정에서 application 의 flavor, build-type, version 을 기반으로 복사하도록 한 것입니다.위와 같이 설정하면 다음과 같이 사용할 수 있습니다.# flavor : qa , build-type : Debug $> ./gradlew assembleQaDebug copyqaDebugApk # 또는 줄여서 아래와 같이 쓸 수 있습니다. $> ./gradlew aQD copyQDA Application Variant 에 대한 변수는 링크에서 확인하실 수 있습니다.3. CI TasksCI 용으로 CheckStyle 과 PMD 를 사용하기 때문에 관련 설정 또한 별도로 처리하였습니다.task pmd(type: Pmd) { source 'src/main' include '**/*.java' ruleSetFiles = files('../pmd.xml') ignoreFailures = true } task checkstyles(type: Checkstyle) { configFile file('../checkstyle.xml') source('src/main') include '**/*.java' classpath = files() showViolations = true ignoreFailures = true } // --------------- // build.gradle apply from: 'ci-tasks.gradle' CheckStyle 과 PMD 설정에 필요한 정보 또한 별도의 script 로 설정하였습니다.4. Gradle Properties빠른 빌드를 위해 추가적인 설정을 하고 있습니다.# gradle.properties # 백그라운드 빌드 org.gradle.daemon=true # 동시 빌드 org.gradle.parallel=true # jvm heap size org.gradle.jvmargs=-Xmx4346m # build jdk org.gradle.java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home 위의 설정 중에서 제일 보셔야 할 것이 org.gradle.jvmargs 입니다. Android Gradle 설정 중에서 위의 값이 적으면 빌드속도가 현저히 느려집니다.빌드 할 때 console log 를 확인하시고 값을 적절하게 맞춰주실 것을 권장합니다.5. Android Gradle DSL 추가 정의하기 // build.gradle // ...중략 android { // 특정 Flavor에서 Release Build 막기 android.variantFilter { variant -> if (variant.buildType.name.equals('release') && (variant.getFlavors().get(0).name.equals('qa') || variant.getFlavors().get(0).name.equals('dev'))) { variant.setIgnore(true); } } buildTypes { debug { debuggable true testCoverageEnabled = project.hasProperty("report_coverage") && report_coverage.toBoolean() } // ..중략... } productFlavors { dev { // demo version applicationId 'com.tosslab.jandi.app.dev' versionName(defaultConfig.versionName + ".dev." + inhouse_version) minSdkVersion project.hasProperty("dev_min_sdk") ? dev_min_sdk : 19 } // ..중략.. } // 빌드 과정에서 CPU 와 Ram 최적화 하기 dexOptions { javaMaxHeapSize "2g" maxProcessCount Math.max(1, ((int) (Runtime.getRuntime().availableProcessors() / 2))) } } variant-filter 를 이용해서 qa 나 dev 용 빌드는 release 버전이 빌드되지 않도록 하였습니다.buildTypes 와 productFlavors 에서는 앞서 설정한 gradle-properties 에 대해서 설정에 따라 기본값이 지정되도록 하였습니다.dexOptions 설정은 개발하는 기기의 PC 환경에 따라 다를 수 있습니다.Android DSL 에 의하면 Dex 빌드 과정에서 최종적으로 사용하는 메모리는 heapsize * process-count 라고 합니다.heapsize 기본값 : 2048MBprocess-count 기본값 : 4참고문서6. Android Resource Image 의 EXIF 정보 삭제하기보통 디자이너가 Photoshop 과 같은 툴을 이용하여 이미지를 만들게 되면 자동으로 adobe 와 관련된 exif 정보가 붙게 됩니다. 그래서 빌드 할 때 libpng warning : iCCP ... 와 같은 warning 메세지를 보실 수 있습니다. 이는 Android Build 과정에서 aapt 가 이미지 최적화 하는 과정에서 불필요한 exif 정보로 인해서 오류를 내게 됩니다.따라서 exif 정보를 초기화 해주는 작업이 필요합니다.맥 사용자에 한해서 지원됩니다.HomeBrew 를 이용해서 exiftool 을 설치하셔야 합니다. exiftool 설명find . -path '*src/main/res/*' -name '*.png' -exec exiftool -overwrite_original -all= {} \; 저는 별도로 쉘 스크립트를 만들어서 실행합니다.아래를 복사해서 붙여넣기로 실행하시면 됩니다.echo "find . -path '*src/main/res/*' -name '*.png' -exec exiftool -overwrite_original -all= {} \;" > exif_clean.sh chmod 744 exif_clean.sh 관련 정보 : adt-dev google group 에서 제시된 해결책Wrap up안드로이드 팀은 Gradle 을 이용하여 반복적일 수 있는 작업을 자동화 하고 다양한 초기화 설정과 편의를 가지고자 하였습니다.초기화 값 검증 및 설정Apk 복사 자동화CI Task 정의Gradle Properties 지정Android Gradle DSL 정의Android Resource Image EXIF 삭제Gradle 을 얼마나 잘 활용하냐에 따라서 조직에 필요한 Task 를 금방 만드실 수 있습니다. 이번 포스팅이 도움이 되었기를 바라며 활용해보실 것을 권장합니다.#토스랩 #잔디 #JANDI #개발자 #개발팀 #앱개발 #안드로이드 #인사이트
조회수 2269

리디북스 서버 스택 소개

2대의 서버로 시작한 리디북스는 각 기능의 요구사항에 최적인 솔루션들을 채용하고, 고가용성(High Availability)을 지향하면서 매우 복잡하고 다양한 구성으로 변모해왔습니다. 이 글에서는 리디북스가 어떤 스택에서 서비스를 제공하고 있는지 간략히 소개하려고 합니다. 각 스택의 선택 이유나 문제에 부딪히며 배운 노하우 등은 차차 포스팅하겠습니다.대략적인 구조리디북스 백엔드 구조도로드 밸런싱로드 밸런싱은 소프트웨어 로드 밸런서인 HAProxy를 이용하고 있습니다. HAProxy는 L4, L7 스위치의 기능 및 로드 밸런싱을 제공하고 구성 역시 매우 간편합니다. 리디북스는 고가용성을 위해 Active - StandBy 서버 한 쌍이 가상 IP를 공유하고, keepalived를 통해 서로의 상태를 확인하며 자동 failover 됩니다. 각 서버군이 사용하는 네트워크 트래픽에 따라 스위치와 연결되어 있는 네트워크의 속도가 다른데, 이를 효율적으로 사용하기 위해 HAProxy 서버 쌍을 2개 구성하여 DNS를 통해 HAProxy로 들어오는 트래픽도 분산하는 방식으로 네트워크 효율화를 이루었습니다.웹 서버Ubuntu 14.04 LTS 기반에 웹서버로는 Apache, Nginx를 사용하고 있습니다. 서점 용 웹 서버, 정적 파일 서버(CSS, JS 등), 통계용 서버, 책 파일에 DRM을 씌워 전송하는 다운로드 서버 등 여러 개의 웹 서버 그룹을 나누어 관리하는데, 각 서버가 하는 역할이나 테스트를 통해 확인한 병목 지점을 고려해 웹서버를 채택합니다.API 서버리디북스는 서점이나 앱에서 이용하는 수많은 API가 존재하는데 종류에 따라서는 초당 수만 개의 호출이 발생하는 경우도 있습니다. 이러한 트래픽을 감당하기 위해 비동기 처리가 필요한 경우 Node.js를 주로 이용하여 구현하고 있습니다. Node.js 프로세스는 PM2를 통해 클러스터 모드로 실행되어 요청을 처리합니다. 클러스터 모드는 프로세스에 대한 로드 밸런싱을 지원하며 프로세스를 순차적으로 재시작할 수 있어 무정지로 서비스를 재시작할 수 있습니다데이터베이스서비스 초기에 MySQL을 사용했고 현재는 MariaDB로 변경한 상태입니다. 한때 DB가 SPOF(Single Point Of Failure)였던 시기를 겪으면서 read/write의 분산을 위해 많은 노력을 들였습니다. 리디북스에서 실행하는 대부분의 데이터 연산은 읽기 동작이므로 애플리케이션 레벨에서 읽기/쓰기 접근을 구분하여 1차적으로 부하를 분산하고, HAProxy를 통해 여러 대의 slave로 분배해 2차적으로 부하를 분산합니다. 쓰기 동작이 빈번하거나 데이터 성격상 NoSQL이 필요한 경우 Couchbase와 Redis를 적극적으로 사용하고 있으며, MariaDB 상에서도 쓰기 동작의 분산 필요성이 대두됨에 따라 상반기에 샤딩을 준비하고 있습니다. 사용자 행동, 트랜잭션 로그 등 하루에도 방대한 양이 쏟아지는 데이터의 경우 Azure 내에 구성한 Hadoop 클러스터에 보관하며, Hive 저장소를 BI(Business Intelligence) 시스템 기반으로 활용하고 있습니다.파일 시스템리디북스에서 다루는 책 파일은 매우 방대하고 중요한 데이터입니다. 어떠한 일이 있어도 데이터 유실이 발생해서는 안되며, 일부 하드웨어 혹은 노드에 장애가 발생하더라도 서비스 장애 없이 파일을 서빙할 수 있어야 합니다. 저희는 GlusterFS로 6대의 노드를 클러스터를 구성하고 이를 파일 접근이 필요한 서버에서 NFS-like 형태로 마운트하여 사용하고 있습니다. 동일 데이터는 여러 노드(3 replica)에 분산 저장되며, 각 노드에도 RAID 구성을 하여 빠른 장애 대응 및 데이터 유실 방지에 노력하고 있습니다.검색리디북스의 책/저자 검색 등은 ElasticSearch를 통해 이루어집니다. 형태소 분석기는 오픈소스인 은전한닢에 따로 정의한 dictionary를 조합해 사용하고 있고, 2대의 노드로 클러스터가 구성되어 있습니다. 추가/변경되는 도서 정보는 증분 색인을 통해 실시간으로 검색 서버에 반영됩니다.작업큐이메일 발송, PUSH 발송 등의 작업들은 웹 애플리케이션이 직접 실행할 경우 페이지 응답속도를 떨어뜨리고, 진행상황 파악이나 실패 시 재시도하는 등의 실행 관리가 어렵습니다. 이런 문제를 해결하기 위해 Beanstalk라는 Work Queue에 작업을 일단 쌓아두고, 여러 대의 서버에서 실행되고 있는 컨슈머들이 작업을 가져와 순차적으로 진행하는 형태로 구성되어 있습니다.모니터링장애 발생 포인트와 시점을 예측할 수 없는 만큼 장애 발생의 빠른 인지를 위해 모니터링은 매우 중요합니다. 리디북스는 99.999%의 고가용성(High Availability)을 목표로, 버그와 장애 없는 안전한 운영을 위해 아래와 같이 다양한 오픈소스 및 유료 솔루션을 도입하여 활용하고 있습니다.30+ 이상의 서버 리소스를 모니터링하기 위한 Munin(On-Premise) 및 NewRelic(SaaS)서버에서 발생하는 각종 오류와 예외를 모니터링하기 위한 Sentry로그인, 결제 등 서점의 핵심적인 기능의 정상 여부를 모니터링하는 Pingdom각종 배치작업과 주기적으로 실행되는 스크립트를 모니터링하기 위한 PushMonNode.js 프로세스나 Redis 상태 모니터링을 위한 Keymetrics(SaaS)데이터의 무결성을 주기적으로 감지하는 각종 In-house 스크립트#리디북스 #서버 #서버개발 #스택 #백엔드 #node.js #개발자 #개발언어 #스킬스택 #소개

기업문화 엿볼 때, 더팀스

로그인

/