스토리 홈

인터뷰

피드

뉴스

조회수 2241

AWS 서비스를 활용한 Kubernetes 클러스터 구축 - VCNC Engineering Blog

Kubernetes 클러스터를 상용 환경에서 운영하기 위해서는 몇 가지 추가 구성요소를 설치해야 합니다. 예를 들어 Ingress를 만들더라도 실제로 트래픽을 받아줄 Ingress Controller를 설치해두지 않았으면 소용이 없습니다. 그리고 모니터링을 위해 컨테이너의 로그나 CPU/메모리 사용량 등을 수집, 조회할 수 있는 서비스도 필요합니다.다행히 이러한 추가 구성요소 또한 Kubernetes 클러스터 위에서 일반 애플리케이션과 거의 같은 방식으로 작동하므로 설치하는 것이 어렵지는 않습니다. 다만 클러스터를 원하는 대로 구성할 수 있는 만큼 선택의 폭이 넓어서 여러 가지 해법을 놓고 고민하게 될 수 있습니다. 이 글에서는 타다 서비스를 위해 Kubernetes 클러스터를 구성할 때 어떤 선택을 했는지, 특히 AWS 환경에서는 어떤 서비스들을 활용할 수 있는지 공유합니다.서비스를 외부에 노출: NGINX Ingress Controller + NLBIngress Controller 고르기Kubernetes에서 클러스터 내부 서비스를 외부에 HTTP(S)로 노출할 때는 Ingress를 사용할 수 있습니다. TLS 암호화, 로드밸런싱, 호스트명/경로 기반 라우팅 등을 제공해서 상당히 편리한데, Ingress가 실제로 작동하기 위해서는 Ingress Controller가 필요합니다.시중에는 다양한 종류의 Ingress Controller 솔루션이 나와 있습니다. 그중 Kubernetes 프로젝트에서 공식 지원하는 NGINX Ingress Controller와 AWS ALB 로드밸런서를 이용하는 AWS ALB Ingress Controller를 두고 고민을 했습니다.타다에서는 클라이언트(모바일 앱)에 실시간 이벤트를 전달하기 위해 gRPC를 사용하고 있어서 gRPC를 지원하지 않는 ALB는 선택할 수 없었습니다. 그리고 AWS ALB Ingress Controller는 현재 Ingress 하나마다 ALB를 1개 생성하는 구조여서 앞으로 노출할 서비스 수가 늘어난다면 비용 효율이 떨어진다고 판단했습니다. 따라서 NGINX Ingress Controller를 선택하게 되었습니다.NGINX Ingress Controller는 NGINX 웹서버를 기반으로 하므로 gRPC 모듈을 비롯하여 다양한 NGINX 모듈을 통해 굉장히 세세한 부분까지 설정할 수 있습니다. NGINX Ingress Controller는 Ingress나 Ingress가 가리키는 서비스의 엔드포인트에 변화가 생길 때마다 동적으로 NGINX 설정을 업데이트하는 방식으로 동작합니다.NGINX Ingress Controller 로드밸런싱NGINX Ingress Controller를 사용해도 외부에서 오는 트래픽을 적절히 분배해 줄 외부 로드밸런서는 필요합니다. AWS의 로드밸런서는 Classic ELB, ALB, NLB가 있습니다. 앞서 설명했듯이 ALB는 gRPC를 지원하지 않아서 Classic ELB를 TCP 모드로 사용하거나 NLB를 사용해야 합니다. Classic ELB는 동시에 많은 연결을 처리하려면 웜 업이 필요한 단점이 있어 NLB를 사용하기로 하였습니다.최근 NLB가 TLS termination을 지원하기 시작했지만, HTTP/2와 gRPC를 사용하기 위해 필요한 ALPN 정보를 설정할 수 없어서 NGINX 수준에서 TLS 암호화를 처리하고 있습니다. NLB 수준에서 TLS 처리를 하면 무료로 자동 갱신되는 ACM 인증서를 사용할 수 있는 등 여러 가지 이점이 있어서 아쉽습니다.Kubernetes에서 LoadBalancer 타입의 서비스를 생성하면 알아서 AWS 로드밸런서를 만들어줍니다. 하지만 이렇게 해서 NLB를 생성하는 방식은 아직 알파 기능입니다. 따라서 먼저 NodePort 타입의 서비스를 생성하여 모든 노드의 특정 포트에 NGINX를 노출한 다음, 별도로 생성한 NLB에 노드들이 속한 오토스케일링 그룹을 연결해주는 방식으로 직접 설정하게 되었습니다.정리해보면 외부에서 오는 트래픽을 처리할 때는 다음과 같은 과정을 거칩니다.모든 서브도메인(*.tadatada.com)은 NLB를 가리킵니다.NLB의 443 포트로 암호화된 HTTP 또는 gRPC 요청이 들어옵니다. NLB는 적절한 Kubernetes 노드 중 하나의 특정 포트(예: 30000번)로 요청을 전달합니다.Kubernetes 노드에서는 포트 번호를 보고 NGINX 서비스로 향하는 요청임을 알 수 있고 NGINX 컨테이너 중 하나로 요청을 전달합니다.NGINX는 복호화를 한 다음 HTTP Host 헤더를 확인하여 요청을 전달할 Ingress를 알아냅니다. 그리고 해당 Ingress의 엔드포인트 중 하나로 복호화한 요청을 프록시합니다.애플리케이션 컨테이너가 요청을 처리합니다.트래픽 흐름: NLB → NodePort → NGINX Ingress Controller → 내부 서비스Pod에 IAM 역할 부여: kube2iamS3, SQS 등 IAM으로 인증하는 AWS 서비스에 접근하려면 인증 정보가 필요합니다. EC2에서는 액세스 키를 직접 넣는 대신 EC2 인스턴스 프로파일로 인스턴스에 IAM 역할을 부여할 수 있습니다. 하지만 하나의 Kubernetes 노드 (=EC2 인스턴스)에는 여러 Pod이 실행될 수 있기 때문에 Pod마다 다른 IAM 역할을 부여하기를 원한다면 인스턴스 프로파일을 활용할 수 없게 됩니다. (인스턴스 프로파일에는 하나의 IAM 역할만 부여 가능)kube2iam을 사용하면 다음과 같이 Pod 어노테이션으로 IAM 역할을 지정할 수 있습니다.apiVersion: v1 kind: Pod metadata: name: aws-cli labels: name: aws-cli annotations: iam.amazonaws.com/role: role-arn spec: ... 설치나 사용법은 문서를 참고하면 어렵지 않은데, 원리를 간단히 설명해 보겠습니다. EC2 인스턴스 안에서는 특정 IP 주소(169.254.169.254)로 접속하면 EC2 메타데이터 API에 접근할 수 있습니다. AWS SDK는 EC2 메타데이터 API를 통해서 인스턴스 프로파일에 붙은 IAM 역할과 IAM 역할에 해당되는 액세스 키 쌍을 받아오게 됩니다.kube2iam은 모든 노드에 실행되면서 Pod 내부에서 EC2 메타데이터 서버 주소로 나가는 모든 요청을 가로챕니다. 그리고 인스턴스 프로파일 정보와 액세스 키 발급 요청을 kube2iam 서버가 대신 처리합니다. 따라서 Pod 안에서는 인스턴스 프로파일이 부여된 EC2 인스턴스 내부에 있는 것처럼 느껴지게 됩니다.추후 AWS SDK에 EKS 지원이 추가되면 별도로 데몬을 설치하지 않고도 Pod에 IAM 역할을 줄 수 있게 될 것으로 보입니다.로그 수집: fluentd + CloudWatch LogsKubernetes의 컨테이너가 stdout/stderr로 출력하는 로그는 노드에만 쌓이고 컨테이너를 재시작하거나 삭제하면 함께 삭제됩니다. 또한 노드의 디스크가 꽉 차는 것을 방지하기 위해 일정 크기를 넘으면 오래된 로그는 없어집니다. 그러므로 로그가 사라지지 않도록 계속 어딘가에 모아두어야 합니다.AWS에서 활용할 수 있는 로그 저장 서비스에는 CloudWatch Logs가 있습니다. fluentd를 DaemonSet으로 노드마다 하나씩 실행해서 컨테이너 로그를 CloudWatch Logs로 전송할 수 있습니다.CloudWatch Logs에 저장한 로그는 최근 나온 CloudWatch Logs Insights로 검색, 분석할 수 있습니다. 아직 나온 지 얼마 되지 않아서 기능이 많지는 않지만, 간단히 조회하는 용도로는 충분합니다.CloudWatch Logs Insights 사용 예모니터링: PrometheusEC2 인스턴스 하나에 서비스 하나를 띄워서 사용할 때는 CloudWatch로 CPU 사용률 등의 지표를 측정할 수 있었습니다. 하지만 Kubernetes를 사용하면 여러 서비스가 하나의 인스턴스에서 동시에 실행될 것이므로 인스턴스 수준의 지표는 무의미합니다. 특히 최소 실행 단위인 컨테이너 수준의 CPU 사용률 같은 값을 측정해야 하는데, CloudWatch를 사용하기에는 과금 체계가 적합하지 않습니다.기본 제공되는 5분 간격의 EC2 지표는 무료지만 CloudWatch에 커스텀 지표를 올리게 되면 지표 당 비용을 지불해야 합니다. 이 때 '지표'는 지표 이름 + 고유한 차원(dimension)의 조합입니다. 예를 들어 CPUUtilization이라는 이름의 지표가 PodName=server-aaaaaaaa과 PodName=server-bbbbbbbb라는 다른 차원으로 올라온다면 각각을 다른 지표로 취급합니다. 따라서 지표 수가 너무 많아지지 않게 조정해야 하는데 그러면 상세하게 모니터링하기가 어렵습니다.비용 문제도 있고, Kubernetes의 여러 가지 정보를 CloudWatch로 내보내는 기존 도구가 없었기 때문에 다른 방법을 찾아보게 되었습니다. 그래서 Kubernetes 모니터링을 위해 많이 사용하는 Prometheus를 선택했습니다. Prometheus를 온전히 사용하기 위해서는 다양한 컴포넌트들이 필요한데, Prometheus Operator Helm 차트를 사용하면 비교적 쉽게 구축할 수 있습니다.Prometheus는 Kubernetes 클러스터 모니터링 외에 애플리케이션 모니터링에도 사용할 수 있습니다. 타다의 애플리케이션들은 Spring Boot로 작성되어 있는데 Spring Boot Actuator와 Micrometer의 Prometheus 지원을 사용해서 애플리케이션 수준의 지표도 Prometheus로 모니터링하고 있습니다. 특히 Prometheus Operator를 사용하면 모니터링 대상을 추가할 때 Prometheus 설정 파일을 수정하지 않아도 Kubernetes에 ServiceMonitor 리소스를 등록하기만 하면 되어서 편리합니다.Prometheus로 수집된 지표는 Grafana 대시보드로 시각화하고, 정해진 조건에서 Alertmanager를 통해 PagerDuty와 Slack에 알림을 보냅니다.Grafana 대시보드의 모습자동 처리량 확장: Cluster AutoscalerKubernetes에서 자동 처리량 확장은 크게 두 종류로 나눌 수 있습니다. 먼저 Horizontal Pod Autoscaler로 CPU, 메모리 사용량에 따라 Pod의 수를 자동으로 조정할 수 있습니다. HPA가 실제로 동작하기 위해서는 오토스케일링을 위한 지표를 제공하는 Metrics Server를 설치해야 합니다. 그런데 부하가 증가해서 HPA가 Pod 수를 늘리려고 할 때 워커 노드에 여유가 충분하지 않으면 새로운 Pod을 실행할 수 없어서 소용이 없습니다. 이 때 워커 노드의 수를 자동으로 조정해주는 것이 Cluster Autoscaler입니다. Cluster Autoscaler는 노드 수를 증가시키기만 하는 것이 아니라 여유가 생겼을 때 노드 수를 자동으로 줄여서 불필요한 비용이 발생하지 않도록 해줍니다.AWS 환경에서 Cluster Autoscaler는 EC2 API를 통해 EC2 오토스케일링 그룹의 Desired Capacity 값을 필요한 노드 수로 조정하는 방식으로 작동합니다. 따라서 Cluster Autoscaler에는 EC2 API를 호출할 수 있는 IAM 권한을 주어야 합니다. 이를 위해 위에서 소개한 kube2iam을 사용할 수 있습니다. 그리고 Cluster Autoscaler가 오토스케일링 그룹을 자동으로 발견할 수 있도록 미리 정해진 태그를 붙여야 합니다.한 가지 주의할 점은 노드의 오토스케일링 그룹이 여러 가용 영역(AZ)에 걸쳐있으면 안 된다는 것입니다. 오토스케일링 그룹이 여러 AZ에 속한 경우 AZ 간 인스턴스 수의 균형을 맞추려고 하는데 이 과정에서 인스턴스가 예기치 않게 종료될 수 있습니다. 이 때 해당 노드에 실행되어 있던 Pod이 안전하게 종료되지 않을 수 있기 때문에 AZ마다 오토스케일링 그룹을 따로 만들고 AZ 간 균형은 Cluster Autoscaler가 맞추도록 설정해야 합니다.도움이 되는 링크들위에서 소개한 컴포넌트들은 다음과 같은 Helm 차트를 통해 설치해서 사용하고 있습니다.stable/nginx-ingressstable/kube2iamincubator/fluentd-cloudwatchstable/prometheus-operatorstable/metrics-serverstable/cluster-autoscalerEKS Workshop: AWS 환경에서 Kubernetes 운영할 때 참고할 만한 정보가 많이 있습니다.Kubernetes Slack 채널: #eks 채널에는 AWS 직원들도 접속해 있어서 높은 확률로 답변을 받을 수 있습니다.
조회수 5228

안드로이드 백그라운드 서비스 개발시 고려해야 할 사항

지난 시간엔 사운들리 백엔드에 대해 설명을 드렸었죠. 이번 시간엔 사운들리 서비스중 클라이언트에 해당하는 안드로이드 SDK, 그 중에서도 백그라운드 서비스에 초점을 맞추어 설명을 해 볼까 합니다.안드로이드의 특징 중 하나로 Service 를 들 수 있습니다. 이 서비스란 녀석은 백그라운드에서 실행 될 수 있다는 점이 가장 큰 특징인데요. 물론 iOS 에서도 일부 지원은 합니다만 매우 제한적인 경우(음악 재생 등)에만 사용 가능합니다.제가 생각하는 백그라운드 서비스 개발 시 유의 사항은 아래와 같습니다.동작 기간 - 상시 동작 해야 하는가, 특정 조건에서 특정 작업을 할때만 동작 해야 하는가글로벌 프로세스 사용 유무 - 서로 다른 어플리케이션에서 접근이 가능 해야 하는가동작 조건 - 특정 시간 혹은 기간마다 동작 해야 하는가, 특정 이벤트 발생시 동작 해야 하는가그 외에도 많은 부분들이 있지만 일단 저 정도만 고려해도 개인적인 생각으로는 충분히 개발 가능하다고 생각 합니다.그러면 각각에 대해서 좀 더 자세하게 알아 볼까요?1. 동작 기간동작 기간에 대해서 이야기 하기 전에 먼저 유저 레벨에서 가장 많이 사용하는 Service 와 IntentService 의 차이점에 대하여 짚고 넘어가보겠습니다.Service 를 상속`Context#startService//Context#stopService` 혹은 `Context#bindService(w/BIND_AUTO_CREATE)//Context#unbindService` 를 통해 수명 조절 (Service 내에서 Service#stopSelf 를 호출하는 방법도 있습니다.)Service 시작된 이후에 커뮤니케이션 가능수명 종료 API(stopService or unbindService) 를 호출 하기 전에는 프로세스가 사라지지 않음 (물론 LMK에 의해서 종료 된다던지 등등이 있지만 여기서는 논외로 하겠습니다.)IntentService 를 상속startService 를 통해 서비스를 시작함사용자가 따로 수명 관리를 할 필요가 없음상기 특징을 보면 Service 는 상시 동작하는 서비스에, IntentService 는 특정 조건에서 동작하는 서비스에 더 특화된 것을 볼 수 있습니다.사운들리 서비스는 백그라운드에서 상시 신호를 감지해야 하므로 Service 를 상속해서 쓰고 있습니다.2. 글로벌 프로세스 사용 유무안드로이드 컴포넌트 속성 중 android:process  속성을 소문자로 시작하는 이름을 쓰면 글로벌 프로세스로 사용 할 수 있습니다. 글로벌 프로세스니까 당연히 다른 어플리케이션에서도 접근이 가능하답니다.아래와 같은 경우에는 글로벌 프로세스를 사용 할 때 더 이점이 있습니다.불필요한 리소스 사용 자제 - 서버와 통신하는 모듈의 경우, 여러 앱에서 동일한 모듈이 사용 될 때 하나의 통로만 사용 하는 것이 네트워크 리소스를 적게 먹습니다.공유 불가능한 자원 사용 - 사운들리 SDK 가 이 경우에 해당합니다. 비가청 대역 음파를 사용하는 특성상 마이크를 사용 해야 하나 안드로이드에서는 서로 다른 어플리케이션 간의 마이크 공유가 불가능합니다.하지만 일반적인 어플리케이션 서비스는 굳이 글로벌 프로세스를 쓸 필요가 없습니다. 모듈 버전에 따른 실행, 데이터 공유 등 골치 아픈게 이것저것이 아니에요... ㅠ3. 동작 조건동작 조건은 크게 time base 와 event base 로 나눌 수 있는데요. 각각의 경우에 서비스를 동작 시킬 트리거를 다르게 쓰는 것이 좋습니다.동작 조건에 따라 안드로이드에서 사용 가능한 트리거는 아래와 같습니다.시간 기반 (time base)AlarmManager 의 alarm API (set, setExact, setExactAndAllowWhileIdle 등)Android System Broadcast (ACTION_TIME_TICK 등)GCM Message이벤트 기반 (event base)Android System Broadcast (ACTION_SCREEN_ON, ACTION_POWER_CONNECTED 등)GCM Message그 외 각종 어플리케이션 사용시 발생되는 이벤트위에서 이야기한 것을 표로 정리하면 아래와 같습니다.동작 기간동작 조건사용해야할 서비스동작 트리거그 외상시동작시간기반 동작Service 를 상속 받아 startService 서비스 시작bindService 를 통해 서비스와 연결하여 커뮤니케이션해당 Service 는 START_STICKY 로 실행AlarmManager 혹은 서버에서 주기적으로 동작하는 GCM Message 사용글로벌 프로세스를 사용 해야 한다면 android:process 속성을 사용이벤트 기반 동작System Broadcast 혹은 GCM Message, JobService 등을 사용작업 할때만 동작시간 기반 동작IntentService 를 상속받아 startservice 로 실행Intent 에 작업 관련된 파라매터를 전달AlarmManager 혹은 서버에서 주기적으로 동작하는 GCM Message 사용이벤트 기반 동작System Broadcast 혹은 GCM Message, JobService 등을 사용Etc. 유의해야 할 부분추가로 백그라운드 서비스 개발 시 유의해야 할 점들을 기술 해 보겠습니다.i) 배터리 절전 기술안드로이드 버전이 올라갈수록, 그리고 벤더들의 기술력이 높아질수록 배터리 절전 기술 역시 발전합니다. 이러한 기술들은 사용자 입장에서는 반가운 기술이지만 개발자들에게는 종종 절망을 선사합니다 ㅜㅜ사운들리 서비스도 개발 과정에서 각종 절전 기술 때문에 고생을 했는데요, 크게 고생한 기술 및 특징은 아래와 같습니다.DozeAndroid 6.0 이후 버전에 적용아래의 상태에서 일정 시간 이후 Doze 모드 진입충전 중이 아님스크린 꺼져 있음일정 수치 이상 움직이지 않음제한되는 사항AlarmManager 의 AlarmJobServiceWakeLock 무시네트워크 접근 제한회피 방법AlarmManager#setExactAndAllowWhileIdle() - Doze 에서도 동작하지만 최대 15분에 한 번씩만 동작 가능GCM high priority messageApp StandbyAndroid 6.0 이후 버전에 적용일정 기간 동안 아래 상황 중 하나도 발생하지 않은 경우 시스템에서 해당 앱을 standby state 로 간주명시적 앱 실행액티비티나 서비스가 포그라운드(전경)에서 실행 중, 혹은 포그라운드에서 실행 중인 앱이 해당 앱의 컴포넌트 사용중알림을 생성하고 유저가 잠금 화면이나 알림 트레이에서 확인한 경우제한되는 사항네트워크 사용 및 동기화 기능 사용 불가회피방법유저와 상호 작용유저가 디바이스 충전스마트 매니저삼성에서 킷캣 (안드로이드 4.4) 이후의 모델 (일부 제외)에 적용일정 시간 이상 유저가 사용하지 않은 앱은 알림 생성 불가관련글: 구글 개발자 블로그의 Android M 관련 변경점ii) LMK (Low Memory Killer)안드로이드의 각각의 프로세스는 특성에 따라 상태가 부여됨각 상태는 제한되는 메모리 사이즈가 정해져 있고, 디바이스의 가용 메모리가 해당 사이즈 이하로 떨어질 시 시스템에서 프로세스를 종료START_STICKY 로 실행한 서비스의 경우 일정 시간 이후에 null Intent 를 가진채로 재시작킷캣 이상에서 PID가 0이 된 채로 남아있는 버그가 있음ActivityManager#getRunningServices 에서 서비스 리스트를 가져 왔을때 찌꺼기가 존재마치며보기엔 복잡해 보이지만 사실 서비스 기획에 맞게 기능들을 골라서 쓰기만 하면 되니까 생각보단 복잡하진 않습니다. '사용자 중심의 나이스한 서비스 기획' 만 있으면 위의 표에서 기능을 골라서 조립만 하면 됩니다.물론 실제 개발 시에는 훨씬 더 고민 해야 될 부분이 많을 겁니다. 네트워크 트래픽도 최소화 해야 하고, WakeLock 도 적절히 써야 하고, 글로벌 프로세스 사용시는 DB 동기화도 시켜야 하고 GCM 은 downstream 이냐  group 이냐 topic 이냐 등등...개인적인 전망으론 장기적으로 Google 에서도 iOS 처럼 백그라운드 서비스 사용에 점점 제한을 둘 것 같습니다. 하지만 완전히 없애진 않을 것 같네요. 나름 특색 이니까요. 그러니 없애지만 않으면 방법을 찾아 낼 수 있을 겁니다.너무 두서없이 주저리주저리 쓴 글 같지만 조금이라도 도움이 되었으면 좋겠습니다.#사운들리 #개발 #개발자 #안드로이드 #안드로이드개발 #앱개발 #앱개발자 #SDK #인사이트 #조언 #경험공유
조회수 1109

테이블을 내 마음대로! 컬럼 추가와 삭제, 테이블 분리

Overview이전까지는 단일 테이블에서 INDEX를 적용하는 효과적인 방법들을 살펴봤습니다. 아직 못 본 개발자를 위해 친절히 링크도 준비했습니다. 이 글을 보기 전에 아래의 글들을 먼저 보는 것이 좋습니다.단일 TABLE을 SELECT하자!: 올바른 SELECT문 작성하기순서대로 척척, ORDER BY: ORDER BY 조건 처리 알아보기원하는 대로 뭉치는 GROUP BY: GROUP BY 조건 처리 알아보기이번 글에서는 테이블에서 컬럼을 추가 또는 삭제하고, 테이블을 분리하는 방법까지 알아보겠습니다.Let’s do it먼저 아래의 컬럼을 추가해봅시다.ALTER TABLE test.TB_MBR_BAS ADD COLUMN AREA_NM    VARCHAR(10)    COMMENT '지역 명'; 그리고 테스트 자료를 넣습니다.UPDATE test.TB_MBR_BAS SET     AREA_NM =         CASE FLOOR(RAND()*15)             WHEN 0    THEN '서울특별시'             WHEN 1    THEN '부산광역시'             WHEN 2    THEN '인천광역시'             WHEN 3    THEN '대전광역시'             WHEN 4    THEN '대구광역시'             WHEN 5    THEN '광주광역시'             WHEN 6    THEN '울산광역시'             WHEN 7    THEN '경기도'             WHEN 8    THEN '강원도'             WHEN 9    THEN '충청남도'             WHEN 10    THEN '충청북도'             WHEN 11    THEN '전라남도'             WHEN 12    THEN '전라북도'             WHEN 13    THEN '경상남도'             WHEN 14    THEN '경상북도'             WHEN 15    THEN '제주도'         END WHERE AREA_NM IS NULL ; 자료를 확인하면 아래와 같이 나옵니다.SELECT     * FROM test.TB_MBR_BAS ; AREA_NM 컬럼을 추가해 지역이 나오도록 했습니다. AREA_NM을 보면 중복되는 지역명이 있습니다. 이럴 때 보통 AREA_NM을 별도의 테이블을 만들어 ID OR 코드를 부여해 처리합니다. 위의 UPDATE 문을 참조하여 ID를 만들면 아래와 같이 만들 수 있습니다.0    : ‘서울특별시’1    : ‘부산광역시’2    : ‘인천광역시’3    : ‘대전광역시’4    : ‘대구광역시’5    : ‘광주광역시’6    : ‘울산광역시’7    : ‘경기도’8    : ‘강원도’9    : ‘충청남도’10    : ‘충청북도’11    : ‘전라남도’12    : ‘전라북도’13    : ‘경상남도’14    : ‘경상북도’15    : ‘제주도’먼저 AREA_NM과 ID를 다룰 테이블을 만들겠습니다.CREATE TABLE test.TB_AREA_BAS  (     AREA_ID        TINYINT UNSIGNED NOT NULL    COMMENT '지역 아이디 '     ,AREA_NM     VARCHAR(10)             NOT NULL    COMMENT '지역 명'     ,PRIMARY KEY (AREA_ID)  ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='TB 지역 기본' ; 테이블을 만들었으면 자료를 넣어줍니다. INSERT INTO test.TB_AREA_BAS  (     AREA_ID      ,AREA_NM  ) VALUES (0,'서울특별시')  ,(1,'부산광역시')  ,(2,'인천광역시')  ,(3,'대전광역시')  ,(4,'대구광역시')  ,(5,'광주광역시')  ,(6,'울산광역시')  ,(7,'경기도')  ,(8,'강원도')  ,(9,'충청남도')  ,(10,'충청북도')  ,(11,'전라남도')  ,(12,'전라북도')  ,(13,'경상남도')  ,(14,'경상북도')  ,(15,'제주도')  ; 자료를 확인하면 아래와 같이 나옵니다.SELECT     * FROM test.TB_AREA_BAS ; 테이블을 만들었다면 test.TB_MBR_BAS 테이블에 AREA_ID 를 추가하여 자료를 넣은 후 AREA_NM 컬럼을 삭제하면 됩니다.이제 AREA_ID를 추가합니다.ALTER TABLE test.TB_MBR_BAS ADD COLUMN AREA_ID TINYINT UNSIGNED NOT NULL COMMENT '지역 아이디'; AREA_NM을 참조하여 AREA_ID를 넣습니다.UPDATE test.TB_MBR_BAS SET     AREA_ID =         CASE AREA_NM             WHEN '서울특별시'    THEN 0             WHEN '부산광역시'    THEN 1             WHEN '인천광역시'    THEN 2             WHEN '대전광역시'    THEN 3             WHEN '대구광역시'    THEN 4             WHEN '광주광역시'    THEN 5             WHEN '울산광역시'    THEN 6             WHEN '경기도'    THEN 7             WHEN '강원도'    THEN 8             WHEN '충청남도'    THEN 9             WHEN '충청북도'    THEN 10             WHEN '전라남도'    THEN 11             WHEN '전라북도'    THEN 12             WHEN '경상남도'    THEN 13             WHEN '경상북도'    THEN 14             WHEN '제주도'    THEN 15         END ; 자료를 확인하면 아래와 같이 나오는데요.SELECT     * FROM test.TB_MBR_BAS ; 최종적으로 AREA_NM 컬럼을 삭제합시다.ALTER TABLE test.TB_MBR_BAS DROP COLUMN AREA_NM; 삭제했다면 자료를 확인해봅시다.SELECT     * FROM test.TB_MBR_BAS ; 이제 두 개의 테이블을 연결해서 조회해보겠습니다. JOIN을 사용하면 되고, Quey 문은 아래와 같습니다.SELECT     T101.MBR_ID      ,T101.MBR_INDFY_NO      ,T101.MBR_NM      ,T101.AGE      ,T101.AREA_ID      ,T102.AREA_NM FROM test.TB_MBR_BAS T101      INNER JOIN test.TB_AREA_BAS T102          ON T102.AREA_ID = T101.AREA_ID  ; 정리하며위에서 보여드린 예시는 두 가지 다른 점이 있습니다. 첫째는 TABLE 뒤에 T101, T101 과 같은 얼라이스를 준 것, 둘째는 INNER JOIN 문장이 들어간 것입니다.만약 테이블이 2개 이상이라면 사용할 테이블 컬럼을 써야 하는데 테이블명을 그대로 쓴다면 너무 길어집니다. 그래서 얼라이스로 테이블을 간단하게 표시하는 것이죠.INNER JOIN은 JOIN 중 가장 기본이 되는 문장입니다. 플랜을 보면 T101 즉 test.TB_MBR_BAS를 차례대로 전부 읽는데, 그때마다 T102인 test.TB_AREA_BAS 를 AREA_ID 를 기준으로 값을 읽습니다. T101에 해당하는 내용과 T102에 해당하는 내용을 보여주는 것이죠. 저는 Database를 쓰는 이유가 바로 JOIN 때문이라고 생각하는데요. 여러분의 생각은 어떤가요. 조금 헷갈린다면 다음에는 JOIN에 대해서 알아보도록 하겠습니다. (자연스러운 결말..!)글한석종 부장 | R&D 데이터팀[email protected]브랜디, 오직 예쁜 옷만#브랜디 #개발문화 #개발팀 #업무환경 #인사이트 #경험공유
조회수 295

프로그래밍 수업의 모든 것.

안녕하세요 엘리스입니다. :)엘리스의 프로그래밍 수업은 누구에 의해서, 어떻게, 어떤 생각을 바탕으로 만들어질까요?미래를 이끌어나갈 컴퓨터 사이언스 기술과 그 근간이 되는 교육 사이에서 좋은 프로그래밍 수업을 만들기 위해 치열하게 고민하는 엘리스의 코스 매니저가 직접 이야기합니다! 마침 엘리스는 코스 매니저 채용 중에 있으니 관심이 있다면 눈여겨 봐주세요!코스 매니저가 관여한 프로덕트로 인하여 사용자가 성장을 하고 있다면 그것은 충분히 의미 있는 일.안녕하세요 저는,트라우마를 극복한 프로그래밍 수업 크리에이터.Q. 자기소개 부탁드려요.A. 엘리스의 프로그래밍 과목을 만드는 코스 매니저 이용희입니다.Q. 엘리스에서 일하게 된 이유는 무엇인가요?A. 원래는 프로그래밍에 대한 트라우마가 있었어요. 하지만 기술 창업에 대한 꿈이 있었기 때문에 프로그래밍은 극복해야 할 산이었죠. 엘리스는 가장 뛰어난 기술자들이 모여 창업한 스타트업이에요. 당연히 기술 창업을 가장 가까이에서 경험할 수 있는 매력적인 곳으로 느껴졌죠. 그리고 프로그래밍 교육을 제공한다는 것 역시 기회로 느껴졌어요. 저와 같이 프로그래밍을 미워하고 두려워하는 사람들에게 보다 쉽게 배울 수 있는 환경을 마련해주고 싶다는 기대로 일을 시작하게 되었습니다.Q. 두려운 대상을 향해 몸을 던지셨군요! 그런데 코스 매니저가 프로그래밍을 몰라도 되나요?A. 많이 알면 알수록 당연히 좋아요. 많이 알고 있을수록 시도할 수 있는 것도 많고 학생에게 전달해줄 수 있는 것은 더욱더 많기 때문에요. 하지만 최소한으로는 Class가 뭔지 알고 있으면 OK. 예를 들어서 코드를 보고 이 코드가 어떤 목적을 갖는지 알 수 있으면 직접 코딩을 하지는 못한다고 해도 괜찮아요.Q. 코스 매니징 외에도 라이브 수업 참여, 조교, 챌린지 사회자 등 많은 역할을 하셨는데 이유가 있나요?A. 좋은 수업을 만들기 위한 첫 번째 방법은 코스를 만드는 모든 과정에 참여하는 사람들의 역할을 직접 체험해 보는 것이라고 생각했어요. 학생으로서, 조교로서, 사회자나 라이브 어시스턴트로서. 이렇게 하니까 학생으로서 수업을 접할 때의 감상은 무엇인지, 조교로서 가르쳤을 때는 어떤 어려움이 있는지를 알 수 있었어요. 라이브 수업 어시스턴트로 참여했을 때는 방송하시는 선생님들의 애로사항을 알 수 있겠더라고요.코스 매니징의 정수.프로그래밍적 성장을 도움으로써 가치를 만들어 냅니다.Q. 코스 매니징의 A to Z는? 구체적인 업무 프로세스가 궁금해요.A. 크게 기획 - 모집 - 제작 - 분석의 네 단계로 이루어져 있어요. 1. 수업 기획 -  어떤 과목을 만들 것인가? 주차별로 무엇을 다룰 것인가? 흥미로운 콘텐츠는? 2. 선생님, 조교 모집 - 엘리스가 구상한 수업을 가장 잘 전달할 수 있는 선생님과 조교를 모집. 3. 수업 제작 및 운영 - 실습 문제, 강의 자료 등을 엘리스의 색깔로 제작하여 수업을 운영. 4. 데이터 분석 - 학생들의 피드백과 데이터를 다음 수업의 발전 및 교육자와의 관계 개선에 반영.Q. 업무 방식은? 어떤 메리트가 있나요?A. 처음부터 끝까지 모든 과정을 주도해나가는 방식이에요. 어떤 회사를 가도 프로덕트의 end to end 프로세스를 전부 경험하기는 어려운데 엘리스에서는 그 전 과정을 경험할 수 있어요. 저는 이러한 경험이 교육 업계나 특정 프로덕트에만 적용할 수 있는게 아니라 다른 업계에 간다고 하더라도 충분히 전환될 수 있는 좋은 경험이라고 생각해요.Q. 미래 산업의 근간이 될 교육을 직접 만든다는 중책을 맡고 계신다고 생각하는데요, 좋은 프로그래밍 수업을 만들기 위해 어떤 노력들을 하시나요?A. 그런 영향을 미칠 수 있다는 게 무서운 일인 것도 같아요. 어떤 사람들은 엘리스를 통해서 프로그래밍을 처음 접하는 것일 수도 있는데 그 경험이 불쾌했다면 앞으로 프로그래밍을 배울 생각이 전혀 들지 않을 수도 있는 거잖아요. 그래서 최대한 다양한 피드백을 받아서 수렴하려고 해요. 외적으로는 대학강의, 수많은 수업들을 참고해요. 여러 강의를 보다보면 좋은 예도 많지만 모든 수업이 재미있지는 않아요. 중간에 듣다 마는 경우도 있고요. 그럴 때마다 내가 왜 중단했고 어떤 요소를 바꾸면 엘리스에서는 학생들이 끝까지 들을 수 있을까 고민해서 반영하려고 하죠.Q. 언제 보람을 느끼나요?A. 내가 관여한 프로덕트가 누군가에게 임팩트를 만들어내고 나뿐만 아니라 프로덕트를 사용하는 사람들이 성장을 하고 있다면 그것은 충분히 가치 있는 일인 것 같아요. 저희 플랫폼에서는 대시보드를 통해서, 그리고 학생이 코드를 어떻게 짜고 있는지 보면서 그 결과를 가시적으로 확인할 수 있어요. 누군가 제가 만든 코스를 수강함으로써 실질적으로 성장하는 게 눈에 보일 때 가장 큰 보람을 느끼는 것 같아요.한 번은 한 선생님께서 학생으로부터 ‘선생님 덕분에 취업할 수 있었어요’라는 메시지를 받은 것을 엘리스와 공유해주셨는데 그때 정말 행복하더라고요. 이게 엘리스가 추구하는 거다,라는 생각을 했어요. 엘리스도 하나의 커뮤니티이고 싶거든요. 이 경우에는 학생-선생님-엘리스가 서로의 영향으로 좋은 결과를 만들어 낸 거죠. 이런 접점을 앞으로 더 많이 만들려고 생각하고 있어요.대시보드에 나타나는 학생들의 학습 현황 및 성취도.엘리스는 이런 팀.가치, 성장, 사람. 포기할 수 없는 세 가지가 있는 곳.Q. 함께 일하는 동료들은 어떤 사람들인가요? 총평을 하자면?A. 항상 내가 최고의 사람들과 함께하고 있다라는 확신이 있어요. 각자 자기 분야에서 최고의 실력을 가진 사람들과 함께 일한다는 것만으로도 큰 자극이 되죠. 프로그래밍이든 스타트업 생존 노하우든 항상 뭔가를 새롭게 배우고 성장하게끔 동기부여를 해주는 사람들이에요. 저는 트라우마가 있었을 정도로 프로그래밍을 두려워했지만 이들과 함께 일하며 작은 피드백을 하나 듣는 것만으로도 제 실력이 빠르게 성장한다는 것을 몸소 느낄 수 있었어요. Q. 엘리스의 분위기, 팀 문화는 어떤가요?A. 새로운 것에 도전하는 것을 환영하는 수평적이고 자유로운 팀. 인턴도 아이디어를 제시할 수 있어요. 이 다음이 더 중요한데, 아이디어에서 그치는 게 아니라 활발한 피드백이 오가요. 아이디어를 실행하기 어렵다고 판단하더라도 왜 그렇고 어떻게 발전시킬 수 있는지 이야기하죠. 실행하게 되었을 때는 아이디어를 제시한 사람에게 일에 대한 권한이 전적으로 주어지고요. 저도 처음엔 파트타임 인턴이었지만, 이런 팀문화 덕분에 계속해서 업무 범위를 확장하고 제 역량을 키울 수 있었어요.코스 매니저 채용.Generalist & Infinite LearnerQ. 현재 코스 매니저를 구인하고 있는데요. 코스 매니저에 적합한 성향이 있나요?A. 두 단어가 떠오르네요. Generalist, 그리고 Infinite Learner. 깊게 한 분야를 아는 사람보다는 얕고 넓게 아는 사람이 더 적합하다고 생각해요. 다르게 말하면 새로운 것을 시도하는 것을 좋아하고 새로운 것을 접할 때 포용력이 높은 사람이요. 두 번째로는 배움에 재미를 느끼는 사람. 엘리스는 교육 스타트업이고 코스 매니저는 직접 교육의 경험을 만드는 사람이니 스스로가 배움에서 행복을 느끼는 사람이라면 훨씬 더 재미있게 일할 수 있겠죠. 한 가지 덧붙이면, 데이터 분석을 배우고 싶은 분께 엘리스는 최고의 장소입니다.Q. 코스 매니저로서 갖추고 있으면 좋은 역량이나 자질이 있다면?A. 소통 능력과 균형 감각. 코스 매니저는 수업을 만드는 모든 단계에서 다양한 이해당사자들과 일하게 돼요. 이들과 원활하게 소통하고 의견을 공유하는 게 중요하죠. 그리고 다양한 사람들 사이에서 최고의 균형을 찾아내는 것도 중요해요. 예를 들어서 선생님의 경우 개발만 해왔고 교육이라는 것을 접해본 적이 없는 분들이 대부분이고, 학생은 프로그래밍을 처음 접하면 그 수업이 좋은 건지 아닌지 평가하기 어려워요. 때문에 코스 매니저가 이 둘 사이에 다리를 놓는 중재자의 역할을 하기 위해서는 다양한 시각에서 볼 수 있는 균형 감각이 필요하다고 생각해요.
조회수 3941

Eclipse Memory Analyzer 소개

안드로이드 개발을 하다보면 종종 OutOfMemory(OOM)에러를 만나게 됩니다. 이전에 올렸던 포스팅에서도 이 문제로 고생을 했는데요, 메모리 누수 관련 문제는 로직 에러와는 달라서 찾기가 매우 난감한 경우가 많습니다. 이러한 메모리 누수 관련 문제를 해결하기 위한 검사 기능을 제공하는 무료 툴이 있습니다. 바로 Eclipse MAT(Memory Analyzer)(MAT)입니다.Eclipse MATMAT은 사용자로 하여금 힙 메모리의 상황을 파악하게 해주어 메모리 누수 현상과 필요없는 메모리 할당을 감지할 수 있도록 도와줍니다. 또한 자동으로 보고서를 작성하여 어떤 객체들이 메모리 누수를 일으키는지에 대한 추측을 해주는 기능을 제공합니다. MAT은 Eclipse 플러그인이기 때문에 사용하려면 Eclipse가 깔려 있어야 합니다. MAT을 설치하려면 MAT 다운로드 페이지에서 자신의 Eclipse버전에 맞는 파일을 받으시면 됩니다.How to use MATMAT을 설치하였다면 Eclipse화면에서 MAT관련 탭이 뜹니다. 탭을 클릭 하고File -> Open Heap Dump 를 누르면 힙 상황이 기록 된 hprof파일을 읽어올 수 있습니다.탭이 뜨지 않는다면Window -> Open Perspective -> Other에서 Memory Analysis 를 누르면 탭이 뜨는 것을 볼 수 있습니다.hprof 파일을 읽어오면 분석을 시작하고 결과를 Overview 화면에 보여줍니다.파이 차트의 각 부분에 마우스를 갖다 대면 옆의 Inspector 화면에 해당 객체의 정보를 보여주는 것을 볼 수 있습니다.InspectorInspector 창에서는 선택된 객체의 내용을 볼 수 있습니다. 해당 객체의 클래스명과 패키지 명 그리고 해당 객체가 가지고 있었던 변수의 내용을 살펴볼 수 있습니다.유용한 기능들MAT에서 가장 중요하게 살펴볼 기능이라고 한다면 Leak suspoect report와 Dominator tree라고 볼 수 있습니다. Leak suspect와 Dominator tree 둘 다 가장 메모리를 많이 차지하고 있는 객체에 대한 정보를 제공합니다.Leak suspectLeak suspect는 가장 큰 용량을 차지하고 있는 객체들을 좀 더 세분된 파이 도표로 보여줍니다. Problem suspect 1을 보면 현재 이 스레드 객체의 크기가 전체 힙 메모리의 크기 중 19.73%를 점유하고 있다는 것을 알 수 있습니다. 전체의 20% 가까이 차지하고 있다는 것은 이 객체를 OOM의 범인(?)이라고 생각할 근거가 됩니다. 해당 객체에 대한 더 자세한 정보를 얻고 싶다면 Details을 클릭하면 됩니다.Dominator treeDominator tree를 띄우면 현재 덤프 된 매모리 스냅 샷 중 가장 큰 용량을 차지하고 있는 객체 순으로 정렬하여 보여줍니다. Leak suspect와 비슷해 보이지만 더 구체적인 정보를 제공한다는 점이 다릅니다. 따라서 Leak suspect로 현 상황에 대한 힌트를 얻은 후 Dominator tree에서 디테일하게 살펴보는 것이 시간을 절약하는 방법입니다.상위에 있는 몇몇 객체들이 가장 의심 되는 객체들이라고 볼 수 있겠습니다. 왼쪽의 화살표를 클릭함으로써 그 객체가 참조하고 있는 다른 객체들에 대한 정보들을 볼 수 있습니다. 각 객체를 클릭하면 옆에 Inspect창의 내용이 달라지는 것을 볼 수 있습니다.실제 이 스냅 샷은 이전 포스팅의 문제를 해결하려고 떠놓은 스냅 샷인데요, 이 결과를 보고 많은 메모리가 네트워크를 통해 받아오는 스트림을 처리하고 문자열로 가공하는데에 낭비되고 있다는 생각이 들어 다른 방법으로 우회하는 방법을 썼고 결과적으로 문제를 해결 할 수 있었습니다.Android에서 MAT사용법먼저 안드로이드 기기에서 힙 덤프를 수행하여 hprof파일을 생성해야 합니다. hprof파일을 생성하기 위해서 간단하게 취할 수 있는 2가지 방법이 있습니다.1. DDMS를 이용한 추출Eclipse의 DDMS를 이용하여 힙 덤프를 추출할 수 있습니다. 아 방법을 쓰려면 앱의 메니페스트 파일에 WRITE_EXTERNAL_STORAGE 권한을 부여해야 하며, sdcard에 쓸 수 있는 권한이 있어야 합니다. 이 방법을 통해 sdcard경로에 앱 패키지명의 hprof파일이 생성됩니다.2. Heap dump method안드로이드 API에서 제공하는 메서드 중에 hprof파일을 생성하는 메서드인 dumpHprofData가 있습니다. 이 메서드는 Debug 클래스의 메서드인 것을 알 수 있는데, 이 Debug 클래스에는 앱의 상태를 점검할 수 있는 여러 유용한 메서드가 있으므로 나중에 필요하면 사용할 수 있도록 익혀두면 좋습니다.Android hporf 파일 변환앞서 설명한 방법을 적용하여 hprof파일을 추출하였어도 안드로이드에서 추출한 hprof파일은 MAT에서 받아들이는 일반적인 hprof포맷과 다르기 때문에 먼저 변환하는 과정이 필요합니다. 이러한 기능을 제공하는 것이 기본 SDK에 포함된 hprof-conv유틸입니다. 이 유틸은 SDK폴더 내의 tools폴더 안에 있는데 사용하려면 콘솔에서$ hprof-conv <안드로이드용 hprof 파일> <변환할 hprof 파일> 를 치시면 됩니다. 이제 변환된 파일을 MAT에서 열면 분석을 하실 수 있습니다.More tipEclipse Memory Analyser (MAT) - TutorialMemory Analyzer BlogJava Performance blog상기의 사이트들은 MAT과 Java의 메모리 처리에 관련된 내용을 포스팅한 사이트들입니다. 한 번 들러보면 좋은 정보를 얻을 수 있을것입니다.#스포카 #꿀팁 #개발 #개발자 #스킬스택 #스택소개 #인사이트
조회수 1182

Event-Driven Programming

Overview마이크로 서비스 사이의 결합도를 낮추고 비동기적인 문제들을 처리할 때는 Event-driven 아키텍쳐가 유용합니다. 이번 글에서는 AWS에서 제공하는 SNS Topic을 이용해 Event-Driven을 알아보겠습니다. Event-Driven Programming프로그램의 제어 흐름이 이벤트의 발생에 의해 결정되는 컴퓨터 프로그래밍 패러다임입니다. publish/subscribe (이하 pub/sub)메시징서버리스 및 MSA에서 안정성 및 확장성을 높이기 위하여 사용되는 비동기 서비스 통신 방법입니다. 게시된 메시지를 다른 시스템에 비동기적으로 전달하고, Topic을 구독하는 모든 구독자는 모든 메시지를 받을 수 있습니다. 특히 게시자는 누가 구독하고 있는지 알지 않아도 되고, 구독자도 메시지의 출처를 알 필요는 없습니다. pub/sub 메시징 기본 / 출처: AWS Compute BlogAmazon SNS Topicpub/sub 방식의 메시징 서비스입니다. AWS의 여러 서비스들이 SNS에 이벤트를 게시할 수 있습니다. SNS Event Publishers / 출처: AWS Compute Blog위의 그림과 같이 구독자는 게시자 서비스에서 트리거된 이벤트에 응답해 필요한 작업을 진행합니다. 예시로 Elastic Transcoder 서비스에서의 Topic을 활용해보겠습니다. 네 가지의 순서를 거칩니다.1. SNS 토픽 생성2. Elastic Transcoder 등록Optional 항목인 Notification 영역에서 상태별 이벤트를 설정할 수 있습니다. On Completion Event에 위에서 생성한 Topic을 선택해 이벤트를 전달받도록 설정합니다. 3. SNS Topic에 구독자로 등록트랜스 코딩이 완료 후 처리할 프로세스를 가진 Lambda 함수 생성하여 위에서 생성한 SNS Topic에 구독자로 등록합니다. 현재 SNS Topic에서 제공하는 프로토콜은 HTTP, HTTPS, Email, Email-JSON, Amazon SQS, Application, AWS Lambda, SMS가 있습니다.4. 서비스 간 이벤트 전달출처: AWS Compute BlogSNS Topic으로 이벤트를 제공하는 AWS 서비스 중 하나를 살펴봤습니다. 이를 이용하면 마이크로 서비스 간에 이벤트를 전달하고 서비스의 분리 및 확장에 유용하게 사용할 수 있습니다.Conclusion오늘은 SNS Topic을 이용한 Event-Driven을 알아봤습니다. 다음 글에서는 마이크로 서비스에서 사용할 수 있는 AWS 서비스들을 다뤄보겠습니다.참고Event-Driven Computing with Amazon SNS and AWS Compute, Storage, Database, and Networking Services글이상근 팀장 | R&D 개발1팀[email protected]브랜디, 오직 예쁜 옷만#브랜디 #개발문화 #개발팀 #업무환경 #인사이트 #경험공유
조회수 2615

PHP CI 환경에서 완전한 Vue 사용하기

편집자 주Vue 또는 VUE로 혼용하나 공식 사이트의 표기에 맞춰 아래와 같이 통일함-Vue-Vuex-Vue-Router목차1.Controller2.VIEW3.webpack Vue 소스 진입점4.webpack 설정5.Package.json6.Vue-Router7.Vuex8.공통 처리 mixin9.요약10.마치며시작하며드디어 브랜디 관리자 서비스에 Vue를 도입하고자 떠났던 여정의 마지막 장입니다. 브랜디 관리자 서비스는 PHP Codeigniter와 jQuery로 구성되어 있습니다. 사실 잘 운영되고 있는 서비스에 리스크가 큰 신기술을 도입하는 것은 도박에 가깝습니다. 몇 시간만 운영이 정지되어도 회사에 엄청난 피해를 안겨줄 수도 있으니까요. 하지만 여러 번의 검증과 실험으로 도박에서 이길 확률을 100%에 가깝게 끌어올린다면 한번 도전해볼 만하지 않을까요?이전 글인 PHP Codeigniter 환경에서 VUE 사용해보기에서 기본적인 webpack + Vue + Codeigniter 환경 구축 방법을 알아봤는데요. 하지만 단순히 webpack과 Vue만 적용했다고 해서 “우리 시스템은 UI 프레임워크로 Vue를 사용하고 있습니다.”라고 말할 순 없습니다. 아주 중요한 숙제가 남았죠.Vue에는 활용도를 대폭 끌어올려주는 Vue-Router와 Vuex Store1)가 있는데 그중 Vue-Router를 이번 글에서 자세히 다루려고 합니다.2) Vue-Router는 Vue.js의 공식 라우터입니다. 공식 홈페이지의 소개는 아래와 같습니다.중첩된 라우트/뷰 매핑모듈화된, 컴포넌트 기반의 라우터 설정라우터 파라미터, 쿼리, 와일드카드Vue.js의 트랜지션 시스템을 이용한 트랜지션 효과세밀한 내비게이션 컨트롤active CSS 클래스를 자동으로 추가해주는 링크HTML5 히스토리 모드 또는 해시 모드(IE9에서 자동으로 폴백)사용자 정의 가능한 스크롤 동작한마디로 정리하면 입력된 URL에 반응해 부분에 해당 URL의 view를 보여주는 기능인 것입니다. 다시 말해 URL이 변경될 때 한 페이지에서 화면 전체를 갈아끼우거나, 화면의 일부분(부분)을 치환해주는 역할을 한다는 것이죠. 더 나아가 해당 화면이 로드되기 전후로 전처리, 후처리 기능까지 가능합니다.착안점Vue와 Vue-Rotuer를 알게 되었을 땐 PHP 기반 프로젝트에 Vue-Router를 적용할 수 없으니 처음부터 새로 만들어야 한다고 생각했습니다. 로그인 인증 문제, 메뉴의 권한 관리 등 모든 것이 Vue 아래에 있어야 한다고 생각했기 때문입니다.어느 날 관리자 서비스에 TDD를 구현해보려고 Python Flask + webpack + Vue 프로젝트를 구성하고 있었습니다. 그러던 중 우연히 Flask + Vue-Router에서 404 페이지를 처리하려면 Flask Fallback 페이지를 Vue-Router 메인 페이지(가 있는 페이지)로 보내고, Vue-Router에서 진짜 매핑된 URL이 없으면 404 처리를 하는 식으로 구성한다는 글을 읽고 문득 호기심이 생겼습니다.‘관리자 서비스에서도 컨트롤러로 여러 URL을 한 가지 페이지로 보낸다면?’PHP를 거쳐 페이지로 이동한 것이므로 권한 관리와 메뉴 트리까지는 PHP에서 처리되면서 URL이 변할 것이고, 실제로 화면을 보여주는 Contents 영역만 를 사용한다면 어떻게 될지 궁금해졌습니다. 바로 하던 일을 멈추고 관리자 소스에 Vue-Router를 활용한 테스트 소스코드를 작성해봤습니다.예상했던 대로 PHP의 로그인 인증 처리를 거치면서 실제로 보이는 부분에는 부분만 정상적으로 치환되었습니다. 이 간단한 실험을 바탕으로 통계 시스템의 일부를 구현하는 데에 Vue-Router와 Vuex Store, 공통 처리 Mixin을 추가해 제작했습니다.1.Controller4개의 페이지를 가진 통계 시스템의 Codeigniter 컨트롤러 모습입니다. 기존의 서비스 URL들이 존재하기 때문에 Fallback을 통으로 Vue-Router로 보낼 순 없었고, 라우터를 사용할 페이지들을 하나의 페이지로 보냈습니다.1-1) /application/controllers/[컨트롤러 경로]... 생략 /* [라우터 view]에서 태그를 포함하고 있습니다. */ public function salesAnalysisProduct() { $this->load->view('[라우터 view]'); } public function salesAnalysisSeller() { $this->load->view('[라우터 view]'); } public function trendAnalysisProduct() { $this->load->view('[라우터 view]'); } public function trendAnalysisSeller() { $this->load->view('[라우터 view]'); } ... 생략 2.VIEWCodeigniter 환경에 반영하는 것이므로 CI에서 인식시킬 PHP view와 webpack에서 빌드 결과를 자동으로 바인딩할 html 파일로 구성됩니다.2-1)/application/views/[Vue용 view 경로]/index.php// [index.php] Vue 를 매핑할 php파일 컨트롤러의 view로딩용 [라우터 view]입니다. ... header, menu 생략 ... //바인딩될 부분 //자동매핑 html 인클루드 <?php include('index.html'); ?> ... footer 생략 ... 2-2)/application/views/[Vue용 view 경로]/index.html webpack의 빌드 결과로 자동으로 생성되는 파일입니다. [removed][removed] 위는 webpack의 HtmlWebpackPlugin에 의해 자동으로 바인딩된 모습입니다. 빌드되기 전 index.html은 다음 항목에 있습니다.3.webpack Vue 소스 진입점관리자에서는 프로젝트 폴더 안에 webpack과 Vue 용 서브 폴더를 두고 webpack.config.js에서 output 옵션을 통해 빌드 결과를 삽입하는 구조입니다. webpack 루트 폴더는 application 폴더와 같은 레벨에 위치하며, 폴더 구조나 파일 위치는 어디에 둬도 상관없습니다. webpack.config.js에서 entry 속성으로 잡아주시면 됩니다.3-1)/[webpack루트]/index.html// HtmlWebpackPlugin으로 스크립트를 삽입하기 위한 빈 템플릿 파일 3-2)/[webpack루트]/index.js/** * 진입용 index.js */ import Vue from 'vue' import axios from 'axios' import router from './router' import App from './App.vue' Vue.prototype.$http = axios new Vue({ el : '#app', router, components : { App }, template : '' }); 3-3)/[webpack루트]/App.vue [removed] import mixin from './common/common-mixin.js' import store from './vuex/store' export default { store, name : 'App' } [removed] Vuex와 통신 모듈 axios, Vue-Router 등을 루트 Vue 객체에 추가해줍니다. 브랜디 관리자의 webpack은 babel을 사용하고 있기 때문에 위의 store처럼 축약해서 작성하면 빌드된 파일에는 store: store와 같이 입력됩니다.Vue-Router는 태그에 자동으로 매핑되며, 위와 같은 구조로 상위 컴포넌트에서 할당되어 있어야 합니다. Vuex와 Vue-Router 설정은 글 아래에서 다루겠습니다.4.Webpack 설정이번에 Vue-Router와 Vuex를 도입하면서 webpack의 설정도 실제 서비스용과 개발용으로 분리했습니다. 폴더는 편의상 추가하였으며, package.json에서 자신이 설정한 경로로 설정하면 됩니다.Webpack 설정 파일은 Webpack의 시작과 끝이라고도 할 수 있습니다. Webpack 설정 파일에서 빌드할 소스의 경로와 빌드 결과 파일의 명명 규칙을 정하고, html 파일에 스크립트파를 자동으로 주입시키거나, Babel 플러그인을 통해 최신 스크립트 작성법을 브라우저를 신경쓰지 않고 사용할 수도 있습니다.그중에서도 중요한 옵션이 있는데 바로 Code Splitting에 관련된 옵션입니다.관리자 초기 Vue 모델에는 Vue-Router가 없었기 때문에 js 번들 파일의 크기가 그렇게 크지 않았습니다. 하지만 Vue-Router를 사용해 싱글 페이지 어플리케이션이 되거나 화면의 UI가 복잡해 컴포넌트 수가 많아지면 번들 js 파일의 크기가 매우 커집니다. 즉, 캐시를 사용하지 않는 익스플로러라면 소스에서 한 글자만 바뀌더라도 모든 페이지에서 거대한 번들 js를 새로 로딩하게 되고, 상당한 서버 자원을 소모합니다.Code Splitting 적용 전위의 이미지는 Code Splitting을 적용하기 전의 번들 js 정보입니다. 실제로 완성된 Vue 프로젝트의 번들 js는 더욱 큽니다. 정말 단순한 페이지 하나를 띄우는데 매번 뚱뚱한 js를 로딩해야 하는 것은 서비스 제공자와 서비스 사용자를 모두 괴롭게 할 것입니다.Code Splitting 적용 후하지만 위처럼 작은 조각으로 나눠 필요한 시점마다 필요한 번들 js만 로드하면 매우 빠른 페이지를 제작할 수 있습니다. 따라서 Code Split 기능은 매우 중요한 이슈입니다.물론 개발을 진행하다 보면 역시 어느 것 하나 쉽게 넘어가지지 않습니다. 관리자의 웹팩은 4.x 버전대를 사용하고 있습니다. 예전에 TF에서는 Webpakc 3.x 버전대를 사용하였는데 당시에는 CommonChunkPlugin 설정을 통해 Code Splitting을 사용할 수 있었습니다. 그대로 관리자에 적용하려 했는데..Removed라고 쓰여 있습니다. 찾아보니 CommonChunkPlugin이 옵티마이즈 옵션 하위의 splitChunk 속성으로 들어가면서 설정 방법이 바뀌었더군요. 머리를 싸매고 설정을 잡습니다.4-1) /[webpack루트]/build/webpakc.config.js : 공통 설정파일'use strict' const HtmlWebpackPlugin = require('html-webpack-plugin'); const { VueLoaderPlugin } = require('vue-loader'); const path = require('path'); module.exports = { entry: { //string, object, array 가능 - 기본은 ./src app: path.join('[스크립트 파일 경로]', 'index.js') //진입점 스크립트 파일입니다. }, output: { path: '[빌드된 js 목적지 경로]', publicPath: '[이미지등의 웹상 리소스 경로]', filename: './[name].[chunkhash].js', // 엔트리 파일명명규칙 chunkFilename: '[id]_[chunkhash].js', // chunk파일 명명 규칙 // --mode development에서는 [id]에도 chunkName들어갑니다. }, //vue와 js, css 로드 규칙을 설정합니다. module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', include: [ /[Vue 소스 경로]/ ] }, { test: /\.js$/, use: { loader: 'babel-loader?cacheDirectory', }, include: [ /[Vue 소스 경로]/ ] }, { test: /\.css$/, oneOf: [ { use: [ 'vue-style-loader', 'css-loader' ] } ] } ] }, resolve: { alias: { '@': '[Vue소스 경로]', // 편의상 소스단축경로를 설정합니다. }, //파일 확장자 자동인식 임포트시 해당 확장자는 생략가능합니다. extensions: ['.js', '.vue', '.json'], }, plugins: [ // Vue 파일 로더 new VueLoaderPlugin(), // html 자동 바인딩 // 아래의 플러그인으로 인해 index.html에 해시네임으로 빌드된 index.js가 자동으로 매핑됩니다. new HtmlWebpackPlugin({ // index.php에서 include할 파일이 생성될 경로와 파일명 입니다. filename: path.join('[View경로]', 'index.html'), // 자동으로 매핑할 진입점파일을 지정합니다. template: path.join('[Vue소스 경로]', 'index.html'), inject: true, minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true } }), ], optimization: { //웹팩 4.x 버전에서 옵티마이즈 속성으로 추가된 CodeSplitting 기능입니다. splitChunks: { //initial - static파일만 분리, async - 동적로딩파일만 분리, all - 모두 분리 chunks: 'async', minSize: 30000, minChunks: 1, maxAsyncRequests: 5, //병렬 요청 chunk수 maxInitialRequests: 3, //초기 페이지로드 병렬 요청 chunk수 automaticNameDelimiter: '_', //vendor, default등 prefix 구분문자 (default : '~') name: true, //development모드일때 파일에 청크이름 표시여부 cacheGroups: { default: { minChunks: 2, //2개 이상의 chunk priority: -20, reuseExistingChunk: true //minChunks이상에서 사용할경우 공통사용 }, //axios, vue 같은 공통 모듈은 vendor로 관리합니다. vendors: { test: /[\\/]node_modules[\\/]/, priority: -10 } } } } }; 4-2) /[webpack루트]/build/webpack.dev.config.js 개발용 설정 파일 (네이밍은 자유)'use strict' const merge = require('webpack-merge') const webpack = require('webpack') const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin const baseWebpackConfig = require('./webpack.config') const config = require('../config').dev //개발용설정 const devWebpackConfig = merge(baseWebpackConfig, { //mode는 chunk[id], 디버깅 코드 등에 영향을 줍니다. webpack 3.x 버전에서는 Env 속성을 통해 관리했다고 합니다. mode: 'development', plugins: [ new BundleAnalyzerPlugin(), //번들 무게 분석기 제대로 스플릿 되었는지 확인할 때 사용합니다. new webpack.DefinePlugin({ env : config.env }), ], watch: true, //코드의 변화를 감지해 자동으로 재빌드해주는 옵션입니다. cache: true, //캐시 사용을 활성화하면 변경사항이 있는 코드만 재빌드합니다. optimization: { //uglify 플러그인 코드 압축 여부를 설정합니다 압축 시 용량을 매우 줄일 수 있으나 빌드 속도가 크게 저하되므로 개발 시에는 꺼줍니다. minimize: false, } }) module.exports = new Promise((resolve, reject) => { resolve(devWebpackConfig); }) 4-3) /[webpack루트]/build/webpack.prod.config.js 서비스용 설정파일 (네이밍은 자유)'use strict' const merge = require('webpack-merge') // 설정파일 결합에 사용합니다. const webpack = require('webpack') const baseWebpackConfig = require('./webpack.config') //베이스 설정파일 const config = require('../config').prod //서비스용 설정 const prodWebpackConfig = merge(baseWebpackConfig, { mode: 'production', //chunk[id], 디버깅 코드등 영향 있음 plugins: [ new webpack.DefinePlugin({ env : config.env }), ], //개발용과 반대로 용량은 줄이고 필요 없는 기능은 꺼줍니다. watch: false, cache: false, optimization: { minimize: true, } }) module.exports = prodWebpackConfig 5.package.json웹팩 설정 파일이 분리되면서 package.json의 런 스크립트도 변경했습니다.... "scripts": { "build": "webpack --config build/webpack.prod.config.js --progress", "build-dev": "webpack --config build/webpack.dev.config.js --progress" }, ... 6.Vue-RouterVue-Router는 위에서 설명한 대로 Vue의 컴포넌트와 밀접하게 결합된 라우터입니다. 그런데 여기서 webpack의 Code Split을 사용하려면 컴포넌트 import 방법이 매우 중요한데요.import './testComponent' 위처럼 import 구문을 사용해 컴포넌트를 불러오면 코드가 쪼개지지 않고 한 덩어리로 빌드되므로 아래와 같은 형태로 사용해야 합니다.const testComponent = () => import('./testComponent') webpack 공식 문서에도 나와있듯이 위처럼 ES2015 Loader spec에 있는 import()를 사용하여 컴포넌트를 생성해야 번들 js가 제대로 분리되며, Dynamic Import가 가능해집니다.Vue-Router를 쓰는 순간 싱글 페이지 어플리케이션이 되기 때문에 이곳에서 설정을 잘못 잡아주는 순간 육중한 컴포넌트 한 덩어리가 튀어나오면서 Code Splitting은 물거품이 되어버립니다. 조심합시다!또한 import 함수 안쪽엔 아래와 같은 주석을 달아야 청크 이름이 적용됩니다.const testComponent = () => import( /* webpackChunkName: '[청크이름]'*/ './testComponent') 라우터 경로 속성인 path 와 Codeigniter의 컨트롤러 경로를 맞춰주는 것이 포인트입니다!6-1) /[webpack루트]/router/index.js - 경로와 파일명은 자유입니다!import Vue from 'vue' import Router from 'vue-router' // 주석의 webpackChunkName = 코드 스플릿 chunk Name으로 사용됩니다. // 꼭 컴포넌트와 청크 이름을 같게 설정할 필요는 없습니다. const SalesAnalysisProduct = () => import(/* webpackChunkName: "salesAnalysisProduct" */ '[컴포넌트 파일 경로]') const SalesAnalysisSeller = () => import(/* webpackChunkName: "salesAnalysisSeller" */ '[컴포넌트 파일 경로]') const TrendAnalysisProduct = () => import(/* webpackChunkName: "trendAnalysisProduct" */ '[컴포넌트 파일 경로]') const TrendAnalysisSeller = () => import(/* webpackChunkName: "trendAnalysisSeller" */ '[컴포넌트 파일 경로]') Vue.use(Router) const router = new Router({ mode: 'history', routes: [ /* 통계 */ { path: '[CI컨트롤러 url]/salesAnalysisProduct', name: 'salesAnalysisProduct', component: SalesAnalysisProduct }, { path: '[CI컨트롤러 url]/salesAnalysisSeller', name: 'salesAnalysisSeller', component: SalesAnalysisSeller }, { path: '[CI컨트롤러 url]/trendAnalysisProduct', name: 'trendAnalysisProduct', component: TrendAnalysisProduct }, { path: '[CI컨트롤러 url]/trendAnalysisSeller', name: 'trendAnalysisSeller', component: TrendAnalysisSeller }, ] }) // 아래의 함수로 전처리 후처리도 가능합니다! router.beforeEach((to, from, next) => { // ... }) router.afterEach((to, from) => { // ... }) export default router 7.Vuex앞서 Vue와 Vuex, 컴포넌트간 통신과 상태 관리에서 소개했던 상태 관리와 통신을 위한 Vuex도 추가합니다. Vuex는 하나의 Store만 쓸 경우 상태 변수의 과포화로 인해 유지 보수가 어려워질 수 있으므로 namespace: true 옵션을 통해 도메인별로 관리합니다.7-1) /[webpack루트]/vuex/store.js - Vuex 진입파일import Vue from 'vue' import Vuex from 'vuex' // 각 도메인별 store들이 들어있는 modules 를 임포트해줍니다. import * as modules from './modules/index' Vue.use(Vuex) export default new Vuex.Store({ state : { }, getter: { }, mutations : { }, actions : { }, modules : modules.default }) 7-2) /[webpack루트]/vuex/modules/index.js - 도메인별 Store 자동 바인딩 스크립트const files = require.context('.', false, /\.js$/) const modules = {} //자신(index.js)를 제외한 파일들을 파일이름을 Key로 modules에 담습니다. files.keys().forEach((key) => { if (key === './index.js') return modules[key.toLowerCase().replace(/(\.\/|\.js)/g, '')] = files(key).default }) export default modules 7-3) /[webpack루트]/vuex/modules/statistics.js(통계 store 파일) - 예시입니다.export default { namespaced : true, //해당 속성을 통해 파일명을 namespace로 사용합니다. state: { /* 상태값 및 데이터 */ ... }, getters: { }, mutations: { /* state 변경처리 */ ... }, actions: { /* 통신처리 */ ... } } namespace: true로 되어있으므로 파일명인 statistics를 namespace로 사용하게 됩니다. 따라서 store 각 항목에 대한 접근은 다음과 같이 이뤄지며 computed 속성에 state: this.$store.state.statistics 처럼 정의해두면 편리합니다.dispatch는 this.$store.dispatch(‘statistics/[action 이름]’)commit은 this.$store.commit(‘statistics/[mutation 이름]’)state 변수 접근은 this.$store.state.statistics.[state 이름]8.공통 처리 mixinapi 통신에 사용되는 통신 라이브러리와 그 라이브러리의 복잡한 설정 코드, 단순한 Toast 출력 함수, 로딩 이펙트를 보여주는 함수 등 모든 항목들이 매 페이지마다 있으면, 통일되지 못한 UI, 페이지마다 일관되지 못한 설정 등으로 휴먼 에러가 발생할 확률이 높아집니다. 유지 보수 측면에서도 비용이 높아집니다. 이러한 단순 반복 코드들은 한번만 정의하고 재사용하는 것이 바람직합니다. 나중에 수정할 때도 용이하죠.공통사항을 묶어 Vue 전역 믹스인으로 Vue 루트 객체에 추가합시다. 단, global 옵션인 만큼 조심해서 써야 합니다. 시스템에 영향을 줄 것 같으면 하위 컴포넌트 mixins 속성에 넣어 해당 스코프에서만 사용하는 것이 바람직합니다.8-1) /[webpack루트]/common/common-mixin.js (파일이름, 경로는 자유입니다!)import Vue from 'vue' import Vue from 'axios' import Cookies from 'js-cookie' const TIMEOUT = '[타임아웃 시간(ms)]' /* mixin의 기본 형태는 Vue 컴포넌트의 형태와 동일합니다. 주로 전역 통신과 상태 관리는 vuex store에서, 전역 data 속성과 전역 함수는 mixin에서 관리합니다. */ Vue.mixin({ /* 전역 사용 data속성 선언 */ data: () => { return { ... //이곳에 선언하는 data 속성은 전역에서 this로 접근 가능합니다. } }, created: function() { // 공용 axios 객체 생성 this.axios = axios.create({ timeout: TIMEOUT, withCredentials: true, //공통해더는 여기에 headers : { } }); //axios 의 success와 error를 mixin method에서 처리 하도록 등록 this.axios.interceptors.response.use(this.onSuccess, this.onError) }, /* 전역 사용 함수 선언 */ methods: { /* axios의 response handling 함수*/ onSuccess : response => { }, onError : function (error) { }, /*GET, POST 등의 통신 함수, Toast(alert) 표출함수, 에러핸들링함수 등 선언*/ /*... 내용이 너무 길어서 생략 ...*/ } }); 9.요약지금까지의 내용은 파일 경로를 토대로 요약하면 다음과 같습니다. 참고로 아래의 폴더 구조는 절대적인것은 아닙니다. 모든 폴더 구조는 자율이며, 폴더 구조에 맞게 webpack.config.js에서 조정해주면 됩니다.[프로젝트 루트] └ [웹팩 루트] └ package.json └ [Vue 소스 루트] └ [common] └ [router] └ index.js // 라우터 설정파일 - CI 컨트롤러와 url 맞춰줘야함 └ [vuex] └ index.js // 도메인별 store module export 스크립트 └ [modules] └ 도메인별 store.js └ [컴포넌트 폴더] //예시에서는 ststistics └ App.vue //진입점 vue파일 Vuex와 전역 mixin 세팅 └ index.html //index.js가 주입될 껍데기 └ index.js //진입점 js Vue-Router와 App.vue 세팅 └ [build] // 빌드파일경로 └ webpack.config.js //베이스 설정파일 └ webpack.dev.config.js //개발용 설정파일 └ webpack.prod.config.js //서비스용 설정파일 └ [application] //Codeigniter 루트 └ [controllers] └ [컨트롤러 경로] // 예시의 통계부분 └ [views] └ [웹팩빌드 결과 폴더] └ [index.php] // CI 에서 로드하는 view (index.html include) └ [index.html] // js 번들이 자동 주입된 빌드결과 파일 └ [include] └ [scripts] └ [빌드결과 js 경로] //public path 속성 경로 └ 빌드 결과 js chunk들 마치며관리자 서비스에서 완전한 Vue를 사용하기 위해 꽤 험난한 과정을 거쳤습니다. 지금도 잘 돌아가는 서비스에 리스크를 감수하면서도 새로운 것을 도입하려는 이유를 찾아야 했고, 한동안은 레거시와 Vue로 된 소스를 2중으로 개발해야 했습니다.게다가 이 글을 작성하기 시작했을 땐 Code Splitting 설정 방법이 바뀌어 적용하지도 못한 상황이었기 때문에 사실 Code Splitting 내용이 없었습니다. 그런데 글을 작성하면서 splitChunk옵션을 성공해버렸어요! 덕분에 이 글도 모두 수정해야 했죠. Vue의 도입을 고려하는 개발자분들에게 도움이 되길 바라는 마음으로 글을 마칩니다.참고1)Vuex Store는 Vue와 Vuex, 컴포넌트간 통신과 상태 관리에 자세히 정리해두었다.2) 브랜디 관리자 서비스는 jQuery로 작성되어 있다. 따라서 jQuery를 베재할 수만은 없는 상황이었다. 이에 따라 기존 jQuery 컴포넌트들에 대한 해결책은 천보성 팀장님이 작성한 JQuery 프로젝트에 VUE를 점진적으로 도입하기를 참고했다. props와 emit 기능을 이용해 jQuery로 제작한 컴포넌트를 깔끔하게 Wrapping 하는 방법에 대해 자세히 기술되어 있으며, 이를 활용하면 레거시 UI 플러그인을 마치 네이티브 Vue 플러그인처럼 사용할 수 있다.글강원우 과장 | R&D 개발2팀[email protected]브랜디, 오직 예쁜 옷만
조회수 2106

프로세스 마이닝과 AI를 통한 프로세스 혁신

지난해 이세돌과 알파고의 대결 이후에 인공 지능 (AI)과 기계 학습은 국내에서 많은 대중들의 관심을 얻어 중요한 추진력을 얻었으며, 모든 산업 분야의 기업들이 해당 기술을 빠른 속도로 계속 적용하여 사용하는 비중이 더욱 높아졌습니다. 실제로 Gartner는 2022년까지 스마트 머신과 로봇이 고학년 전문직 분야를 대체할 수 있을 것으로 내다봤으며, 심지어는 인공지능이 경영자 CEO도 대체 가능할 것인지에 대한 논의도 일어나고 있습니다. 이것은 사람이 과거 경험에 의해서 의사 결정을 내리 듯이 인공 지능도 확보한 데이터를 기반으로 의사 결정 모델을 만들 수 있다는 유사성에 기반합니다.  인공 지능에 의한 의사 결정은 사람한테 종종 있을 수 있는 감정이나 개인적 이해관계 및 관례에 의해 불합리한 판단에서 벗어나 데이터의 의한 객관적 판단을 할 수 있다는 장점이 있습니다.여기서 중요한 것은 인공지능이 학습하기 위한 “데이터”입니다.  지금까지 머신러닝이 막대한 이미지, 음성, 영상 데이터를 축적한 후 해당 데이터의 특징을 추출하여 패턴을 학습하여 자연어 처리 등을 통해 사람처럼 인식하여 분류하거나 상황을 판단하였듯이 기업 내 여러 가지 업무 활동에 머신 러닝을 적용하기 위해서는 이와 마찬가지로 관련 데이터가 필요합니다.제조 분야의 공정 관리, 공공 서비스, 물류 공급망 관리 등 전통적인 기업 내 업무 프로세스는 인공 지능에 의한 자동화과 효율화를 통해 혁신이 필요한 분야입니다. 기존에 외부 협력 업체로부터의 납기 예측, 소요되는 자재 인력 등 리소스 산정, 생산 스케줄, 장비 파라미터 입력값 등은 사람에 의해 수작업으로 진행 시 몇 주에서 수개월 소요되었지만, 인공 지능과 기계 학습 기반의 솔루션 도움으로 정확하게 지속적인 추세를 인식하고 인간의 개입 없이 데이터 중심의 결정이 가능해집니다.지금까지 기업 내 축적된 엄청난 양의 데이터를 활용하여 여러 산업 분야에서 숨겨진 패턴과 상관관계, 이상 징후 및 불량 탐지, 고객 수요 예측 등이 시도되었습니다. 하지만 이러한 시도들은 기업 내 문제 요인을 파악하여 우선적으로 어떤 부분에 초점을 맞추어 개선을 해야 하는지 알아야 하므로, 기업 경영 활동 전반에 걸쳐 돌아가는 판세를 읽는 노력이 필요합니다. 하지만, 기업 내에서 이뤄지고 있는 프로세스는 충분히 복잡하여, 개별 단위 작업의 전문가들은 존재하겠지만, 각 개별 부서, 구성원, 시스템 간에서 발생하는 다양한 상호작용과 이에 따른 예외 상황이 존재하여 이를 파악하기가 쉽지 않습니다.프로세스 마이닝은 데이터 기반의 프로세스 분석을 통해 문제 부분을 파악하여, 실제 인공 지능이나 머신 러닝을 적용하여 개선할 부분을 찾을 수 있도록 도와줍니다. 그리고, 프로세스 개선을 위해 머신러닝을 적용하기 위해서는 앞서 말한 것처럼 “데이터”가 학습될 수 있는 형태의 기반을 제공합니다.아래 그림과 같이 이벤트 로그를 기반으로 프로세스 모델을 생성하고, 수집된 패턴들과 각 분기 단계에서의 주요 성과 지표들을 디지털화하여 인공지능이 이해할 수 있는 형태로 축적합니다 이렇게 축적된 프로세스 패턴 데이터를 가지고 알파고가 최적화된 다음의 한 수를 예측하듯이 프로세스 마이닝은 인공 지능 기술과 결합하여 과거 프로세스에 대한 이해뿐만 아니라, 현재 시점에서 앞으로의 프로세스를 예측하여 합리적인 의사 결정을 도와줄 것입니다.#퍼즐데이터 #개발팀 #개발자 #개발후기 #인사이트
조회수 545

성장하려면 완벽한 바퀴보단 조잡한 자전거를.

2017년부터 현재까지 엘리스와 함께 다양하고 유익한 프로그래밍 수업을 만들어오고 계신 김건우 선생님을 만났습니다! 학생의 성장에 강력한 동기부여를 받고, 그 누구보다도 사람에 대해서 깊이 생각하는 개발자가 되고 싶다는 멋진 건우님의 이야기를 함께 들어봐요. :)김건우 님모빌리티 플랫폼 타다 개발자엘리스 프로그래밍 선생님• 도전! 디버깅 입문• 본격! 프로그래밍• 파이썬 실전 데이터 분석• 코딩학교 II - 파이썬• 코딩학교 I - 파이썬• 코딩학교 : 도전 20문제 - 파이썬KAIST 전산학부Q. 선생님 안녕하세요! 자기소개 부탁드려요.안녕하세요. 저는 모빌리티 서비스인 타다에서 모바일 클라이언트 개발을 하고 있는 김건우라고 합니다. 타다의 iOS와 안드로이드 앱을 만들고 있습니다. 엘리스에서는 지금까지 6번 정도 강의를 해왔구요, 주로 코딩을 갓 시작하신 분들이 그다음 레벨로 넘어가기 전에 코딩에 익숙해지기 위한 수업들을 진행해 왔습니다.Q. 2017년부터 꾸준히 강의를 해오셨어요. 강의를 계속하신 이유가 무엇인가요?그전에도 학생들을 오프라인으로 가르쳐본 적은 있었는데 온라인으로 가르치는 건 되게 다른 경험이었어요. 완전히 다른 일을 하는 느낌이었고 그게 재밌어서 자연스레 계속하게 된 것 같아요.무엇보다도 다음 강의를 계속하게 되었던 원동력은 학생들이 성장한다라는 느낌을 받을 때였던 것 같아요. 입에 발린 말처럼 들릴 수도 있겠지만 진짜 그런 걸 느끼거든요. 학생들의 얼굴을 직접 보지는 못하지만 질문 수준들이 확 올라온다는 걸 느낄 때가 있어요. 1,2주 차와 3,4주 차가 다를 때 특히. 그럴 때 '아 좀 더 하고 싶다'는 마음이 드는 것 같아요.Q. 강의할 때의 애로사항이나 어려움은 무엇이었나요?저도 그렇고 제 주변에 강의를 하시는 다른 분들을 봤을 때 영향력을 가지고 싶다는 욕구가 강의를 하는 이유 중 하나인 것 같아요. 그런데 오히려 여기에서 오는 부담도 있어요. 제가 생각하기에는 크게 중요하지 않아서 적당히 설명하고 넘어갔는데, 나중에 보면 단단히 잘못 이해하고 있는 분들도 있는 거예요. 수강생 분들은 내가 훨씬 많은 것을 안다고 생각하고 그렇기 때문에 큰 비판 없이 수용할 수 있는데 내가 이렇게 해도 되는 걸까에 대한 고민을 한 경우가 많았어요. 이것 때문에 스트레스를 많이 받았고요. 그래서 사실 준비할 시간이 충분히 없다고 느껴지면 강의 제안에 거절을 많이 했어요. 급하게 준비해도 물론 강의를 낼 수야 있겠지만 죄책감이 많이 들더라고요.Q. 강의 제작에 있어 어떤 것을 많이 고려하셨나요?어떻게 하면 재미를 느낄 수 있을까라는 고민을 많이 했어요. 저는 배우면서 제일 중요한 거는 흥미라고 생각하고, 그 흥미를 위해서는 강의가 제공하는 콘텐츠와 그것을 전달하는 방식이 중요하거든요. 그래서 첫 번째로는 이제 막 파이썬 문법 정도를 뗀 사람들이 '뭐가 제일 궁금할까?'를 많이 고민했구요. 그다음에는 그들이 '이걸 배워서 뭘 하고 싶을까'를 고민했죠. 시쳇말로 저는 코딩으로 밥 벌어먹고 사는 사람인데 이게 본업이 아니거나, 혹은 코딩을 처음 배우기 시작하는 분들이 무엇을 원할지 많이 생각했던 것 같아요.Q. 그래서 얻은 답은 무엇이었나요?세상에서 존재하는, 남이 하는 걸 본 적 있는 어떤 일을 내가 비슷하게나마 해보는 것. 그게 되게 클 거라고 생각했구요. 예를 들면 트럼프 대통령이 연설에서 제일 많이 쓴 단어가 뭘까? 뉴스를 보다 보면 쉽게 접할 법한 자료들이 있잖아요. 평소에는 그냥 '이렇게 조사를 했나 보네' 하고 넘어갈 텐데 내가 직접 그 연설문을 가지고 그 단어를 직접 찾아보는 거는 다른 경험일 거라고 생각해요. 그리고 그렇게 어딘가에서 본 적 있는 결과물을 직접 만들어 낼 때 학생들이 더 많은 흥미를 느낄 거라고 생각을 했어요.파이썬 실전 데이터 분석 실습 화면Q. 라이브 수업에서부터 녹화 수업까지 엘리스의 변천사와 함께 하셨는데 가장 기억에 남는 일화가 있다면요?라이브에 사람들이 되게 많이 들어왔을 때가 기억에 남아요. 무료로 강의를 공개했을 때가 한번 있잖아요? 그때 몇천 명의 학생들이 수강 신청을 했어요. '아 진짜 큰일 났다 라이브.'라고 생각했죠. 그런데 다행히 수천 명의 학생들이 들어오진 않았어요. 그래도 나중에 돌이켜보니 꽤 많이 들어온 건데? 싶더라고요.확실히 녹화형으로 가면서 마음은 많이 편해졌어요. 라이브가 재미는 있는데 되게 큰 부담이 돼요. 말실수 내지는 제가 완벽하게 흐름을 꿰고 있지 않으면 헤매는 걸 모두가 다 보게 되잖아요. 오타 하나 때문에 오류가 계속 나는 경우도 많거든요. 라이브 때는 항상 컴퓨터 2대로 진행하는데 그레이더가 잘못되어 있어서 '아 여러분 잠시만요'하고 한쪽에서 계속 고친다든지 이런 돌발 상황들이 많이 있었던 게 기억나네요.라이브 수업 당시 강의 화면Q. 여러 과목 중 특히 추천해주고 싶은 과목이 있으신가요?파이썬 실전 데이터 분석이요. 문제 설계에서부터 시작해서 실습 문제, 프로젝트까지 제가 공을 가장 많이 들인 과목이거든요. 프로젝트 설계도 신경을 많이 썼구요. 말씀드렸던 ‘학생들이 뭘 하고 싶을까’에 대한 고민을 가장 많이 했고 콘텐츠에 그대로 반영된 과목이라고 생각해요.Q. 어떤 학생들에게 어떤 도움이 되는 과목인가요?‘파이썬은 배웠지만 이걸로 뭘 하지’를 고민하는 학생들에게 ‘데이터만 있으면 파이썬으로 아주 쉽게 원하는 것을 뽑아내고 인사이트를 얻을 수 있다’는 걸 알려주는 과목이에요. 라이브러리를 최대한 덜 쓰고 파이썬 기본 문법만 가지고도 할 수 있도록 만들었어요. 대단한 개발자만 이런 걸 할 수 있는 게 아니라는 것을 알려주고 싶었어요. 파이썬에서 기본적으로 배웠던 string 다루는 법, list 이런 것만 가지고도 가능하다는 걸 학생들에게 알려주고 싶었고 자신감을 갖게 해주고 싶었어요.Q. 다음에는 어떤 강의를 만들고 싶으신가요?지금 하고 있는 일이 앱 개발이라서 관련 강의를 생각하고 있어요. 앱 개발을 하다 보면 특히 세팅에 많은 시간이 들어요. 다른 개발보다 더더욱이요. 엘리스는 세팅을 하지 않고 코딩을 시작할 수 있다는 게 되게 큰 장점이잖아요. 오히려 파이썬 기본 코딩 같은 것은 일반 컴퓨터에서도 세팅이 아주 간단한 편이에요. 그런데 앱 개발 같은 경우에는 진짜 많이 필요하거든요. 그래서 앱 개발에 대한 강의를 한다면 엘리스의 장점을 훨씬 더 많이 발휘할 수 있는 분야인 것 같고 제가 지금 하고 있는 일이기도 하고요.Q. 코딩 초급 단계의 학습자가 가장 어려워하는 것과 성취도를 높이기 위해 중요한 건 뭘까요?학생분들이 에러가 뜨면 일단 패닉을 하세요. 사실 코딩을 하다 보면 10년 차이든 신입이든 에러 내는 건 똑같거든요. 당연히 사람은 완벽할 수가 없고 에러 내는 것은 어쩔 수 없는 건데. '어 큰일 났다'라고 일단 생각을 하시는 것 같아요. 그런데 다음 스텝으로 넘어가려면 그 에러 코드를 읽어야 하거든요. 그래서 저는 디버깅 수업이 재미는 별로 없었을지라도 학생들에게 실질적으로 도움이 되게 많이 될 거라고 생각해요. 그리고 그 스텝을 넘어가면 그래도 내가 성장할 수 있는 발판이 열린다고 생각을 하고요.질문에서도 수준의 차이가 난다고 느낄 때가 있어요. “어 왠지 모르겠는데 안돼요”와 “내가 어떤 걸 해보니까 이런 에러가 났는데 이것도 해봤는데 안되더라 그래서 질문을 했다”라고 콘텍스트 설명을 충분히 하는 학생분들이 계세요. 후자가 더 도와주고 싶기도 하고, 도와줄 수 있기도 하고요. 학생들이 좀 더 에러를 두려워하지 않고, 또 잘 질문하는 법을 배우면 성장할 수 있을 것이라고 생각해요.도전! 디버깅 입문 수업 화면Q. 코드 질문을 잘하는 팁이 있다면요?질문에 포함되어야 할 것은 세 가지가 있어요. 가장 먼저 제일 중요한 것은 ‘내가 얻고 싶은 결과’ 예요. 그리고 ‘지금의 상황’과 ‘시도해본 것’. 한 문장으로 말하면 ‘내가 얻고 싶은 결과가 무엇인데, 지금의 상황은 이렇고, 어떤 것을 시도해보았지만 여전히 안 된다.’라고 할 수 있을 것 같아요.개발자끼리 일을 할 때도 그런 경우가 많아요. 제가 a가 안 된다라고 열심히 설명을 하고 있었는데 사실 제가 얻고 싶은 결과는 애초에 a를 안 해도 되는 거였어요. 그런데 내가 잘 질문하지 않으면 옆사람은 a 되는 법만 열심히 가르쳐주게 되는 거죠. 사실 내가 진짜 하고 싶은 걸 더 잘 이룰 수 있는 방법인 b가 있고, 또 b가 더 쉬울 수도 있는 거거든요. 그래서 질문을 잘하는 게 중요합니다.Q. 프로그래밍을 하면서 슬럼프는 없었나요?사실 재미를 잃은 적은 별로 없었어요. 잘 안 된 적은 많이 있지만 재미는 계속 있었던 것 같아요. 잘 안 될 때는 그냥 다른 분야를 좀 보다 오고 그랬어요. 뭔가 잘 안 되는 대부분의 경우는 내가 당연히 겪어야 하는 일인데 그걸 힘들게 느끼는 거라고 생각해요. 그럴 땐 다른 걸 보면서 리프레쉬하거나 쉬었다가 다시 했던 것 같아요. 그런데 사실 저는 제가 덕업일치라고 생각하거든요. 복 받은 것 같아요.Q. 프로그래밍 실력을 키우려는 사람에게 해줄 조언이 있나요?첫 번째는 알고리즘 문제를 푸는 능력이에요. 두 가지 방법이 있다고 생각해요. 다시 태어나거나, 그래도 문제를 많이 풀어보거나. 사실 알고리즘 문제는 제가 되게 취약한 분야예요. 알고리즘을 진짜 잘하는 사람들이 있어요. 중고등학교 때부터 트레이닝을 잘해놓고, 머리도 좋고요. 그런 사람들은 정말 내가 생각하지도 못한 풀이를 내놓거든요. 그래서 저는 알고리즘은 지금 열심히 한다고 해서 잘 안 되는 것일 수 있다, 그냥 못하지 않을 정도로 중간만 가자라고 생각을 해요. 많이 풀어보면 중간은 갈 수 있어요. 그리고 그런 문제들이 굉장히 많고요.두 번째로는 읽기 쉬운 프로그램을 짜는 것이에요. 협업할 때 소통하기 좋은 프로그램을 짜는 게 되게 중요해요. 사실 대부분의 코딩 면접에서도 이걸 본다고 생각하고요. 쉽게 말해서 변수 이름을 하나 정할 때도 사람 이름을 저장하는 변수명을 ‘a’라고 지으면 아무도 이해 못하잖아요. 코드를 적기 전에 이걸 보는 사람은 어떻게 생각할지 고민을 좀 더 하면서 코드를 적는 연습을 하고 좋은 코드를 많이 보다 보면 늘 수 있다고 생각해요.마지막 세 번째는 프로그램을 설계하는 능력인데요. 이것은 진짜로 일을 해봐야 한다고 생각합니다. 회사에서 일을 하거나 개인 프로젝트를 하거나. 어쨌든 사람들이 쓰는 무언가를 만들어봐야만 느는 거라고 생각을 합니다.Q. 많은 분들이 학교에서 배우는 것과 실무의 간극이 큰 것 같아 어떻게 대비하면 좋을지 궁금해하세요.컴퓨터 사이언스는 그래도 가장 그 간극이 적은 분야라고 생각해요. 저는 굉장히 놀랐어요. “아 이렇게까지 많이 쓰는구나”했죠. 학교 공부를 잘한다고 개발을 잘하는 건 아니지만 좋은 개발을 하고 좋은 프로그램의 동작 방식을 설계하는 데에는 학교에서 배우는 것이 관련성이 크다고 생각해요. 사실 스타트업일수록 더 그렇거든요. 제가 만약 큰 회사에 갔다면 정말 피처 하나만 개발하겠지만 스타트업일수록 더 많은 일을 하고 설계에도 참여를 하게 되는데 그런 설계를 하기 위해서는 학교에서 배우는 과목들이 정말로 중요해요. 저는 그래서 간극이 크다는 건 잘못된 표현인 것 같고, 단지 내가 이걸 배워서 어디에 쓸지를 모르는 것뿐이라고 생각해요.Q. 개발자로서 좋은 태도가 있다면 무엇이라고 생각하시나요?끊임없이 배워야 해요. 예를 들어 아이폰 새로운 게 나왔다, 하면 그 아이폰에서 어떤 기능을 지원하는지 새로 나온 건 뭔지 내가 지금까지 짰던 프로그램이 그 폰에서 돌아가지 않으면 어떻게 하지, 이런 걸 다 고민해야 해요. 기술이 너무 빨리 변하고 있고 사람들의 기준도 높아져요. “당연히 그거 되어야 하는 거 아니야?”라고 생각하는데 실제로는 그게 되게 당연하지 않은데도 불구하고요.Q. 향후 5년, 10년 후에 어떤 일을 하고 싶으신지 궁금해요.대학 입학할 때는 사실 디자이너가 하고 싶었어요. 그래서 산업디자인과를 가야겠다고 생각했죠. 그런데 이것저것 하다 보니까 코딩이 재미있고 또 디자인보다 조금 덜 힘들 것 같다고 생각했어요. 쉽게 말해 취업도 잘 될 것 같았고, 디자인은 처음부터 시작해야 하는데 프로그래밍은 해본 경험이 있었구요. 지금 남들보다 조금 더 잘하기 때문에 성취감을 빨리 느낄 수 있어서 치고 나갈 수 있을 거라고 생각을 해서 전산학과를 택했어요.그런데 결국에는 사람이 자기가 원래 하고 싶었던 걸 보게 되는 것 같아요. 그래서 저는 사람들을 연구하는 개발자가 되고 싶어요. 사람들이 제가 만든 프로그램을 어떻게 쓸지, 뭘 원하고 어떤 생각을 하며 사용할지, 그럼 나는 어떻게 만들어야 할까, 이런 걸 고민하는 사람이 되고 싶어요. 요즘에는 UX엔지니어라고 많이 부르더라고요. 사람들과 가장 가까운 개발자, 디자인에도 많은 이해를 하고 있는 그런 개발자가 되고 싶어요.Q. 수강생 분들에게 한 말씀 부탁드려요!일단 뭘 만들어보셨으면 좋겠어요. 공부도 당연히 중요하지만 공부하는 건 만드는 게 아니거든요. 제가 되게 좋아하는 그림이 있어요.Illustration by Henrik Kniberg내가 성장할 때는 아주 조잡하더라도 작동하는 무언가를 만들고 점점 더 낫게 만드는 게 좋다는 의미예요. 제가 이 그림을 되게 좋아하거든요. 그래서 저는 이론 공부도 해야 하지만 직접 무언가를 만들어 보라고 말해주고 싶어요.Q. 건우님에게 엘리스란?가르치는 즐거움을 제대로 알게 해 준 곳.의미 있는 프로그래밍 교육 경험을 만들고,강의 제작 지원을 받으며 부수입을 얻고 싶은 분이라면엘리스 교육자에 주저없이 지원해주세요. :)▶ 교육자 지원하기
조회수 1350

크몽 gulp 개선기

안녕하세요. 프론트개발자 bk입니다 :)이 글은 gulp사용법에 대한 글이 아닙니다. build 자동화 도구를 개선할까 말까 고민하는 개발자들을 위해 제 경험을 공유드리려 합니다.음... build 자동화 꼭 해야 해..?가 아닙니다. 크몽이라는 서비스가 어떤 개발 환경을 통해 만들어졌는지, 좀 더 편하고 효율적으로 개발 생활을 즐기기 위해 어떻게 개선을 했는지에 대한 개발 경험을 나눠 보려고 합니다.왜 이 작업을 하게 되었고 뭐가 그리 중요했는지, 크몽 개발 환경에서 gulp가 개선되어야 했던 이유에 초점을 맞추었습니다.시작에 앞서본격적인 gulp에 대한 이야기를 하기 전에 왜 내가 크몽에 입사하자마자 gulp를 개선해야겠다 마음먹었습니다.크몽에서의 개발크몽에 입사한 지 이제 3개월이 되었습니다. 회사의 개선사항, 변화가 필요한 것들에 대해선 반드시 말하는 스타일이라 크몽의 자유로운 분위기와 수평적 문화는 정말 만족했고 적응에 큰 어려움은 없었습니다.첫 주는 개발환경 laravel + vuejs 공부의 시간을 보냈고 둘째 주부터 이벤트 페이지를 맡아서 작업했습니다. 기존 사용하였던 개발환경과 크게 다르지 않아 크게 어려움 없이 이벤트 페이지 작업을 완료하고 배포가 되었습니다.호환성을 위한 es6 환경 필요성하지만 늘 그렇듯 다음 날 출근을 하니 버그가 날 기다리고 있었습니다. 조금 생소한 버그였습니다. script관련 오류였는데, 이전의 개발환경에선 babel, browserify가 거의 대부분의 script에 걸려있었기 때문에 습관적으로 es6로 작업했습니다. 결국은 es5스타일로 복구하여 수정했습니다. 곰곰이 생각해보니 호환성을 위해 es6를 사용하지 않는 것이 아닌 es6를 사용하도록 환경이 구성되어야 하는 게 맞는 것 아닌가 라는 생각했습니다.gulp가 개선되어야만 하는 이유크몽에 입사한 지 1주일 만에 다른 작업을 뒤로하고 회사에서 gulp만 외치고 다녔습니다. 다른 무언가 개선을 하려면 gulp가 필연적으로 개선이 되어야 했습니다. 기존의 개발환경은 파일 수정할 때마다 terminal에서 gulp를 명령어를 쳐야 했습니다. 주르륵 코드를 적고 한번 새로고침해서 짠하고 바뀌는 스타일이 아니라, 내가 짠 코드도 의심이 되어 자주 스텝별로 확인 스타일이라 이러한 현재 환경은 저와 정말 맞지 않았습니다.앞잡이(크몽의 프론트앤드 멤버) 챕터 회의 때 gulp개선을 요청하였고 모두에게 현재의 문제를 공유하고 gulp개선을 해야 하는 이유에 대해 설득 한 뒤 크몽개발팀 내 프로젝트 일정으로 잡히게 되었다.나 편하자고 시작한 작업, 내가 편한 건 팀원도 편하다우선 gulp 개선의 가장 큰 목적은 4가지였다.es6 및 최신 기술과 라이브러리를 사용하자gulp watch를 효율적으로 사용하자script태그와 style태그로 쓰는 것을 지양하자 (.js, .scss파일 많아지는 것에 대한 부담 가지지 말자)script, style, directory 구조를 기능별로 구조화시키자bk's PLANs그렇게 gulp는 이렇게 만들었습니다.기존 크몽 개발 환경에서 너무 확 바뀌진 않도록 개발자 분들과 협업하여 flow를 최대한 유지하며 작업했습니다. (공통 모듈, 유틸, 서비스 관련, 인증, 라이브러리, 이벤트, 구매 판매 트랙, sass)로 모듈을 나누어 bundle을 하였고 각각에 watch를 걸어 파일을 변경하면 자동으로 관련 모듈만 bundle이 실행되도록 작업했습니다.gulp를 위한 작업이었지만directory구조도 깔끔해지고 project도 좀 더 가벼워졌습니다. 계획은 거창했고 의욕은 앞섰지만 build 자동화 툴을 제대로 만져본 적이 경험이 없어서 (gulp, elixir, babel, browserify, stream) 작업과 공부를 병행하느라 예상보단 조금 더 시간이 걸렸지만 결과적으론 개선된 지금이 훨씬 개발하기 편해졌다.불필요한 작업이 습관이 되기 전에 개선을 실행했습니다.사실 크몽의 이전 개발환경에선 gulp가 크게 중요하지 않았지만, 크몽의 팀원이 많아지고 개발자도 많아지면 제가 아니더라도 크몽팀 누군가는 했을 작업이었습니다. 더 나은 환경이 분명히 존재하는데도 불구하고 기존의 불필요한 작업이 습관이 되어 개선을 망설이거나 하는 회사, 개발자가 많다고 생각합니다.개발자가 더 나은 환경에서 개발하는 걸 막자고 할 사람은 없을 것입니다. 그것이 입사한 지 1개월이 되든 10년이 되든 누가 말하든지 간에 말입니다. 갓 들어온 주니어 개발자의 말을 잘 들어주고 gulp 개선에 대한 필요성을 인정해주어 작업이 가능했던 것 같습니다.올바른 방향으로 문제 해결방법을 목표로 삼았습니다.앞으로의 bk의 계획이제 gulp가 완성이 됨과 동시에 directory 구조와 es6가 해결되었으니, 원래 가장 하려던 크몽의 코드 스타일, ESLint를 적용할 예정입니다. 그 후 vue2 마이그레이션 작업이 진행될 예정입니다.마무리작지만 하나하나 개선해 나가면 더 나아진 개발환경 구축이 되고 이런 작은 개선 사항들이 모여서 더 나은 크몽이 될 것이라 생각합니다.real _마무리이렇게 개발했던 경험을 블로그로 포스팅한 건 이번이 처음입니다.역시 글을 쓰는 건 어렵고 두서없었지만 build 자동화 툴에 대해 더 깊게 공부할 시간을 가지게 되어 좋은 경험이었습니다.글을 마무리 지으려니 어떻게 지어야 할지 모르겠네요.그래서 급 마무리 인사드립니다.이렇게 부족한 글 귀한 분들께서 읽어주셔서 감사합니다.다음 포스팅에는 크몽의 개발 조직문화 소개로 돌아오겠습니다.#크몽 #개발팀 #개발자 #개발문화 #경험공유 #인사이트
조회수 2656

WHATAP Python APM 이야기...

백엔드 서비스로 Python을 사용한다면 만나게될 상황을보다 쉽게 해결하기 위한 와탭의 Python APM, 개발하게 된 이유입니다.파이썬은 배우기 쉽고, 어디서나 실행되는 언어라고 이야기되며, 인기도 높습니다. 생각보다 많은 곳에서 배울 수 있으며, 혼자 배우기도 좋습니다. 그런데, 이 규모가 확대되어서 스타트업의 경우에 Python을 사용하여 백엔드 서비스를 개발하는 경우를 찾는 것이 어렵지 않습니다. 또는, 수학적인 알고리즘이거나 ML(머신러닝)과 같은 영역이거나 블록체인등에서 Python을 사용하여 API geteway나 broker를 사용하는 경우에 한정한 상황을 고려하고 있습니다.Python으로 백엔드 서비스를 만들 때에는 성능과 설계 부분에 대해서 많은 걱정을 하게 됩니다. 이런 상황을 만나게되는 개발자는 여러가지 문제를 만나게 됩니다. 그 문제에 와탭은 집중합니다.!와탭은 백엔드 서비스를 Python으로 개발시에 만나게 되는 상황을 가장 최우선으로 생각하게 되었습니다.Python으로 '설계', '개발'되고 '테스트'된 후에 '배포'되는 상황에서 서비스의 불완전함과 속도상의 문제, 리소스의 불협화음등을 '유지보수'하는 단계를 '성능 튜닝'이라고 정의하고, 이를 고려한 상황을 보다 단순화하는 것이라고 생각하게 되었습니다. 이를 어떻게 처리하느냐가 와탭 Python의 핵심 가치라고 생각하였습니다.----- 이 부분은 Python korea 페이스북에서 '배권한'님이 지적하신 내용을 기반으로 일부 첨언되었습니다.----- python native 개발자들에게는 불필요한 설명에 해당됩니다.파이썬은 분명, 읽기 쉽고 사용하기 쉬운 것은 장점이며, 라즈베리파이 위에서 동작되는 기민함은 정말 매력적입니다. <- 원래 문장.(* 현재에는 jvm도 동작합니다. 하지만, 작고 기민하게 다양한 IoT 디바이스에서 폭넓게 활용되는 것은 파이썬의 장점은 분명하지 않나 합니다. 이 부분에 대한 지적이 있어서 첨언합니다. )내부 구성상 비동기식으로 쓰레딩이 아니라, 단일 이벤트 루프를 사용하는 비동기식 작성은 매우 효과적입니다. <- 원래 문장.(* 이 부분도 asyncio나 gevent등에 대한 이야기이고, CPython의 언어 구현상 GIL때문에 쓰레드가 비효율적이라는 이야기를 거론하고 싶었으나, 일반적으로 파이썬에 대한 언어를 사용할때에 대부분 사용하는 이유가 단일 이벤트 루프기반의 비동기식 작성이 매우 일반적으로 사용되기 때문에, 이렇게 서술되었습니다. 하지만, 이런 설명은 백엔드로 Python을 사용하는 경우에 대부분의 프레임웍들에서 처리되고 있기 때문에 서술이 불분명하다는 지적이 있었습니다. 당연, 백엔드 서비스를 개발할때에 사용되는 wsgi interface등에 맞추어서 서술되는 경우에는 이런 설명이 무의미합니다.다만, 이렇게 서술한 이유는 Java를 기반으로 APM이 개발되어졌기 때문에 이 부분에 대한 서술이나 설명이 필요하다고 생각한 저의 과도한 설명이 되겠습니다.이 부분은 Python Native개발자들에게는 불필요한 설명이 되겠습니다. 하지만, 백엔드 서비스를 개발하면서 만나게될 환경에서는 이 부분에 대한 이해가 어느정도 필요하다고 생각되어 서술된 내용이라고 생각해주시면 감사하겠습니다. )----------------------------------------------------------------------------------------------------------------------이 방식은 복잡한 자원 경쟁이나 교착상태를 발생하지 않게 되며, 기본 코딩과 유지보수를 정말 수월하게 만들어 줍니다. 그만큼 일관성이 높은 수학 알고리즘을 구현하는데 매우 적합합니다. 하지만, 냉정하게, 비즈니스 로직이나 분기가 많은 업무 로직에 적합한 언어는 아닙니다.하지만, 수학적 알고리즘 기반의 주요 모듈 위에 데이터베이스가 일부 필요하고, 웹서비스의 형태로 가동되는 구조라면 파이썬은 매우 훌륭한 선택이 되고 있으며, 생각보다 많이 사용됩니다.그런 이유 중의 하나는 파이썬의 멀티패러다임 구성과 같은 구성에서는 자바에서처럼 굳이 프린트를 위해서 객체지향 클래스를 만들 필요 없이 간단한 함수형 스타일도 가능하게 구성이 됩니다. ( 자바 8에서는 이런 함수 기능도 추가되었습니다. )단순한 구조와 방식 때문에 파이썬 개발은 요즘처럼 ML이나 AI 등의 기술적 요소들이 많이 사용되는 환경에서는 매우 효과적입니다. 백엔드 파이썬 개발이 많이 보이게 되는 이유이기도 하죠.또한, 파이썬 개발의 단점이라고 지적되던 문제들도 현재에는 실행 속도 문제는 사실상 큰 문제가 되지 않는 상황입니다. 일례로, 파이파이(PyPY)로 실행된 파이썬 코드는 웬만한 수준의 C 코드보다 빠르게 동작합니다.굳이 더 지적하자면, 모바일 컴퓨팅과 브라우저에 따른 웹 애플리케이션 클라이언트는 굳이 파이썬으로 작성할 필요성을 느끼지 못한다고 이야기하는 정도입니다.하지만, 이런 파이썬 개발에 가장 큰 문제가 있습니다.테스팅 없이는 동작하기 어렵고,실제 동작 환경에서만 등장하는 오류의 발생파이썬의 특성상 동적 입력 형태에 따르는 더 많은 테스팅을 필요로 하고 있으며, 실제 실행시간에만 나타나는 오류를 찾는 것이 가장 큰 문제가 있습니다. 이 부분은 수많은 파이썬 개발자들을 괴롭히고 있습니다.( 단편적으로 파이썬 개발환경이 매우 고도화되어있지 않으며, 파이썬으로 백엔드 서비스를 만들 것이라고 예측하지 못한 점도 있을 것입니다. 앞으로 파이썬 개발이 더 고도화 되기를 기원합니다. )이 가장 큰 문제를 잡기 위해서와탭은 집중하였습니다.파이썬 백엔드 개발 시의 문제 해결!물론, Python도 디버깅에 대한 지원 유틸리티가 존재합니다.pdb라는 파이썬 디버깅 모듈을 통해서 Step over/Step into, 중단점(breakpoint) 설정, 콜 스택 검사, 소스 리스팅, 변수 치환 등을 할 수 있습니다.‘Phthon -m pdb 파이썬 파일. py’의 형태로 디버그 동작 화면에서 세부적인 동작을 트레이스 해보는 방식을 사용하거나, pdb모듈을 import 한 후에 pdb.set_trace()를 중단하고 싶은 부분에 넣어서 사용하는 방식도 사용됩니다. 또한, 디버그 세션을 사용하는 방식이며, PDB를 사용하여 디버깅하는 방식들도 흔하게 사용됩니다.PyCharm, PTVS, Spyder 등의 IDE를 사용해서 디버깅을 하는 방법은 전통적인 개발환경과 동일하게 사용할 수 있습니다.하지만, 이 방식들은 백엔드 서비스에는 맞지 않게 되며 개발자들은 백엔드 서비스 동작시에 디버그 추적을 위한 로그를 거는 방식을 흔하게 사용하게 됩니다. ( 너무도 전통적인 방식이죠. )정말 백엔드로 파이썬을 사용하고 있다면, 오류 추적이나 동작 메커니즘을 추적한다는 것은 매우 귀찮고 번거로운 작업이 됩니다.만들어지는 파이썬의 모든 파일에 해당 로그를 넣었다가 빼었다가, 배포의 오류를 만나는 상황까지 매우 번거로운 작업들이 끊임없이 반복되게 됩니다. 이런 상황들을 추적하기 위한 APM의 추적 기능들을 찾게 됩니다.또한, Python의 특징상 수학 알고리즘으로 구성된 API 중개인의 형태를 취할 경우에 DB에 대한 접근을 위한 ORM에서의 추적과 외부 웹 호출들이 뒤섞이게 되면서 오류 추적은 매우 짜증스러운 단계로 진화되게 됩니다.Python으로 백엔드 개발을 하게 되면만나게 되는 매우 짜증스러운 상황이죠.그래서, 와탭의 Python APM은 이 문제에 집중하기 위해서 와탭 고유의 문제 해결 방식을 그대로  아키텍처로 적용하여서 개발시에 편하고 빠르게 성능을 추적할 수 있도록 제작되었습니다. Python 백엔드 개발을 위한 최선의 방향을 제시합니다.Python개발자는 와탭의 APM을 설치하면 매우 손쉽게 웹 트랜잭션의 단계, 에러 추적, 클래스 추적, DB의 형태 및 Slow Query추적, 외부 호출 메커니즘의 구성 등을 설치 이후부터 빠르게 추적할 수 있으며, 개발자의 실수이거나 다른 외부 호출의 문제, DB와의 관계 등을 빠르게 잡아낼 수 있습니다.에러를 추적하기 위한 로그를 동작한다던지, 실환경시에 배포를 다시 한다던가 하는 귀찮은 작업을 모두 제거하는 것뿐만 아니라, 매우 통계적으로 의미 있는 와탭의 트랜잭션 추적 메커니즘을 사용할 수 있게 됩니다.파이썬을 기반으로 백엔드를 구성하는 곳이라면,와탭 APM은 매우 의미 있는 결과를 도출할 수 있습니다.와탭 Python의 세부적인 기능을 조금 더 상세하게 설명드리겠습니다.가장 먼저, 실시간 트랜잭션 모니터링!5초 주기로 트랜잭션을 수집하는 와탭의 방식은 서버의 부하를 최소화하면서 가장 의미 있는 데이터들을 수집하고 데이터 기반으로 오류와 트랜잭션을 빠르게 추적할 수 있게 합니다.파이썬 개발 시의 동작성을 체크하기 위한 와탭만의 고유의 진행 중인 트랜잭션 실시간 모니터링 기능인 아크 이퀄라이져와 동작된 웹 트랜잭션의 종료시간을 기준으로 시각화하여 동작된 트랜잭션의 상황을 한눈에 파악할 수 있습니다.와탭 Python APM위의 그림을 보면, Active Transaction으로 불리는 원형( 아크 이퀄라이져라 함 )으로 실제 동작중인 트랜잭션의 개수와 동작속도 등을 체크할 수 있으며, Hitmap을 통해서 종료된 트랜잭션의 속도를 시각화하여 볼 수 있습니다. 이 두 개의 시각화 만으로도 느린 트랜잭션을 추적 관리할 수 있습니다.Python 트랜잭션 추적 및 분석개발자는 단지 APM을 동작시켰을 뿐이지만, postgreSQL 데이터베이스에 연결하고 SQL문장을 주고받는 부분들을 하나의 시각화된 관점으로 나열해서 확인할 수 있습니다.각각의 동작 시간을 추적하는 것은 물론이고, 이 내용은 ORM으로 매핑된 상태에서도 SQL의 동작 순서대로 시각화되기 때문에 순서가 꼬이거나 문제가 발생되는 부분들을 손쉽게 찾아볼 수 있게 합니다.이외에도 와탭 APM( Java, Node, PHP 등의 모든 APM)에 기본적으로 제공되는 트랜잭션 추적 모듈 이외에도 사용자가 원하는 모듈 추적에 대한 기능들을 플러그인 형태로 정의할 수 있습니다. 더 복잡한 추적을 위해서 와탭의 고유기능을 추가적을 확대 사용이 가능합니다.WHATAP_HOME 의 plugin.json파일에 적절한 내용을 수정하여 특정 모듈의 데이터를 추적할 수 있습니다. 특정 모듈의 데이터를 추적하거나, 사용자 별로 원하는 모듈을 추적할 수 있습니다.*사용 안내:•[module_name]: 추적하고자 하는 대상의 모듈 명. import 하는 모듈 명 이기도 하다.•[class_name]: 추적하고자 하는 대상의 클래스 명. 없다면 ‘’(empty string)으로 사용한다.•[def_name]: 추적하고자 하는 대상이다.•args_indexes: 추적하고자 하는 대상의 아규먼트 인덱스. 여러 개일 경우 , 로 구분한다.•kwargs: 추적하고자 하는 대상의 키워드 명. 여러 개일 경우 , 로 구분한다.Plugin 기능 사용위의 예제에서는 Plugin과 SQL update문장의 순차적인 실행,세부 Plugin 설정에서 사용자의 모듈명, 추적 클래스 명, 추적대상과 아규먼트 인덱스, 키워드 등을 추적할 수 있습니다.*사용 예:plugin.json{"[module_name]": {      "class_name": "[class_name]",      "def_name": "[def_name]",      "args_indexes": ", ",      "kwargs": ", "},"httplib2": {      "class_name": "Http",      "def_name": "request",      "args_indexes": "1",      "kwargs": "method"},"faker.providers.address": {      "class_name": "Provider",      "def_name": "street_address",      "args_indexes": "",      "kwargs": ""}}두 번째, 데이터베이스를 매핑한 ORM과 SQL의 순서와 속도, Slow Query!매우 당연하게 파이썬을 기반으로 백엔드 개발을 할 경우에 데이터베이스를 사용하게 되며, 이에 대한 Slow Query와 관련된 추적하는 것이 개발자에게 필요하게 됩니다. 향후, RDS기반을 사용하게 되면 Query추적은 대부분의 데이터베이스 처리에 기본이 될 것입니다.현재 지원되고 있는 mysql / postgresql에 대하여 SQL Query, Fetch Count, SQL Query수행 시간을 수집합니다.Python개발 시에 RDBMS(관계형 데이터베이스 관리 시스템)를 선택하면 거의 항상 ORM(객체 관계 매핑) 라이브러리를 함께 사용하게 됩니다.특히, 파이썬에서는 이런 ORM라이브러리가 다양하고 사용하기 쉽기 때문에, 매우 흔하게 사용하고 있습니다.ORM의 장점으로는 쿼리를 생성하거나 추상화하는 대신, 데이터 베이스 시스템에 대한 접근을 쉽게 할 수 있는 장점이 있습니다. 다만, 이러한 장점 때문에 실제 만들어진 쿼리가 어떠하고 쿼리 수행 시간이 얼마나 걸리는지에 대해서는 추적이 어렵다는 점이 있습니다.이처럼, 파이썬의 특징상 ORM(객체 관계 매핑) 라이브러리를 사용할 경우에 추상화된 쿼리가 어떻게 동작하고, 실제 어떤 상황으로 발생 및 동작되는지를 한눈에 파악할 수 있게 합니다.ORM으로 매핑된 SQL의 순차적인 동작 상태 파악그리고, 세 번째. 외부 호출 추적파이썬 백엔드 개발 시에 사용되는 외부 호출(request/httplib2)등의 외부 호출과 관련된 호출 정보 및 수행 시간 등을 수집합니다.외부 호출을 사용하는 경우에는 각각의 호출에 대한 지연시간에 대해서 세밀하게 추적해야 하므로, 이와 관련된 에러와 지연시간 등을 추적하는 것은 매우 중요한 개발 시의 관점입니다.Python 외부 호출 추적마지막 중요 관점 네 번째는, 튜닝을 위한 다양한 프로파일 데이터의 제공을 이야기할 수 있습니다.와탭의 파이썬 에이전트는 위에서 나열되는 성능 저하를 위한 요소들의 전체적인 관점에서 수집하고 그 데이터들을 시각화할 수 있습니다.데이터베이스를 효율적으로 사용하고 있는지, 사용하는 ORM툴과 매핑과의 관계, 쿼리와 쿼리의 수행 시간과 상태에 대한 추적, 외부 호출시간과 각각의 지연되는 외부 호출과의 관계와 순서 등이 전체적으로 백엔드로 개발되는 Python의 성능 튜닝에 영향을 주게 되는 것이죠.그 이외에도 전체적으로 백엔드 서비스의 TPS, 응답 시간, 서비스 리소스 사용량과 어떤 에러가 발생되고 있는지를 알 수 있습니다.서비스 사용자가 사용하는 상세한 정보들을 프로파 일릉 함으로써 이들의 연관관계를 한분에 파악하게 해줍니다. 와탭에서 관리되는 프로파일 정보는 - 트랜잭션, SQL Query, 외부 HTTP호출, Error, User Agent, Client IP 등의 상관관계들입니다.그리고, 덤으로... Python이 설치 운영되는 전체적인 패키지의 버전을 한눈에 파악할 수 있는 것은 너무도 당연한 기능입니다.설치된 Python 패키지 확인그리고, 와탭의 DNA를 그대로 이어받은 APM이기 때문에, 기본적인 APM의 기능들을 대부분 담고 있습니다. 처음 와탭 APM을 접하시는 분들을 위해서 간단하게 설명드리면 다음과 같습니다.CUBE 메뉴는 시간을 기점으로 와탭 Python APM이 설치된 이후부터 현재까지의 모든 상황들을 추적 관찰할 수 있습니다. 주말에 오류 간 난 상황이라던지, 특정 오류의 발생 시점을 알고 있는 경우에 빠르게 해당 문제가 발생한 위치나 SQL 등을 추적할 수 있습니다.상세한 일간, 주간, 월간 리포트나 MAU 등을 추적할 수 있는 리포트 기능들은 와탭만이 가지고 있는 장점에 해당됩니다.Python으로 백엔드 웹서비스를 개발하고 계시다면, WHATAP Python APM은 개발과 운용을 매우 풍요롭고 빠르게 해줍니다.파이썬 백엔드 서비스 개발자라면 와탭 APM!
조회수 1119

장애를 가장 빠르게 알아내는 액티브 트랜잭션

IT 서비스는 장애가 발생할 수 밖에 없습니다. 현대의 서비스는 지속적으로 커지고 복잡해지고 있습니다. 이를 해결하기 위한 MSA 구조는 장애의 규모를 줄여줄수 있지만 장애는 여전히 발생합니다. 그렇기 때문에 최근 애플리케이션 운영은 장애의 규모를 줄이고 장애를 빠르게 해결하는데 집중하고 있습니다.  그런데 이미 오래전부터 장애를 빠르게 해결하는 문화를 가진 지역이 있습니다. 바로 우리가 살고 있는 대한민국 서울입니다. 2000년에 엔터프라이즈의 IT 서비스가 태동될 때, 경험많은 해외 IT 기업들이 5년이 걸릴것이라 예상하는 ERP 시스템 통합을 한국의 기업들은 2년에서 3년만에 이뤄내는 기적(IT 지옥의 시작)을 이뤄냅니다. IT 기술이 전혀 없던 나라에서 빠르게 엔터프라이즈 IT 서비스들을 만들어 나가다보니 많은 문제들이 생겼습니다. IT 엔지니어의 혹사도 문제였지만 급하게 만들어진 IT 서비스들을 운영하는 것도 쉽지가 않았습니다. 2000년 중반의 어렵던 프로그래머의 삶을 대표하는 이미지이 때, 국내에 APM(Application Performance Mangement, 애플리케이션 성능 관리) 솔루션들이 혜성처럼 나옵니다. APM 솔루션을 통해 서비스 장애 원인을 알아낼 수 있었기 때문에 국내 엔터프라이즈 서비스를 운영하던 기업들에게 APM 솔루션은 단비와 같았습니다. 그리고 국내 APM 솔루션들은 해외 솔루션들과 비교되는 몇몇 특징을 가지고 있었는데, 그 중 하나가 실시간 어플리케이션 분석이였습니다. 그 중에서도 대표적인 실시간 분석 기능이 액티브 트랜잭션입니다. 액티브 트랜잭션애플리케이션 성능 분석 솔루션은 종료된 트랜잭션을 분석하는 기술입니다. 고객의 요청에서 응답까지의 과정을 트랜잭션이라고 합니다. 이렇게 완료된 고객의 요청을 하나 하나 분석하면 애플리케이션의 성능을 알아낼 수 있습니다. 그리고 액티브 트랜잭션은 종료되기 전의 트랜잭션을 분석하는 것입니다. 아직 완료되지 않은 트랜잭션을 분석하기 때문에 액티브 트랜잭션은 장애를 가장 빠르게 볼 수 있는 선행지표가 됩니다. 이해를 돕기 위해 아래에 벤더별 액티브 트랜잭션을 보여드립니다. 제니퍼소프트의 Active Service트랜잭션의 요청건수, 진행건수(Active Service), 완료건수가 상단에 나옵니다. 하단에는 다양한 방법으로 진행건수Active Service)를 보여주고 있습니다. 액셈의 Active Transaction트랜잭션의 요청건수, 대기건수(Active Service), 완료건수가 상단에 나옵니다. 하단에는 대기건수만(Active Transaction)를 보여주고 있습니다.와탭랩스의 Active Transaction트랜잭션의 진행건수를 원형으로 보여주고 있습니다. 와탭의 서비스는 대용량 분석을 위해 기존의 이퀄라이즈를 원형으로 보여주는 특징을 가지고 있습니다. 액티브 트랜잭션은 서비스를 오픈하는 과정에서 큰 효과를 보입니다. 아직 서비스가 완벽하지 않은 상태에서 부하 테스트를 하게 되면 서비스에 락이 걸리면서 트랜잭션이 연속으로 홀딩되면서 서비스 전체가 다운되기도 하는데, 이렇게 되면 종료된 트랜잭션으로는 분석이 불가능하기 때문입니다. 장애 상황에서의 액티브 트랜잭션장애 상황이 되면 일반적으로 액티브 트랜잭션의 양이 증가하게 됩니다. 아래는 와탭의 성능추이에서 볼수 있는 엑티브 트랜잭션의 건수를 표현하는 지표입니다. 평소 액티브 트랜잭션이 10건 이하였다면 아래와 같은 상황은 장애 상황일 확률이 높습니다. 마무리애플리케이션 성능을 분석하는 기준은 트랜잭션입니다. 데이터 분석 기준으로는 종료된 트랜잭션을 추적하는 것이 가장 중요합니다. 하지만 액티브 트랜잭션은 선행지표로서의 의미와 함께 종료된 트랜잭션으로 분석할 수 없는 상황을 알아낼 수 있는 중요한 지표이기도 합니다. 여러분이 사용하는 애플리케이션 성능 분석 도구가 있다면 액티브 트랜잭션 지표도 잘 활용하시기 바랍니다. #와탭랩스 #개발자 #개발팀 #인사이트 #경험공유 #일지

기업문화 엿볼 때, 더팀스

로그인

/