Buefy에 material icon이 포함되어 있지 않기 때문에 별도로 import 해서 써야 한다.

 

1. 먼저 아래 명령어를 통해 mdi를 설치한다.

npm install @mdi/font

 

2. main.js에서 import 한다.

import '@mdi/font/css/materialdesignicons.css'

다시 기본에 충실하기로 했다.


만 3년 동안 프로 개발자로 일했다. 정말 다양한 이슈들을 해결해야만 했다. 개발자의 일이란 결국 문제를 해결하는 것이었다. 문제를 해결하기 위해서 많은 도구를 가져다 썼다. 최근엔 많은 머신들에서 제각각 돌고 있는 CronJob들을 보다 효율적으로 관리하기 위해 Airflow를 썼다. 차후에 개발할 것들을 위해 GraphQL에 대해 공부하기도 했다. 스터디에 나갔더니 Kubernates에 대해 다들 이야기하길래 내가 하고 있는 프로젝트들에 적용할 수 있을 지 살펴보고 있다.


다양한 도구들을 써보고 노하우를 위키에 남긴다. 때때로 팀원들에게 공유하기도 한다. 문득 드는 생각이 있다. 어느 도구를 쓰든지 결국 컴퓨터를 다루는 일이라는 걸 깨닫는 순간이 오더라는 것이다. 도구가 도깨비 방망이가 아니고 컴퓨터를 어떻게 잘 다룰 지에 대한 고민들로 탄생한 것들에 불과하다는 것이다.


하드웨어 위에 커널, 커널 위에 시스템 라이브러리, 그 위에 OS가 있고 그 위에 다시 도구들이 있다. 수차례 추상화 되었지만 결국 컴퓨터를 다루는 일이다. 컴퓨터를 잘 알면 더 잘 쓸 수 있다. 운동 생리학을 알아야 달리기를 잘 하는 것은 아니지만 달리기를 잘하는 사람이 운동 생리학을 공부한다면 더 잘 뛸 수 있다. 컴퓨터에 대해 잘 알고 도구를 쓰는 것과 그렇지 않고 쓰는 것은 다를 수밖에 없다. 깨달음이 오자 갈급해졌다.


컴퓨를 잘 안다는 것은 무엇일까? 고리타분한 말이지만 4대 과목에 대해 이야기하지 않을 수 없다. 운영체제, 네트워크, 자료구조와 알고리즘, DB다. 여기에 클린 코드 한 권을 더해 다시 기본을 공부해보고자 한다. 예전에는 컴퓨터 개론 수업에 왜 계산기부터 등장하는지 이해를 못했다. 하지만 이제는 안다. 계산기부터 공부해보고자 한다. 컴퓨터의 태초가 무엇이고 그것이 어떻게 발전해왔는지. 그 원리가 어떻게 현대 컴퓨터로 이어지고 있는지. 위대한 기술에 대해 바닥부터 훑어볼 예정이다.


4년 차에 다시 읽는 기본서 시리즈를 연재하고자 한다. 혹시 함께할 마음이 있으면 연락바란다.

'Tech' 카테고리의 다른 글

신입 초보 개발자 1년 회고  (1) 2017.02.03
TDD 적용기  (0) 2016.10.06
다양한 예제로 학습하는 데이터 구조와 알고리즘 for Java  (0) 2015.11.10
신입 개발자로 입사하고 1년이 지났다. 기술적으로 보다 성장했고 자신감도 붙었다. 무엇보다 협업하는 법을 배울 수 있었다. 어떠한 활동들이 나의 성장을 이끌었는지 회고해보려 한다. 혹시 이제 신입으로 입사하는 개발자들에게 도움이 될 수 있을지 모른다는 생각에서다.

신입은 채용 시 실력도 보지만 잠재력을 높은 비중으로 평가한다. 그래서인지 신입 개발자들의 실력 스펙트럼은 다양하다. 초보인 나와 달리 실전 경험이 풍부한 개발자들에게는 필요하지 않는 글일 수 있다.



가장 도움이 된 책
클린 코드 - 로버트 마틴


인간은 음식에서 나는 ‘나쁜 냄새’를 본능적으로 안다. 하지만 코드에서 나는 ‘나쁜 냄새’를 구별하긴 어렵다. 이 책은  코드의 ‘나쁜 냄새’에 대한 감을 찾을 수 있게 해준다. 

‘나쁜 냄새’가 뭔지 알아야 비로소 협업하는 개발자가 될 수 있다.  코드를 짜는 것을 넘어 남의 코드를 리뷰할 수 있기 때문이다. 이 책은 업계에서 좋고 나쁜 코드에 대한 레퍼런스로 여겨진다. 

클린 코더 - 로버트 마틴


신입은 시니어의 요구에 ‘예예’하기 바쁘다. 내가 그랬다. 빡빡한 일정이 떨어지면 밤을 새서라도 맞춰야 하는 줄 알았다. 불가능해보이는 일정을 극적으로 달성하는 것이 바로 '프로 개발자'라고 생각했다.

하지만 이 책에서 말하는 '프로 개발자'란 조금 다르다. 프로 개발자는 명백히 달성할 수 있는 요구에 대해서만 예라고 말하며(3장) 제품 퀄리티를 떨어뜨릴 수 있는 무리한 요구에 대해서는 아니라고 말할 줄(2장) 안다. 내가 밑줄 친 '프로의 마음가짐'은 다음과 같다. 괄호 안은 문장이 들어 있는 소제목이다.

- 프로가 실수하면, 스스로 뒷감당을 해야 한다. (함부로 바라지 마라)
- 프로라면 한 명도 빠짐없이 오류에 책임을 져야 한다. 오류가 명백하지 않더라도 상황이 어떻게 돌아가는지 밝혀야 한다. (기능에 해를 끼치지 마라)
- 코드에 결함이 있는 걸 알면서도 QA에게 코드를 보내는 일은 매우 프로답지 못한 행동이다. (QA는 아무것도 찾지 못해야 한다)
- 100% 테스트 커버리지를 권장하냐고? 권장이 아니라 강력히 요구한다. 작성한 코드는 한 줄도 빠짐없이 전부 테스트해야 한다. (제대로 작동하는지 아닌지 알아야 한다) 
- 프로 개발자는 코드와 테스트에 확신이 넘치기 때문에, 시도 때도 없이 이리 저리 코드를 바꿔도 마음이 평안하다. (구조에 해를 끼치지 마라)

신입 개발자가 어떤 태도로 일에 임해야 하는지 알려주는 책으로 일독을 권한다. 

리팩토링 - 마틴 파울러

 
리팩토링은 겉으로 드러나는 기능은 그대로 둔 채, 알아보기 쉽고 수정하기 간편하게 소프트웨어 내부를 수정하는 작업을 의미한다. 이 책은 그 방법들을 빼곡히 수록한 책이다. 

나는 이 책을 스터디 교재로 삼아 읽었다. 여러 방법들을 내가 실제 작업하고 있는 소스에 적용해보았다. 아마 이 책을 읽는 가장 효율적인 방법 중 하나일 것이다. 테스트를 짠 뒤 그 안정감 위에서 코드를 더 좋게 개선하는 작업을 반복하자 코드가 몰라보게 달라졌다.

Pro Git

 
Git은 필수다. 협업을 잘 하는 개발자가 되기 위해선 Git을 한번쯤 깊게 공부해야 한다고 생각한다. 선배에게 ‘코드가 날아갈 것 같아요’라고 말하지 말자. 

이응준님의 글에 ‘프로 Git 읽는 법’이 잘 정리되어 있다. 



가장 도움이 된 멘토
'메소드는 10줄 이내, 클래스는 200줄 이내로'
사내 Objective-C 교육을 담당한 강사님의 말이다. 좋아 보여서 꾸준히 실천하고 있다. 나는 강사님이 말한 원칙을 지키기 위해 무던히 노력했다. 메소드가 10줄이 넘어가면 메소드 추출(Extract Method)를 실시했고 클래스가 200줄이 넘어가면 클래스 추출(Extract Class)로 라인 수를 줄였다. 고통스러운 훈련으로 보일지 모르지만 신입에게는 큰 도움이 된다고 생각한다.

Pull Request를 활용한 코드 리뷰 중심의 교육
신입 교육에서는 PR을 통한 코드 리뷰의 중요성에 대해 귀에 못이 박히도록 들었다. 모든 작업은 PR로 날렸고 문제가 있으면 merge가 거부됐다. PR에 대해 이해하고 필요성을 절감하는 좋은 경험이었다. 실무에 와서도 PR을 통한 코드 리뷰에 적극적으로 참여했다. 



가장 도움이 된 프로젝트 - 라이브러리 개발
입사하자마자 앱을 한 차례 만들고 그 뒤로는 라이브러리를 만들었다. 재밌는 경험이었다. 라이브러리는 개발자들이 쓴다. 개발자들은 코드를 열어보기 때문에 부끄럽지 않은 코드를 짜야 했다. 내가 택한 방법은 이미 만들어진 유명 오픈 소스(Alamofire나 Gifu 같은)를 모방하는 일이었다. 좋은 코드를 보고 좋은 코드를 짜려고 노력하다보니 상당히 실력 향상에 도움이 됐다.



가장 도움이 된 컨퍼런스 - Let’s Swift
내가 iOS 개발자여서다. 가장 인상 깊었던 세션은 Viper, POP, RxSwift에 관한 세션이었다. 늘 ViewController가 비대해지는 문제를 겪고 있었기 때문에 VIPER가 반가웠다. POP는 OOP의 단점을 일부 보완할 수 있는 매력적인 방식이었다. 덕분에 실무에서 적용해볼 수 있었고 주위 개발자들로부터 좋은 반응을 얻었다. POP를 활용해 작은 토이를 만들어보기도 했다. RxSwift는 무척 흥미로워 다음 도전해볼 주제로 남게 되었다.



2016년에 진행했던 스터디
slipp 10차 스터디 - Hacker Rank
사내 리팩토링 스터디



시기별로 많이 했던 공부 
1분기 - Git
Pro Git 읽기
사내 Git 강의 : reflog, stash, pull —rebase, git flow 등을 배워 실전에서 매우 유용하게 사용했다.

2분기 - Swift

3분기 - 리팩토링

4분기 - Data Science
k-MOOC - 빅데이터 첫 걸음 (완강), 포스텍 유환조 교수님
k-MOOC - 경제통계학 1부 (완강), 서울대 류근관 교수님



마치며
1년 간 많이 성장했다. 좋은 평가를 받았고 그에 따른 보상도 받았다. 내가 일을 하며 느끼는 기쁨은 대부분 동료 개발자로부터 왔다. 좋은 프로젝트에서 좋은 동료들과 함께하는 기쁨을 계속 누리고 싶다. 




'Tech' 카테고리의 다른 글

4년 차에 다시 읽는 기본서  (0) 2019.03.27
TDD 적용기  (0) 2016.10.06
다양한 예제로 학습하는 데이터 구조와 알고리즘 for Java  (0) 2015.11.10
[Project Name]-Swift.h라는 헤더 파일을 생성해 이를 인터페이스로 삼아 스위프트 코드에 접근합니다. 다만 모든 스위프트 코드를 Objective-C에서 사용할 수 있는 것은 아닙니다. 스위프트에서만 가능한 타입들은 사용이 배제됩니다. 호환이 안되는 type의 인자가 들어가 있는 메소드는 bridge header에 생성되지 않습니다. 

따라서 Objective-C에서 사용 가능한 Swift 코드를 만들기 위해선 스위프트 타입 호환성을 잘 고려해서 코딩해야 합니다. 다음 문서는 스위프트 타입 호환성에 대해 상세히 기술하고 있습니다. 


옵셔널
객체만 옵셔널로 사용 가능합니다. 메소드 인자에 옵셔널이 있는 경우 이를 nullable로 바꾼다고 나와 있지만 이는 객체에만 해당합니다. 옵셔널의 태생 자체가 nullable의 범위를 primitive type과 enum type 등으로 넓히기 위해 태어난 것이기 때문입니다.

프로토콜
프로토콜에 @objc를 붙여서 선언해야만 사용할 수 있습니다.

enum
enum type이 Int가 아닐 경우 사용할 수 없습니다.

기타 사항은 문서 참조

'Tech > iOS' 카테고리의 다른 글

[Swift] Class와 Struct 중에 뭘 쓸까?  (0) 2016.10.28
@noscape, @autoclosure  (0) 2016.10.24
optional을 쉽게 설명해보자  (0) 2016.05.17
Hashable Protocol  (0) 2016.02.28
Objective-C 시절부터 immutable 사용이 강조되어 왔습니다. 변하지 않는 값의 사용이 증가할수록 에러 확률이 줄고 컴파일러 또한 보다 적극적으로 최적화할 수 있기 때문입니다. class는 reference type이고 struct는 value type입니다. 가능하다면 mutability control 측면에서 struct를 사용하는 것이 권장됩니다.

애플 문서에서는 다음과 같을 때 struct를 쓰라고 권장하고 있습니다. 

  • 관련있는 간단한 데이터를 encapsulation
  • 값이 reference 되지 않고 copy되는 것이 더 타당한 경우
  • struct에 저장된 property들 역시 value type인 것이 자연스러움
  • 기존의 type에서 상속될 필요가 없는 경우


'Tech > iOS' 카테고리의 다른 글

스위프트 타입 호환성  (0) 2017.01.11
@noscape, @autoclosure  (0) 2016.10.24
optional을 쉽게 설명해보자  (0) 2016.05.17
Hashable Protocol  (0) 2016.02.28
Closure는 reference type이다. 한번 생성되어 var / let으로 대입된 것은 별도의 instance로 존재하며 다른 곳에 대입되어도 reference 된다.

@noescape
closure를 parameter로 전달받은 함수는 그 closure를 함수 안에서만 사용하고 바로 파기한다는 것을 명시
closure를 보관하지 않기 떄문에 retain cycle 문제에서 자유로움
compiler가 closure의 수명에 대해서 더 많은 정보를 받으므로 더욱 적극적인 optimizing을 하게 됨

@autoclosure
parameter가 없고 return이 있는 closure를 받는 function은 closure를 autoclosure로 선언할 수 있음
func printNextValue(@autoclosure value: () -> String) {

}

autoclosure를 사용하게 선언되어 있는 function을 호출할 때는 closure 대신 간단한 구문을 사용할 수 있음
printNextValue(values.remove(at: 0))

해당 구문 자체가 자동으로 closure가 되어 전달
func printNextValue(@autoclosure value: () -> String) {
     NSLog(“value \(value())”)
}

구문을 작성한 시점에 동작이 일어나지 않고 전달된 closure가 실행되는 시점에 동작이 일어남. 지연해서 실행할 필요가 있을 때 유용

주의 : 코드의 실행이 읽는 위치에서 바로 되는 경우가 아닌데다 closure인지 인지하지 못할 가능성이 높아 가독성을 매우 떨어뜨림


출처 : 애플 도큐먼트

'Tech > iOS' 카테고리의 다른 글

스위프트 타입 호환성  (0) 2017.01.11
[Swift] Class와 Struct 중에 뭘 쓸까?  (0) 2016.10.28
optional을 쉽게 설명해보자  (0) 2016.05.17
Hashable Protocol  (0) 2016.02.28
TDD라기 보다는 테스트를 꼼꼼히 한번 짜봤다고 해야 할까. 좋은 점은 안정감이다. 코드를 여러군데 수정해도 테스트 코드가 있으니 안심이 된다. 과감하게 리팩토링을 할 수 있게 됐다. '테스트 없이는 리팩토링도 없다’는 말을 몸소 체득하게 된 것. 앞으로 나는 테스트 없이 개발을 하지 못할 것 같다.

왜 이렇게 테스트를 짜는데 망설여 왔을까? 테스트의 중요성에 대해서는 누누이 들었다. 여기저기서 읽기도 하고 신입교육 때도 들었다. 스프링 개발을 할 때는 어설프게 짠 적이 있었지만 커버리지가 매우 낮았다.

이유는 내가 앱 개발을 하고 있기 때문인 것 같다. 급박한 일정에 쫓기다보면 뷰 컨트롤러가 비대해지기 마련인데 이 경우 테스트 코드를 짜기 쉽지 않다. 뷰를 처리하는 로직이 다른 것과 섞여 그렇다. 

결과적으로 테스트 코드를 짜고자 하는 노력은 어떻게 하면 SOLID 원칙을 충실히 따르면서 구조화된 코드를 짤 수 있을까 하는 고민으로 이어졌다. Clean Code(로버트 마틴), Refactoring(마틴 파울러), 구현 패턴(켄트 백) 등의 서적을 열심히 탐독하고 있다. 여기에 헤드 퍼스트 디자인 패턴도 같이 읽고 있다. 


로버트 마틴의 Clean Coder에서는 TDD의 세 가지 법칙을 다음과 같이 소개한다.

1. 실패한 단위 테스트를 만들기 전에는 제품 코드를 만들지 않는다.
2. 컴파일이 안 되거나 실패한 단위 테스트가 있으면 더 이상 단위 테스트를 만들지 않는다.
3. 실패한 단위 테스트를 통과하는 이상의 제품 코드는 만들지 않는다.

실무에 적용해보니 이는 매우 유용하다.

-

같은 책에서는 확신, 결함 주입 비율, 용기, 문서화, 설계 등을 TDD의 장점으로 꼽는다. 내가 이미 느끼는 바가 책에 쓰여 있어 반가웠고 더욱 확신이 들었다. 

특히 설계에 있어 많은 효용을 가져다주는 것 같다. 테스트를 하기 위해서는 함수가 public 상태로 실행될 수 있어야 한다. 이를 만족시키기 위해서 고민하다 보면 자연스레 설계가 좋아지는 것 같다.



앱을 업데이트하고 올렸더니 다음과 같은 메시지가 나왔다.

"zip 정렬되지 않은 APK를 업로드했습니다. APK에 zip 정렬 도구를 실행한 다음 다시 업로드해야 합니다."

stackoverflow를 검색해보니 zipalign을 사용하면 된다고 나와 있었다. zipalign이 무엇인지는 문서에서 확인할 수 있다. 

sdk 폴더의 build-tools로 이동한 다음 빌드에 사용한 gradle plugin 버전으로 들어간다. 여기에 zipalign이 위치해 있다.

zipalign -v 4 foo.apk bar.apk

다음과 같이 입력해주면 되지만… 결과는 fail이었다. 마지막에 다음과 같이 찍혔다.

4413714 resources.arsc (BAD - 2)
Verification FAILED

구글링을 해보니 명확한 원인은 찾을 수 없었고 수동으로 signing을 하면 된다고 하는 글이 있었다.

수동 사인은 다음과 같이 할 수 있다.

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore [keystore file] foo.apk [alias]

여기서 alias가 뭔지 고민했는데 다음 명령어를 통해 확인할 수 있다.

keytool -keystore [keystore file] -list -v

이번에는 다음 메시지가 나온다.

jarsigner: unable to sign jar: java.util.zip.ZipException: invalid entry compressed size

이는 이미 사인되어 있는 apk일 경우에 나오는 메시지라 한다. 사이닝 정보다 담기는 META-INF 폴더를 다음 명령어로 지운다.

zip -d foo.apk META-INF/\*

자 이제 올려볼까? 이젠 디버그 모드로 되어 있다고 하면서 안 된다. 마지막으로 menifest에 다음을 추가한다.

android:debuggable="false"

된다… 힘들었다


'Tech > Android' 카테고리의 다른 글

SyncAdapter는 무엇이죠?  (0) 2016.05.10
UNEXPECTED TOP-LEVEL EXCEPTION Multiple dex files define  (0) 2015.09.09
AsyncTaskLoader는 무엇이죠?  (0) 2015.08.14
optional을 쉽게 설명해보자.

물음표 뜻 그대로 '없을 수도 있어’라는 뜻이다.

Objective-C에서는 값이 없으면 nil을 return하는 방식으로 이를 구현했는데 이는 NSObject를 상속한 개체만 가능했기 때문에 한계가 있었다. structure, enum 등까지 모두 포함해 ‘값이 없음’을 표현하게 위해 optional이 도입됐다.

만약 var number: Int?라고 선언하게 된다면 number는 nil 상태로 초기화된다.

이렇게 선언한 number를 그냥 쓰게 되면 값이 있을 수도 있고 없을 수도 있기 때문에 컴파일 에러가 발생한다. xCode는 느낌표를 쓸 거냐고 물어본다. 이는 force unwrapping인데 값이 무조건 있다고 가정하고 넘어가자는 것이다.

만약 값이 없으면 크래쉬가 발생하기에 위험하다. 이를 막기 위해 optional binding을 쓴다.

if let actualNumber = Int(possibleNumber) {
     "print("\"\(possibleNumber)\" has an integer value of \(actualNumber)”)"
}

이는 "만약 Int(possibleNumber)가 반환한 Int가 값을 가지고 있으면 이를 새로운 변수인 actualNumber에 할당해라"는 뜻이다.

guard let을 사용할 수도 있다.

guard let rowCount = branch?.services?.count else {
     return 0
}

guard는 if와 비슷하다. 조건 구문의 boolean 값에 따라 statements가 실행된다. 다른 점은 늘 else가 있다는 것이다.

if와 달리 예외 처리에 주로 사용된다.

-

optional에 대해 한번 정리하는 차원에서 글을 썼다. 사실 앱 개발을 공부하는데 있어서 모든 레퍼런스는 집어 치우고 공식 문서만 보면 된다(고 고수들이 그랬다).

'공식 문서를 보면 되는데 왜 나는 쓰고 있지?'란 생각이 가끔 들었다. 사실 나는 학습에 외국어보단 모국어가, 글보단 영상이 효과적이라고 생각한다. 요즘엔 멍 때리면서 tryhelloworld 보는 게 낙이다. 

이건 공식 문서와 달리 한글로 쓰여있기 때문에 1g의 의의를 지닐 수 있을 것이다.


'Tech > iOS' 카테고리의 다른 글

스위프트 타입 호환성  (0) 2017.01.11
[Swift] Class와 Struct 중에 뭘 쓸까?  (0) 2016.10.28
@noscape, @autoclosure  (0) 2016.10.24
Hashable Protocol  (0) 2016.02.28

SyncAdapter는 무엇이죠?

SyncAdapter는 2010년 구글 IO에서 발표됐습니다. 디바이스와 서버를 자동으로 동기화시켜주는 기능을 합니다. 다음과 같이 Account가 추가됩니다. 어떤 방식으로 sync할 것인지는 사용자가 매니지할 수 있습니다. 

1. 서버의 데이터가 변경됐을 때
2. 디바이스의 데이터가 변경됐을 때
3. 시스템이 네트워크 메시지를 보냈을 때
4. 특정 주기로
5. 필요할 때


SyncAdapter 장점

1 ~ 4번의 sync 시 프레임워크 내 어카운트가 등록되어 별도의 인증없이 가능합니다. 게다가 디바이스의 베터리 상황에 따라 OS가 sync 여부를 판단한다고 합니다. 구글 도큐멘트에선 5번을 권장하진 않습니다. 유저에게 리프레쉬 권한을 주면 데이터가 변경되었다는 아무런 근거 없이 sync를 시도하게 되어 네트워크와 배터리 자원을 효율적으로 이용하지 못하게 된다는 게 설명입니다. (안드로이드 디벨로퍼 문서 참조)


SyncAdapter 단점

SyncAdapter는 Content Provider와 붙어 다닙니다. Content Provider는 다른 어플리케이션과 데이터를 공유하지 않으면 굳이 만들 필요가 없는데 SyncAdapter를 쓰려면 달아야 한다는 거죠. 물론 Dummy로 만들면 CP를 모두 구현하지 않아도 됩니다. SyncAdapter를 Device와 서버 간의 데이터 전송을 전담하는 객체로 만들 수 있는 까닭에 구조적으로 앱을 더 깔끔하게 만들 수 있게도 해줍니다. 

+ Recent posts