회사와 집에서 각각의 맥으로 개발 작업을 한다. 소스 자체는 git으로 관리를 하지만 가끔 집에서 또는 회사에서 작업한 내용을 push 하질 않아 이동한 장소에서 가장 최근에 작업한 소스를 확인하지 못해 낭패를 몇 번 겪은 이후 iCloud 동기화가 가능한 Documents 폴더 아래에 넣어서 사용해 볼까 싶어 작년부터 그렇게 작업을 시작했다.


큰 문제는 없었다. 각각의 장소에서 이동할 때마다 작업한 내용을 따로 push 하지 않아도 알아서 그럭저럭 잘 동기화를 해주었다. 


그런데 대략 2주 전부터 문제가 발생했다.


느닷없이 iCloud 동기화를 위한 업로드 파일 크기가 대략 40 기가 정도로 표시되면서 맥북은 상시 iCloud 업로드 상태가 되었고 뭔가 동기화가 제대로 되지 않는 듯 끝이 나지 않고 진행되는 듯하다가 다시 처음부터 시작되기를 무한 반복했다. 이는 사내의 트래픽 증가로 이어졌고 Finder에서 업로드되는 파일을 확인해 보았지만 40기가 씩이나 업로드될 것이 없었다. 총 전송 파일 갯수 및 전송량도 계속 다시 카운트를 하는 듯 0에서 20기가~40기가 사이를 반복했다.


짐작하기로는 얼마 전에 firefox 소스를 체크해 볼 일이 있어(mozilla-central) 별 생각없이 동기화가 되는 폴더에서 소스를 받아 컴파일을 한 적이 있었다. 이 때 엄청나게 많은 파일이 생성되며 그 파일들이 동기화 업로드가 되려는 걸 확인해서 iCloud폴더에서 제외했던 적이 있었는데 아마도 이로인해 발생하기 시작한 것이 아닌가 싶었다.


결국 이 문제를 해결하고자 이런저런 검색을 해본 결과 apple 개발자 사이트에서 iCloud 동기화를 해제했다가 다시 시작해보라는 글귀를 보고 회사 맥북에서 그렇게 진행했지만 증상은 여전했고 이 미친 업로드 증상은 집의 맥북에서도 나타나기 시작했다. 아마도 제대로 동기화가 꼬이기 시작한 듯싶었다.


그래도 뭐 알아서 해결해주겠지... 싶은 마음으로 2-3일 있었을까. 오늘 재택근무를 하느라 어제 회사에서 개발했던 부분을 이어하려고 보니 해당 소스가 전-혀 동기화되어 있지 않음을 확인했다.


iPhone 파일 앱을 통해 해당 폴더를 확인해 보니 회사에서 작업한 내용이 전혀 반영되지 않은 것으로 보아 회사 맥북에서 변경된 내역이 동기화 자체가 되지 않았다는 것을 알게 되었고 허탈함에 빠졌다. 월, 화요일 작업 내용 자체가 없었기에 차이는 매우 컸는데 최소한 2-3일 동안 최신으로 동기화가 되지 않았다는 이야기였다. 이 와중에도 집의 맥북은 뭘 그리 동기화하려는지 대략 14기가 정도의 파일 업로드 시도를 무한 반복하고 있다.


다행히 어제 작업 완료 후 소스를 push 해 놨기에 큰 문제는 없었지만 지금과 같은 방식으로 작업하는 소스를 관리하다가는 뭔가 큰 코 다치겠다는 경각심이 들었다.


그나저나 iCloud 동기화는 여러모로 실망이다. 아이폰에서 사진을 관리하는 것 말고는 타 클라우드 서비스처럼 선택적 동기화도 안되고 현재 동기화 진행 상황을 제대로 확인할 수 있는 방법도 없으니 맥북 상에서 파일 관리의 목적으로는 가능하면 사용을 하지 않는 방안으로 가는 것이 좋을 것 같다.





2018.03.17


* Dart2를 A Tour of the Dart Language 문서를 바탕으로 간단히 정리해 본다. 


공식 안내 문서의 첫 번째 예제 샘플을 살짝 수정하여 테스트해 봤다. 


Hello Dart2 :)



결과




코드를 통해 알 수 있는 특징들.

  • Indent block은 2칸. 
    • 강요 사항은 아니겠지만 로마에선 로마법을 따르는 것이... (Effective Dart: Style 참조)
  • 코드 내의 Comment는 //로 사용하면 된다.
  • main()이 시작점이다.
  • 변수 선언은 var로 한다. var로 변수를 선언할 경우 타입은 알아서 판단한다.
    • (당연하지만) 명시적으로 타입을 지정하여(String) 변수를 선언할 수도 있다.
  • 함수 선언 시 리턴 값이 없는 경우(void) 생략이 가능하다.
    • 그렇다면 리턴 값은 var가 될 수 있을까?

안된다.

  • console 출력은 print. 변수를 출력하고 싶을 때는 $[변수명] 또는 ${[변수명]}
    • 코드의 끝에는 ';' 붙여야 한다. (대부분의 언어에서 당연한 건데 요새 주 개발 언어가 swift / python이다 보니 새삼스레 눈에 들어온다.)



코드를 통해서는 보이지 않지만 안내서에 나와있는 알아두어야 할 기본적인 사항들

  • Dart의 모든 것은 Object 클래스에서 파생된 object이다.( Everything you can place in a variable is an object, and every object is an instance of a class. Even numbers, functions, and null are objects. All objects inherit from the Object class.)
  • var 말고 num 같이 지정된 정적 타입으로 변수를 선언하면 사용자의 의도가 분명해지고, 해당 변수에 대해 정적 타입 검사가 가능하다. (var를 쓰기보단 사용 의도를 확실히 하도록 정적 타입으로 변수를 선언하는 것이 좋을 것 같다.)
  • Strong mode : Strong mode에서는 정적 검사 및 런타임 검사를 실행함으로써 런타임 전에도 코드 오류를 잡을 수 있다고 하는데 Dart2에서는 Strong mode가 선택 불가한 기본 사양이라고.. Dart1을 접하지 않았던 나에게는 그냥 넘어가도 되는 이야기 같다.
  • 함수 내에서 함수를 만들 수 있다.
  • public / private / protected 같은 접근 제한자가 없다. 다만 _(밑줄)로 시작하는 식별자는 비공개라고 한다. (이거 마음에 든다.) 
  • 식별자는 문자 또는 _(밑줄)로 시작한다.
  • 다트 도구는 경고 및 오류의 두 가지 종류의 문제를 보고 한다. 경고는 코드가 작동하지 않을 수도 있지만 프로그램 실행을 방해하지는 않는다. 오류는 컴파일 타임 또는 런타임 시로 나누어 볼 수 있는데, 컴파일 타임 오류일 경우는 코드가 전혀 실행되지 않고, 런타임 오류일 경우는 코드가 실행되는 동안 예외가 발생한다.
  • 값이 할당되지 않은 모든 변수의 초기값은 null이다.


좀 더 코드를 뜯어보면.

  • void printNumber(num aNumber)에서의 num은 무엇인가?

Dart의 Built-in Type 중 하나. Dart에는 아래와 같은 Built-in Type이 있다고 한다.

  • Number : 숫자. subtype으로 int, double가 있다. 결국 저 num은 int 또는 double 형태의 변수를 의미한다. int의 범위는 -2^53 ~ 2^53. double은 64비트형. int, double로 명시적으로 써도 되고 num으로 퉁쳐도 되는 것 같다.
  • String : 문자열
  • Boolean : true / false
  • List : [1, 2, 3]
  • Map :   key, value로 구성.

var map = {

  'hello': 'world',

  'name': 'genkino'

};


var code = {

  42: 'Answer to the Ultimate Question of Life, the Universe, and Everything',

  52: 'genkino's nickname'  

};

  • Runes : UTF-32 코드값으로 이루어진 문자열. 다른 언어에서 보지 못한 독특한 자료형이다.

var clapping = '\u{1f44f}';


Runes input = new Runes(

  '\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}');

 print(new String.fromCharCodes(input));


뭐.. 이런 식으로 사용된다고 한다. 다양한 이모티콘이 출력된다.


  •  Symbol : 안내서를 봤을 때는 명확히 이해가 가지 않는다. Dart에서 선언된 연산자 또는 식별자라고 하는데 꼭 사용할 필요는 없지만 이름으로 식별자를 참조하는 API의 경우에는 식별자 이름이 변경되지만 식별자 심벌은 변경되지 않으므로 쓸만하다(?)라는 설명이 붙어있다. unique id 같은 용도인가..? 이 부분은 Dart를 좀 더 사용하면서 자연스럽게 알게 될 것이라고 기대(;;) 해 본다. 


하나만 더 확인하고 넘어가자면

  • final / const : 둘 다 선언하면 값을 변경할 수 없다는 공통점이 있는데 약간의 차이가 있다. final의 경우는 한번 값을 할당하면 재 할당을 할 수 없다는 의미라면 const의 경우는 상수같이 사용된다는 의미..?(컴파일 타임에 상수처럼 사용된다..?) java에서의 final과 c에서의 const가 연상된다.

final과 const의 차이를 눈으로 확인할 수 있는 코드를 만들어 보았다.


// Code

...

final DateTime now = new DateTime.now();

const DateTime coNow = new DateTime.now(); 

now = new DateTime.now();

...


// Run

Warning: Cannot resolve setter.   

now = new DateTime.now();   

^^^ 


main.dart:11:26: Error: Not a compile-time constant.   

const DateTime coNow = new DateTime.now();

                                              ^^^^^^^^^^^^^^^^^^


new DateTime.now()의 값은 실행 시에 결정되는 값인데 final / const는 각각 다르게 반응한다.


final의 경우 컴파일 시 에러가 나지 않지만 한번 값이 할당되면 재 할당을 할 수 없다. (Warning에 setter가 없다고 나온다. getter만 있다는 설명이 더 명확한 듯) 실행 시에 결정되는 값을 할당할 수 있다.


const는 실행 시에 결정되는 값은 할당할 수 없다. 애초에 런타임 전에 정해지는 값만 할당 가능하다. (24라던가 24*2 라던가 'hello world' 라던가...)


하나 더 만들어 봤다.


  • const list = [1, 2]; 는 에러. 
  • const는 const 성격의 값만 할당이 가능하다. 아마도 list는 런타임 시에 값이 정해지는 타입인 것으로 보인다.
  • final의 경우는 앞의 예제에서도 확인했듯이 런타임 시에 값이 정해지는 타입도 할당 가능.
  • const로 할당된 값(Instance)은 각자 다른 변수에 할당하더라도 같은 Instace이기 때문에 비교를 하면 true
  • const가 아니라면 같은 값일지라도 다른 instance이기 때문에 비교 시 false

아직 명확하지는 않고 쓰임을 어떻게 구분할지 아직 확실히 들어오지는 않다만,

  • final은 setter가 없이 getter만 존재하는 형태.
  • const는 상수처럼 취급.

으로 정리해본다.


오늘은 여기까지.






2018.03.16


https://android.jlelse.eu/comparing-apk-sizes-a0eb37bb36f


* 아침에 재미있는 글을 보게 되었다. 안드로이드 환경에서의 개발 언어별 APK 크기 비교 글이었는데 링크된 글을 읽어보면 알겠지만  java(539k) / kotlin(550k)에 비해 react(7M) / flutter(7.5M)는 거의 10배 이상 차이가 났다. 아무래도 좀 크긴 하겠지라고 생각했지만 10배 이상이라니...


react나 flutter의 경우에는 아무래도 하나의 Layer가 더 필요하기 때문에 이런 결과가 나왔다고 보는데 테스트에 사용된 앱은 매우 단순한 앱이기에 일반적인 앱에서의 크기 비교가 궁금하다. 단순히 드는 생각에는 앱이 복잡해지거나 다양한 기능이 제공된다고 해서 react 또는 flutter의 베이스에 해당하는 라이브러리의 크기가 그에 따라 기하급수적으로 커질 것 같지는 않고 어느 정도 크기에 수렴될 것 같아서 어느 정도 이상 크기의 앱이라면 저 정도(10배 이상) 차이는 나지 않을 것이라는 생각이 드는데 관련된 내용을 한번 찾아봐야겠다.


스마트폰의 램이나 저장공간의 기본 사양이 매년 상향됨에 따라 어느 순간부터 개발에 있어 이러한 부분은 크게 신경 쓰지 않았었다. 그런데 글을 읽고 보니 - 이렇게 10배 이상 차이가 날 수도 있다면 - 일반적인 안드로이드 환경도 그렇지만, 특히나 안드로이드 Go처럼 상대적으로 저사양, 저용량이 맞춰진 플랫폼에서는 더더욱 배포본의 크기도 신경 써야겠다는 생각을 하게 되었다.





2018.03.09

딱 하나의 테스트 케이스에 한해 테스트 실패도 아니고 런타임 에러... 참으로 감질나는 상황이다.



HackerRank를 다시금 틈틈이 해보려고 마음을 먹은 지 한 2주일 정도 된 것 같다.


이전에 한참 이런 식의 것이 유행(?)했을 때 따로 시간을 마련해서 - 뭐 월, 수, 금 몇 시부터 한 시간.. 이런 식으로 - 작정하고 해보자고 마음먹었었지만, 딱 그 시간에 맞춰 도장 깨기 하듯 문제를 차례차례 박살내기가 쉽지 않았다. 무엇보다 업무나 다른 일상에 차이면서 우선순위가 낮다 보니 문제를 풀기는커녕 그 시간을 마련하는 것조차 쉽지 않았다.


그래서 이번엔 그냥 틈틈이 생각나는 대로 한 문제씩만 - 뭐 시간이 되면 2, 3 문제도 좋지만 - 풀어보자고 생각하니 가벼운 마음으로 풀 수 있게 되었다. 게다가 하루 정도 사이트에 들어가지 않으면 이메일로 '너 문제 안푸냐? 이 문제 한번 풀어볼래?'라는 식의 메일을 툭 던져주는데 그때 시간을 한 10-20분 정도 집중하여 할애하면서 푸는 것도 꽤 효과가 있었다. 


그나저나, 테스트 실패는 많이 겪어봤는데 런타임 에러는 처음이라 무지 당황했다. 아마도 무한루프라던지 스택 오버플로우라든지 그러한 상황이 아닐까라는 추측을 하면서 코드를 리뷰해봤지만 도무지 감이 잡히지 않았다.


결국엔 저 10번 샘플의 입력값을 받아보고 나서야 - 받자마자 - 아! 하는 탄식과 함께 코드를 수정했고 겨우 통과를 했다. 입력 값을 알기 전까지는 코드 어느 부분이 오류인지 전혀 예측조차 못했는데 입력 값을 보자마자 코드 상의 오류가 눈에 확 들어오는 게 어이없기도 하고 웃겼다. 아마도 테스트 케이스가 없었다면 난 내가 짠 코드에 오류가 있는지도 몰랐을 것이다. 


HackerRank를 통해 배운 점은 아래와 같다.


* 시간을 정해놓고 하는 것보다 남는 시간 틈틈이 하는 것이 효과가 있는 경우도 많다.

* 코드를 작성할 때 테스트 케이스는 반드시 필요하다.

* 문제를 제대로 해결하는 코드라고 해도 HackerRank의 테스트 케이스 중에서는 시간 제약으로 인해 실패하는 경우도 많다. 이 경우에는 다른 방법의 해결책을 생각해 봐야 하는데 이 경우 문제의 본질을 제대로 파악하는 것, 다른 시각으로 문제를 바라보는 것이 필요하다. 



아직까지는 습관이 되었다고 하기엔 애매한 상황인데 꾸준히 함으로써 습관을 들여놓고 싶다.





2018.03.07


* 구글에서 개발자를 위한 머신러닝 단기 집중 과정 코스를 열었다. 


https://developers.google.com/machine-learning/crash-course/


강의를 제공한다는 뉴스를 접했을 때, 기사 내용 중 이제 머신러닝에 대해서는 모든 사람이 제대로 아는 것이 중요하다는 생각이 들어서 과정을 만들었다는 이야기를 언뜻 봤었다. 놀랍게도(?) 한글이 지원되며 강의 동영상은 자막이 지원되겠거니 라고 생각했는데 한글 더빙으로 강의가 나온다. 인트로 강의를 다 보고 나서야 알게 된 내용이지만,


이 동영상 강연의 음성 더빙은 머신러닝 기술을 사용하여 생성되었습니다. 위의 의견 보내기를 클릭하고 버그 신고서 및 제안사항을 제출하여 Google에서 음성 더빙 기술을 개선하도록 도와주세요.

이라고 언급이 되어 있었다. 그렇다면 영어 음성을 인식해서(뭐.. 가능한 절차고) 이를 구글 번역으로 번역한 후(이것도 이젠 꽤 자연스럽게 가능하고) 번역한 문장을 읽는다(뭐... 이건 이제 놀랍지도 않지만)는 건데 나눠 놓고 보면 그다지 신기할 것이 없다고 생각해도 이 과정이 매끄럽게 반영되어 있다는 생각을 하니 새삼 놀랍다. (영상에 나오는 화자의 나이대와 분위기를 분석해서 그에 어울리는 목소리로 나와주면 더더욱 놀랐을 텐데 ㅎㅎㅎㅎ)


인트로 영상에서 아래와 같은 내용이 나온다.


이제 머신러닝을 숙지해야 하는 세 가지 실질적인 이유 외에 철학적인 이유도 있습니다. 머신러닝은 문제에 관해 생각하는 방법을 바꿉니다. 소프트웨어 엔지니어는 논리적이고 수학적으로 사고하도록 훈련을 받았습니다.  내 프로그램의 속성이 옳다는 것을 입증하기 위해 주장을 사용하죠. 머신러닝이 있으면 수리과학에서 자연과학으로 초점이 바뀝니다. 불확실한 세계를 관찰하고 실험을 하고 논리가 아닌 통계를 사용하여 실험 결과를 분석합니다. 과학자처럼 사고할 수 있는 능력을 갖추면 시야가 넓어지고 전에는 탐험할 수 없었던 새 영역이 펼쳐집니다. 그럼 그 여정을 즐기며 탐험하시기 바랍니다.


요컨대 관점이 바뀌면서 지금과는 다른 시각으로 문제를 바라볼 수 있게 된다는 이야기인데 부끄럽게도 이러한 시각으로 바라본 적은 없었다. 그저 새로운 기술이라고만 생각했던 나의 관점에도 새로운 변화가 있어야겠다는 자각이 든다.

+ Recent posts