[JS] 14일 만에 GitHub 스타 천 개 받은 차트 오픈소스 개발기


:bar_chart: Re-usable, easy interface JavaScript chart library based on D3 v4+:chart_with_upwards_trend: 


billboard.js is a re-usable, easy interface JavaScript chart library, based on D3 v4+.

Documents

Playground

Play with the diverse option generating on the fly!

Supported chart types

Chart Types








1. 14일만에 GITHUB 스타 1K 받은    차트 오픈소스 개발기    박재성

2. 차트란 무엇인가?


3. 훗 차트, 너란녀석1) 데이터의 시각화 2) 차트 라이브러리? 1)의 구현을 위한 도구 그러나 차트의 적용은 무엇일까?  결국, 시각화가 기본이다. UI(디자인) + 인터렉션  구현(적용)이 관건


4. CHARTS ARE EVERYWHERE iOS 10  89% iOS 9  9% Earlier  2%


5. 차트 같은걸 끼얹나? 차트는 자주 접하지만, 개발은 그렇지 않다. 한번 개발(또는 경험)되더라도 지속적인  개선 요인이 별로 없어 경험 향상이 어렵다.

6. YOU, 차트 개발 해야함 몇 가지의 선택지들 직접 개발한다. 외부 라이브러리를 사용한다.  → 상용 or 오픈소스 어떤 기술을 사용할 것인가?  → Vector(SVG) or Bitmap(Canvas)


7. 그래, 직접 개발!Good Luck! 진심으로 행운을 빕니다.   

https://giphy.com/gifs/starwars-star-wars-force-3ohuPdEqZR8tDeuN3O


8. 역시, 외부 라이브러리!상용 or 오픈소스? 상용 → 결국 비용의 문제  라이센스 비용 부담 (ex. Highcharts 10 developer $3,320) 오픈소스 → 어떤 라이브러를 사용할 것인가?  결정의 어려움 (많은 고려요소 필요)

9. 다양한 차트 라이브러리어떤 것을 선택할 것인가?  [참고] https://bestof.js.org/tags/chart

10. 기술 선택 가이드 성능 중요(빠른 대용량 데이터 처리),  상대적으로 디자인은 덜 중요한 경우 → Canvas (비트맵) 디자인 및 요소별 커스터마이징,  다양한 해상도(Zoom) 중요 → SVG (벡터) [참고] SVG 대 캔버스: 선택 방법

11. 영역별 다른 관점, 디자인 보단 실시간 변화 표현 중요 대용량 트래픽의 실시간(realtime) 변화 확인 수치의 변화가 중요. 기본 디자인 사용에 문제 없음 관리도구 등에 적합. 소수의 참여자(admin)

12. 영역별 다른 관점, 엔드 유저대상, 다양한 디자인/UX 중요 주로 정적인 데이터의 시각화 디자인과 UX 적용의 유연성 필요 대규모의 불특정 사용자(엔드유저)를 대상

13. 그간 네이버에서의 차트서비스들마다 다른 라이브러리를 사용 그리고 그로 인한 다양한 문제

14. 문제들 기술적 know-how 축적 안됨 상용 라이브러리 사용시 비용 문제 경험이 누적되지 않아 차트 적용(디자인/개발)시,  매번 반복되는 리소스의 낭비

15. 물론, 처음엔 자체 개발 그러나, 성공적이진 못했다. 서비스 적용 이후, 메인터넌스 잘 안됨 개발 주체의 부재상황(이직 등)  또는 다른 서비스 개발 등으로 인한 지원 어려움 타 라이브러리 대비 범용성 부족

16. 그렇다면 오픈소스 사용은 어떨까? 지속적 업데이트, 기술적 트렌드 반영, 안정성 등을  기대할 수 있으니 합리적이지 않을까? 향후 오픈소스 업데이트 지속되지 않을 경우,  fork를 통한 유지 고려도 가능 공통된 라이브러리를 사용하면, 각각 다른 라이브러리 사용으로 인한 관리 및 기술경험 누적되지 않는 이슈 해결 기대 [참고] 그간 사용되었던 다양한 차트 라이브러리들:  ,  ,  ,  ,  , etc.NVD3 C3.js Chart.js Highcharts echarts

17. 직접 개발도 해봤고, 외부(상용/오픈)의 것도 사용해 봤으니 간접적인 형태로 접근해 보자 라이브러리의 발전은 생태계에 맡기자. 필요한 기능은 PR을 통해 해결 오픈소스는 일정 수준 검증 되었다. 다양한 문서, practice가 존재한다.

18. 그래서, 만들다. C3.JS 확장 라이브러리 개발

19. C3.JS 선정이유 가장 인기있는 D3.js 기반 한정 Popularity 비교:  → GitHub star, 써드파티 앱, StackOverflow 질문 수, etc. 간결한 인터페이스 풍부한 문서, 예제 등  → 구글검색 결과: C3.js(22만) Vs. NVD3(6만4천) 네이버 서비스들에서 이미 다수에서 사용 엔드 유저 대상이므로, 디자인/기능 커스터마이징 용이성 중요

20. 개발 시작 고난의 시작

21. 개발시 겪게 되는 문제들 커뮤니케이션 디자인 & 인터렉션 커스터마이징 그리고 또 그리고 수많은...

22. 커뮤니케이션나의 이름은 무엇 인가요?  차트 개발 경험이 많이 없는 경우, 부르는 명칭도 제각각

23. 디자인 가이드 각 요소들의 크기와 위치를 가이드에 맞춰주세요.

24. OMG! SVG TEXT I'm SVG text 텍스트 스타일링은 가능 <br> 같은거 안됨. 줄바꿈은 새로운 노드로 위치(via attributes) 여백 등의 조정이 어려움  → transform:translate 또는 <tspan> 사용

25. 모바일 환경 C3.js는 모바일 환경 미지원 Swipe 제스처를 통한 데이터 확인 UX 필요


26. 환경별 다른 이벤트 발생 터치하고 바로 떼었을 때


 iOS 11 (iPhone 7) touchstart → touchend → mouseover → mousemove → mouseout (포커스 이동되면 발생)

 Android 7 (Galaxy S8) touchstart → touchend → mouseover → mousemove → mousedown → mouseup → click → mouseout (포커스 이동되면 발생) http://jsbin.com/xiyara


27.   최소값y축 기반 값에 따른 up/down 표현 0 1 2 3 4 100,000 100,500 101,000 101,500 102,000 102,500 103,000 103,500 104,000 0 1 2 3 4 0 10,000 20,000 30,000 40,000 50,000 60,000 70,000 80,000 90,000 100,000 110,000 위의 차트는 모두 동일한 값을 표현하고 있습니다.

28. 데이터는 없지만, 데이터는 표현해야 한다? 데이터가 0인 경우,  표현이 되어야 할까? 안되어야 할까? 

29. C3+ C3.JS 확장 라이브러리를 만들다.

30. C3+? C3.js를 확장한 테마 형태의 디자인 차트 생성 C3.JS: 확장 + 기능 보완 + 테마 커스텀 축 지원 범례 템플릿 모바일 지원 테마를 통한 차트 생성 확장 옵션

31. 블로그/포스트 통계 적용[네이버 블로그] 블로그 통계가 새로워졌습니다! [네이버 포스트] 훨씬 좋아진 통계, 지금 제공합니다!

32. C3+ GOAL 매번 다른 기술/라이브러리를 다루는  반복적인 비용 제거 기본적 디자인(테마)을 활용해  커스터마이징(디자인)에 따른 비용 제거 기술적 경험 축적: SVG, D3, C3.js

33. BUT, 현실적 문제직면 장기적 관점에서, C3+ 발전을 위해 외부 공개 목표 하지만, 래퍼/애드온 형태의 지속적 발전과 효용성 의문 기반 라이브러리인 C3.js 지속성 의문 오픈소스의 발전에 기댈 수 있을 것이란 기대는  C3.js의 더딘 발전(또는 중단?)으로 위기 직면

34. Re-usable, easy interface JavaScript chart library based on D3 v4+

35. 차트를 만들어 봅시다.

36. STEP 1 파일을 로딩 합니다.<!-- D3.js를 로딩 --> <script src="https://d3js.org/d3.v4.min.js"></script> <!-- billboard.js와 기본 스타일을 로딩 --> <script src="billboard.js"></script> <link rel="stylesheet" href="billboard.css">

37. STEP 2 차트가 노출될  영역을 설정합니다. <div id="chart"></div>

38. STEP 3 옵션과 함께 차트를 생성합니다. Declarative API bb.generate({ bindto: "#chart", data: { columns: [ ["data1", 30, 200, 100, 400, 150, 250], ["data2", 100, 80, 130, 240, 350, 90], ["data3", 150, 120, 58, 135, 258, 159] ], type: "bar", colors: { data1: "#2acefd", data2: "#f87070", data3: "#1f77b4" }, labels: true } });

39. 짠! bar   line   spline   pie   gauge   area‑spline   step   donut   scatter 30 200 100 400 150 250 100 80 130 240 350 90 150 120 58 135 258 159 0 1 2 3 4 5 0 50 100 150 200 250 300 350 400 450 data1 data2 data3

40. 커스터마이징150개 이상의   제공 SVG 노드: 필요한 경우, 직접 핸들링 가능  CSS로 스타일링 가능  다양한 옵션

41. THE UNKNOWN WAY TO FORK에서 공개까지

42. C3.JS 프로젝트 참여 시도원 개발자 및 커미터에게 메일을 통한 문의 

43. 일단 활동하자PR도 보내고 이슈들에 대한 답변도 하고 [참고] https://github.com/c3js/c3/issues/1924#issuecomment-271224192

44. 그렇게 몇 주가 흘렀지만 메일 회신도 없고, 프로젝트 ACTIVITY도 딱히 없는 상태...

45. 공개적 문의issue를 등록해 공개적으로 프로젝트 유지 문의 [참고] https://github.com/c3js/c3/issues/1965

46. 그리고, 그 다음날

47. 그래, FORK 하자'향후 오픈소스의 업데이트 지속 안될 경우,  fork를 통한 유지'의 명제 당면한 C3.js의 미해결 과제들: D3 최신버전 v4+ 미지원 모바일 환경에 대한 지원 부족 오래된 개발 스타일 코드 (ES3) SVG polyfill 제거 등등...

48. 합리성, 당위성 & 신뢰 Fork 한다고 해서 사용자가 오진 않는다. 기존 커뮤니티에 당위성이 제시 필요 과연 이 사람(개발자)이 믿을만 한가?

49. THE JOURNEY GOING FROM D3 V3 TO V4  WITHIN TWO MONTHS

50. OOPS~, D3 V4v3 → v4: Breaking Changes  공식 문서( ) 있으나,  마이그레이션 가이드 없고 만들지 않을거임.  Changes in D3 4.0 [참고]   https://github.com/d3/d3/issues/2893 D3 V4 - What's new?

51. D3 V4로 업그레이드변경된 모듈에 대한 목록을 모두 작성  v3 v4 d3.time.scale d3.scaleTime d3.svg.line() d3.line d3.behavior.drag d3.drag ... 모듈의 behavior 변경되어, 기존과 유사한 것도 있지만  다르게 처리되는 것들이 대다수 이전 버전과 변경된 문서를 읽고 비교하고, 테스트 하고...

52. 그외 작업들 차트 생성 흐름에 따른 오류들의 순차적 해결/변환 ES3 → ES6로 전환 병행 및 개발 환경 변경 API 문서화 ( ) 테스트 코드 업데이트(d3 v4 호환) 및 커버리지 개선 JSDoc

53. RELEASE 3주전 YAY~!, 이제 끝이 보인다.

54. 어느 날, 갑자기 두둥~ 갑작스러운 C3.js 차기 릴리즈 계획과 새로운 커미터 추가 [참고] https://github.com/c3js/c3/issues/2033

55. 고민이미 많은 진전을 통해 릴리즈를 앞둔상황 계획만을 통한 발전에 대한 의문 커미터 추가 후에도 활발한 활동 없어,  빠른 시일 내 D3 v4 지원 어렵다는 판단 계획대로  릴리즈 하자.

56. 오픈소스 네이밍원래는 C3+ 2.0으로 계획, 그러나 C3.js 연관성의 부정적 의견 'billboard'는 음악 차트 의미는 다르지만 '차트'를 연관 오랫동안 친숙한 이름 FE 프로젝트에서는 기 등록된 npm 모듈명 확인 필요 [참고] Open Source Project Name Checker

57. RELEASE!2017년 6월8일, v1.0.0 공개

58. 그러나, 공개한다고 갑자기 관심과 사용자가 몰려오진 않는다. 홍보전략 필요

59. 직접 발로뛰기 다수의 'ECHO' 사이트에 등록하기 JavaScript Live Echo JS Hacker News 많은 곳에서 해당 사이트에 등록된 정보를 활용, 재전파 한다.

60. 뉴스레터 소개 요청하기 JavaScript Weekly [참고] FE 관련 뉴스레터는 사실, 한 곳에서 발행  https://cooperpress.com/

61. 유력 매체 소개     JavaScript Weekly 소개 JavaScript Daily 소개

62. GITHUB TRENDING!JavaScript 언어부문 3위 기록 [참고] https://github.com/trending/javascript

63. GITHUB STAR 공개 후, 첫 6일간 700개 14일 후, 1,000개 도달! Star의 가치는?  cdnjs 등록은 최소 200개 요구됨 Vuejs도 첫 6일간 615개 How I Got From 0 to 1 000 Stars on GitHub in Three Months

64. THIRD-PARTY APPS!Angular, React, R, Web Components 등의  자발적인 프로젝트들의 등장 [참고] https://github.com/naver/billboard.js/wiki/Third-party-applications

65. 지속적 성장월 npm 다운로드 수 June 370 July 479 Aug 862 Sep 1,124 [참고] npm-stat: billboard.js, 2017.6.8 ~ 9.30

66. 충실한 문서문서 작성은 아주, 아주 중요하다. 대표 사이트:  C3.js에서 마이그레이션 하기 가이드 잘 작성된 API 문서 왜 Fork 하게 되었나? Readme https://naver.github.io/billboard.js/

67. 80여개의 풍부한 예제많은 예제는 '무엇'이 가능 또는 할수 있는지 보여줄 수 있다.  https://naver.github.io/billboard.js/demo/

68. 이제 부터가 시작 Star의 수는 보다 발전할 수 있도록 도와주는 역할 이슈에 대한 빠른 대응 필요 신규 기능과 버그에 대한 처리 을 통해 향후 방향에 대한 정보제공Roadmap

69. 사용자를 위한 지속적 기능 추가

70. PLAYGROUND온라인에서 바로 옵션들을 수정하고 확인  [참고] https://naver.github.io/billboard.js/playground/

71. 신규 옵션들과 문서 C3+ 경험들을 통한 신규 옵션  꾸준한 문서 업데이트 API는 한번 작성되면 끝이 아니다. 정확한 의미와 동작을 기술 그리고 지속적 업데이트

72. 오픈소스의 중요한 요소들 안정성, 충분한 문서 그리고 책임감 [참고] http://opensourcesurvey.org/2017/

73. 오픈소스의 어려움누군가의 노력이 대가없이 제공되는 것.  그러나, 쉽게 비난 받기도 한다.   https://twitter.com/spf13/status/907403135592878080

74. 의연하게 대처하기 You shouldn’t let strangers on the internet negatively affect your mood or your drive  ...  The trolls feed on your  annoyance and discourse.  ― Sindre Sorhus [참고]   Between the Wires: An interview with open source developer Sindre Sorhus 1,139 npm Packages

75. WHY DO OPEN SOURCE? 세상에서 내가 도움 받은 것에 대해  다시 기여하는 의미있고 가치있는 행동 [참고]   네이버 오픈소스 가이드 GitHub Open Source Guides

76. SPECIAL THANKSMASAYUKI TANAKA AND ALL OF THE C3.JS CONTRIBUTORS,  FOR YOUR GREAT EFFORTS AND WORKS TO THE COMMUNITY!

77. 고맙습니다.  Thank You.  Gracias.  https://github.com/naver/billboard.js/



...

저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水

Realm은 어떻게 효율적인
 데이터베이스를 만들었나?

https://deview.kr/2017/schedule/206


Realm은 SQLite만 사용되던 모바일 데이터베이스 시장에서 혁신적인 대안으로 평가받고있는 오픈소스 데이터베이스 입니다. 현재 10만명 이상의 개발자들이 개발에 사용하고있고, 20억대 이상의 디바이스에 설치되어 있습니다. 


Realm을 빠르고 효율적인 데이터베이스로 만들기 위해 사용되었던 여러 기술과 고려되었던 여러 사안들이 있습니다. Realm이 이슈들을 어떤 방법으로 대처해왔는지를 살피고 거기에서 응용과 프레임워크 개발에서 얻을 수 있는 교훈을 살펴봅시다.




how can realm_make_efficient_mobile_database

1. Realm은 어떻게 효율적인 데이터베이스를 만들었나? Leonardo YongUk Kim Java team

2. GreenDao ORMLite SQLite Realm

3. 첫번째 비결 Zero copy

4. Zero copy “최대한 복제를 미루는 것입니 다.”

5. 왜 Zero copy인가? 

public class City { private String name; private long votes; 

public String getName() { return name; } 

public void setName(String name) { this.name = name; } 

public long getVotes() { return votes; } 

public void setVotes(long votes) { this.votes = votes; } } 

제로 카피 없는 세상을 생각해 봅시다.

6. 왜 Zero copy인가? 

public class City { 

private String name; private long votes; 

public String getName() { return name; } 

public void setName(String name) { this.name = name; } 

public long getVotes() { return votes; } 

public void setVotes(long votes) { this.votes = votes; }

 }

ORM이나 JSON 파서가 채워줘야 해요. 

ORM이나 JSON 파서가 채워줘야 해요.

7. 왜 Zero copy인가? public class City { private String name; private long votes; public String getName() { return name; } public void setName(String name) { this.name = name; } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } public List<City> hydrate() { List<City> results = new ArrayList<>(); while (hasNextItem) { City c = new City(); c.setName(name); c.setVotes(votes); results.add(c); } return results; } 너가 뭘 쓸지 몰라서 다 준비했어요.

8. 왜 Zero copy인가? public List<City> hydrate() { List<City> results = new ArrayList<>(); while (hasNextItem) { City c = new City(); c.setName(name); c.setVotes(votes); /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ results.add(c); } return results; } 너가 뭘 쓸지 몰라서 다 준비했어요. 수화라고 번역합니다. 객체의 필드를 채우는 일입니다.

9. 왜 Zero copy인가? public List<City> hydrate() { List<City> results = new ArrayList<>(); while (hasNextItem) { City c = new City(); c.setName(String.valueOf(name)); c.setVotes(Integer.parseInt(votes)); /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ /* invoke other setters */ results.add(c); } return results; } 어쩌면 매번 변환이 필요할지 몰라Yo~!

10. 왜 Zero copy인가? public class City { private String name; private long votes; public String getName() { return name; } public void setName(String name) { this.name = name; } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } 만약에 사용자가 getName만 필요하면? votes값의 변환과 설정은 필요없는 것 아닌가?

11. 왜 Zero copy인가? public class City { private String name; private long votes; private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } public long getVotes() { return votes; } public void setVotes(long votes) { this.votes = votes; } } row에서 해당 column만 이제 가져옵시다. name을 채우지 맙시다. row의 해당 column에 기록합니다. “사용하지 않을지 모르는 항목을 위한 작업을 최대한 뒤로 미루자.”

12. 보일러플레이트

13. 보일러플레이트 public class City { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 프로그래머에게 직관적인 코드

14. 보일러플레이트 public class City { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class LazyCity { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 프로그래머에게 비관적인 코드 꼭 이렇게 짜야하나요?

15. 보일러플레이트 public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City{ private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 반복적인 작업은 기계에게 맡겨야 합니다. “Annotation Processing Tool (APT)” 생성된 클래스는 모두 RealmProxy가 붙습니다.Realm 객체는 RealmObject를 상속 받습니다.

16. 반복적인 작업은 기계에게 맡겨야 합니다.

 “Annotation Processing Tool (APT)” 

“어노테이션 프로세싱 툴은 어노테이션으로 부터 새로운 객체를 생성합니다.”


17. Man vs Code 

City CityRealmProx y 사용자의 원본 객체 (RealmObject) 기계가 생성한 객체 (RealmProxy) 어노테이션 프로세싱 툴 (APT)


18. Man vs Code Realm의 APT는 AbstractProcessor를 상속한 RealmProcessor로 구현됩니다. AbstractProcessor +process(annotations, roundEnv) RealmProcessor RealmObject RealmProxy RealmObject RealmProxy RealmObject RealmProxy

19. Man vs Code writer.emitAnnotation("Override") .beginMethod( "void", // return type "copy", // method name EnumSet.of(Modifier.PROTECTED, Modifier.FINAL), // modifiers "ColumnInfo", "rawSrc", "ColumnInfo", "rawDst"); // parameters writer.emitStatement("final %1$s src = (%1$s) rawSrc", columnInfoClassName()); writer.emitStatement("final %1$s dst = (%1$s) rawDst", columnInfoClassName()); for (VariableElement variableElement : metadata.getFields()) { writer.emitStatement("dst.%1$s = src.%1$s", columnIndexVarName(variableElement)); } writer.endMethod(); “마법은 없습니다. Java 코드를 생성하는 것은 고통스러운 일입니다.”

20. Man vs Code “마법은 없습니다. Java 코드를 생성하는 것은 고통스러운 일입니다.” 1. StringBuilder 2. Template engines 1. Apache Velocity (7년만에 부활) 2. Apache FreeMaker 3. Pebble Template Engine 4. Thymeleaf Template Engine 3. Code generators 1. JavaPoet 2. JavaWriter (개발 중단. Java Poet이 후속작) 3. jcodemodel (2005년 경부터 개발 중단) 당신은 용자 코드도 찍어내면 그만? 내가 코드를 짜는 건지 코드가 날 짜는 건지. 튜토리얼이 많은 애가 개발이 잘 안돼. 그래도 스퀘어가 제일 낫지 않나?

21. APT가 해법인가?

22. APT가 해법인가? public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } APT는 어떤 메서드가 어떤 역할인지 이해하지 못합니다.

23. APT가 해법인가? public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 암묵적인 컨벤션을 가정합니다. 구 버전의 Realm에서는 항상 표준적인 이름의 getter와 setter를 강제합니다. name이란 필드에 대해 getName과 setName을 쓰지 않을까요?

24. APT가 해법인가? public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public class CityRealmProxy extends City { private final int COLUMN_NAME = 0; public String getName() { return (String) getRow().getSting(COLUMN_NAME); } public void setName(String name) { getRow().setString(COLUMN_NAME, name); } } 부모가 name 필드와 어떤 상호작용을 하고 있을지 예상할 수 없습니다. 구 버전의 Realm은 커스텀 동작을 금지하고 부모 클래스의 동작을 무시했습니다. City의 getName은 어떤 부가 작업을 하고 있을까요? City의 setName은 어떤 부가 작업을 하고 있을까요?

25. 바이트 코드 뒤집기

26. 바이트 코드 뒤집기 City name CityRealmProx y CityRealmProxyInterface +realmGet$name: String +realmSet$name(name) ZeroCopy관련 객체를 위한 인터페이스 name 필드에 접근하는 모든 코드 대신 realmGet$name과 realmSet$name이 호출되도록 변조합 니다. realmGet$name과 realmSet$name를 오버라이드해서 Zero copy 부분을 구현합니다. APT로 코드 생성 인터페이스 구현

27. 바이트 코드 뒤집기 public class CityRealmProxy extends City implements CityRealmProxyInterface { private final int COLUMN_NAME = 0; public String realmGet$name() { return (String) getRow().getSting(COLUMN_NAME); } public void realmSet$Name(String name) { getRow().setString(COLUMN_NAME, name); } } 내부용 게터와 세터는 RealmProxy 아래 생성됩니다.

28. 바이트 코드 뒤집기 public class City implements CityRealmProxyInterface { private String name; public String getName() { return (String) realmGet$name(); } public void setName(String name) { realmSet$name(name); } public String realmGet$name() { return name; } public void realmSet$Name(String name) { this.name = name; } } “바이트코드가 변조된 City객체 입니다.” public class City extends RealmObject { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }

29. 바이트 코드 뒤집기 public class City implements CityRealmProxyInterface { public String name; public String realmGet$name() { return name; } public void realmSet$Name(String name) { this.name = name; } } “이제는 getter와 setter가 없어도 됩니다.” public class City extends RealmObject { public String name; } name 필드에 대한 접근은 모두 게터와 세터 호출로 변경됩니다.

30. 바이트 코드 뒤집기 City CIty 사용자가 생성한 객체 바이트 코드 변조된 객체 Transformer “Transformer는 빌드된 결과를 변조합니다.”

31. 바이트 코드 뒤집기 class RealmTransformer extends Transform { @Override void transform(Context context, Collection<TransformInput> inputs, Collection<TransformInput> referencedInputs, TransformOutputProvider outputProvider, boolean isIncremental) throws IOException, TransformException, InterruptedException { … } } 이 트랜스포머가 필드에 대한 접근들을 모두 Realm의 게터와 세터로 변조합니다.

32. 바이트 코드 뒤집기 “마법은 없습니다. 바이트 코드를 변조하는 것은 고통스러운 일입니다.” 1. ASM 2. BCEL 3. CGLIB 4. Javassist 5. AspectJ 중간 정도 난이도의 도구. Realm이 사용.

33. 다른 DB도 Zero copy?

34. 다른 DB도 Zero copy? SQLite 시스템 적인 경계 Object Object Object Object Object Object ORM

35. 다른 DB도 Zero copy? SQLite 시스템 적인 경계 Object Object Object Object Object Object ORM 이 영역까지만 lazy하게 미룰 수 있음.

36. 다른 DB도 Zero copy? SQLite 시스템 적인 경계 Object Object Object Object Object Object ORM 경계를 넘어서 lazy한 처리는 어려움.

37. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; “Realm은 생각보다 더 게으릅니다.”

38. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; Realm 은 오프셋도 리미트도 없습니다.

39. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; 이 시점에서는 실제 데이터를 받아오지 않습니다. 실제 데이터를 가지고 있지 않기 때문에 특수한 리스트 구조를 가지고 있습 니다.

40. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; 이 시점에 첫 번째 사람에 대한 메타 데이터만 가지고 옵니다.

41. 더 많은 Zero copy 가능성 realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { Person person = realm.createObject(Person.class); person.setId(1); person.setName("Young Person"); person.setAge(14); } }); final RealmResults<Person> people = realm.where(Person.class).findAll(); final Person person = people.first(); final String name = person.name; 이 시점에 첫 번째 사람의 정보 중 name만 접근합니다.

42. 더 많은 Zero copy 가능성 Realm은 lazy하게 동작하기 위해 특별한 클래스를 가집니다. 1. RealmObject 2. RealmResults 3. RealmList DB 엔진의 지원 때문에 전체적으로 게을러질 수 있습니다.

43. 조금 더 빨라지기 위 해

44. 조금 더 빨라지기 위해 final RealmResults<Person> people = realm.where(Person.class).findAll(); for (Person person : people) { final String name = person.name; } 객체의 전체 필드가 필요한 경우는 드뭅니다. 모바일 데이터베이스의 특징을 생각해봅시다.

45. 조금 더 빨라지기 위해 10 30 40 3 4 6 10 Row 3 전통적인 Row 우선 B-Tree리프가 10번째 Row까지 가진다는 것을 의미 nam e votes 패딩 리프는 보통 연속된 Array Row에 속한 모든 Column

46. 조금 더 빨라지기 위해 10 30 40 3 4 6 10 Row 3 연속된 name 검색 nam e votes 패딩 인접한 데이터는 name이 아니다.

47. 조금 더 빨라지기 위해 캐시를 생각해봅시다. (3회 적중) nam e votes 패딩 nam e votes 패딩 nam e votes 패딩 nam e votes 패딩 캐시 라인 캐시 히트 캐시 미스

48. 조금 더 빨라지기 위해 구조를 컬럼 기준으로 바꾸어봅시다. nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e 캐시 라인

49. 조금 더 빨라지기 위해 구조를 컬럼 기준으로 바꾸어봅시다. (12회 적중) nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e nam e 캐시 라인 캐시 히트 캐시 미스

50. 조금 더 빨라지기 위해 4 8 12 Realm의 Column 우선 B-Tree nam e nam e nam e nam e 리프가 4번째 컬럼까지 가진다는 것을 의미 동질적인 데이터이기에 예측가능한 사이즈

51. 4 8 12 Realm의 전체 트리 nam e nam e nam e nam e nam e votes Perso n Group (DB와 같은 개념) Table Column B-tree 4 8 12 vote votes votes votes Ro ot

52. Root가 있는 이유?

53. Root가 있는 이유? 4 8 12 nam e nam e nam e nam e nam e votes Perso n 4 8 12 vote votes votes votes Ro ot 전체 Group을 하나의 스냅샷으로 인 지.

54. Root가 있는 이유? 현재 버전을 포인팅 Ro ot 현재 버전 삭제될 과거 버전 “Multi Version Concurrency Control” Git, 현대적인 DBMS에서 사용.

55. Root가 있는 이유? Ro ot 다른 사용자는 현재 버전에 Lock 없이 접근. 새 버전을 작성중 . 읽기는 언제나 비 배타적입니다.

56. Root가 있는 이유? Ro ot 새로 작성된 버전으로 옮겨가는 것만 락이 필요합 니다. Ro ot 쓰기만 배타적입니다. 다른 사용자는 여전히 이전 버전에 접근 중. 루트를 이동

57. Root가 있는 이유? "MVVC는 효율을 위해 사용성을 일부 희생합니다.” 1. 읽기는 Lock이 필요하지 않으며 언제나 가능합니다. 2. 쓰기는 Lock이 필요합니다. 3. 객체는 어떤 시점을 참고하고 있기 때문에 다른 스레드로 전달될 수 없습니 4. 다른 스레드에서 객체를 참고하는 것은 즉시 이루어집니다. 프로그래머에게 직관적이지는 않습니다.

58. 이전 버전을 읽을 가 능성?

59. 이전 버전을 읽을 가능성? Ro ot 다른 사용자는 현재 버전에 Lock 없이 접근. 새 버전을 작성중 . “다른 사용자는 여전히 구 버전을 접근하게 되지 않나요?”

60. 이전 버전을 읽을 가능성? Person 객체 (Leonardo) v1 Person 객체 (Leonardo) v1 스레드 A 스레드 B Person 객체 (Leonardo) v2 1. 스레드 A에서 Person 객체 업데이트. 2. 업데이트 내역이 전파. Person 객체 (Leonardo) v2 3. 스레드 B의 라이브 객체가 자동 업데이 트. 3. 스레드 B의 객체의 리스너에게 모두 업데이트 내용을 통보.

61. 추가적인 최적화

62. 추가적인 최적화 4 8 12 nam e nam e nam e nam e nam e votes Perso n 배열은 얼마나 많은 공간을 차지할까? 4 8 12 vote votes votes votes Ro ot

63. 추가적인 최적화 0 1 0 1 votes가 최대 1인 경우 “최대 값이 1인 경우 4개의 votes는 4bits를 차지합니다.” Boolean 타입이 가장 효율적으로 저장됩니다.

64. 추가적인 최적화 00 01 10 01 최대 값이 2로 변경되었습니다. “최대 값이 2인 경우 4개의 votes는 8bits를 차지합니다.”

65. 추가적인 최적화 000 101 010 001 최대 값이 5로 변경되었습니다. “최대 값이 5인 경우 4개의 votes는 12bits를 차지합니다.”

66. 추가적인 최적화 4 8 12 노드의 실제 구조 nam e nam e nam e nam e nam e votes Perso n 4 8 12 vote votes votes votes Ro ot 4 8 12 개별 노드는 3개의 배열을 사용합니 다. 유연하지만 오버헤드가 있습니다.

67. 추가적인 최적화 nam e votes Perso n vote votes votes votes 4 8 12 만약에 데이터가 뒤로만 추가된다면 더 최적화를 할 수 있습니 다. 모든 노드가 다 차있다면 처음과 마지막 인덱스만 있으면 됩 니다.

68. 추가적인 최적화 nam e votes Perso n vote votes votes votes 4 12 물론 이러한 꿈은 삽입과 삭제가 이뤄지면 물거품이 됩니다. 모든 노드가 다 차있다면 처음과 마지막 인덱스만 있으면 됩 니다.

69. 흥미로운가요?


70. 기회는 여러분에게 열려있습니다. “Realm은 오픈소스입니다.”

Realm Java https://github.com/realm/realm-java 

Realm Objective C & Swift https://github.com/realm/realm-cocoa 

Realm Xamarin https://github.com/realm/realm-dotnet 

Realm Reactive Native & Node.js https://github.com/realm/realm-js 

Realm Object Store 공통 모듈 https://github.com/realm/realm-object-store 

Realm Core 핵심 엔진 https://github.com/realm/realm-core


71. Realm을 바로 사용하실 수 있습니다. 

Realm Java 문서 https://realm.io/docs/java/latest/ 

Realm Swift 문서 https://realm.io/docs/swift/latest/ 

Realm Objective C 문서 https://realm.io/docs/objc/latest/ 

Realm React Native 문서 https://realm.io/docs/javascript/latest/ 

Realm Xamarin 문서 https://realm.io/docs/xamarin/latest/

72. 최신 모바일 기술은 Realm에서 https://realm.io

73. Thank you



...

저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水

[Node.js] chromium binding 기술을 node.js에 적용해보자


https://deview.kr/2017/schedule/213


chromium binding 기술을 node.js에 적용해보자

1. Chromium Binding 기술을 Node.js에 적용해보자! Name: Jinho Bang E-Mail: zino@chromium.org

2. 0. 요약

3. 이 세션에서 다룰 내용은..

4. Node.js에서 Native Module을 바인딩 하는 방법이다.

5. 그런데 이미 Node.js에는 바인딩을 위한 방법들이 제공되고 있다.

6. 그러나 그 방법이 아름답지 않다.

7. 이 세션에서는 그러한 문제를 분석하고

8. 좀 더 아름답게 해결하는 방안을 모색해본다.

9. 1. JS에서 왜 Native Module을 사용하는가?

10. 성능(Performance)

11. Low Level APIs

12. 기존에 잘 만들어진 코드가 Native 일때

13. 어쨌든 Node.js를 사용한다면 사용중인 패키지의 30%는 Native이다.

14. 2. 예제를 통해 알아보는 기존의 Native Module 연동 방식

15. sum()함수를 구현해보자(JS 호출) let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]); JS JS function sum(elements) { let s = 0; elements.forEach(element => { s += element; }); return s; }

16. sum()함수를 구현해보자(Native 호출) let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]); JS Native int sum(std::vector<int> elements) { int s = 0; for (int i = 0; i < elements.size(); i++) s += elements[i]; return s; } ?

17. 그런데 Javascript에서 어떻게 호출할까?

18. 기존의 Native Module 연동 방식 var spawn = require('child_process').spawn; var sum = spawn('sum', [...]); sum.stdout.on('data', result => { process(result); ... }); 아마 우리가 원한게 이런것은 아니지 말입니다..

19. 기존의 Native Module 연동 방식 • Node.js C++ Addon • https://nodejs.org/dist/latest-v8.x/docs/api/addons.html • NAN(Native Abstraction for Node) • Node.js C++ Addon이 V8 Public API를 사용하기 때문에 V8 변화에 민감하다. • Node.js를 업데이트 할때마다 문제가 발생하는 것을 해결. • https://github.com/nodejs/nan • N-API ß Latest! • Node.js 8.0이후부터 지원, 8.6에서 Stable Release • NAN과 유사한 방식이지만, ABI-Stable을 보장. (즉, 재컴파일 불필요) • V8 Public API가 아닌 Node.js에서 한번 Wrapping하여 제공하므로 다른 엔진으로 교체도 가능. • https://nodejs.org/dist/latest-v8.x/docs/api/n-api.html

20. N-API에 이르기까지 많은 개선이 있었지만, Binding 코드를 작성하는 것을 위한 개선은 없었다.

21. N-API를 사용하여 Binding 해보자 napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } uint32_t length = 0; napi_get_array_length(env, args[0], &length); double sum = 0; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; } 다음의 예제는 N-API를 사용하여 Native Binding을 하고 있다. 그러나.. 6줄 짜리 sum()함수가 35줄이 된다.

22. N-API를 사용하여 Binding 해보자 const sum = require(‘sum’); let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]); N-API를 사용하여 Binding을 하면 Javascript에서 호출 할 수 있다.

23. 3. 기존의 문제점 파헤치기

24. 지금부터 코드가 많이 나오는데.. 굳이 그 코드들을 이해하실 필요는 없습니다!

25. 문제점1: Argument Check napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); // 문제점1. JS argument는 Runtime에 결정되므로 개발자가 직접 체크해야한다. if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; }

26. 문제점2: Type Checking for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); // 문제점2. 각 Array Element의 Type Checking도 직접해야한다. napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; }

27. 문제점3: Type Converting // 문제점3. JS에서 Native Type Converting을 직접해야한다. double value; napi_get_value_double(env, element, &value); sum += value; } // 문제점3. Native에서 JS Type Converting을 직접해야한다. napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum;

28. uint32_t length = 10000; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); ... } 문제점4: Memory Management napi_value length . . . … 내가 아는 Stack Pop Push

29. uint32_t length = 10000; for (int i = 0; i < length; i++) { // napi_get_element()를 호출할 때마다 // 새로운 object를 생성하고 HandleScope에 // 쌓이게 됨. napi_value element; napi_get_element(env, i, &element); ... } 문제점4: Memory Management napi_value napi_value napi_value napi_value napi_value napi_value … napi_value i = 9999 i = 9998 i = 4 i = 3 i = 2 i = 1 i = 0 HandleScopeStack Heap

30. 문제점4: Memory Management for (int i = 0; i < length; i++) { napi_handle_scope scope; napi_status status = napi_open_handle_scope(env, &scope); napi_value element; napi_get_element(env, i, &element); ... napi_close_handle_scope(env, scope); }

31. 문제점5: Readability napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } uint32_t length = 0; napi_get_array_length(env, args[0], &length); double sum = 0; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; } int sum(std::vector<int> elements) { int s = 0; for (int i = 0; i < elements.size(); i++) s += elements[i]; return s; } // 문제점5. Binding 코드가 많이 삽입되면서 가독성이 떨어진다.

32. 요약 • 기존의 방법은 TypeChecking/Converting과 같은 노가다를 반복해야 한다. • Memory 관리 Mechanism이 다르고 Binding을 위해 사용되는 API를 다룰 줄 알아야 하므로 V8, N-API, JS, C++과 같은 지식 모두를 필요로 한다. • 전체적인 코드의 복잡도가 증가한다.

33. 4. Chromium에서 Blink와 V8은 어떻게 연결되나?

34. 왜 Chromium을 살펴보나?

35. Chromium은 V8의 또 다른 Embedder이다.

36. ♥ ≡ ♥ Blink (Rendering Engine) V8 (Javascript Engine) Node.js Native Module V8 (Javascript Engine)

37. document.getElementById();

38. <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

39. V8 Engine과 Blink Engine의 관계 V8 Engine Chromium Loader <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

40. V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader DOM Parsing <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

41. V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing <script> document.getElementById(‘hello’); </script> JS Evaluate <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

42. V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate Actually, called document.getElementById(); <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script> <script> document.getElementById(‘hello’); </script>

43. V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate Actually, called document.getElementById(); Return JS Wrapper Object let div = document.getElementById(‘hello’); <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script> <script> document.getElementById(‘hello’); </script>

44. <script> document.getElementById(‘hello’); </script> V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate V8 Binding Actually, called document.getElementById(); Return JS Wrapper Object let div = document.getElementById(‘hello’); Type Checking/Converting Manage Isolate and Context <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

45. <script> document.getElementById(‘hello’); </script> V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate WebIDL Binding Actually, called document.getElementById(); Return JS Wrapper Object let div = document.getElementById(‘hello’); Auto-generated!! <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

46. V8 Binding이란? • Chromium에서 V8과 Blink를 연결하는 코드이다. • 사용자가 직접 짜지 않고 WebIDL으로부터 자동 생성(auto-generation)된다. • WebIDL은 JS Engine과 Web Engine을 연결하는 Web 표준에 의해 정의된다. • https://heycam.github.io/webidl/ • https://www.w3.org/TR/api-design/

47. 코드레벨로 살펴보는 WebIDL // WebIDL [Constructor] interface Calculator { double sum(sequence<long> elements); };

48. 코드레벨로 살펴보는 WebIDL // WebIDL [Constructor] interface Calculator { double sum(sequence<long> elements); }; napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } uint32_t length = 0; napi_get_array_length(env, args[0], &length); double sum = 0; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; } VS

49. 코드레벨로 살펴보는 WebIDL // User’s Native Code class Calculator { public: double Sum(std::vector<int> elements) { int sum = 0; for (int i = 0; i < elements.size(); i++) sum += elements[i]; return sum; } };

50. 코드레벨로 살펴보는 WebIDL // User’s JS code var calculator = new Calculator(); console.log(calculator.sum([1, 2, 3, 4, 5, 6, 7, 8, 9]));

51. 요약 • Chromium에서 V8과 Blink의 관계는 Node.js에서 V8과 Native Module의 관계와 동 등하다. • V8과 Blink를 연결하는 Layer를 V8 Binding(WebIDL Binding)이라고 부른다. • V8 Binding(WebIDL Binding)은 WebIDL을 이용해 Auto-generated 된다.

52. 5. Node.js Native Module과 V8은 어떻게 연결되나?

53. const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8');

54. V8 Engine과 Native Module의 관계 V8 Engine Node Runtime const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8');

55. V8 Engine과 Native Module의 관계 V8 Engine V8 Engine Node Runtime JS Evaluate const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8');

56. V8 Engine과 Native Module의 관계 V8 Engine Native Module V8 Engine V8 Engine Node Runtime JS Evaluate Actually, called open() and read() const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8');

57. V8 Engine과 Native Module의 관계 V8 Engine Native Module V8 Engine V8 Engine Node Runtime JS Evaluate Return JS Wrapper Object const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8'); Actually, called open() and read()

58. V8 Engine과 Native Module의 관계 V8 Engine Native Module V8 Engine V8 Engine Node Runtime JS Evaluate Return JS Wrapper Object V8 Binding Type Checking/Converting Manage Isolate and Context const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8'); Actually, called open() and read()

59. 복습: N-API를 사용하여 Binding 해보자 napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } uint32_t length = 0; napi_get_array_length(env, args[0], &length); double sum = 0; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; } 이미 우리가 여러번 말했듯이 이러한 과정을 반복한다. 이런식으로 장인 정신을 발휘하면 잘 만들 수 있다!

60. <script> document.getElementById(‘hello’); </script> 복습: V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate WebIDL Binding Actually, called document.getElementById(); Return JS Wrapper Object let div = document.getElementById(‘hello’); Auto-generated!! <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

61. Node.js에 Auto Binding을 적용한다면.. • IDL을 제외하고는 추가적인 Binding 코드를 직접 작성하지 않아도 된다. • 바인딩 코드와 실제 User Implementation이 완벽히 분리된다. • V8(또는 N-API)을 이해하지 않아도 된다. • 안전하고 빠르게 바인딩할 수 있다.

62. 실제 사례: Open CV Binding // Open CV Matrix를 생성하는 5개의 함수 오버로딩.. let m1 = new Matrix(); let m2 = new Matrix(rows, cols); let m3 = new Matrix(10, 20, CV_32F); let m4 = new Matrix(10, 20, CV_32F, [1, 2, 3]); let m5 = new Matrix(m4, 10, 20, 30, 40);

63. 실제 사례: Open CV Binding // 이 Matrix의 실제 Binding 구현은 다음과 유사하다. // https://github.com/peterbraden/node-opencv/blob/master/src/Matrix.cc#L132 Matrix* mat; if (info.Length() == 0) { mat = new Matrix; } else if (info.Length() == 2 && info[0]->IsInt32() && info[1]->IsInt32()) { mat = new Matrix(info[0]->IntegerValue(), info[1]->IntegerValue()); } else if (info.Length() == 3 && info[0]->IsInt32() && info[1]->IsInt32() && info[2]->IsInt32()) { mat = new Matrix(info[0]->IntegerValue(), info[1]->IntegerValue(), info[2]->IntegerValue()); } else if (info.Length() == 4 && info[0]->IsInt32() && info[1]->IsInt32() && info[2]->IsInt32() && info[3]->IsArray()) { mat = new Matrix(info[0]->IntegerValue(), info[1]->IntegerValue(), info[2]->IntegerValue(), info[3]->ToObject()); else { // if (info.Length() == 5) { ... }

64. 실제 사례: Open CV Binding // 만약 WebIDL Binding을 사용했다면.. [ Constructor(), Constructor(long rows, long cols), Constructor(long rows, long cols, long type), Constructor(long rows, long cols, long type, sequence<long> scalar), Constructor(Matrix m, long x, long y, long z, long w) ] interface Matrix { ... };

65. 실제 사례: Open CV Binding // 만약 당신이 WebIDL 고수였다면.. [ Constructor(), Constructor(long rows, long cols, optional long type, optional sequence<long> scalar), Constructor(Matrix m, long x, long y, long z, long w) ] interface Matrix { ... };

66. 요약 • Node.js에서 V8과 Native Module 사이의 Binding은 개발자가 직접 한땀 한땀 개발해 야만 했다. • Chromium에서 사용되는 WebIDL Binding을 도입한다면, 그러한 장인정신을 발휘하 지 않고도 쉽고 빠르게 개발할 수 있다.

67. 6. Node.js를 위한 WebIDL Auto Binding 구현하기

68. What should we do? • WebIDL을 해석한 후 N-API를 사용하는 적절한 Binding 코드를 생성한다.

69. Blink에서 WebIDL이 처리 되는 과정 WebIDL User Native Implementation

70. Blink에서 WebIDL이 처리 되는 과정 WebIDL IDL Parser User Native Implementation Input

71. Blink에서 WebIDL이 처리 되는 과정 WebIDL IDL Parser Binding Code GeneratorInput User Native Implementation

72. Blink에서 WebIDL이 처리 되는 과정 WebIDL Code Template IDL Parser Binding Code GeneratorInput Input User Native Implementation

73. Blink에서 WebIDL이 처리 되는 과정 WebIDL Generated Code Based on V8 Code Template IDL Parser Binding Code GeneratorInput Input Build User Native Implementation

74. Blink에서 WebIDL이 처리 되는 과정 WebIDL Generated Code Based on V8 Code Template IDL Parser Binding Code Generator User Native Implementation Input Input Build Reference

75. Blink에서 WebIDL이 처리 되는 과정 WebIDL Generated Code Based on V8 Code Template IDL Parser Binding Code Generator Output Binary User Native Implementation Input Input Build Build Reference Build

76. What should we do? • IDL Parser를 구현한다. (Front End) • Code Generator를 구현한다. (Back End)

77. How to implement • IDL Parser를 구현한다. (Front End) • 이미 잘 구현 된 WebIDL Parser가 있다: https://github.com/w3c/webidl2.js • 우리는 AST(Abstract Syntax Tree)를 IDL Definitions로 만들어 주는 것만 하면 된다. • Code Generator를 구현한다. (Back End)

78. How to implement • IDL Parser를 구현한다. (Front End) • 이미 잘 구현 된 WebIDL Parser가 있다: https://github.com/w3c/webidl2.js • 우리는 AST(Abstract Syntax Tree)를 IDL Definitions로 만들어 주는 것만 하면 된다. • Code Generator를 구현한다. (Back End) • Python의 Jinja2를 JS로 포팅 한 Nunjucks가 있다: https://github.com/mozilla/nunjucks • 우리는 C++ Binding Code (N-API를 사용한)를 잘 생성해주는 로직을 짜기만 하면 된다.

79. IR (IDL Definitions) • Compiler의 FrontEnd의 역할. IR(Intermediate Representation)을 생성. • Constructing 단계에서 다음의 두가지 요소가 추가적으로 필요함. • Extended attribute validation • Dependency resolution. IDL Parser (Front End) IDL Tokens AST (Abstract Syntax Tree) Lexing Parsing Constructing

80. IDL Parser (Front End) [Constructor] interface Hello { double test(World world); }; [{ type: 'interface', name: 'Hello', partial: false, members: [ [...] ], inheritance: null, extAttrs: [ [...] ] }] [Constructor] interface World { readonly attribute value; }; Dependency Resolution Constructing Parsing [{ ... name: 'Hello', members: [ [{ idlType: 'World’, ... }] ], }]

81. Code Generator (Back End) V8 Engine Native Binding Code IR (IDL Definitions) Contexts Logic Processing Template Processing Code Template • Compiler의 BackEnd의 역할. IR을 Input으로 최종 결과물(binding code) 생성. • 코드 생성을 위해 Nunjucks Template Engine을 사용.

82. Code Generator (Back End) {% for argument in member.arguments %} auto {{argument.name}} = NativeTypeTraits<IDL{{argument.type | camelcase-}} >::NativeValue(info.Env(), info[{{loop.index - 1}}]); {% endfor %} {% if member.type != "void" %}auto return_value = {% endif %} {% if member.is_static -%} {{name}}::{% else %} impl_->{% endif %} {{member.name | camelcase}}({{-member.arguments[0].name-}} {%- for i in range(1, member.arguments.length) -%} , {{member.arguments[i].name-}} {% endfor %}); return JSTypeTraits(info.Env(), return_value);

83. Code Generator (Back End) {% for argument in member.arguments %} auto {{argument.name}} = NativeTypeTraits<IDL{{argument.type | camelcase-}} >::NativeValue(info.Env(), info[{{loop.index - 1}}]); {% endfor %} {% if member.type != "void" %}auto return_value = {% endif %} {% if member.is_static -%} {{name}}::{% else %} impl_->{% endif %} {{member.name | camelcase}}({{-member.arguments[0].name-}} {%- for i in range(1, member.arguments.length) -%} , {{member.arguments[i].name-}} {% endfor %}); return JSTypeTraits(info.Env(), return_value);

84. Code Generator (Back End) if (info.Length() != 2) { Napi::RangeError::New(info.Env(), "Invalid").ThrowAsJavaScriptException(); return Napi::Value(); } // 복잡한 Type Mapping 및 Converting은 개발자에게 노출하지 않는다. double number1 = NativeTypeTraits<IDLDouble>::NativeValue(info.Env(), info[0]); double number2 = NativeTypeTraits<IDLDouble>::NativeValue(info.Env(), info[1]); // 사용자가 작성한 User Native Implementation을 여기서 호출한다. auto return_value = impl_->Add(number1, number2); return JSTypeTraits(info.Env(), return_value);

85. Code Generator (Back End) class Calculator { public: Calculator() {} // 개발자는 JS Engine의 public API가 어떻게 동작하는지 알 필요가 없다. // WebIDL Spec에 따라 IDL type이 정확한 platform object type과 mapping된다. double Add(double number1, double number2) { return number1 + number2; } }

86. 요약 • Node.js에 WebIDL Binding을 구현하기 위해서는 IDL Parser와 Code Generator 두 가지를 구현해야 한다.

87. 7. Bacardi Project

88. Introduce Bacardi Project • Node.js에서 Chromium이 사용하는 WebIDL Auto Binding을 적용하기 위한 오픈소 스 프로젝트입니다. • https://github.com/lunchclass/bacardi

89. Introduce Bacardi Project • Node.js에서 Chromium이 사용하는 WebIDL Auto Binding을 적용하기 위한 오픈소 스 프로젝트입니다. • https://github.com/lunchclass/bacardi • Chromium Committer들이 주축으로 만들어 갑니다. zino@chromium.org hwanseung@chromium.org

90. How to test Bacardi # Git clone repository $ git clone https://github.com/lunchclass/bacardi

91. How to test Bacardi # Git clone repository $ git clone https://github.com/lunchclass/bacardi # If you are using MacOS $ xcode-select –install # If you are using Linux $ sudo apt-get install g++ git make python wget

92. How to test Bacardi # Git clone repository $ git clone https://github.com/lunchclass/bacardi # If you are using MacOS $ xcode-select –install # If you are using Linux $ sudo apt-get install g++ git make python wget # Build & Test $ ./bacardi build && ./bacardi test

93. Details 

• 자세한 것은 Repository를 참조. 

• https://github.com/lunchclass/bacardi 

• 테스트가 아닌 간단한 예제는 examples 디렉토리를 참조. 

https://github.com/lunchclass/bacardi/tree/master/examples

94. Bacardi with Electron # Build for Electron & Run Electron app $ ./bacardi build_electron && ./bacardi electron

95. Bacardi with Electron - SimRank 두 객체의 유사도를 구하는 알고리즘.

96. Bacardi with Electron - SimRank 만약 여러분이 사용하고 싶은 구현이 Node.js에 존재하지 않는다면..

97. Bacardi with Electron - SimRank 구글링(Googling)을 해보니 SimRank의 C++ 구현은 존재한다. 

https://github.com/roukaour/simrank

98. Bacardi with Electron - SimRank

99. Bacardi with Electron - SimRank 이것을 그대로 Javascript로 binding하여 Electron app에 출력해보자. 

https://github.com/lunchclass/bacardi/pull/135 [ Constructor(), Constructor(long k, double c) ] interface ElectronNative { void addEdge(string head, string tail); void calculateSimRank(); double similarity(string node1, string node2); };

100. Bacardi with Electron - SimRank

101. Bacardi with Electron - SimRank

102. Bacardi의 향후 계획

• 2017년 4분기까지 C++ Binding 구현 완료 - NPM 배포 

• OpenCV & Tensor Flow Binding Bacardi로 옮기기 

• Cross Platform Build 지원 

• Welcome to contribution (https://github.com/lunchclass/bacardi)

Bacardi project is an effort to provide multi-language binding for Node.js native layer.

103. 요약

 • Node.js에 WebIDL Binding을 구현하기 위해서는 IDL Parser와 Code Generator 두 가지를 구현해야 한다. 

• 모두가 같은 노력을 할 필요 없으므로 오픈소스 프로젝트(Bacardi Project)로 진행중이 며, 이를 Node.js Native Module 개발에 활용할 수 있다.

104. 8. Binding 성능에 관한 이야기

105. Native가 JS보다 느릴 수도 있다 

• V8은 매우 빠르다. 

• V8과 Native Addon을 연결하는 Binding은 생각보다 Overhead가 있다. 

• Chromium에서 하드웨어 가속을 써서 ASM + C++을 사용한 Matrix의 구현보다 Pure JS의 구현이 10배 이상 더 빠르다. (관련링크: https://groups.google.com/a/chromium.org/d/msg/blink-dev/V_bJNtOg0oM/lECG9SikFwEJ) V8 Engine Native ModuleV8 Engine V8 Binding Standalone JS Implementation Native Implementation

106. Native가 JS보다 느릴 수도 있다

107. Native가 JS보다 느릴 수도 있다 

• Matrix 계산이 Binding Layer를 지나기 위한 Overhead보다 작기 때문에 발생 

• 어떤 연산이 Binding Layer의 Overhead보다 작고 빈번히 호출이 된다면 JS가 더 빠를 수도 있다. V8 Engine Native ModuleV8 Engine V8 Binding Standalone JS Implementation Native Implementation 이 Layer를 많이 지나다닐 수록 성능은 떨어집니다!

108. 이것을 개선하려면? 

• 가능하면 한 쪽 World에서 머무르도록 한다. 

• uftrace와 같은 프로파일링 툴을 통해 실제 빈번하게 호출되는 지점을 찾을 수 있음. 

https://github.com/namhyung/uftrace V8 Engine Native ModuleV8 Engine V8 Binding Standalone JS Implementation Native Implementation 이 Layer를 가능하면 적게 지나다니는 것이 Key Point

109. uftrace를 사용한 call-graph 추적

110. uftrace를 사용한 call-graph 추적 Native Type Converting을 위해 Type Checking을 반 복적으로 하고 있음을 알 수 있음.

111. No Type Checking // Binding Overhead를 줄이기 위해 NoTypeChecking이라는 Extended Attribute를 추가할 수 있다. interface PerformanceTest { [NoTypeChecking] long fibonacci(long n); };

112. No Type Checking // 그러면 Native Code를 생성할 때 TypeChecking을 생략할 수 있다. // 어떤 Input이 들어올지가 명확하고 예상가능한 경우에 사용할 수 있다. if (!js_value.IsNumber()) { Napi::TypeError::New(env, "Invalid").ThrowAsJavaScriptException(); return Napi::Value(); } ASSERT(info[0].isNumber()); long n = js_value.ToNumber().DoubleValue();

113. Dictionary Key Caching 

• JSObject에 Value를 읽거나 Key값을 체크할 때, napi_has_named_property() 또는 napi_has_property()를 사용할 수 있다. 

https://nodejs.org/dist/latest-v8.x/docs/api/n-api.html#n_api_napi_has_property 

https://nodejs.org/dist/latest-v8.x/docs/api/n-api.html#n_api_napi_has_named_property 

• napi_has_named_property() 함수는 napi_has_property()와는 달리 Native String을 JS String으로 변환해야 하므로 상대적으로 비싼 연산이다. 

• 이 문제를 개선하기 위해서 어떤 Object에 Value를 읽거나 Key값을 체크할 때 생성한 JSString을 Native World에서 Caching할 수 있다.

114. Q & A

115. Thank you



...

저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水

책 읽어주는 딥러닝: 배우 유인나가 해리포터를 읽어준다면 DEVIEW 2017

https://deview.kr/2017/schedule/192



코드 : https://github.com/devsisters/multi-speaker-tacotron-tensorflow 

음성 합성 데모 : http://carpedm20.github.io/tacotron 

발표 소개 : https://deview.kr/2017/schedule/182 



...

저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水

개발자가 알려주는 ‘AI 연구가 괴로운 순간’ 7가지

http://www.bloter.net/archives/292312


인공지능(AI) 기술이 발전하면서 관련 전문가 몸값도 치솟고 있다. 최근 국내에서도 대기업에서 스타트업까지 인공지능 전문가를 찾는다는 이야기를 많이 한다. 이런 상황에서 기술 업계에 있는 여러 대학생, 대학원생, 개발자, 엔지니어 등은 자신의 직업이나 진로에 대해 한번쯤 고민하게 된다. 임도형 엑셈 기술연구소 수석연구원도 그런 부류에 속한다. 10년 넘게 오랫동안 자바, 서버 솔루션을 만들었던 임도형 개발자는 최근 엑셈 기술연구소에 합류하면서 AI 관련 연구 및 개발을 담당하고 있다. 그는 학부시절 전자공학을 전공했으며, 대학원에서 인지과학을 공부했다. 대학원 시절에 살펴봤던 내용이 지금 인공지능 기술이라고 불리는 신경망, 패턴인식, 컴퓨터비전 등이다. 임도형 연구원은 “졸업했을 당시는 인공지능 기술의 침체기여서 전공을 살릴 데가 없었다”라며 “올해 초 새로운 일에 도전하고자 인공지능 개발 일을 시작했다”라고 밝혔다.


임도형 연구원은 인공지능 업무에 대해 ‘하이 리스크, 하이 리턴'(High risk , High return)의 속성을 가졌다고 표현한다. 얻는 것도 많지만 특히 기업에서 일하는 과정에선 괴로운 점도 생각보다 많다는 뜻이다. 그리고 지난주 열린 데이터과학 컨퍼런스 ‘데이터야놀자‘에서 인공지능 협업 개발자로 힘든 점들을 다음과 같이 공유했다.


1. 소프트웨어 개발이 차라리 더 쉽다

소프트웨어 개발은 아예 처음부터 뒤엎어서 다시 개발하지 않는다면 일정 시점에 결과를 얻을 수 있다. 물론 이 자체도 어려울 수 있다. 하지만 AI는 더하다고 한다. 임도형 연구원은 “소프트웨어 개발도 고달픈 부분도 있지만 그래도 몇 달을 하고 나면 ‘결과를 (어떻게든) 만들수 있겠다’는 감이 있었다”라며 “인공지능은 ‘이게 해서 될까’라는 질문에 계속 부딪힌다”라고 말했다.

현재 임도형 연구원은 공장 기기의 고장 상황을 예측하고 원인을 찾아내고, 궁극적으로 생산성을 높여주는 방법을 개발 중이다. 이 과정에서 가장 많이 받는 질문이 “그거 돼요?”란다. 문제는 여기에 어떤 근거를 들어 확답해주기 어려운 점이다. 보통 인공지능 연구는 ‘과거 이런 사례가 있었는데, 해당 사례를 우리 업계에도 적용해보자’라는 식으로 발전하기 때문이다. 따라서 완전히 동일한 상황과 조건에 맞는 참고 사례를 찾기 힘들다. 대부분 처음 시도하는 경우가 많다. 임도형 연구원은 “된다고 믿기 때문에 하는 것입니다 라고 답할 수밖에 없다”라며 “그 과정에서 스트레스를 받는다”라고 말했다.


2. 정리되지 않은 코드들

소프트웨어 개발은 기능을 구현, 테스트, 배포 등으로 나뉘므로 개발 과정을 분리해 설명할 수 있다. 작은 단위의 일이 완료되는 시점도 분명하다. 인공지능 분야는 다르다. 결과를 도출하기까지 중간에 반복되는 과정이 많다. 무엇인가 시도하고, 결과를 보고, 고민하고, 다시 일부 상황을 바꿔서 시도하고, 결과를 보고 고민을 한다. 또 소프트웨어 개발처럼 코드 리뷰도 하고, 리팩토링에 문서화까지 완료해서 보내기에는 시간이 부족하다. 임도형 연구원은 “변수이름, 디렉토리 구조 등이 엉망인데 결과를 내보내야 한다는 것 때문에 결국 정리를 못하고 시간에 쫓긴다”라고 설명했다.


3. 실행 결과를 보기까지 기다리는 긴 간격

인공지능 업무는 많은 데이터를 활용할 수 밖에 없다. 여기에 데이터를 학습시키고 결과를 얻기까지 오랜 시간이 필요하다. 물론 작은 데이터로 작업하면 몇 분 만에 결과를 얻을 수 있지만, 큰 데이터는 그 과정에 몇 시간이 소요된다. 가령 ‘저장’ 버튼을 누르고 저장 완료가 뜨기까지 몇 시간이 걸린다고 생각해보자. 기다리는 시간 동안 다른 업무를 해야 할지, 무작정 기다려야 할지 결정해야 한다.

임도형 연구원은 “몇 분이야 기달리수 있지만 10분만 넘어가면 다른 업무를 하다 다시 돌아오는 과정을 반복하면서 집중력이 떨어진다”라며 “기다리는 것을 4-5번 하다보면 하루가 다 가서 오늘 뭘 했는지에 대한 복잡한 감정이 든다”라고 설명했다. 이런 상황을 극복하기 위해 임도형 연구원은 목·금요일이면 주말동안 뭔가를 실행시켜 볼 것을 준비해두는 버릇이 생겼다. 기다리는 시간을 줄여, 월요일 출근하자마 결과를 볼 수 있게 하는 식이다.


4. 공부할 수 없는 업무시간

회사는 학교가 아닌 만큼, 어떻게든 결과를 보여야 한다. 인공지능 분야는 상대적으로 논문을 많이 읽어야 하는데, 회사에선 그럴 여유가 없다. 특히 작은 회사라면 인공지능 기술 자체를 발전시키기보다 산업체에서 당장에 활용할 기술을 개발할 가능성이 높다. 임도형 연구원은 “새로운 논문을 정말 제대로 이해하고 코드까지 실행해보려면 최소 하루나 2-3일은 걸린다”라며 “여유를 갖고 공부할 시간이 없으니 업무 시간 외에 뭔가를 공부해야 할 것 같은 압박이 온다”라고 말했다.


5. 쏟아지는 자료

인공지능 연구에선 새로운 시도를 하고, 일부 변경하고 다시 실험하는 과정이 계속된다. 이때 결국 자신이 아는 범위에서 해결책을 찾게 된다. 그러다보니 많은 정보를 습득하고 배우면 유리하다. 이를 위해 임도형 연구원은 텐서플로우 코리아같은 커뮤니티에 자주 들어간다. 최근에는 자료를 보고 이해하는 속도보다 새로운 자료가 나오는 속도가 더 빠르다고 한다. 그는 “누군가 진행한 실험에 대해 자세히 들여다보고 싶은데, 그러다보면 1-2시간은 훌쩍 간다”라며 “그러한 자료를 감당해야 한다는 것이 꽤 스트레스”라고 말했다.


AI 분야에만 보이는 독특한 현상도 소개했다. 보통 대학에서 발행되는 논문은 가장 최신의 기술을 다루는 경우가 많다. 그래서 학교에서 논문을 발표하면 이후에 기업이 해당 논문을 보고 활용한다. 인공지능 분야는 이와 반대다. 산업계에서 ‘이렇게 하면 이게 됩니다’라는 것을 발표하고 이를 학교에서 나중에 다뤄서 논문을 내놓는다.


6. 데이터의 부재

인공지능 업무에선 데이터가 반드시 필요하다. 하지만 기업에서 준비된 데이터는 가공된 상태가 아니다. 여기에 데이터를 정제하고, 필요한 것만 빼내고, 어떤 모양인지 확인하는 작업은 많은 시간이 걸린다. 임도형 연구원은 “누군가는 데이터 정제 과정과 실제 AI 업무과정의 비율이 8대2라고 표현하는데, 내가 느끼는건 98대2다”라며 “많은 사람이 데이터를 읽어서 정리하는 코드를 짜고 있으며, 오히려 학습시키는 코드는 짧다”라고 설명한다. 거기다 데이터 정리하는 코드들은 모듈화나 재활용이 힘든 경우가 많다고 한다. 따라서 새로운 데이터를 다룰 때마다 AI 업무가 아닌 데이터를 정리하는 데 많은 시간을 뺏기는 경우를 자주 경험할 수 있다. 막상 정제한 코드에 원하는 데이터가 충분치 않은 경우도 꽤 있다고 한다.


7. 느껴지지 않는 데이터

인공지능에서 활용되는 데이터의 크기는 엄청나다. 이때 그냥 나열돼 있는 데이터를 보는 것은 의미가 없다. 기업에서 얻은 데이터는 수백개의 열로 이뤄진 경우도 많다고 한다. 그래서 평균, 분포 등 데이터 특성을 전체적으로 파악해야만 다음 작업이 가능하다. 이를 위해서는 어떻게 시각화할지에 대한 감도 필요하다. 만약 시각화하는 능력이 부족하다면 데이터를 이해하고 활용하는 데 한계가 올 수 있다.

임도형 연구원은 발표 마지막에 머신러닝 업계의 구루라고 불리는 앤드류 응 스탠포드 교수의 말을 인용했다. ‘끊임없이 실천하고, 하기 싫은 작업도 하라'(pratice, pratice, pratice and do the dirty work)라는 문장이었다. 임도형 연구원은 “협업에서 AI 업무란 실행시키고, 결과를 확인하고 다시 고민하는 과정의 무한반복이다”라며 “최신 기술을 다루지만 이런 곳에서도 힘든 작업이 있다는 것을 알려주고 싶었다”라고 말했다. 동시에 그는 AI 업무를 고민하고 있는 사람에게 다음과 같이 조언했다.

“최근 AI 일을 하고 싶은 개발자들이나 학생들을 많이 보았습니다. 대학에서 진로 관련 특강 요청도 많이 하시더군요. 이 업무에 도전하고 싶은 분이 있다면 겁 먹지는 마십시오. 코딩할 때도 처음부터 모든 이론을 이해하지 않아도 시작할 수 있습니다. 오히려 작동하는 코드를 실행해보고 반복하면서 원리를 이해하곤 합니다. 인공지능 분야에서 활용되는 소스코드는 상당수가 외부에 공개됐습니다. 수식이 잔뜩 들어 있는 자료를 보는 데 시간을 너무 쏟지 말고, 일단 코드를 다운받고 실행해보세요. 수식이 어렵다면 일단 수식의 사용법부터 익혀보길 권장합니다.”




...

저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水

‘데뷰’에서 보여준 네이버의 미래기술 10가지

‘생활환경지능'(Ambient Intelligence)’. 지난해 송창현 네이버 CTO가 데뷰행사에서 밝혔던 네이버의 기술 목표다. 다소 모호해 보였던 이 목표의 구체적인 결과물이 ‘데뷰 2017’ 현장에서 공개됐다.

1. 엠비덱스

송창현 네이버 CTO 겸 네이버랩스 대표가 ‘원 모어 띵'(One more thing)이라고 운을 띄우며 가장 마지막에 발표한 기술이다. 그만큼 자랑할만한 기술이라고 할 수 있다. ‘엠비덱스’는 한마디로 말하면 로봇팔이다. 사람팔과 비슷한 관절 구조를 가져와 유연하고 정밀한 활동을 하도록 지원하는게 특징이다. 코리아텍과의 산학협력으로 개발했으며, 무게는 2.63kg로 사람 팔보다 가볍다. 네이버가 발표한 대부분의 로봇은 가까운 미래에 적용하려고 개발한 기술인 것에 비해 엠비덱스는 보다 먼 미래를 바라보고 개발하는 기술이라고 한다.

석상옥 네이버랩스 로보틱스 그룹 리더는 행사 이후 진행된 기자간담회에서 “로봇팔은 로봇공학의 궁극적인 목적”이라며 “사람을 도와주려면 팔이 있어야 하고, 이를 통해 사람 팔이 할 수 있는 많은 일을 대체할 수 있을 것”이라고 설명했다. 또한 그는 “기존 공장에서 사용되고 있는 로봇팔은 무겁고 정밀하지 않기 때문에 사람이 다칠 위험이 있다”라며 “엠비덱스는 가볍고, 힘을 제어할 수 있어 보다 안전하게 다양한 일을 할 수 있을 것”이라고 밝혔다.

2. 어라운드

실내 자율주행 로봇이다. 일종의 로봇 청소기 진화버전이라고 볼 수 있다. 로봇이 실내의 장애물 등을 미리 파악하고, 동시에 위치를 인식해서 원하는 장소로 자동으로 이동한다. 3D 실내 구조를 파악하는 M1과 자율 주행 로봇이 합쳐진 결과다. 현장에서는 예스24 서점과 협력해 ‘어라운드’를 테스트한 결과도 공개했다. 영상에 따르면 사용자가 어라운드 위에 책을 놓으면 자동으로 직원이 있는 공간으로 이동한다.

이번 데모는 책을 이동해주지만, 네이버는 어라운드를 활용해 다양한 업무를 실내에서 활용할 수 있을 것으로 설명했다. 과거 실내 자율주행 로봇은 비싼 센서나 높은 프로세싱 파워가 필요해 상용화의 걸림돌이 되곤 했다. 네이버는 클라우드 기능을 활용해 가격을 대폭 낮췄다고 한다. 석상옥 네이버랩스 로보틱스 그룹 리더는 “복잡한 기능을 하는 뇌는 클라우드에 있고, 몸은 로봇에 남겨두는 형태”라며 “일반적인 자율주행에 쓰이는 라이더도 500만원 수준이지만 어라운드에는 샤오미에서 사용되던 몇십만원 수준의 부품을 활용했다”라고 비용을 낮춘 점을 강조했다.

3. 에어카트

가벼운 힘으로 누구나 무거운 물체를 운반할 수 있는 전동 카트다. 카트 손잡이에 달린 힘 센서가 실시간으로 카트의 움직임을 제어하기 때문에, 누구든 따로 조작 방법을 배울 필요없다. 비탈길에선 자동으로 브레이크가 작동된다. 송창현 CTO는 “회사 동료들이 무거운 짐을 들고 다니는 것을 보고 이것도 해결 못하면서 로봇 기술을 연구하느냐라는 이야기가 나왔다”라며 “그렇게 해서 떠올린 아이디어가 에어카트”라고 설명했다.

4. 아키

위치 정보를 알려주는데 특화된 웨어러블 기기다. 아이들과 부모를 위해 고안됐으며, 실내 공간에서도 자녀의 정확한 위치정보를 부모에게 제공한다. 머신러닝을 활용해 사용자가 반복 방문한 장소 시간 상황을 스스로 인지하고 아이의 생활 패턴을 학습해 아이가 갑자기 다른 곳으로 이탈한 정보도 쉽게 알려준다고 한다. 어느 정도 관심을 받을지는 지켜봐야 하겠지만 컴퓨터, 모바일, 스피커 외에 네이버가 웨어러블 기기라는 새로운 플랫폼을 다뤘다는 점에서 인상적이다. 아키는 2018년 1월에 공식 출시될 예정이다.

5. 4륜 밸런싱 전동 스케이트보드

사람이 단순히 몸을 기울이는것 만으로도 겉보기에는 가속, 감속, 방향전환이 가능한 전동 스케이트보드다. 시속 40km까지 속도를 낼 수 있다. 2개의 기울기 센서로 무게중심을 제어해 보다 안전한게 특징이다. 아직은 초기 개발 단계 수준이라고 한다.

6. 어웨이 오픈플랫폼

‘어웨이’는 지난 8월 정식 출시된 차량용 인포테인먼트 플랫폼이다. 2018년 상반기에는 어웨이 익스텐션, 어웨이 키트, 파트너사 하드웨어를 함께 구성해 관련 생태계를 확장해나간다고 한다. 어웨이 익스텐션은 서비스, 콘텐츠 제공사를 위한 각종 기술 모음으로 어웨이에 영상, 음악 등을 지원할 수 있게 도와준다. 이를 위한 음성인식 기능이나 차량 데이터 등을 연동해줄 것으로 보인다. 어웨이 키트는 단말기 제조업체를 위한 기술도구로 차량 내 네이버 서비스를 제공하거나 화면 크기 관리 등을 쉽게 할 수 있게 지원한다.

송창현 CTO는 어웨이 설문조사 결과도 이날 함께 발표했는데, 차량 공유 서비스 ‘그린카’ 이용자 500여명을 대상을 질문했다. 응답자는 내비게이션과 음성인식 기술이 어웨이에서 가장 만족한다고 답했다. 송창현 CTO는 “주목할 점은 차량 공유시장이 늘어나면서 자신이 소유하지 않은 차를 이용할 기회가 많아지고 있다”라며 “이러한 시장에서 나에게 맞춤화된다는게 중요하게 작용할 수 있다”라고 강조했다.

7. 자율주행 기술
네이버랩스는 직접 개발한 자율주행차가 한국 시내를 이동하는 데모영상을 공개했다. 한국의 기술 기업으로는 처음으로 인가받아 현장에서 운전했다고 한다. 데모 영상에서는 차량이 차선을 변경하며 속도를 조절하고 앞차를 파악하고 목적지까지 가는 모습을 보였다.

8. 클로바 플랫폼

네이버가 개발한 인공지능 플랫폼으로, 지난해 아미카로 발표됐다가 클로바로 이름이 바뀌었다. 클로바 앱, 인공지능 스피커 등에 이미 클로바가 활용돼고 있다. 네이버랩스는 앞으로 클로바 익스텐션 키트, 클로바 인터페이스 커넥트, 클로바 API를 확장시켜 소프트웨어 및 하드웨어 관련 생태계를 키울 것으로 보인다.

9. 웨일

지난해 발표한 네이버가 발표한 웹브라우저다. 베터버전은 100만회 넘게 다운로드됐으며, 올해 10월16일 정식 버전을 공개했다. 12월에는 모바일용 웨일도 공개할 예정이다. ‘웨일 연구소‘라는 온라인 공간에서 사용자들의 피드백을 받고, 수정하는 과정을 거쳤다. 여기에 참여한 인원은 1만명이다.


10. D2 스타트업 팩토리

기술은 아니지만 네이버이 스타트업 지원 프로그램인 D2 스타트업 팩토리도 인상적이었다. 최근 2년간 D2스타트업 팩토리는 1800여개 스타트업을 검토하고, 이중 국내 기술 스타트업 16곳에 투자를 진행했다. 가장 관심있는 분야는 역시 인공지능이다. 또한 2017년 네이버 및 네이버랩스가 국내와 해외 기술회사에 투자한 금액은 400억원 정도이다. 석상옥 네이버랩스 로보틱스 그룹 리더는 “실내 자율주행 로봇을 만들 때 위치 관련 기술은 D2를 통해 협력하는 스타트업과 함께 연구했다”라고 설명하기도 했다.




...


저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水

성공지침서가 서점에 차고 넘치는 시대에 실패하는 방법을 알려주겠다고 하는 책이 있다. 코카콜라 엔터프라이즈 회장을 역임한 도널드 키오(Donald R. Keough)가 쓴 《The Ten Commandments for Business Failure》라는 책이다. 저자는 '이러면 반드시 실패한다'며 비즈니스의 성공 요소를 역설적으로 제시하고 있는데, 그 내용의 핵심만 간략히 소개한다.

1. 모험은 하지 마라(Quit Taking Risks)
근 50년 전에 피터 드러커가 지적한 것처럼, 미래의 존속을 보장하기 위해 기업의 현재 자산을 가지고 신중하게 모험을 감행하는 것은 경영진의 주된 임무다. 한 번도 실패해보지 않은 기업이 있다면, 그 기업의 경영진은 밥값을 하지 못하고 있는 것이다.

2. 입장을 절대 바꾸지 마라(Be Inflexible)
한때 놀라운 혁신의 선봉에 섰다가 현재는 요지부동의 안일한 빠져든 기업들이 많다. 어째서일까? 무엇이건 바꾸는 것은 어렵기 때문이다. 주위 환경이 변할 때 요지부동하라. 계속해서 그런 입장을 고수하라. 꿈쩍도 하지 말라. 분명히 실패하게 될 것이다.

3. 자기 자신을 격리시켜라(Isolate Yourself)
기업의 리더들이 직원들과 어떤 식으로 관계를 맺고 있는가는 정말 중요하다. 고립주의자는 사람들을 멀리하고 루머를 양산하다가 얼마 후에는 혐오감까지 생기게 만든다. 하지만 실패하고 싶다면 이것이야말로 성공 전략이다.

4. 한 치의 오류도 없는 사람인 척 하라(Assume Infallibility)
우선 잘못이나 문제는 절대 시인하지 말라. 무언가 잘못된 방향으로 나아가고 있다는 생각이 들면 은폐하거나, 위기가 본격화될 때까지 기다렸다가 외부 요인이나 다른 누군가의 탓으로 돌려라. 다행히 고객들은 말썽을 부릴 때가 많다. 일이 틀어지면 무조건 고객에게 덮어씌우면 된다.

5. 법은 정도껏 지켜라(Play the Game Close to the Foul Line)
깨진 유리창을 방치하면 사람들은 창문 외의 나머지 부분도 부수어버린다. 창문을 깨도 아무 일도 일어나지 않으니 더 부수어도 괜찮다는 메시지를 표출하기 때문이다. 기준을 확실히 지키지 못하면 고객이나 직원들에게 충분한 신뢰감을 심어주지 못한다. 그러면 실패하게 된다.

6. 생각할 시간을 갖지 마라(Don't Take Time to Think)
누구나 실수할 수 있다. 그러나 진정으로 실패하고 싶다면, 실수를 자세히 따져보는 일은 피하고 분석도 하지 말라. 그러면 같은 실수를 계속 저지를 것이다. 그래도 실패하기로 작정했다면, 생각할 시간을 가져서는 안 된다. 나아가 자신이 생각할 것을 다른 사람에게 넘겨버리면 책임을 피할 수 있다.

7. 전문가와 외부 컨설턴트를 무조건 믿어라(Put All Your Faith in Experts and Outside Consultants)
천재로 보였던 이들의 안목이 실은 지혜의 반대일 때가 많다. 대기업 경영에서 특히 이러한 현상이 자주 나타난다. 경영은 기술이지 과학이 아니다. 인간의 행동을 수치로 나타내고 정량화하려는 사람들을 조심하라. 숫자로 모든 것을 해결할 수는 없다. 그것은 상상력의 결핍이다.

8. 관료주의를 사랑하라(Love Your Bureaucracy)
'관료주의'라고 불리는 게임이 있다. 모두들 원 안에 서 있는데 아무 행동이나 먼저 하는 사람이 지는 게임이다. 관료주의에 젖어 있는 모든 부서에 이와 유사한 상황이 존재하는데, 그러한 내부 귀족들에 대해서는 도저히 거스를 방법이 없다.

9. 헷갈리는 메시지를 전달하라(Send Mixed Messages)
'진정 중요한 것이 무엇인가'에 관해 혼란스러운 메시지를 전달하는 것은 조직을 혼돈에 빠지게 만드는 첩경이다. 직원이나 고객들에게 일관성이 결여된 메시지를 전달하면 목표를 헷갈리게 만들어 결국은 실패를 부른다.

10. 미래를 두려워하라(Be Afraid of the Future)
우리는 배를 이끄는 선장들이 미지의 땅으로 사라질까봐 두려워하는 시대를 지나왔다. 오늘날의 과학 시대에, 산업화된 세계에 살면서 미래에 대해 공포를 갖는 것은 어리석은 행동이다. 그러나 실패하고 싶다면 미래를 두려워하는 것은 좋은 태도다.


저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水
도메인 네임서버 또 바꾸어야함

http://notice.tistory.com/2406


10월 말, 티스토리 서버가 교체됩니다.

서버 교체로 인해 서버 IP가 변경되면 일부 블로그는 접속 문제가 발생할 수 있습니다.

티스토리 기본 도메인(ex. abc.tistory.com)이 아닌 개인 도메인을 사용하는 블로그, 그 중에서도 A레코드에 IP 주소를 설정한 블로그에 한해 나타나게 될 현상입니다.

이에 대응 방법을 안내하오니 미리 숙지하시어 관리해 주시길 부탁드립니다.


대상

개인 도메인을 A레코드 IP주소로 설정한 블로그

언제까지

~ 2017년 10월 30일

무엇을

개인 도메인이 새로운 서버를 바라보도록 DNS 설정을 변경해 주세요.

서버 교체 후 블로그 접속 문제가 발생하지 않도록

어떻게

개인 도메인 호스팅업체 사이트에서 아래 방법 중 하나로 적용해 주세요.

A레코드를 CNAME레코드로 변경

A레코드 유지한 채 IP 변경



A레코드 유지한 채 IP 변경


- IP만 변경하면 되지만 추후 서버 IP가 바뀔 때마다 변경해줘야 하는 번거로움이 있습니다.

- A 레코드에 있는 현재 IP(175.126.170.70 / 175.126.170.110)를 삭제하고 아래의 새 IP를 입력해 주세요.


새로운 IP

27.0.236.139



출처: http://notice.tistory.com/2406 [티스토리에서 알려드립니다.] 

...


저작자 표시
신고
Posted by 홍반장水 홍반장水

합목적성

Extreming X 2017.10.13 14:45

[합목적성] ( [合目的性, , 영 purposiveness, 프 finalite]) 

목적에 적합하다는 것을 뜻한다. 


인간의 사상(事象)에만 적용되는 것이 아니라 자연의 사상(事象)에도 적용된다. 여기에는 두 가지 뜻이 있다. 

1) 어떠한 사상(事象)이 목적을 지향하고 있는 것과 수단이 목적에 적합하다는 것을 뜻하는 경우, 

2) 부분이 전체에, 전체의 각 부분이 서로 적합하다는 것을 뜻하는 경우이다. 


인간과 의복의 관계처럼 목적과 수단이 외적인 관계일 때 외적 합목적성이라 말하고 생물체나 공예품처럼 전체가 목적이고 각 부분이 수단의 의미를 가질 때 내적 합목적성이라 말한다. 


인간의 사상(事象)에 있어서도 반드시 계획적이며 의식적인 목적 활동이 이와 같은 합목적성의 전제가 되는 것은 아니며, 또한 합목적이라고 말하는 모든 사상(事象)에 의인적(擬人的)인 의식적 계획성(예컨대 신의 계획성)을 상정하는 것은 잘못이다. 합목적성이라는 개념은 의식적 목적 활동의 경우 이외에는 이러한 사태가 어떻게 하여 발생하였는가를 설명하는 원리는 될 수 없다. 


기계론적으로 설명할 수 없는 경우에는 물질의 보다 높은 차원의 운동 형태에 의해서 명확하게 되지 않으면 안 되며, 이것은 넓은 의미에서의 인과율을 부정하는 것은 아니다. ⇒판단력 



...

저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水

[세미나] 시작해요 언리얼 2017 제주


http://start.unrealsummit.co.kr/











...


저작자 표시 비영리
신고
Posted by 홍반장水 홍반장水