From 2cd48fd698230f2aaf9b6afc6fca442bc60c5ba8 Mon Sep 17 00:00:00 2001 From: Hanbyul Lee Date: Fri, 8 Nov 2024 20:19:36 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EC=95=84=EC=A7=81=20baseurl=20=EB=B0=98=EC=98=81?= =?UTF-8?q?=20=EC=95=88=20=EB=90=9C=20=EA=B2=83=20=EC=B0=BE=EC=95=84?= =?UTF-8?q?=EC=84=9C=20=EC=A0=95=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\263\240-\353\246\254\353\251\244\353\262\204.md" | 2 +- ...\260\215-\353\217\204\354\240\204\352\270\260.md" | 4 ++-- ...\240\204-\353\214\200\354\235\221\352\270\260.md" | 8 ++++---- ...\225\261-\353\247\214\353\223\244\352\270\260.md" | 8 ++++---- ...252\250\353\213\210\355\204\260\353\247\201-1.md" | 12 ++++++------ ...\235\204-\354\234\204\355\225\230\354\227\254.md" | 12 ++++++------ ...252\250\353\213\210\355\204\260\353\247\201-2.md" | 6 +++--- ...\206\214\355\231\224-\355\225\230\352\270\260.md" | 8 ++++---- ...4\240\201\354\232\251\355\225\230\352\270\260.md" | 8 ++++---- ...5\204\260\353\262\240\354\235\264\354\212\244.md" | 6 +++--- ...35\204-\355\225\230\353\212\224\352\260\200-1.md" | 8 ++++---- ...5\224\204\353\241\234\354\240\235\355\212\270.md" | 6 +++--- _posts/2016-04-27-crop.md | 8 ++++---- ...\217\204\354\236\205-\355\233\204\352\270\260.md" | 6 +++--- ...3\217\204\354\236\205\355\225\230\352\270\260.md" | 6 +++--- ...\235\230-\354\204\261\354\236\245\352\270\260.md" | 6 +++--- ...\240\201\355\231\224-feat-ruby-prof-benchmark.md" | 8 ++++---- ...\246\254\353\267\260-\353\260\233\352\270\260.md" | 2 +- ...\355\214\200-2022-1q-\355\232\214\352\263\240.md" | 6 +++--- ...4\240\210\354\225\275\355\225\230\352\270\260.md" | 2 +- ...rn-berry-\353\217\204\354\236\205\352\270\260.md" | 4 ++-- 21 files changed, 68 insertions(+), 68 deletions(-) diff --git "a/_posts/2015-10-14-amazon-web-services-capistrano-\352\267\270\353\246\254\352\263\240-\353\246\254\353\251\244\353\262\204.md" "b/_posts/2015-10-14-amazon-web-services-capistrano-\352\267\270\353\246\254\352\263\240-\353\246\254\353\251\244\353\262\204.md" index 79e2062..bb516c6 100644 --- "a/_posts/2015-10-14-amazon-web-services-capistrano-\352\267\270\353\246\254\352\263\240-\353\246\254\353\251\244\353\262\204.md" +++ "b/_posts/2015-10-14-amazon-web-services-capistrano-\352\267\270\353\246\254\352\263\240-\353\246\254\353\251\244\353\262\204.md" @@ -21,7 +21,7 @@ tags: 지금 우리가 배포하려는 서버는 다음과 같은 구조를 가지고 있다고 가정합니다. -[![서버구조](/images/8yVXHQuTvF.png)](https://blog.dramancompany.com/wp-content/uploads/2015/09/스크린샷-2015-09-25-14.42.22.png) +[![서버구조]({{ site.baseurl }}/images/8yVXHQuTvF.png)](https://blog.dramancompany.com/wp-content/uploads/2015/09/스크린샷-2015-09-25-14.42.22.png) 이와같은 구조에서 배포를 할 경우 일단 ELB 구성이 되어 있으므로 다음과 같은 순서로 무중단 배포는 가능합니다. diff --git "a/_posts/2015-11-18-tom\352\263\274-jaden\354\235\230-\354\262\253-\355\216\230\354\226\264-\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215-\353\217\204\354\240\204\352\270\260.md" "b/_posts/2015-11-18-tom\352\263\274-jaden\354\235\230-\354\262\253-\355\216\230\354\226\264-\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215-\353\217\204\354\240\204\352\270\260.md" index eb3b658..cb331f8 100644 --- "a/_posts/2015-11-18-tom\352\263\274-jaden\354\235\230-\354\262\253-\355\216\230\354\226\264-\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215-\353\217\204\354\240\204\352\270\260.md" +++ "b/_posts/2015-11-18-tom\352\263\274-jaden\354\235\230-\354\262\253-\355\216\230\354\226\264-\355\224\204\353\241\234\352\267\270\353\236\230\353\260\215-\353\217\204\354\240\204\352\270\260.md" @@ -102,13 +102,13 @@ MPA로 B/O 제품들을 개발하던 Jaden은 시스템 속도 개선, 생산성 턴제 방식의 페어 방식의 페어 프로그래밍을 진행하던 중, 둘 다 아무래도 처음 정했던 1시간이 애매한 시간이라는 생각이 들었습니다. 1시간이 집중도가 한참 높아질 때여서 1시간 마다 턴 변경을 자주 놓치게 되었고 그러다 보니 키보드를 잡고 있지 않은 사람의 집중도가 약간 떨어지는 경향이 있었습니다. 그래서 방식을 동시제로 변경했습니다. 다음 사진을 보시죠. -[![pair_programming](/images/lksLiI09Bl.jpg)](https://blog.dramancompany.com/wp-content/uploads/2015/11/pair_programming.jpg) +[![pair_programming]({{ site.baseurl }}/images/lksLiI09Bl.jpg)](https://blog.dramancompany.com/wp-content/uploads/2015/11/pair_programming.jpg)   사진 왼쪽의 노트북에서는 설계와 관련된 내용을 작성, 가운데의 모니터로 코드를 공유, 오른쪽의 노트북으로는 결과 실행을 합니다. 가운데의 키보드와 트랙패드는 우측 노트북과 연결하여 Tom이 사용하고 Jaden은 우측의 노트북으로 코드를 작성합니다.[](http://deopard.cafe24.com/wp-content/uploads/2015/10/pair_programming.jpg) -[![slack-for-ios-upload-1]({{ site.baseurl }}/images/IabfBFuDLV.jpg)](https://blog.dramancompany.com/wp-content/uploads/2015/11/Slack-for-iOS-Upload-1.jpg) [![slack-for-ios-upload-2](/images/PDFZ57K6U8.jpg)](https://blog.dramancompany.com/wp-content/uploads/2015/11/Slack-for-iOS-Upload-2.jpg) +[![slack-for-ios-upload-1]({{ site.baseurl }}/images/IabfBFuDLV.jpg)](https://blog.dramancompany.com/wp-content/uploads/2015/11/Slack-for-iOS-Upload-1.jpg) [![slack-for-ios-upload-2]({{ site.baseurl }}/images/PDFZ57K6U8.jpg)](https://blog.dramancompany.com/wp-content/uploads/2015/11/Slack-for-iOS-Upload-2.jpg) _<혼자가 아닌 둘이니 개발 설계에 대해 토의도 하면서 화이트보드에 적을 수도 있습니다>_ diff --git "a/_posts/2015-11-25-\353\246\254\353\251\244\353\262\204\354\235\230-\354\225\210\353\223\234\353\241\234\354\235\264\353\223\234-6-0-m\353\262\204\354\240\204-\353\214\200\354\235\221\352\270\260.md" "b/_posts/2015-11-25-\353\246\254\353\251\244\353\262\204\354\235\230-\354\225\210\353\223\234\353\241\234\354\235\264\353\223\234-6-0-m\353\262\204\354\240\204-\353\214\200\354\235\221\352\270\260.md" index 906ad71..6906c3a 100644 --- "a/_posts/2015-11-25-\353\246\254\353\251\244\353\262\204\354\235\230-\354\225\210\353\223\234\353\241\234\354\235\264\353\223\234-6-0-m\353\262\204\354\240\204-\353\214\200\354\235\221\352\270\260.md" +++ "b/_posts/2015-11-25-\353\246\254\353\251\244\353\262\204\354\235\230-\354\225\210\353\223\234\353\241\234\354\235\264\353\223\234-6-0-m\353\262\204\354\240\204-\353\214\200\354\235\221\352\270\260.md" @@ -10,7 +10,7 @@ date: "2015-11-25" 리멤버 또한 구글이 준 유예기간 동안 프리뷰 이미지 및 오픈 테스트 랩 등을 활용해 새로운 안드로이드 M버전에 대응하였습니다. 그 과정을 공유드리고자 합니다. -[![pv9AcTqS-gotB5ply6js6SgqwcMrXcvbZlicenbfWh5Q-iW7cf6RrGM-TR7dSM0Z2BbVGA=s2048](/images/6O5FqHXNU1.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/pv9AcTqS-gotB5ply6js6SgqwcMrXcvbZlicenbfWh5Q-iW7cf6RrGM-TR7dSM0Z2BbVGAs2048.png) 안드로이드 6.0 마시맬로우 마스코트. 필자는 이 그림과 똑같은 피규어가 있습니다. +[![pv9AcTqS-gotB5ply6js6SgqwcMrXcvbZlicenbfWh5Q-iW7cf6RrGM-TR7dSM0Z2BbVGA=s2048]({{ site.baseurl }}/images/6O5FqHXNU1.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/pv9AcTqS-gotB5ply6js6SgqwcMrXcvbZlicenbfWh5Q-iW7cf6RrGM-TR7dSM0Z2BbVGAs2048.png) 안드로이드 6.0 마시맬로우 마스코트. 필자는 이 그림과 똑같은 피규어가 있습니다. ## **M버전, 무엇을 대응해야 하나?** @@ -80,7 +80,7 @@ M버전의 대응의 90%는 권한모델을 넣는 것 이였습니다. 그만 [http://developer.android.com/intl/ko/reference/android/Manifest.permission\_group.html](http://developer.android.com/intl/ko/reference/android/Manifest.permission_group.html) -[![6.0 부터는 사용자가 설정창에서 권한그룹 단위로 허용/거부를 명시적으로 할 수 있습니다.](/images/j4mU7284G3.jpeg)](https://blog.dramancompany.com/wp-content/uploads/2015/11/권한그룹-설정창.jpeg) M버전 부터는 사용자가 설정창에서 권한그룹 단위로 허용/거부를 명시적으로 할 수 있습니다. +[![6.0 부터는 사용자가 설정창에서 권한그룹 단위로 허용/거부를 명시적으로 할 수 있습니다.]({{ site.baseurl }}/images/j4mU7284G3.jpeg)](https://blog.dramancompany.com/wp-content/uploads/2015/11/권한그룹-설정창.jpeg) M버전 부터는 사용자가 설정창에서 권한그룹 단위로 허용/거부를 명시적으로 할 수 있습니다. ### 사용자에게 필요한 권한을 요청하자 @@ -275,7 +275,7 @@ public static void requestOverlayPermission(Activity activity) { 설정창으로 넘어가게 하는 것은 쉽지만, 사용자에게 낯선 권한을 허용받기 위해서는 왜 이 권한이 필요한지를 잘 설명하는 것이 중요하겠습니다. -[![system_window_alter는 다른 권한들과 다르게 '다른 앱 위에 그리기' 설정창에서 직접 허용받아야 합니다.](/images/ii392AL6Dc.jpeg)](https://blog.dramancompany.com/wp-content/uploads/2015/11/다른앱-위에-그리기.jpeg) system\_window\_alert는 다른 권한들과 다르게 '다른 앱 위에 그리기' 설정창에서 직접 허용받아야 합니다. +[![system_window_alter는 다른 권한들과 다르게 '다른 앱 위에 그리기' 설정창에서 직접 허용받아야 합니다.]({{ site.baseurl }}/images/ii392AL6Dc.jpeg)](https://blog.dramancompany.com/wp-content/uploads/2015/11/다른앱-위에-그리기.jpeg) system\_window\_alert는 다른 권한들과 다르게 '다른 앱 위에 그리기' 설정창에서 직접 허용받아야 합니다. '다른 앱 위에 그리기' 권한을 사용할 수 있는지 여부는 [Settings.canDrawOverlays()](http://developer.android.com/intl/ko/reference/android/provider/Settings.html#canDrawOverlays(android.content.Context))를 이용해 알 수 있습니다. 하지만 아쉽게도 system\_window\_alert는 다른 권한들처럼 [onRequestPermissionsResult()](http://developer.android.com/intl/ko/reference/android/support/v4/app/ActivityCompat.OnRequestPermissionsResultCallback.html#onRequestPermissionsResult(int, java.lang.String[], int[]))으로 사용자가 권한을 허용/거부한 결과값을 알수 없습니다. 그래서 저희는 위 코드에서도 보이듯이 [startActivityForResult()](http://developer.android.com/intl/ko/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int))로 요청하여 [onActivityResult()](http://developer.android.com/intl/ko/reference/android/app/Activity.html#onActivityResult(int, int, android.content.Intent))에서 결과값을 받아 작업을 실행하였습니다. @@ -308,7 +308,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { ### **최초의 마시맬로우 기기, 넥서스 5x만의 이슈** -[![image00](/images/EiKh8CHhDy.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/image00.png) 넥서스 5x. 필자가 사용하고 있는 폰 입니다. +[![image00]({{ site.baseurl }}/images/EiKh8CHhDy.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/image00.png) 넥서스 5x. 필자가 사용하고 있는 폰 입니다. ### 1\. 전화번호가 국제번호로 변경되어서 옵니다 diff --git "a/_posts/2015-12-04-electron\354\234\274\353\241\234-\354\233\271-\354\225\261-\353\247\214\353\223\244\353\223\257-\353\215\260\354\212\244\355\201\254\355\206\261-\354\225\261-\353\247\214\353\223\244\352\270\260.md" "b/_posts/2015-12-04-electron\354\234\274\353\241\234-\354\233\271-\354\225\261-\353\247\214\353\223\244\353\223\257-\353\215\260\354\212\244\355\201\254\355\206\261-\354\225\261-\353\247\214\353\223\244\352\270\260.md" index f57bc9b..e3c3579 100644 --- "a/_posts/2015-12-04-electron\354\234\274\353\241\234-\354\233\271-\354\225\261-\353\247\214\353\223\244\353\223\257-\353\215\260\354\212\244\355\201\254\355\206\261-\354\225\261-\353\247\214\353\223\244\352\270\260.md" +++ "b/_posts/2015-12-04-electron\354\234\274\353\241\234-\354\233\271-\354\225\261-\353\247\214\353\223\244\353\223\257-\353\215\260\354\212\244\355\201\254\355\206\261-\354\225\261-\353\247\214\353\223\244\352\270\260.md" @@ -12,7 +12,7 @@ date: "2015-12-04" # **Electron** -# [![Electron](/images/E62En13yxt.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-16-오후-4.42.42.png) +# [![Electron]({{ site.baseurl }}/images/E62En13yxt.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-16-오후-4.42.42.png) [Electron](http://electron.atom.io/)은 [Chromium](https://www.chromium.org/)과 [Node.js](https://nodejs.org)를 이용하여 데스크톱 앱을 HTML, CSS, JavaScript로 쉽게 만들 수 있게 해주는 프레임워크입니다. GitHub에서 Atom editor를 만들기 위해서 시작된 프로젝트로 원래 이름은 Atom Shell이었다가 Electon으로 이름이 바뀌었습니다. 앞서 말씀드린 것과 같이 Electon을 이용하면 쉽게 cross-platform 앱을 개발할 수 있습니다.  또한 웹 개발자분들도 익숙한 언어와 코드를 재사용하여 쉽게 데스크톱 앱을 개발할 수 있습니다. @@ -26,7 +26,7 @@ date: "2015-12-04" #### Electron으로 만들어진 앱들 -[![스크린샷 2015-11-16 오후 4.48.30](/images/vzNrP9v0w8.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-16-오후-4.48.30.png) +[![스크린샷 2015-11-16 오후 4.48.30]({{ site.baseurl }}/images/vzNrP9v0w8.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-16-오후-4.48.30.png) [여기](http://electron.atom.io/#built-on-electron)를 확인해보시면 Electron을 이용하여 만들어진 앱들이 나와 있습니다. 아마 제일 앞의 세 개가 낯익으실 텐데, GitHub의 text editor인 Atom, Slack Technologies의 협업 메신저인 Slack, MS의 Visual Studio Code가 있습니다. 세 가지 앱 모두 제가 사용을 하는 앱이고(Atom과 Slack은 컴퓨터가 켜져 있는 시간의 99%) Mac과 Windows 모두 그 퀄리티에 만족을 하면서 사용하고 있었기 때문에 Electon으로도 충분히 좋은 앱을 만들 수 있다고 판단했습니다. @@ -34,7 +34,7 @@ date: "2015-12-04"   -[![5743792](/images/6YWIILjtjG.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/5743792.png) +[![5743792]({{ site.baseurl }}/images/6YWIILjtjG.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/5743792.png) Slack이나 Atom을 Windows 환경에서 인스톨러를 실행할 경우 기존의 '다음', '다음' 그리고 '다음'의 과정 없이 로딩 이미지가 잠깐 뜨다가 바로 앱이 실행됩니다. 그리고 업데이트도 Chrome처럼 언제 일어났는지도 눈치챌 수 없을 정도로 자연스럽게 일어납니다. 이는 [Squirrel 인스톨러](https://github.com/Squirrel)가 자동으로 해주는 부분입니다. 꼭 Squirrel 인스톨러를 사용해야 하는 것은 아니지만, Slack이나 Atom 같은 경우 Squirrel 인스톨러를 사용하여 만들었고 이들이 주장하는 "인스톨과 업데이트는 간단해야 한다"가 제일 만족스러운 부분이었습니다. 정말 인스톨러나 업데이터를 만드는데 신경을 거의 쓰지 않아도 됩니다(한번 이해만 한다면..). @@ -48,7 +48,7 @@ Slack이나 Atom을 Windows 환경에서 인스톨러를 실행할 경우 기존 공식 홈페이지에 나와 있는 [튜토리얼](https://github.com/atom/electron/tree/master/docs-translations/ko-KR)이 잘 되어있다고 생각하기 때문에 이 글에서는 개발 방법에 대한 얘기는 별도로 다루지 않도록 하겠습니다. 그보다 큰 그림을 이해하기 위한 구조를 소개해드리겠습니다. -[![스크린샷 2015-11-16 오후 4.17.55](/images/yO1l9h0trE.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-16-오후-4.17.55.png) 크게 두 가지 프로세스가 존재합니다. Renderer 프로세스는 Chromium 기반으로 HTML, CSS, JavaScript를 이용하여 웹 페이지를 만들듯 view를 구성합니다. Main 프로세스는 Node.js 기반으로 일반적인 Node application이라고 생각하시면 되겠습니다. 모든 node 모듈들을 가져다 쓸 수 있습니다. 그리고 각 프로세스마다 electron 앱에 접근해서 사용할 수 있게 만든 electon에서 제공되는 API들이 담긴 모듈들이 있습니다. 그리고 두 process 사이를 통신할 수 있게 해주는 ipc와 remote module이 존재합니다. 웹 개발자는 원래 front-end를 개발하던 것과 같이 Renderer 프로세스 쪽을 개발하고 back-end를 Node.js로 개발하듯 Main 프로세스 쪽을 개발하면 됩니다. 그때그때 필요한 Electron의 API만 찾아 쓰면 기존의 웹 개발하던 것과 차이가 거의 없습니다. +[![스크린샷 2015-11-16 오후 4.17.55]({{ site.baseurl }}/images/yO1l9h0trE.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-16-오후-4.17.55.png) 크게 두 가지 프로세스가 존재합니다. Renderer 프로세스는 Chromium 기반으로 HTML, CSS, JavaScript를 이용하여 웹 페이지를 만들듯 view를 구성합니다. Main 프로세스는 Node.js 기반으로 일반적인 Node application이라고 생각하시면 되겠습니다. 모든 node 모듈들을 가져다 쓸 수 있습니다. 그리고 각 프로세스마다 electron 앱에 접근해서 사용할 수 있게 만든 electon에서 제공되는 API들이 담긴 모듈들이 있습니다. 그리고 두 process 사이를 통신할 수 있게 해주는 ipc와 remote module이 존재합니다. 웹 개발자는 원래 front-end를 개발하던 것과 같이 Renderer 프로세스 쪽을 개발하고 back-end를 Node.js로 개발하듯 Main 프로세스 쪽을 개발하면 됩니다. 그때그때 필요한 Electron의 API만 찾아 쓰면 기존의 웹 개발하던 것과 차이가 거의 없습니다.   diff --git "a/_posts/2015-12-17-\354\225\210\354\240\225\354\240\201\354\235\270-\354\204\234\353\271\204\354\212\244-\354\232\264\354\230\201\354\235\204-\354\234\204\355\225\234-\354\204\234\353\262\204-\353\252\250\353\213\210\355\204\260\353\247\201-1.md" "b/_posts/2015-12-17-\354\225\210\354\240\225\354\240\201\354\235\270-\354\204\234\353\271\204\354\212\244-\354\232\264\354\230\201\354\235\204-\354\234\204\355\225\234-\354\204\234\353\262\204-\353\252\250\353\213\210\355\204\260\353\247\201-1.md" index 11a9916..822f98d 100644 --- "a/_posts/2015-12-17-\354\225\210\354\240\225\354\240\201\354\235\270-\354\204\234\353\271\204\354\212\244-\354\232\264\354\230\201\354\235\204-\354\234\204\355\225\234-\354\204\234\353\262\204-\353\252\250\353\213\210\355\204\260\353\247\201-1.md" +++ "b/_posts/2015-12-17-\354\225\210\354\240\225\354\240\201\354\235\270-\354\204\234\353\271\204\354\212\244-\354\232\264\354\230\201\354\235\204-\354\234\204\355\225\234-\354\204\234\353\262\204-\353\252\250\353\213\210\355\204\260\353\247\201-1.md" @@ -34,11 +34,11 @@ APM하면 가장 먼저 [Jennifer](http://www.jennifersoft.com)같은 솔루션 APM의 아주 기본적인 기능입니다. NewRelic은 아래 그림과 같이 각 컴포넌트/시스템별로 쪼개서 트랜잭션 수행 시 걸린 시간을 측정합니다. -[![transaction_response_time](/images/u0U9Ihvc9a.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/transaction_response_time.png) +[![transaction_response_time]({{ site.baseurl }}/images/u0U9Ihvc9a.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/transaction_response_time.png) 리멤버 서버 애플리케이션의 경우 모니터링 대상이 되는 컴포넌트들은 아래와 같습니다. -[![transaction_components](/images/YY6nOuPBRd.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/transaction_components.png) +[![transaction_components]({{ site.baseurl }}/images/YY6nOuPBRd.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/transaction_components.png) - Middleware: Rails에서 HTTP 요청을 parsing하여 해당 Controller로 라우팅하는 등 Application 코드가 아닌 Rails 자체에서 요청 처리에 걸린 시간 - Ruby: 개발자가 개발한 애플리케이션에서 걸린 시간 @@ -46,7 +46,7 @@ APM의 아주 기본적인 기능입니다. NewRelic은 아래 그림과 같이 - Redis: Redis에 접속하여 명령을 전달하고 응답을 받기까지 걸린 시간 - Web external: 구글, 네이버, 페이스북 등 외부 API를 호출하여 응답을 받기까지 걸린 시간 -위 그림에서는 오후 2:30분부터 3시까지 ActiveRecord에서 시간이 오래 걸린 것을 볼 수 있습니다. 따라서 이 때 DB에 뭔가 이슈가 있었는지 확인을 해볼 필요가 있습니다.[![system-health](/images/US5qJ1kryg.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/system-health.png) +위 그림에서는 오후 2:30분부터 3시까지 ActiveRecord에서 시간이 오래 걸린 것을 볼 수 있습니다. 따라서 이 때 DB에 뭔가 이슈가 있었는지 확인을 해볼 필요가 있습니다.[![system-health]({{ site.baseurl }}/images/US5qJ1kryg.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/system-health.png) Apdex는 시스템의 전반적인 상태를 나타냅니다. 평균 응답 시간의 threshold(App Server 기본값은 0.5초, Browser는 7초)를 설정하여 특정 시간 동안 이 값을 만족시키지 못하면 alert를 발생시키게 됩니다. Apdex는 순수하게 서버에서 요청을 처리한 시간과 사용자의 브라우저 입장에서 걸린 시간 두 가지를 나누어 보여줍니다. @@ -54,7 +54,7 @@ Throughput은 분당 유입되는 요청의 수를 나타냅니다. 따라서, #### **B. Transaction Traces** -[![transaction_traces](/images/YOR3GW3tZW.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/transaction_traces.png) +[![transaction_traces]({{ site.baseurl }}/images/YOR3GW3tZW.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/transaction_traces.png) 이것도 APM에서 제공하는 기본 기능입니다. 각 트랜잭션에서 메소드별로 처리 시간을 쪼개 보여줍니다. 따라서 어느 메소드에서 시간이 가장 오래 걸렸는지 쉽게 파악할 수 있고 이를 토대로 애플리케이션 혹은 DB 쿼리 튜닝을 할 수 있습니다. 아마 많은 분들이 익숙하신 기능이라 생각됩니다. @@ -62,7 +62,7 @@ Throughput은 분당 유입되는 요청의 수를 나타냅니다. 따라서, 에러 추적을 위한 강력한 기능입니다. 아래와 같이 애플리케이션 내에서 예외가 발생하면 트랜잭션의 여러 가지 속성(요청한 사용자  ID, 요청 시간 등)과 함께 스택 트레이스를 보여줍니다. -[![error_traces](/images/IDK4LAfzeU.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/error_traces.png) +[![error_traces]({{ site.baseurl }}/images/IDK4LAfzeU.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/error_traces.png) 위 에러는 리멤버 앱에서 저장한 명함을 구글 주소록에 동기화할 때 발생한 에러입니다. 구글 주소록 API는 단시간에 너무 많은 요청이 일어나면 위와 같이 UserRateLimitExceeded와 같은 에러를 리턴하는데 이는 개발이나 테스트 환경에서 일어나기 무척 힘든 에러입니다. APM이 없었다면 아마 발견할 수 없었을 것이고 고객 클레임이 들어왔을 것이 분명합니다. 그러나 꾸준한 모니터링을 통해 위 에러를 발견하고 적절히 수정하여 고객 만족도를 더욱 높일 수 있었습니다. @@ -70,7 +70,7 @@ Throughput은 분당 유입되는 요청의 수를 나타냅니다. 따라서, NewRelic은 제 경험상 기능에 대한 업데이트가 빠른 편입니다. 얼마 전에는 NewRelic Insight 모듈(애플리케이션에서 발생하는 이벤트를 분석해주는 도구)을 이용하여 에러를 분석해주는 Error analytics 기능을 추가하였습니다. -[![error_analytics](/images/57cun9RtTZ.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/error_analytics.png) +[![error_analytics]({{ site.baseurl }}/images/57cun9RtTZ.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/error_analytics.png) 물론 단점도 있습니다. 빠르게 업데이트되다 보니 버그도 간혹 생깁니다. 실제로 위의 Error analytics가 추가되고 나서, Background job에서 발생하는 에러가 NewRelic에 잡히지 않는 버그가 있었습니다. 하지만 그에 대한 대응도 빠르게 해주는 편입니다. (버그 리포팅을 했더니 친절하게 응대해주고, 1주일만에 버그 fix한 에이전트를 릴리즈해주었습니다. 이 정도면 괜찮지 않은가요?^^) diff --git "a/_posts/2015-12-17-\354\262\230\354\235\214-windows-\354\204\244\354\271\230-\355\214\214\354\235\274\354\235\204-\353\260\260\355\217\254\355\225\230\353\212\224-\352\260\234\353\260\234\354\236\220\353\223\244\354\235\204-\354\234\204\355\225\230\354\227\254.md" "b/_posts/2015-12-17-\354\262\230\354\235\214-windows-\354\204\244\354\271\230-\355\214\214\354\235\274\354\235\204-\353\260\260\355\217\254\355\225\230\353\212\224-\352\260\234\353\260\234\354\236\220\353\223\244\354\235\204-\354\234\204\355\225\230\354\227\254.md" index e2f3d62..63579b4 100644 --- "a/_posts/2015-12-17-\354\262\230\354\235\214-windows-\354\204\244\354\271\230-\355\214\214\354\235\274\354\235\204-\353\260\260\355\217\254\355\225\230\353\212\224-\352\260\234\353\260\234\354\236\220\353\223\244\354\235\204-\354\234\204\355\225\230\354\227\254.md" +++ "b/_posts/2015-12-17-\354\262\230\354\235\214-windows-\354\204\244\354\271\230-\355\214\214\354\235\274\354\235\204-\353\260\260\355\217\254\355\225\230\353\212\224-\352\260\234\353\260\234\354\236\220\353\223\244\354\235\204-\354\234\204\355\225\230\354\227\254.md" @@ -10,11 +10,11 @@ date: "2015-12-17" 앱 개발을 완성하고 설치 파일까지 만들었다고 모든 것이 끝났다고 생각하시면 안됩니다. 별 생각 없이 설치 파일을 웹에 게시하고 웹페이지에서 다운을 받으면 다음과 같은 화면들을 만나게 됩니다. -[![스크린샷 2015-11-10 오후 6.35.09](/images/Jt0qBXzKtT.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-10-오후-6.35.09.png)_<이 파일은 위험해!>_ +[![스크린샷 2015-11-10 오후 6.35.09]({{ site.baseurl }}/images/Jt0qBXzKtT.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-10-오후-6.35.09.png)_<이 파일은 위험해!>_ -[![alert](/images/nXzCSwax1h.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/alert.png)__ +[![alert]({{ site.baseurl }}/images/nXzCSwax1h.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/alert.png)__ -[![스크린샷 2015-11-17 오후 3.16.01](/images/I8ex3ttEZR.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-17-오후-3.16.01.png)__ +[![스크린샷 2015-11-17 오후 3.16.01]({{ site.baseurl }}/images/I8ex3ttEZR.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-17-오후-3.16.01.png)__ 만약 사용자들이 이런 메시지를 본다면 기껏 열심히 만들어 놓은 앱이 악성 프로그램 취급받게 될 것입니다. 자, 앱 개발은 끝났을 지라도 앱 배포는 이제부터 시작입니다. 이 배포에 걸리는 시간은 생각하는 것보다 _오래_ 걸립니다. @@ -40,13 +40,13 @@ date: "2015-12-17" 이렇게 서명을 완료하면 다음과 같이 뭔가 부족해 보이던 설치파일이 -[![unsigned_installer](/images/i0pAygdDq3.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-17-오후-3.56.59.png) +[![unsigned_installer]({{ site.baseurl }}/images/i0pAygdDq3.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-17-오후-3.56.59.png) 다음과 같이 든든하게 변합니다. -[![signed_installer](/images/tPvQ9mFC8z.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-17-오후-3.58.52.png) +[![signed_installer]({{ site.baseurl }}/images/tPvQ9mFC8z.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-17-오후-3.58.52.png) -[![스크린샷 2015-11-17 오후 4.12.27](/images/4veBpYPpXS.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-17-오후-4.12.27.png) +[![스크린샷 2015-11-17 오후 4.12.27]({{ site.baseurl }}/images/4veBpYPpXS.png)](https://blog.dramancompany.com/wp-content/uploads/2015/11/스크린샷-2015-11-17-오후-4.12.27.png) _<올.바.른. 인증서입니다.>_ diff --git "a/_posts/2015-12-22-\354\225\210\354\240\225\354\240\201\354\235\270-\354\204\234\353\271\204\354\212\244-\354\232\264\354\230\201\354\235\204-\354\234\204\355\225\234-\354\204\234\353\262\204-\353\252\250\353\213\210\355\204\260\353\247\201-2.md" "b/_posts/2015-12-22-\354\225\210\354\240\225\354\240\201\354\235\270-\354\204\234\353\271\204\354\212\244-\354\232\264\354\230\201\354\235\204-\354\234\204\355\225\234-\354\204\234\353\262\204-\353\252\250\353\213\210\355\204\260\353\247\201-2.md" index d40aaf0..1570d35 100644 --- "a/_posts/2015-12-22-\354\225\210\354\240\225\354\240\201\354\235\270-\354\204\234\353\271\204\354\212\244-\354\232\264\354\230\201\354\235\204-\354\234\204\355\225\234-\354\204\234\353\262\204-\353\252\250\353\213\210\355\204\260\353\247\201-2.md" +++ "b/_posts/2015-12-22-\354\225\210\354\240\225\354\240\201\354\235\270-\354\204\234\353\271\204\354\212\244-\354\232\264\354\230\201\354\235\204-\354\234\204\355\225\234-\354\204\234\353\262\204-\353\252\250\353\213\210\355\204\260\353\247\201-2.md" @@ -48,7 +48,7 @@ APM이 현재 시스템의 상태를 실시간으로 보여주는 것에 좀 더 저희가 운영하는 ELK 구성은 다음 그림과 같습니다. -[![elk_architecture](/images/nN49QRk9Gx.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/elk_architecture.png) +[![elk_architecture]({{ site.baseurl }}/images/nN49QRk9Gx.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/elk_architecture.png) #### **A. Logstasher** @@ -86,7 +86,7 @@ ELK Stack에 대해서는 인터넷에 돌아다니는 자료도 워낙 많고, 하지만 서버 사양 말고도 튜닝할 포인트들이 많았기 때문에 일단 m4.xlarge급 인스턴스(CPU 4개, 메모리 16GB)로 유지해도 충분하다고 판단하였습니다. 현재 각 애플리케이션이 차지하고 있는 메모리 사용량은 아래와 같습니다. -[![elk_memory](/images/mtruXi8OkK.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/elk_memory.png) +[![elk_memory]({{ site.baseurl }}/images/mtruXi8OkK.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/elk_memory.png) #### **B. Index Template 최적화** @@ -94,7 +94,7 @@ ELK Stack에 대해서는 인터넷에 돌아다니는 자료도 워낙 많고, 가장 먼저 눈에 띈 것은 ElasticSearch가 기본적으로 로그의 모든 속성을 다 인덱싱하고 있다는 것이었습니다. 이는 ElasticSearch를 설치하고 나면 기본적으로 [Dynamic Mapping](https://www.elastic.co/guide/en/elasticsearch/guide/current/dynamic-mapping.html) 기능이 활성화되어 있기 때문이었습니다. 따라서 검색에 꼭 필요한 필드들만 index를 생성하도록 인덱스 템플릿을 조정해 줄 필요가 있습니다. -[![elk_index](/images/05p6PHuaTg.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/elk_index1.png) +[![elk_index]({{ site.baseurl }}/images/05p6PHuaTg.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/elk_index1.png) 위의 템플릿 설정에서 "\_default\_" 의 "dynamic" 속성을 false로 지정하여 지정된 필드 이외에는 인덱싱하지 않도록 설정하였습니다. diff --git "a/_posts/2016-01-01-rds-mysql\354\227\220\354\204\234-rds-aurora\353\241\234-db\354\235\264\354\240\204-\353\213\244\354\232\264\355\203\200\354\236\204\354\235\204-\354\265\234\354\206\214\355\231\224-\355\225\230\352\270\260.md" "b/_posts/2016-01-01-rds-mysql\354\227\220\354\204\234-rds-aurora\353\241\234-db\354\235\264\354\240\204-\353\213\244\354\232\264\355\203\200\354\236\204\354\235\204-\354\265\234\354\206\214\355\231\224-\355\225\230\352\270\260.md" index c380a9e..0f3bcde 100644 --- "a/_posts/2016-01-01-rds-mysql\354\227\220\354\204\234-rds-aurora\353\241\234-db\354\235\264\354\240\204-\353\213\244\354\232\264\355\203\200\354\236\204\354\235\204-\354\265\234\354\206\214\355\231\224-\355\225\230\352\270\260.md" +++ "b/_posts/2016-01-01-rds-mysql\354\227\220\354\204\234-rds-aurora\353\241\234-db\354\235\264\354\240\204-\353\213\244\354\232\264\355\203\200\354\236\204\354\235\204-\354\265\234\354\206\214\355\231\224-\355\225\230\352\270\260.md" @@ -30,7 +30,7 @@ DB이전을 할 때 다운타임을 최소화 하기 위한 방법은 놀라울 우선 AuroraDB의 인스턴스를 생성해 보겠습니다. 생성 시 기존에 사용하던 MySQL Master DB의 최신 Snapshot을 이용해 AuroraDB로 Migrate합니다. MySQL MasterDB를 선택하고, 상단의 Instance Actions탭에서 "Take Snapshot"을 눌러 현재 시점의 스냅샷을 준비해주세요. -[![Migrate Lastest Snapshot](/images/hDKynz6I9p.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/스크린샷-2015-12-09-오후-12.45.08.png) +[![Migrate Lastest Snapshot]({{ site.baseurl }}/images/hDKynz6I9p.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/스크린샷-2015-12-09-오후-12.45.08.png) 스냅샷이 준비되었다면, "Migrate Latest Snapshot"를 눌러줍니다. @@ -42,7 +42,7 @@ _**자, Migrate버튼을 누르기 전에 이쯤에서 정말 중요한 메모 > SHOW MASTER STATUS; -[![스크린샷 2015-12-09 오후 6.11.10](/images/ybh08w1UGn.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/스크린샷-2015-12-09-오후-6.11.10.png) +[![스크린샷 2015-12-09 오후 6.11.10]({{ site.baseurl }}/images/ybh08w1UGn.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/스크린샷-2015-12-09-오후-6.11.10.png) 확인 하셨나요? 그러면 재빨리 Migrate버튼을 눌러 인스턴스를 생성합니다. @@ -64,7 +64,7 @@ _**자, Migrate버튼을 누르기 전에 이쯤에서 정말 중요한 메모 드디어 되었군요. 4시간 반의 티 타임 끝에 AuroraDB 인스턴스가 준비되었습니다. 이 글을 읽으시는 분 들은 마이그레이션이 언제 완료되나 무작정 기다리지 마시고, "DB Cluster Details"탭의 "Migration Progress"를 참고하시면 현재 진행 상황을 자세하게 알려주니, 저처럼 무작정 기다리지 않으셔도 될 것 같습니다.(있는 줄 몰랐습니다..) -[![스크린샷 2015-12-09 오후 4.19.13](/images/Z7W7yXbb4O.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/스크린샷-2015-12-09-오후-4.19.13.png) +[![스크린샷 2015-12-09 오후 4.19.13]({{ site.baseurl }}/images/Z7W7yXbb4O.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/스크린샷-2015-12-09-오후-4.19.13.png) AuroraDB 인스턴스가 준비되었다면, 다음 단계로 넘어가도록 하겠습니다. @@ -82,7 +82,7 @@ IP를 잘 적어둔 후, RDS Instances 콘솔에 접속한 후 MySQL의 Security 창이 열리면, "Add Rule"를 해 Row하나를 추가 한 후 Type은 "_**All traffic**_"으로 지정하고, 아까 적어 둔 AuroraDB의 아이피를 다음과 같이 적어줍니다. "1.1.1.1/32" (DB 이전을 완료 한 후에는 방금 추가한 Rule을 삭제해 주세요.) -[![스크린샷 2015-12-09 오후 6.06.52](/images/BhcBMP9YI5.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/스크린샷-2015-12-09-오후-6.06.52.png) +[![스크린샷 2015-12-09 오후 6.06.52]({{ site.baseurl }}/images/BhcBMP9YI5.png)](https://blog.dramancompany.com/wp-content/uploads/2015/12/스크린샷-2015-12-09-오후-6.06.52.png) 이제 VPC 설정은 다 되었습니다. diff --git "a/_posts/2016-03-11-\354\225\210\353\223\234\353\241\234\354\235\264\353\223\234\354\227\220-flux-\354\240\201\354\232\251\355\225\230\352\270\260.md" "b/_posts/2016-03-11-\354\225\210\353\223\234\353\241\234\354\235\264\353\223\234\354\227\220-flux-\354\240\201\354\232\251\355\225\230\352\270\260.md" index a0431e6..3f02c4b 100644 --- "a/_posts/2016-03-11-\354\225\210\353\223\234\353\241\234\354\235\264\353\223\234\354\227\220-flux-\354\240\201\354\232\251\355\225\230\352\270\260.md" +++ "b/_posts/2016-03-11-\354\225\210\353\223\234\353\241\234\354\235\264\353\223\234\354\227\220-flux-\354\240\201\354\232\251\355\225\230\352\270\260.md" @@ -6,11 +6,11 @@ date: "2016-03-11" --- -[![flux](/images/fDdKUa7aKL.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/flux.png) +[![flux]({{ site.baseurl }}/images/fDdKUa7aKL.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/flux.png) Flux는 MVC모델의 단점을 보완하기 위해 페이스북에서 고안한 패턴으로, 웹개발 환경에서 먼저 쓰여지기 시작하였습니다. [2014년에 페이스북에서 Flux를 발표](https://facebook.github.io/flux/)하였는데, 발표 후 많은 웹개발자들의 관심과 함께 기술적인 논의도 활발히 이루어졌습니다. -[![플럭스](/images/ScNebVF999.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/flux-diagram-white-background.png) 플럭스는 리액트와 함께 웹 분야에서 등장한 패턴입니다. +[![플럭스]({{ site.baseurl }}/images/ScNebVF999.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/flux-diagram-white-background.png) 플럭스는 리액트와 함께 웹 분야에서 등장한 패턴입니다. 저는 이것이 무엇이길래 다들 이렇게 주목하는가 궁금했습니다. 그리고 이것이 패턴이라면, 안드로이드에도 적용하여 구조개선을 이룰 수 있지 않을까, 기대감을 품고 학습을 시작하였습니다. 결론을 먼저 말씀드리면, 기대했던만큼 좋은 패턴은 아니라고 생각합니다. 단점도 있고, 새로운 패턴이라고 하기에 모호한 부분이 있습니다. 하지만 MVC, MVP 등의 전통 패턴과는 다른 관점으로 생각할 수 있도록 안내하고, 어떠한 경우에 있어서는 개발을 하기 쉽도록 도와줍니다. @@ -28,7 +28,7 @@ Flux를 짧게 설명하면, 데이터를 단방향으로 흐르도록 하여, Action은 어느 뷰에서나 생성될 수 있습니다. Dispatcher는 생성된 Action을 스토어에 보내고, 스토어는 Action을 수행 후 다시 Dispatcher를 통해 View에게 자신의 데이터가 갱신되었음을 알립니다. 이 일련의 과정에서 Action을 전역으로 전달하는 Dispatcher는 다양한 방법으로 구현할 수 있습니다. 위 프로젝트에서는 Bus라는 클래스로 직접 구현하였습니다. 하지만 이 글을 읽으시는 분들께서 만약 싱글톤을 이용한 전역 이밴트 관리가 익숙하지 않으시다면, 유명한 라이브러리인 [이밴트 버스](https://github.com/greenrobot/EventBus)를 사용해서 Dispatcher를 대체할 수 있습니다. -[![이벤트 버스](/images/CSgHC8so6F.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/EventBus-Publish-Subscribe.png) 위 그림에서 Event를 Action, Event Bus를 Dispatcher로 생각하면 이해가 쉽습니다. Subscriber는 Action을 받는 곳으로, Store 또는 View가 될 수 있습니다. +[![이벤트 버스]({{ site.baseurl }}/images/CSgHC8so6F.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/EventBus-Publish-Subscribe.png) 위 그림에서 Event를 Action, Event Bus를 Dispatcher로 생각하면 이해가 쉽습니다. Subscriber는 Action을 받는 곳으로, Store 또는 View가 될 수 있습니다.   @@ -36,7 +36,7 @@ Action은 어느 뷰에서나 생성될 수 있습니다. Dispatcher는 생성 리멤버에서는 명함 교환방 기능에서 Flux를 사용하였습니다. 명함 교환방은 오프라인 행사에서 여러명이 명함을 쉽게 온라인으로 교환할 수 있도록 돕는 기능입니다. 이 때 중요한 것은 ‘교환방’ 데이터 입니다. 명함 교환방은 교환방에 들어온 후에 시작되는 기능이기 때문에, 교환방에서 일어나는 대부분의 이밴트는 교환방 데이터에 의존합니다. 그리고 교환방의 데이터를 변화시킵니다. 다양한 뷰와 모델에서 하나의 데이터에 접근하고, 건드리는 것입니다. -[![명함 교환](/images/fDAmlP00QX.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/리멤버-명함교환방-이미지.png) 교환방에 입장 후 교환방 데이터를 기반으로 초대, 명함교환 등의 작업이 일어납니다. +[![명함 교환]({{ site.baseurl }}/images/fDAmlP00QX.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/리멤버-명함교환방-이미지.png) 교환방에 입장 후 교환방 데이터를 기반으로 초대, 명함교환 등의 작업이 일어납니다. 처음에는 평소와 같이 이밴트에 집중하여 교환방 데이터를 갱신하였습니다. 하지만 교환방 안에서 이루어지는 기능들이 많아지면서 데이터가 흐르는 방향이 급격히 늘어났습니다. 그리고 내가 지금 있는 화면에서 ‘교환방’ 데이터가 어떤 경우로 변화되는지, 예상하기 힘든 핑퐁이 이루어지게 되었습니다. 대략 아래의 코드와 같습니다. diff --git "a/_posts/2016-03-16-realm-\353\215\260\354\235\264\355\204\260\353\262\240\354\235\264\354\212\244.md" "b/_posts/2016-03-16-realm-\353\215\260\354\235\264\355\204\260\353\262\240\354\235\264\354\212\244.md" index fdd55b1..2782027 100644 --- "a/_posts/2016-03-16-realm-\353\215\260\354\235\264\355\204\260\353\262\240\354\235\264\354\212\244.md" +++ "b/_posts/2016-03-16-realm-\353\215\260\354\235\264\355\204\260\353\262\240\354\235\264\354\212\244.md" @@ -8,7 +8,7 @@ date: "2016-03-16" \* 아래 글은 Realm-Java 0.87.5 버전을 기준으로 작성되었습니다. 현재는 0.88.0이 나왔으며, 그에따라 약간 다른 내용이 있을 수 있습니다. [Changelog](https://github.com/realm/realm-java/blob/master/CHANGELOG.md)를 참조하시면서 글을 보신다면, 혼동하지 않고 볼 수 있습니다. -[![realmDark](/images/cHTKOE1KHo.jpg)](https://blog.dramancompany.com/wp-content/uploads/2016/03/realmDark.jpg) 안드로이드에 기본적으로 설치된 Sqlite 기반으로 다양한 ORM이 있습니다. Realm은 엔진부터 새로 만든 데이터베이스 입니다. 그래서 Sqlite보다 빠르면서도, ORM과 같은 기능이 자연스럽게 제공되어 다루기 편합니다. +[![realmDark]({{ site.baseurl }}/images/cHTKOE1KHo.jpg)](https://blog.dramancompany.com/wp-content/uploads/2016/03/realmDark.jpg) 안드로이드에 기본적으로 설치된 Sqlite 기반으로 다양한 ORM이 있습니다. Realm은 엔진부터 새로 만든 데이터베이스 입니다. 그래서 Sqlite보다 빠르면서도, ORM과 같은 기능이 자연스럽게 제공되어 다루기 편합니다. 리멤버는 최근에 API를 v2로 리팩토링 하면서 데이터 스키마를 많이 변경했습니다. 그에 따라 클라이언트도 리팩토링이 필요했고, 자연스럽게 사용하던 기술 스택을 재구성하였습니다. 그 과정에서 큰 부분을 차지했던 Realm에 대해 1. 왜 선택했는지, 2. 어떤 제약이 있는지, 3. 활용 Tip, 4. 장단점 등을 공유하고자 합니다. @@ -20,7 +20,7 @@ date: "2016-03-16" Realm은 성능을 강점으로 내세웁니다. 실제로 얼마나 빠른지, 사용하는 GreenDAO와 비교해보았습니다. -[![스크린샷 2016-03-14 오후 4.45.04](/images/GNWjtU8Ges.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/스크린샷-2016-03-14-오후-4.45.04.png) [![스크린샷 2016-03-14 오후 7.57.59]({{ site.baseurl }}/images/eFNQhGJOmj.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/스크린샷-2016-03-14-오후-7.57.59.png) +[![스크린샷 2016-03-14 오후 4.45.04]({{ site.baseurl }}/images/GNWjtU8Ges.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/스크린샷-2016-03-14-오후-4.45.04.png) [![스크린샷 2016-03-14 오후 7.57.59]({{ site.baseurl }}/images/eFNQhGJOmj.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/스크린샷-2016-03-14-오후-7.57.59.png) 데이터가 많아질수록 Realm의 성능이 더 좋은 것을 볼 수 있습니다. 우리는 로컬DB에 쌓아야 할 명함 데이터가 20,000개를 넘는 사용자도 종종 있어, Realm을 사용한다면 성능에서 큰 이점이 있다고 생각하였습니다. @@ -163,7 +163,7 @@ Realm에서 제공하는 초기화 메소드 Realm.getDefaultInstance() 에서 Realm 객체는 쓰레드 간 직접 전달이 불가능하지만, 같은 Realm DB 값의 객체라면, 다른 쓰레드에서 접근하여도, 참조하는 객체는 하나입니다. (위에서 설명한 [Auto Refresh](https://realm.io/kr/docs/java/latest/#section-7)가 가능한 원리입니다.) 때문에 하나의 쓰레드에서 Realm 객체를 삭제한다면, 다른 쓰레드에서 동일한 Realm 객체를 참조하지 못합니다. 이것은 삭제 순서를 보장할 수 없는 다중 쓰레드 상황에서 예외를 초래합니다. Realm.isValid() 를 통해 삭제 여부를 체크하여도, 종종 다른 쓰레드에서 삭제가 된 Realm 객체라며 [크래시](http://crashes.to/s/32733fab0d8)를 발생시킵니다. 최대한 주의를 기울이지만, 다중 쓰레드 환경에서 이러한 시간차를 예방하는 것은 힘듭니다. -[![다른 쓰레드에서 따로 접근하여도, 같은 Realm DB 객체라면, 하나의 인스턴스를 참조합니다. 따라서 하나의 쓰레드에서 Realm 객체를 삭제한다면, 다른 쓰레드에서 접근하지 못합니다.](/images/9qxralsZes.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/스크린샷-2016-03-14-오후-5.58.08.png) 다른 쓰레드에서 따로 접근하여도, 같은 Realm DB 객체라면, 하나의 인스턴스를 참조합니다. 따라서 하나의 쓰레드에서 Realm 객체를 삭제한다면, 다른 쓰레드에서 접근하지 못합니다. +[![다른 쓰레드에서 따로 접근하여도, 같은 Realm DB 객체라면, 하나의 인스턴스를 참조합니다. 따라서 하나의 쓰레드에서 Realm 객체를 삭제한다면, 다른 쓰레드에서 접근하지 못합니다.]({{ site.baseurl }}/images/9qxralsZes.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/스크린샷-2016-03-14-오후-5.58.08.png) 다른 쓰레드에서 따로 접근하여도, 같은 Realm DB 객체라면, 하나의 인스턴스를 참조합니다. 따라서 하나의 쓰레드에서 Realm 객체를 삭제한다면, 다른 쓰레드에서 접근하지 못합니다. 사실 sychronoized 등을 활용하면 해결방법이 없지는 않습니다. 하지만 자주 수행해야 하는 작업을 이런 방식으로 처리하는 것은 비효율이 큽니다. 그리고 다행히 이 현상은 자주 일어나지 않습니다. 그래서 지금은 의도적으로 크래시를 감수하고 있습니다. diff --git "a/_posts/2016-03-16-\352\260\234\353\260\234\352\267\270\353\243\271\354\235\200-\354\226\264\353\226\273\352\262\214-\354\235\274\354\235\204-\355\225\230\353\212\224\352\260\200-1.md" "b/_posts/2016-03-16-\352\260\234\353\260\234\352\267\270\353\243\271\354\235\200-\354\226\264\353\226\273\352\262\214-\354\235\274\354\235\204-\355\225\230\353\212\224\352\260\200-1.md" index 9fd674a..b7d1cfb 100644 --- "a/_posts/2016-03-16-\352\260\234\353\260\234\352\267\270\353\243\271\354\235\200-\354\226\264\353\226\273\352\262\214-\354\235\274\354\235\204-\355\225\230\353\212\224\352\260\200-1.md" +++ "b/_posts/2016-03-16-\352\260\234\353\260\234\352\267\270\353\243\271\354\235\200-\354\226\264\353\226\273\352\262\214-\354\235\274\354\235\204-\355\225\230\353\212\224\352\260\200-1.md" @@ -19,13 +19,13 @@ tags: 개발 그룹의 업무 환경은 [애자일 방법론](https://ko.wikipedia.org/wiki/%EC%95%A0%EC%9E%90%EC%9D%BC_%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4_%EA%B0%9C%EB%B0%9C)에 기반을 두고 있습니다. 애자일 방법론 중 [스크럼](https://ko.wikipedia.org/wiki/%EC%8A%A4%ED%81%AC%EB%9F%BC_(%EC%95%A0%EC%9E%90%EC%9D%BC_%EA%B0%9C%EB%B0%9C_%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4))을 중심으로 업무를 처리합니다. 큰 flow는 다음 그림과 비슷합니다. 제품(혹은 프로젝트)에 대한 모든 task들이 담겨있는 프로덕트 백로그가 존재하며, 이번 스프린트에 진행할 task들을 스프린트 백로그에 옮깁니다. 그 후에는 하루와 총 스크럼 기간 두 단위로 나누어 일을 진행합니다. 저희가 실제로 어떻게 사용하는지에 대한 자세한 내용은 뒤에서 다루겠습니다. 혹시 Agile 방법론이나 스크럼 등의 용어가 생소하신 분이라면 위키피디아에서 가볍게 읽어보고 오시는 것을 추천해 드립니다. -[![스크럼 프로세스](/images/ezZSp9Ibdn.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/1000px-Scrum_process.svg_.png) 스크럼 프로세스 (출처: 위키피디아) +[![스크럼 프로세스]({{ site.baseurl }}/images/ezZSp9Ibdn.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/1000px-Scrum_process.svg_.png) 스크럼 프로세스 (출처: 위키피디아) ## Planning 개발 그룹의 업무 계획 단위는 Yearly Planning, Phase, Phase break, Sprint로, 총 세 가지로 나누어 볼 수 있습니다. Yearly planning은 장기 계획, Phase는 중기 계획, Sprint는 단기 계획를 나타냅니다. 이렇게 장기, 중기, 단기로 나누어 계획을 짜는 이유는 다양한 시점에서 우리가 올바른 방향과 속도로 나아가고 있는지 계속 인지하기 위함입니다. 또한 상황에 따라 적절하고 lean하게 계획을 조율하여 리소스를 효율적으로 사용하며 목표에 다다를 성공률을 높히기 위함입니다. 다음은 Sprint, Phase, Phase break 등의 모든 업무 단위들을 포함하여 하나의 그림으로 나타낸 표입니다. 다음 표가 전체 사이클이며 다음과 같은 사이클을 반복합니다. -[![개발 그룹 업무 사이클](/images/w1PrAGQOuh.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/Screen-Shot-2016-03-15-at-11.10.57-AM.png) 개발 그룹 업무 사이클 +[![개발 그룹 업무 사이클]({{ site.baseurl }}/images/w1PrAGQOuh.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/Screen-Shot-2016-03-15-at-11.10.57-AM.png) 개발 그룹 업무 사이클 ### Sprint @@ -51,9 +51,9 @@ tags: 그리고 페이즈 기간 동안 정말 열심히 일을 하다가 적절한 시기에 break time을 가질 수 있으니 burnout을 막는데 매우 큰 역할을 하고 있습니다. 내부에서는 이 페이즈 브레이크 기간을 신의 한수라고 평가하고 있습니다. -[![제 1회 드라마앤컴퍼니 해커톤 커팅식](/images/tnD1o30fnc.gif)](https://blog.dramancompany.com/wp-content/uploads/2016/03/output_1ehvRU.gif) 제 1회 드라마앤컴퍼니 해커톤 커팅식 (w/ 두루마리 휴지) +[![제 1회 드라마앤컴퍼니 해커톤 커팅식]({{ site.baseurl }}/images/tnD1o30fnc.gif)](https://blog.dramancompany.com/wp-content/uploads/2016/03/output_1ehvRU.gif) 제 1회 드라마앤컴퍼니 해커톤 커팅식 (w/ 두루마리 휴지) -[![Phase 2 정선](/images/nq8YupMDLu.jpg)](https://blog.dramancompany.com/wp-content/uploads/2016/03/Slack-for-iOS-Upload-3.jpg) Phase 2 정선 워크샵 (@하이원) +[![Phase 2 정선]({{ site.baseurl }}/images/nq8YupMDLu.jpg)](https://blog.dramancompany.com/wp-content/uploads/2016/03/Slack-for-iOS-Upload-3.jpg) Phase 2 정선 워크샵 (@하이원) ## 마무리 diff --git "a/_posts/2016-03-18-rails-engine\354\235\204-\354\235\264\354\232\251\355\225\234-zeus-\355\224\204\353\241\234\354\240\235\355\212\270.md" "b/_posts/2016-03-18-rails-engine\354\235\204-\354\235\264\354\232\251\355\225\234-zeus-\355\224\204\353\241\234\354\240\235\355\212\270.md" index be5ad58..06355d4 100644 --- "a/_posts/2016-03-18-rails-engine\354\235\204-\354\235\264\354\232\251\355\225\234-zeus-\355\224\204\353\241\234\354\240\235\355\212\270.md" +++ "b/_posts/2016-03-18-rails-engine\354\235\204-\354\235\264\354\232\251\355\225\234-zeus-\355\224\204\353\241\234\354\240\235\355\212\270.md" @@ -20,7 +20,7 @@ date: "2016-03-18" 위의 그림에서 보듯이, 명함 요청과 명함 도메인은 전체 라이프사이클에 걸쳐 다양한 애플리케이션에 의해 생성, 수정, 조회와 같은 작업이 일어납니다. 따라서 애플리케이션마다 동일한 명함과 명함 요청의 모델 코드가 들어가 있습니다. -[![duplicate_rails_model](/images/9ewUHgMDkx.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/duplicate_rails_model.png) +[![duplicate_rails_model]({{ site.baseurl }}/images/9ewUHgMDkx.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/duplicate_rails_model.png) ### 2\. Don't Repeat Yourself @@ -32,7 +32,7 @@ date: "2016-03-18" ### 3\. Microservices -[![microservice](/images/Ctcmq9aiB8.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/microservice.png) +[![microservice]({{ site.baseurl }}/images/Ctcmq9aiB8.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/microservice.png) 도메인 업무를 수행하는 모델을 별도의 Internal API 서버로 구성하고 각 애플리케이션은 Internal API를 호출합니다. 이렇게 하면 중복 코드를 제거하게 되어 도메인 모델 코드의 유지 보수가 용이해집니다. 그러나 고려해야 할 단점도 많습니다. 사실 Microservice나 그 전신(?)인 SOA Architecture가 고스란히 가지고 있는 단점이기도 합니다. @@ -47,7 +47,7 @@ Microservice는 시스템의 크기가 크고, 팀/조직/프로세스가 잘 ### 4\. Rails Engine -[![rails_engine](/images/I9YQipTCCY.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/rails_engine.png) +[![rails_engine]({{ site.baseurl }}/images/I9YQipTCCY.png)](https://blog.dramancompany.com/wp-content/uploads/2016/03/rails_engine.png) 언뜻 보면, 첫 번째 방법인 중복 모델을 그대로 유지하는 것과 별반 다를 게 없어 보이지만 여기에는 아주 중요한 차이가 있습니다. Rails Engine은 별도의 애플리케이션으로 관리되지만, Ruby 라이브러리인 Gem(Java에서는 jar)의 형태로 각 애플리케이션에 import 될 수 있습니다. 따라서 모든 도메인 모델 코드는 Rails Engine 애플리케이션에 작성하고, 각 애플리케이션에서는 라이브러리 클래스를 사용하듯이 이를 가져다가 사용하면 됩니다. 아래는 API 애플리케이션에서 실제로 Rails Engine을 사용하는 예시 코드입니다. diff --git a/_posts/2016-04-27-crop.md b/_posts/2016-04-27-crop.md index d371cf1..7bfb7a7 100644 --- a/_posts/2016-04-27-crop.md +++ b/_posts/2016-04-27-crop.md @@ -70,7 +70,7 @@ if let rectangles = detector.featuresInImage(image, options: options) { 또한, CIDetector는 사용자가 원하는 특성에 맞는 형테를 찾을 수 있도록 여러가지 옵션을 제공하고 있습니다. 이중에서 리멤버 앱에서 중요한 옵션은 CIDetectorAspectRatio 였습니다. 일반적인 종이 명함의 가로/세로 비율이 1.8 정도인 것을 감안해, 이 옵션을 설정해 주면, CIDetector는 이미지 내에서 가로/세로 비율이 1.8에 근접한 사각형들을 찾아주게 됩니다. -[![resize_IMG_2983](/images/TfY64C2qop.png)](https://blog.dramancompany.com/wp-content/uploads/2015/10/resize_IMG_2983.png) CIDetector를 사용해 찾아낸 사각형 영역 +[![resize_IMG_2983]({{ site.baseurl }}/images/TfY64C2qop.png)](https://blog.dramancompany.com/wp-content/uploads/2015/10/resize_IMG_2983.png) CIDetector를 사용해 찾아낸 사각형 영역 이렇게 원하는 Target의 특성을 고려하여 여러가지 옵션을 설정해 주면 더 정확한 결과를 얻을 수 있습니다. @@ -95,7 +95,7 @@ let outputImage = perspectiveCorrection?.outputImage ``` -[![IMG_2965](/images/JuZVZnU2Ce.png)](https://blog.dramancompany.com/wp-content/uploads/2015/10/IMG_2965.png) Perspective correction이 적용된 이미지 +[![IMG_2965]({{ site.baseurl }}/images/JuZVZnU2Ce.png)](https://blog.dramancompany.com/wp-content/uploads/2015/10/IMG_2965.png) Perspective correction이 적용된 이미지 이와 같이 iOS에서는 CoreImage를 통해 수월하게 명함 영역을 찾을 수 있었습니다. @@ -178,9 +178,9 @@ VisualizeImageData.colorizeGradient(derivY, derivY, -1, outputGradient, null); ConvertBitmap.bitmapToGray(outputGradient, grayProcY, null); ``` -[![x-axis sobel operation 결과](/images/M9eM3iwQAs.png)](https://blog.dramancompany.com/wp-content/uploads/2015/10/test-x-crop.png) x-axis sobel operation 결과 +[![x-axis sobel operation 결과]({{ site.baseurl }}/images/M9eM3iwQAs.png)](https://blog.dramancompany.com/wp-content/uploads/2015/10/test-x-crop.png) x-axis sobel operation 결과 -[![y-axis sobel operation 결과](/images/Z7YJSgkZGL.png)](https://blog.dramancompany.com/wp-content/uploads/2015/10/test-y-crop.png) y-axis sobel operation 결과 +[![y-axis sobel operation 결과]({{ site.baseurl }}/images/Z7YJSgkZGL.png)](https://blog.dramancompany.com/wp-content/uploads/2015/10/test-y-crop.png) y-axis sobel operation 결과 #### Line detection diff --git "a/_posts/2016-05-25-\353\223\234\353\235\274\353\247\210\354\235\230-pair-programming\352\263\274-code-review-\353\217\204\354\236\205-\355\233\204\352\270\260.md" "b/_posts/2016-05-25-\353\223\234\353\235\274\353\247\210\354\235\230-pair-programming\352\263\274-code-review-\353\217\204\354\236\205-\355\233\204\352\270\260.md" index cd7c289..3b4672a 100644 --- "a/_posts/2016-05-25-\353\223\234\353\235\274\353\247\210\354\235\230-pair-programming\352\263\274-code-review-\353\217\204\354\236\205-\355\233\204\352\270\260.md" +++ "b/_posts/2016-05-25-\353\223\234\353\235\274\353\247\210\354\235\230-pair-programming\352\263\274-code-review-\353\217\204\354\236\205-\355\233\204\352\270\260.md" @@ -28,7 +28,7 @@ PP와 CR을 해야 하는 이유에 대해서는 많은 article들과 서적에 따라서 장기적인 관점에서 전체 개발에 필요한 시간이 감소한다고 볼 수 있습니다. 버그가 감소하기 때문에 불필요한 디버깅이 없어지고, 설계가 개선되어 추후 디버깅을 하거나 기능을 추가 개발할 때 필요한 시간이 줄어들기 때문입니다. 어떤 유망한 회사에 투자를 하면 처음에는 가지고 있는 여유 자금이 줄어들어 손실로 보이지만, 장기적으로 손익분기점을 넘게 되면 큰 이득을 얻습니다. 마찬가지로 PP와 CR도 처음에는 시간과 노력이라는 투자가 필요하지만, 시간이 지나 성숙도가 올라가면 큰 이득을 얻는다는 것을 경험했습니다. -[![design_stamina_hypo](/images/0E5CeuWiA4.png)](https://blog.dramancompany.com/wp-content/uploads/2016/05/design_stamina_hypo.png) +[![design_stamina_hypo]({{ site.baseurl }}/images/0E5CeuWiA4.png)](https://blog.dramancompany.com/wp-content/uploads/2016/05/design_stamina_hypo.png) > _**출처: [http://martinfowler.com/bliki/DesignStaminaHypothesis.html](http://martinfowler.com/bliki/DesignStaminaHypothesis.html)**_ > @@ -94,11 +94,11 @@ Tom님과 API 개발을 할 때도 마찬가지 방식으로 진행하였습니 PR을 사용할 때는 크게 두 가지 방식이 있는 것 같습니다. 하나는 원본 repository를 fork한 별도의 repository에서 PR을 생성하는 방법이고, 다른 하나는 같은 repository에 브랜치를 하나 만들어 여기서 PR을 생성하는 방법입니다. 저희는 이 중 브랜치 방식을 택하여 시도를 해보았습니다. 그 이유는 Tom님, Jaden님 모두 이미 git flow를 사용하고 있는 상황이었고, 또 같은 repository에 브랜치를 하나 만드는 것이 리뷰어가 코드를 받아 확인하고 실행하는 것이 더 쉽다고 생각했기 때문입니다. -[![pr_code_review](/images/fFCosMNs4d.png)](https://blog.dramancompany.com/wp-content/uploads/2016/05/pr_code_review.png) +[![pr_code_review]({{ site.baseurl }}/images/fFCosMNs4d.png)](https://blog.dramancompany.com/wp-content/uploads/2016/05/pr_code_review.png) 위 그림과 같이 git flow의 convention을 사용하여 feature/profile(기능 추가 개발 시), fix/profile(버그 픽스) 등과 같은 브랜치를 만들고 여기에 관련 코드를 커밋 & 푸시합니다. 모든 작업이 끝나면 develop 브랜치로 PR을 하나 생성한 후 사내 커뮤니케이션 도구인 Slack으로 리뷰어들에게 리뷰를 요청합니다. 리뷰어들은 PR에 line comment를 달아 리뷰를 해줍니다. -[![review_comment](/images/6ehVeGVEaD.png)](https://blog.dramancompany.com/wp-content/uploads/2016/05/review_comment.png) +[![review_comment]({{ site.baseurl }}/images/6ehVeGVEaD.png)](https://blog.dramancompany.com/wp-content/uploads/2016/05/review_comment.png) 필요하면 코드 리뷰를 더 재미있고 쉽게 만들어주는 PR 기반의 도구를 사용할 수도 있습니다. diff --git "a/_posts/2016-08-04-\354\225\210\353\223\234\353\241\234\354\235\264\353\223\234\354\227\220-\355\205\214\354\212\244\355\212\270-\353\217\204\354\236\205\355\225\230\352\270\260.md" "b/_posts/2016-08-04-\354\225\210\353\223\234\353\241\234\354\235\264\353\223\234\354\227\220-\355\205\214\354\212\244\355\212\270-\353\217\204\354\236\205\355\225\230\352\270\260.md" index afb0e90..606684b 100644 --- "a/_posts/2016-08-04-\354\225\210\353\223\234\353\241\234\354\235\264\353\223\234\354\227\220-\355\205\214\354\212\244\355\212\270-\353\217\204\354\236\205\355\225\230\352\270\260.md" +++ "b/_posts/2016-08-04-\354\225\210\353\223\234\353\241\234\354\235\264\353\223\234\354\227\220-\355\205\214\354\212\244\355\212\270-\353\217\204\354\236\205\355\225\230\352\270\260.md" @@ -10,7 +10,7 @@ date: "2016-08-04" 우리는 저번 페이즈 브레이크 때 클라이언트 개발자들끼리 모여 테스트에 대해 논의하였습니다. 그리고 테스트부터 CI까지 이어지는 전략을 정립하고, 각 플랫폼에 맞게 적용하였습니다. 이번 포스팅에서는 안드로이드에서 테스트를 도입하기 위해 했던 구조적인 고민과 적용, 그리고 참고했던 링크들을 나누고자 합니다. -[![클라이언트는 코드가 자주 변화하기 때문에 TDD까지는 힘든 것이 사실이지만, 최대한 테스트를 마련함으로써 안정성을 높일 수 있습니다.](/images/0dJ5oHKY48.png)](https://blog.dramancompany.com/wp-content/uploads/2016/05/red-green-refactor.png) 클라이언트는 코드가 자주 변화하기 때문에 TDD까지는 힘들지만, 최대한 테스트를 마련함으로써 안정성을 높일 수 있습니다. +[![클라이언트는 코드가 자주 변화하기 때문에 TDD까지는 힘든 것이 사실이지만, 최대한 테스트를 마련함으로써 안정성을 높일 수 있습니다.]({{ site.baseurl }}/images/0dJ5oHKY48.png)](https://blog.dramancompany.com/wp-content/uploads/2016/05/red-green-refactor.png) 클라이언트는 코드가 자주 변화하기 때문에 TDD까지는 힘들지만, 최대한 테스트를 마련함으로써 안정성을 높일 수 있습니다. # **MVC에서 MVP로** @@ -20,7 +20,7 @@ MVC는 웹 어플리케이션에서 많이 사용하는 패턴입니다. 안드 [http://tosslab.github.io/android/2015/03/01/01.Android-mvc-mvvm-mvp.html](http://tosslab.github.io/android/2015/03/01/01.Android-mvc-mvvm-mvp.html) -[![안드로이드는 V와 C가 함께 있고, Context의 존재 때문에 MVC에 제약이 있습니다. 이것은 테스트를 어렵게 합니다.](/images/mvqUPQ6OYK.png)](https://blog.dramancompany.com/wp-content/uploads/2016/05/MVC_MVP.png) 안드로이드는 V와 C가 함께 있고, Context의 존재 때문에 MVC에 제약이 있습니다. 이것은 테스트를 어렵게 합니다. +[![안드로이드는 V와 C가 함께 있고, Context의 존재 때문에 MVC에 제약이 있습니다. 이것은 테스트를 어렵게 합니다.]({{ site.baseurl }}/images/mvqUPQ6OYK.png)](https://blog.dramancompany.com/wp-content/uploads/2016/05/MVC_MVP.png) 안드로이드는 V와 C가 함께 있고, Context의 존재 때문에 MVC에 제약이 있습니다. 이것은 테스트를 어렵게 합니다. # **Dagger2** @@ -112,7 +112,7 @@ public class SigninEmailFragmentTest { 배포 자동화를 돕는 툴로는 Jenkins와 Travis가 있습니다. 설치형과 PaaS 형태의 차이점이 있습니다. 배포할 제품이 많고 주기가 짧다면 자체적으로 구축한 Jenkins 서버에서 진행하는 것이 자유도가 높습니다. 하지만 우리는 리멤버 한가지 제품만을 개발하고, 소수의 개발자가 배포를 하기 때문에, 관리비용을 줄일 수 있는 Travis를 선택하였습니다. -[![private repo를 사용하려면 유료이지만, 젠킨스 또한 설치 후 관리해야 하는 비용을 생각하면, Travis의 비용이 비싸지 않은 편이다.](/images/BVjYopw0aY.jpg)](https://blog.dramancompany.com/wp-content/uploads/2016/05/Travis-CI-logo.jpg) private Repository를 사용하려면 유료이지만, 관리비용을 줄이고 빠르게 개발할 수 있는 Travis를 선택하였습니다. +[![private repo를 사용하려면 유료이지만, 젠킨스 또한 설치 후 관리해야 하는 비용을 생각하면, Travis의 비용이 비싸지 않은 편이다.]({{ site.baseurl }}/images/BVjYopw0aY.jpg)](https://blog.dramancompany.com/wp-content/uploads/2016/05/Travis-CI-logo.jpg) private Repository를 사용하려면 유료이지만, 관리비용을 줄이고 빠르게 개발할 수 있는 Travis를 선택하였습니다. Travis를 안드로이드에 적용하기 위해서는 프로젝트 Root에 .yml을 추가하여야 합니다. Travis를 안드로이드에 적용하기 위한 가이드는 아래 링크를 참고해주세요. diff --git "a/_posts/2016-08-08-\353\223\234\353\235\274\353\247\210\354\227\220\354\204\234-1\353\205\204\354\235\230-\354\204\261\354\236\245\352\270\260.md" "b/_posts/2016-08-08-\353\223\234\353\235\274\353\247\210\354\227\220\354\204\234-1\353\205\204\354\235\230-\354\204\261\354\236\245\352\270\260.md" index 4d3e482..340b283 100644 --- "a/_posts/2016-08-08-\353\223\234\353\235\274\353\247\210\354\227\220\354\204\234-1\353\205\204\354\235\230-\354\204\261\354\236\245\352\270\260.md" +++ "b/_posts/2016-08-08-\353\223\234\353\235\274\353\247\210\354\227\220\354\204\234-1\353\205\204\354\235\230-\354\204\261\354\236\245\352\270\260.md" @@ -26,7 +26,7 @@ https://speakerdeck.com/rfrost77/rimembeo-andeuroideu-byeonceongi 그렇게 가입이 안되거나, 명함이 사라지거나 등의 몇번 큰 버그가 있었습니다. 운영을 고려하지 않고 많은 변화를 주었기 때문입니다. 불안정한 개발로 사용자 경험을 해치는 실수를 하면서, 레거시가 꼭 나쁜 것은 아니구나, 그것들까지 감싸면서 안정적으로 개발하는 것이 진짜 서비스를 ‘운영’하는 것이라는 것을 배웠습니다. 트렌드와 최신 기술을 꾸준히 따라가고 배우는 자세는 개발자로서 필요합니다. 하지만 실제 서비스는 약간의 퍼포먼스보다 검증된 안정성이 더욱 중요합니다. 저는 비용을 치루고 나서야 안정성을 검증하고 변화를 적용하는 자세를 배울 수 있었습니다. -[![운영되고 있는 서비스는 약간의 퍼포먼스보다 안정성이 더 중요한 이슈입니다.](/images/q5u87ea39y.jpg)](https://blog.dramancompany.com/wp-content/uploads/2016/08/20621818_blog.jpg) 운영되고 있는 서비스는 약간의 퍼포먼스보다 안정성이 더 중요한 이슈입니다. +[![운영되고 있는 서비스는 약간의 퍼포먼스보다 안정성이 더 중요한 이슈입니다.]({{ site.baseurl }}/images/q5u87ea39y.jpg)](https://blog.dramancompany.com/wp-content/uploads/2016/08/20621818_blog.jpg) 운영되고 있는 서비스는 약간의 퍼포먼스보다 안정성이 더 중요한 이슈입니다. ## 문제 정의, 깊은 고민 @@ -34,7 +34,7 @@ https://speakerdeck.com/rfrost77/rimembeo-andeuroideu-byeonceongi 저는 이전까지 직감과 경험을 바탕으로 빠르게 무언가를 판단 하였습니다. 좋게 말하면 결단력 있는 것이지만, 가벼운 고민으로 좋은 의사결정을 하지는 못했습니다. 드라마에서 여러 의사결정을 보면서 문제에 잘 접근하는 방법을 배웠습니다. 구체적으로 그림을 그려보는 것이 중요합니다. 실제적인 깊은 고민은 의사결정을 단단하게 하고, 혹 결정이 실패하더라도 많은 Lessons Learned을 줍니다. 너무 긴 시간을 소요하면 안되겠지만, 내가 할 수 있는 최선의 깊이까지 바르게 고민하는 자세는, 매 선택으로부터 나를 발전시키는 중요한 발판 입니다. -[![문제를 정의하고 구체적으로 선택지를 따져가여 깊이 고민합니다.](/images/mugGHox6bX.jpeg)](https://blog.dramancompany.com/wp-content/uploads/2016/08/다운로드.jpeg) 문제를 정의하고, 다양한 선택지를 구체적으로 고민하며, 바른 해결책을 찾아갑니다. +[![문제를 정의하고 구체적으로 선택지를 따져가여 깊이 고민합니다.]({{ site.baseurl }}/images/mugGHox6bX.jpeg)](https://blog.dramancompany.com/wp-content/uploads/2016/08/다운로드.jpeg) 문제를 정의하고, 다양한 선택지를 구체적으로 고민하며, 바른 해결책을 찾아갑니다. ## 좋은 비전을 공유하는 훌륭한 동료들과 재밌게 일하는 경험 @@ -42,7 +42,7 @@ https://speakerdeck.com/rfrost77/rimembeo-andeuroideu-byeonceongi 회사는 무언가를 함께 이루어나가며, 과정에서의 수익을 공유하는 집단입니다. 함께 이룰 무언가를 우리는 비전이라고 부릅니다. 가능성 있고 재미있는 비전 아래에는 좋은 사람들이 모이고, 모두 목표를 위해 자신의 최선을 다합니다. 드라마앤컴퍼니는 그런 일이 일어나고 있는 회사입니다. 우리가 바라보는 큰 그림을 위해 한 방향으로 함께 달리고 있습니다. 지금의 좋은 경험은 앞으로의 커리어에서도 타성에 젖지 않고, 목표를 향해 힘껏 달리도록 동기를 부여해주는, 긍정적인 마인드의 원동력이 될 것입니다. -[![좋은 비전을 훌륭한 동료들과 함께 잘 풀어내는 지금의 경험은, 앞으로의 커리어를 긍정적으로 쌓아갈 중요한 양분입니다.](/images/eY43G4ePVX.jpg)](https://blog.dramancompany.com/wp-content/uploads/2016/08/vision.jpg) 좋은 비전을 훌륭한 동료들과 함께 잘 풀어내는 지금의 경험은, 앞으로의 커리어를 긍정적으로 쌓아갈 중요한 양분입니다. +[![좋은 비전을 훌륭한 동료들과 함께 잘 풀어내는 지금의 경험은, 앞으로의 커리어를 긍정적으로 쌓아갈 중요한 양분입니다.]({{ site.baseurl }}/images/eY43G4ePVX.jpg)](https://blog.dramancompany.com/wp-content/uploads/2016/08/vision.jpg) 좋은 비전을 훌륭한 동료들과 함께 잘 풀어내는 지금의 경험은, 앞으로의 커리어를 긍정적으로 쌓아갈 중요한 양분입니다.   diff --git "a/_posts/2016-11-28-ruby-\354\275\224\353\223\234-\354\204\261\353\212\245-\354\265\234\354\240\201\355\231\224-feat-ruby-prof-benchmark.md" "b/_posts/2016-11-28-ruby-\354\275\224\353\223\234-\354\204\261\353\212\245-\354\265\234\354\240\201\355\231\224-feat-ruby-prof-benchmark.md" index 476c00f..6462674 100644 --- "a/_posts/2016-11-28-ruby-\354\275\224\353\223\234-\354\204\261\353\212\245-\354\265\234\354\240\201\355\231\224-feat-ruby-prof-benchmark.md" +++ "b/_posts/2016-11-28-ruby-\354\275\224\353\223\234-\354\204\261\353\212\245-\354\265\234\354\240\201\355\231\224-feat-ruby-prof-benchmark.md" @@ -161,7 +161,7 @@ Sort by: total_time 전체 call stack을 html 형식으로 보여줍니다. 필요한 상황에 따라 node를 접고, 일정 값 이상의 %를 소요한 메소드들만 필터링하여 볼 수 있습니다. 각 node를 보면 **A%(B%)**와 같은 형식으로 표시되는데, 앞의 **A**는 위 **GraphPrinter**의 **%self**에 해당하는 값이고, **B**는 부모의가 호출한 자식 메소드들을 기준으로 소요한 시간의 비율입니다. -[![screen-shot-2016-11-22-at-9-51-13-pm](/images/E9Ct9ib0vP.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/Screen-Shot-2016-11-22-at-9.51.13-PM.png) CallStackPrinter 예시 +[![screen-shot-2016-11-22-at-9-51-13-pm]({{ site.baseurl }}/images/E9Ct9ib0vP.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/Screen-Shot-2016-11-22-at-9.51.13-PM.png) CallStackPrinter 예시 # **성능 최적화 과정** @@ -320,13 +320,13 @@ Test.ready

User size

Hit rate

user

system

total

real time

5

1

0.040000

0.000000

0.040000

0.034104

5

0.5

0.020000

0.000000

0.020000

0.018707

5

0.1

0.000000

0.000000

0.000000

0.000003

10

1

0.130000

0.00000

0.130000

0.129068

10

0.5

0.090000

0.00000

0.090000

0.094217

10

0.1

0.020000

0.00000

0.020000

0.021157

20

1

0.510000

0.00000

0.510000

0.513110

20

0.5

0.360000

0.00000

0.360000

0.356309

20

0.1

0.080000

0.00000

0.080000

0.086764

30

1

1.070000

0.01000

1.080000

1.072212

30

0.5

0.800000

0.00000

0.800000

0.807687

30

0.1

0.190000

0.00000

0.190000

0.199311

50

1

2.900000

0.01000

2.910000

2.907888

50

0.5

2.130000

0.00000

2.130000

2.136653

50

0.1

0.550000

0.00000

0.550000

0.546068

100

1

11.780000

0.030000

11.810000

11.838261

100

0.5

8.570000

0.020000

8.590000

8.626450

100

0.1

2.150000

0.010000

2.160000

2.157522

150

1

26.100000

0.060000

26.160000

26.241357

150

0.5

19.310000

0.050000

19.360000

19.406512

150

0.1

4.880000

0.010000

4.890000

4.908961

500

1

291.680000

1.000000

292.680000

294.109574

500

0.5

220.220000

0.890000

221.110000

222.306764

500

0.1

56.030000

0.220000

56.250000

56.555782

-[![image2016-11-8-14-35-54](/images/IjmaIOra6b.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-14-35-54.png) [![image2016-11-8-14-35-59](/images/mE5s6bLT8W.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-14-35-59.png) [![image2016-11-8-14-36-2]({{ site.baseurl }}/images/OGxEzLsWaM.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-14-36-2.png) [![image2016-11-8-14-36-5](/images/zuaJMa15RA.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-14-36-5.png) [![image2016-11-8-15-34-28]({{ site.baseurl }}/images/rflCZUjqfU.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-15-34-28.png) 테스트 결과를 보면 전화번호로 검색된 리멤버 사용자 수와 거의 비례하게 소요 시간이 증가하며, 현재 사용하고 있는 사용자 수가 그리 많지 않음에도 매우 오랜 시간이 걸린다. +[![image2016-11-8-14-35-54]({{ site.baseurl }}/images/IjmaIOra6b.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-14-35-54.png) [![image2016-11-8-14-35-59]({{ site.baseurl }}/images/mE5s6bLT8W.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-14-35-59.png) [![image2016-11-8-14-36-2]({{ site.baseurl }}/images/OGxEzLsWaM.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-14-36-2.png) [![image2016-11-8-14-36-5]({{ site.baseurl }}/images/zuaJMa15RA.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-14-36-5.png) [![image2016-11-8-15-34-28]({{ site.baseurl }}/images/rflCZUjqfU.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-15-34-28.png) 테스트 결과를 보면 전화번호로 검색된 리멤버 사용자 수와 거의 비례하게 소요 시간이 증가하며, 현재 사용하고 있는 사용자 수가 그리 많지 않음에도 매우 오랜 시간이 걸린다. #### 분석 ruby-prof로 상세하게 call-stack 등 어느 메소드에서 많은 시간을 소요했는지 분석해보면 다음과 같다. -[![image2016-11-8-15-36-4]({{ site.baseurl }}/images/emXhATlGmE.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-15-36-4.png)[![image2016-11-8-15-36-19](/images/hlAXp5tTiD.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-15-36-19.png) +[![image2016-11-8-15-36-4]({{ site.baseurl }}/images/emXhATlGmE.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-15-36-4.png)[![image2016-11-8-15-36-19]({{ site.baseurl }}/images/hlAXp5tTiD.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-15-36-19.png) 가장 많은 시간을 소요한 부분은 전화번호 파싱을 담당하는 gem인 **Phonelib의** **Phonelib::Core#****parse** 부분임을 알 수 있다. API에서는 Phonelib을 이용한 파싱을 2번 사용하고 있다. @@ -378,7 +378,7 @@ User::Entity에서 mobile을 불러 Phonelib를 호출 하는 부분을 제거

User size

Hit rate

user

system

total

real time

5

1

0.000000

0.000000

0.000000

0.000177

5

0.5

0.000000

0.000000

0.000000

0.000147

5

0.1

0.000000

0.000000

0.000000

0.000003

10

1

0.000000

0.000000

0.000000

0.000197

10

0.5

0.000000

0.000000

0.000000

0.000228

10

0.1

0.000000

0.000000

0.000000

0.000170

20

1

0.000000

0.000000

0.000000

0.000426

20

0.5

0.000000

0.000000

0.000000

0.000432

20

0.1

0.000000

0.000000

0.000000

0.000316

30

1

0.000000

0.000000

0.000000

0.000952

30

0.5

0.000000

0.000000

0.000000

0.000856

30

0.1

0.000000

0.000000

0.000000

0.000484

50

1

0.000000

0.000000

0.000000

0.001935

50

0.5

0.000000

0.000000

0.000000

0.001270

50

0.1

0.000000

0.000000

0.000000

0.000728

100

1

0.010000

0.000000

0.010000

0.005805

100

0.5

0.010000

0.000000

0.010000

0.004177

100

0.1

0.000000

0.000000

0.000000

0.001609

150

1

0.010000

0.000000

0.010000

0.011655

150

0.5

0.000000

0.000000

0.000000

0.008360

150

0.1

0.010000

0.000000

0.010000

0.002741

500

1

0.120000

0.000000

0.120000

0.121817

500

0.5

0.090000

0.000000

0.090000

0.087188

500

0.1

0.030000

0.000000

0.030000

0.023976

-[![image2016-11-8-15-45-29](/images/uszThg0PLl.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-15-45-29.png)[![image2016-11-8-15-45-25](/images/FjKL72xEw0.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-15-45-25.png) +[![image2016-11-8-15-45-29]({{ site.baseurl }}/images/uszThg0PLl.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-15-45-29.png)[![image2016-11-8-15-45-25]({{ site.baseurl }}/images/FjKL72xEw0.png)](https://blog.dramancompany.com/wp-content/uploads/2016/11/image2016-11-8-15-45-25.png) #### 성능 비교 diff --git "a/_posts/2021-11-08-code-guru-reviewer\353\245\274-\354\202\254\354\232\251\355\225\230\354\227\254-\354\275\224\353\223\234\353\246\254\353\267\260-\353\260\233\352\270\260.md" "b/_posts/2021-11-08-code-guru-reviewer\353\245\274-\354\202\254\354\232\251\355\225\230\354\227\254-\354\275\224\353\223\234\353\246\254\353\267\260-\353\260\233\352\270\260.md" index 5e84803..c16e244 100644 --- "a/_posts/2021-11-08-code-guru-reviewer\353\245\274-\354\202\254\354\232\251\355\225\230\354\227\254-\354\275\224\353\223\234\353\246\254\353\267\260-\353\260\233\352\270\260.md" +++ "b/_posts/2021-11-08-code-guru-reviewer\353\245\274-\354\202\254\354\232\251\355\225\230\354\227\254-\354\275\224\353\223\234\353\246\254\353\267\260-\353\260\233\352\270\260.md" @@ -23,7 +23,7 @@ Amazon CodeGuru는 코드 품질을 높이고 애플리케이션에서 가장 위 설명은 AWS에서 공식적으로 설명하고 있는 내용입니다. 나와 있는 것처럼 말 그대로 코드 리뷰를 자동화해주는 기능입니다. 기계학습을 한 똑똑한 프로그래밍 언어의 전문가가 한 명 더 있어 Pull Request 단계에서 코드 리뷰를 해준다고 생각하시면 됩니다. 현재는 Java와 Python만 지원하고 있습니다. -![AWS CI/CD pipeline with CodeGuru & UnitTest - DEV Community](/images/125892722-da641d48-e54a-4f4e-8303-8b09d99167bf.png) +![AWS CI/CD pipeline with CodeGuru & UnitTest - DEV Community]({{ site.baseurl }}/images/125892722-da641d48-e54a-4f4e-8303-8b09d99167bf.png) ## **왜 필요한가요?** diff --git "a/_posts/2022-04-28-\355\224\204\353\241\234\353\215\225\355\212\270-\353\224\224\354\236\220\354\235\270\355\214\200-2022-1q-\355\232\214\352\263\240.md" "b/_posts/2022-04-28-\355\224\204\353\241\234\353\215\225\355\212\270-\353\224\224\354\236\220\354\235\270\355\214\200-2022-1q-\355\232\214\352\263\240.md" index 0e0c45a..53eea03 100644 --- "a/_posts/2022-04-28-\355\224\204\353\241\234\353\215\225\355\212\270-\353\224\224\354\236\220\354\235\270\355\214\200-2022-1q-\355\232\214\352\263\240.md" +++ "b/_posts/2022-04-28-\355\224\204\353\241\234\353\215\225\355\212\270-\353\224\224\354\236\220\354\235\270\355\214\200-2022-1q-\355\232\214\352\263\240.md" @@ -53,7 +53,7 @@ date: "2022-04-28"
-![1분기 회고 form](/images/abcdefghi.png "1분기 회고 form") +![1분기 회고 form]({{ site.baseurl }}/images/abcdefghi.png "1분기 회고 form")
@@ -140,7 +140,7 @@ KPT 회고 방식을 참고하였습니다. 해당 form은 조직의 구성과
-![이상적 복리 구조라면...](/images/jobvmtff9c.png "이상적 복리 구조라면…") +![이상적 복리 구조라면...]({{ site.baseurl }}/images/jobvmtff9c.png "이상적 복리 구조라면…")
@@ -154,7 +154,7 @@ KPT 회고 방식을 참고하였습니다. 해당 form은 조직의 구성과
-![더글러스 엥겔바트의 A,B,C 작업 시각화](/images/81opw4u39c.png "더글러스 엥겔바트의 A,B,C 작업 시각화") +![더글러스 엥겔바트의 A,B,C 작업 시각화]({{ site.baseurl }}/images/81opw4u39c.png "더글러스 엥겔바트의 A,B,C 작업 시각화")
diff --git "a/_posts/2022-10-07-\354\234\240\354\240\200-\353\252\251\353\241\235\354\235\204-redis-bitmap-\352\265\254\354\241\260\353\241\234-\354\240\200\354\236\245\355\225\230\354\227\254-\353\251\224\353\252\250\353\246\254-\354\240\210\354\225\275\355\225\230\352\270\260.md" "b/_posts/2022-10-07-\354\234\240\354\240\200-\353\252\251\353\241\235\354\235\204-redis-bitmap-\352\265\254\354\241\260\353\241\234-\354\240\200\354\236\245\355\225\230\354\227\254-\353\251\224\353\252\250\353\246\254-\354\240\210\354\225\275\355\225\230\352\270\260.md" index 840a83a..1e1b282 100644 --- "a/_posts/2022-10-07-\354\234\240\354\240\200-\353\252\251\353\241\235\354\235\204-redis-bitmap-\352\265\254\354\241\260\353\241\234-\354\240\200\354\236\245\355\225\230\354\227\254-\353\251\224\353\252\250\353\246\254-\354\240\210\354\225\275\355\225\230\352\270\260.md" +++ "b/_posts/2022-10-07-\354\234\240\354\240\200-\353\252\251\353\241\235\354\235\204-redis-bitmap-\352\265\254\354\241\260\353\241\234-\354\240\200\354\236\245\355\225\230\354\227\254-\353\251\224\353\252\250\353\246\254-\354\240\210\354\225\275\355\225\230\352\270\260.md" @@ -55,7 +55,7 @@ Redis에 대상 유저를 저장하는 용도로 채택한 이유로는 아래 두번째 설문에서는 유저 19만명에게 타겟팅하고, 얼만큼의 메모리가 소모되었는지 확인해보겠습니다. 동일하게 타겟팅한 유저의 양만큼 SET이 추가됩니다 ![]{{ site.baseurl }}/images/xrsP0sy2Tq.png) -이때 약 10439.65 KB (10.6902 MB)의 메모리가 소모됩니다. ![19만명일때 SCARD로 188608을, MEMORY USAGE로 10690200을 결과로 받은 이미지](/images/peQlPgY4BT.png) +이때 약 10439.65 KB (10.6902 MB)의 메모리가 소모됩니다. ![19만명일때 SCARD로 188608을, MEMORY USAGE로 10690200을 결과로 받은 이미지]({{ site.baseurl }}/images/peQlPgY4BT.png) 19만명의 유저의 참여 정보를 저장하기 위해서 약 10MB에 달하는 메모리를 사용한다는 것은 문제가 될 것으로 우려하였습니다. 수 백만명을 대상으로 하는 설문 10개가 동시에 진행된다면 오로지 유저 목록을 담기 위해 사용하는 Redis의 메모리 크기만해도 기가바이트 단위가 될 것을 짐작할 수 있습니다. diff --git "a/_posts/2023-02-22-\353\246\254\353\251\244\353\262\204-\354\233\271-\354\204\234\353\271\204\354\212\244-\354\242\214\354\266\251\354\232\260\353\217\214-yarn-berry-\353\217\204\354\236\205\352\270\260.md" "b/_posts/2023-02-22-\353\246\254\353\251\244\353\262\204-\354\233\271-\354\204\234\353\271\204\354\212\244-\354\242\214\354\266\251\354\232\260\353\217\214-yarn-berry-\353\217\204\354\236\205\352\270\260.md" index 7e4fff3..4f2fc4c 100644 --- "a/_posts/2023-02-22-\353\246\254\353\251\244\353\262\204-\354\233\271-\354\204\234\353\271\204\354\212\244-\354\242\214\354\266\251\354\232\260\353\217\214-yarn-berry-\353\217\204\354\236\205\352\270\260.md" +++ "b/_posts/2023-02-22-\353\246\254\353\251\244\353\262\204-\354\233\271-\354\204\234\353\271\204\354\212\244-\354\242\214\354\266\251\354\232\260\353\217\214-yarn-berry-\353\217\204\354\236\205\352\270\260.md" @@ -456,7 +456,7 @@ yarn 2.x 버전 부터는 pre-hook(ex. `preinstall` , `prepare` 등) 을 지원
-![image](/images/HypdCkq7Fh.png) +![image]({{ site.baseurl }}/images/HypdCkq7Fh.png)
@@ -492,7 +492,7 @@ AWS Codebuild - 편집 - 아티팩트 - 캐싱 메뉴 하단
-![image](/images/oEhoS7O3yb.png) +![image]({{ site.baseurl }}/images/oEhoS7O3yb.png)