Learning by Copying

In my mid-20s, liberal arts major, returning student. This was me when I started learning programming in NEXT. It was very difficult. All the new information pouring out was overwhelming. It was frustrating to continue not even knowing what I didn’t know. Over time, I was able to gradually learn the learning style that suits me and it greatly helped me become a real programmer. The difficulties that everyone faces in the beginning, what you need is ‘finding the learning style that suits you.’ The learning style that suited me the most was copying.

The Beginning of Copying: The Programming Assignment that Left Students in a Mental Breakdown

There was an incident that left students in a mental breakdown after only a few weeks into the first semester. Due to a communication error between the professors of the lecture and lab classes within the ‘Data Structure and Algorithm’ course, we got a ‘Tower of Hanoi’ coding assignment before learning about recursion theory. So about a month into learning programming, I had to solve the Tower of Hanoi without knowing about the concepts of recursion. Back then, there was no way of knowing about the horrors of that assignment. After the weekend, I came back to school on Monday, which was the deadline. It was a mess. There were so many people who didn’t go home and stayed in school all weekend trying to solve the problem. There were a lot of them who got almost no sleep, and they all looked worn out. Even then, almost no one was able to solve the problem. It was a scene of shock and fear.

I did it differently. I was able to solve the problem in a few hours. I tried a few times with my own knowledge and found the solution through Googling. I did not copy-paste the results from the Internet but figured it out as I ran it line by line, and understood the solution until I could write the same thing on my own. But when I came to school and saw the other students who stayed up for two nights trying to solve the problem on their own, I felt like I did something wrong. I felt guilty as if I cheated or studied in a way that was too convenient. I was reminded of my high school teacher who said that you won’t get better in math if you see the answer.

Copying Codes: Blindly copy codes when your brain is in sleep mode

I listened to online classes when I lost concentration in the evening or when I just didn’t want to use my head. I signed up for Treehouse’s paid membership and purchased paid courses at Udemy. App development courses usually have theoretical explanations and most of them are in the form of completing a sample app by copying the codes that the instructor types on screen. These types of lectures quickly get boring when you’re in a good state of mind. Online lectures seem like good study tools to use when your mind is kind of in a void state.

When I made several sample apps without paying much attention, they became good reference codes for my own. I opened up the sample apps and looked for the codes to learn how they’re done again whenever I remembered them but couldn’t remember how they were done. It was a code I’d written anyway so I was able to find what I wanted, and when I did, my memory came back quickly. These sample apps that I collected for months stayed useful for almost a year after I started learning programming.

Copying an app: Refer to well-made apps and copy them

The security card widget app which got first place in the App Store also began by copying. But this was not a copy of just one app. I got parts that I liked from several apps. Especially for UI/UX, I copied Apple’s basic apps or other well-made apps. For example, when I was working on the screen which shows the security card in the notification center, I installed several calculator apps that support widgets and got the UI that I thought was the best. As you copy well-made apps, you get your own ideas and your skills improve as you develop in ways you couldn’t have come up on your own.

Perfect match with copying: applying and repeating

Thankfully, my coding skills continuously improved over time. I looked for the best practice, copied them as needed, and made them mine. Copying was a learning style that suited me well. I couldn’t sit in one place for too long, and I realized that I’ve been gaining knowledge by imitating the optimal methods established by the people before me, or copying someone who is better than me. For example, when starting a game for the first time, it was more fun to learn by looking for strategies and imitating good gamers by watching their videos rather than trying to play blindly. The important thing is, even if I start by imitating, once I find the pattern and figure out the principle, I quickly apply them to find my own methods. Programming is no different. There is a pattern. Just like there is something called a ‘software design pattern,’ once you learn how to solve a problem, you can apply it to solve other problems as well.

There is a similar aspect in programming with physical exercise, so even if you understand it with your head, if you don’t keep training yourself with your own hands, you’ll soon forget it and continue to stay unable to do it on your own. I followed the online lectures without any thoughts, but as I kept repeating, there were more than 20 apps that I made by following the lectures. Actually, there are lots of repetitions after making a couple of sample apps. You get to repeat creating a ViewController from the storyboard, create a class, assign it, and connect IBOutlet/IBAction countlessly. But after repeating it several times, my hands started to move before my eyes. The moment I finished working before the instructor, and waiting for the lecture to catch up with me was very satisfying. It was copying at first, but as I kept on repeating, it became my muscle memory.

🥑 Job Survival Strategy 1: Imitating how a good developer works

‘Learning by copying’ naturally became my method of growth in actual work. I was lucky to have a senior who sat beside me and made me watch him work and it helped me greatly. I learned a lot from watching and copying the way he moved back and forth between windows in IDE, the way he opened and closed source files, frequently used shortcuts, how to use debugging tools, how to get through situations where you get stuck when you’re writing or modifying a code.

Also, in Xcode, the ID of the person who generated the source file remains as an annotation. So I studied by collecting the codes written by my mentor by searching for his ID in the whole project and looking for codes that I can imitate. While doing that, I learned as the new knowledge I acquired would fuse with or replace the ones I had.

🥑 Job Survival Strategy 2: Making a Retrospective Note

There were times when I repeatedly faced frustration while learning programming. I knew I did it several times, but I couldn’t remember as I tried to do it again, and my hands wouldn’t move well on the keyboard. I tried to look for ways to do it again, but I couldn’t even remember where to start looking. So I started to write retrospective notes at some point. I started writing without any format at first, but as I kept on writing, it started to have a certain format. I recorded (1) what I tried to do, (2) how I solved it, (3) things I learned or things that didn't work well, or points I got stuck in. There were a lot of codes, and I wrote all of them by hand. For the first time in my life, I used a notebook until the final page. Just like the sample apps, I looked at this notebook for almost a year until it wore off. When you first start programming, you rarely learn something at once, and you need to repeat something dozens of times to make it your own.

The retrospective notes were very helpful for my programming studies, so I kept on writing them even in actual work. I mainly recorded the new things I learned from work, especially the things I got stuck in at first and resolved after. Just like the study notes, I referred to the retrospective notes from work quite often. Then I found out that I did not write any retrospective notes starting from my second year as a developer. I should think about whether I should start writing them again.

Wrapping Up

Lastly, finding the fun of programming greatly helps in terms of long-term motivation. I experienced a slump after learning development for about a year. I could do things that I was told to do in class, but somehow it was not fun. I almost gave up on development as I was working on Html/CSS. I was at the crossroads of whether I should continue to attend NEXT, or give up and go back to college.

Fortunately, things changed after I encountered mobile app development. App development was interesting, and a new major in start-ups was created just in time. The development process of a team of friends deciding what to make together was so fun. The definition of fun is going to vary from person to person. I encourage beginners to explore development areas that stimulate their interests and curiosity, and learn about development in a way in which you can have fun with it.

이 글의 초안을 읽어준 조소현, 류성두 님에게 고마움을 전합니다.

Tags: learning to program, mooc, next institute  

[번역] 초짜가 된 기분

원문: Paul Graham의 Being a Noob

어렸을 때는 나이가 들면 모든걸 알게 되겠지 생각했다. 막상 내가 나이 들어 보니 전혀 그렇지 않다.

요새 여러 방면에서 초짜가 된 기분이 자주 든다. 창업자들과 얘기를 나누면 그 분야에 대해 전혀 모르겠고, 읽는 책의 주제는 생소하고, 새로운 나라에 가보면 당최 일이 어떻게 돌아가는지 모르겠다.

초짜로 돌아간 기분은 썩 달갑지 않다. 초짜라는 단어도 별로 좋은 뜻이 아니다. 그런데 오늘, 초짜가 되는 것에 담긴 긍정적인 의미를 깨달았다. 가까이서 봤을때는 초짜처럼 보일지언정, 멀리서 보면 덜 초짜라는 것이다.

예를 들어 당신이 고향을 떠나 머나먼나라로 여행을 떠난다면 처음에는 낯선 곳에서 자신이 더 바보같고 어색하고 이방인처럼 느껴질 것이다. 그러나 막상 가보면 고향에 남았을 때보다 훨씬 많은걸 보고 배울수 있다. 그러니 초짜가 되는 것과 무지(無知)는 음의 상관관계이다.

근데 새로운 분야에서 초보가 돼보는 것이 실제로 우리에게 좋은 거라면, 우리는 왜 그 느낌이 싫은걸까? 그런 거부감이 대체 어떤 진화론적 의미가 있는걸까?

내 생각에 초짜가 된 기분을 느끼는 원인은 두 종류가 있다. 무지할 때와 새로운 것을 시도할 때. 내가 초짜일 때 느끼는 불편함은 우리의 뇌가 ‘어서 빨리 상황을 좀 파악해봐’라고 명령하는 것이다. 인류의 역사를 돌이켜 봤을때 옛날에는 주변 상황을 빨리 파악해서 위험으로부터 벗어나는게 생존에 유리했다. 수렵/채집 생활을 하던 인류도 자신의 인생은 복잡하다고 생각했겠지만 오늘날만큼 주변 상황이 빠르게 바뀌지는 않았다. 어느날 갑자기 암호화폐를 어떻게 받아들여야 할지 결정할 일은 없었다. 그러니 옛날에는 새로운 문제를 발견하는 능력보다는 당장의 배고픔을 해결하는 편이 생존에 유리했다. 식량이 부족했던 시대에 배고픔을 경계했던 것 때문에 인간은 초짜가 된 느낌을 경계하게 된 것이다.

이제는 도리어 식량이 넘쳐나서 문제인 시대에, 배고픔을 두려워하는건 엉뚱하다. 초짜가 된 느낌을 두려워하는 것도 마찬가지다.

새로운 걸 시도할때는 처음엔 불편한 느낌도 들고 우스갯거리가 될 것 같은 두려움이 들기도 한다. 하지만 당신이 초짜가 된 느낌을 자주 느낄수록, 더 좋다.

Tags: being a noob, paul graham  

자연의 코드

지난주 하루는 퇴근하고 넥스트 스승님들이 계신 코드스쿼드에 방문해서 프로그래밍을 배우고 있는 분들과 공부법, 취업, 면접 등등 나의 경험을 공유하고 잡담도 하고 질문도 받는 시간을 가졌다. 질의응답을 하던 와중에 내가 ‘자연의 코드’라는 단어를 사용했다. 네이버 핵데이에 멘토로 여러 번 참여하면서 멘티 분들의 코드를 봤을때 그렇게 느꼈다는 말이었다. (핵데이 멘티들 중에 인턴 합격한 사람도 있고 못한 사람도 있지만 결국 대부분 취업도 잘했고, 비록 아깝게 면접에 떨어진 분들도 결코 실력이 떨어지지 않는다. 그들이 개발을 못한다는 말이 아님). 그랬는데 어떤 분이 ‘자연의 코드’가 어떤 의미인지 더 자세히 말해달라고 했고, 즉흥적으로 내뱉은 단어인 탓에 설명이 좀 부족했던 것 같다. 그래서 이 글을 통해 다시 정리해봤다.

코드 생김새

멘토님의 표현을 빌리자면, “코드를 읽지 않고 생긴 윤곽만 봐도 기본이 안된 코드는 걸러낼 수 있다”. 소스코드를 딱 열어보면 정리가 필요해보인다는 느낌이 드는 경우가 있다. 그 이유는 거창한게 아니라 줄바꿈, 띄어쓰기, 메서드나 프로퍼티의 순서 등이 일관성이 없기 때문이다. 코드도 글의 일종이고 결국 사람이 그걸 읽는다. 글이 적절한 크기의 문단으로 나뉘어져 있고 논리적인 흐름이 일관되면 읽기 수월한 것처럼 코드도 시각적으로 보이는 생김새/윤곽이 가독성에 영향을 준다. 예를 들어,

👇 삐쭉삐쭉한 코드 예시

func doSomething() {

  let blah = ...
  for item in items {
    print(item.name)

  }


}
var myData: [String: Data]

private func somethingElse() -> String {
  return "Hello World"
}
func justDoIt() {
  // whatever..
}

👇 그나마 정돈된 코드 예시

var myData: [String: Data]

func doSomething() {
  let blah = ...

  for item in items {
    print(item.name)
  }
}

func justDoIt() {
  // whatever..
}

private func somethingElse() -> String {
  return "Hello World"
}

개발자마다 선호하는 줄바꿈 스타일이 다르긴 하지만, 최소한 하나의 파일 내에서는 일관성을 지키는게 좋다. 코드의 생김새가 들쭉날쭉하면 코드를 해석할 때 들어가는 시각적인 부하가 커져서 눈도 아프다. 물론 핵데이니까 시간이 부족해서 평소보다 정리를 더 못한 것일 수도 있다. 나도 멘토님에게 처절한 코드 리뷰를 받았었다. 엔터 하나도 목적없이 허투루 치지 말라고.

또한 메서드나 프로퍼티 선언 순서도 정리의 대상이 될 수 있다. 가장 흔한 정렬 방법은 IBOutlet과 프로퍼티를 먼저 선언하고 메서드를 그 뒤에 이어서 선언하는 방식일 것이다(프로퍼티 - 메서드 순). 하지만 멘토님께서 클래스 내부 코드의 순서를 통해서도 개발자의 의도를 담을 수 있다고 알려주셨다. 개발자가 소스파일을 열어보는 이유는 그 클래스가 무슨 일을 하고 이걸 어떻게 사용하는지 알기 위해서일 것이다. 그래서 클래스에 대해 알고 싶은 사람이 가장 먼저 알아야 할 public 프로퍼티나 메서드가 맨 위에 있으면 파일을 열자마자 바로 보이기 때문에 쉽고 빠르게 정체를 파악할 수 있다. 만약 내부 동작까지 궁금하다면 점점 스크롤을 내려가면서 private 프로퍼티나 메서드를 참고하면 된다(public - private 순). 멘토님에게서 이런 리뷰를 받고 나서 고민해보고 오랫동안 이렇게 저렇게 시도해보면서 나름의 규칙을 정립하게 되었다. 그래서 나는 public 프로퍼티 - public 메서드 - private 메서드 - private 프로퍼티/IBOutlet 순으로 코드를 정리한다(샘플 앱 참고). IBOutlet이나 프로퍼티가 맨 밑에 있는 것이 처음에는 어색하기도 했지만, public 프로퍼티/메서드를 맨 위에 두는 장점을 살리면서 시각적으로도 정돈된 윤곽을 유지할 수 있다. 동료들도 딱히 거부감을 표현하지 않아서 고수하고 있다. 새로 가게 될 팀에서는 어떨런지. 이것도 정답은 없다. 자신의 기준을 세우고, 일관성 있게 적용하면 될 것 같다.

잘못된/생소한 구조

핵데이 멘토링하면서 상속을 잘못 쓴 코드를 많이 봤다. 객체 지향 프로그래밍을 처음 배울때 코드 재사용을 위해 상속을 사용한다고 배우기도 했고, 예제를 여러 개 보다보면 상속이 객체 지향 프로그래밍의 정점인 것처럼 느껴지기도 한다. 하지만 알고 보니 객체 지향 프로그래밍에서 가장 어려운 것이 상속이었다. 오죽하면 ‘상속을 잘 쓰는 방법은 상속을 쓰지 않는 것이다’라는 우스갯소리도 있고 상속보다는 구성(Composition over inheritance)이라는 OOP 원칙도 존재한다.

다음으로 자주 보는 것은 생소한 객체 간 정보 전달 방식(inter-object communication)이다. iOS 에서는 객체 간 정보를 전달할 때 쓰는 몇 가지 패턴이 있다. Delegate 패턴, NotificationCenter, Key-Value Observing, Closure를 전달하는 방법 등 네 가지 정도 사용할 수 있다. 정확한 코드는 기억이 안나지만 특이한 방법으로 데이터를 주고 받는 코드를 본 적이 있다. 당장에 원하는대로 작동은 할 수 있지만 iOS 컨포넌트들과 어울리지 않으면 나중에 코드 수정이 필요할 때 문제가 생길 수 있고 무엇보다 다른 iOS 개발자가 봤을 때 불필요하게 해석이 오래 걸리게 된다.

Human Interface Guidelines 위배

앞에 두 개에 비해서는 비중이 낮지만 iOS 개발자라면 HIG를 잘 알아야 한다고 생각한다. 핵데이 특성상 디자이너나 기획자 없이 개발자 본인이 앱의 UI/UX를 신경써야 하는데, 가끔씩 기묘한 플로우를 맞닥뜨릴 때가 있었다. 예를 들어 뷰컨트롤러 간의 이동은 크게 모달과 푸시 두 가지가 있는데 상황에 맞게 적절히 써줘야한다. 만약에 뷰컨트롤러를 모달로 띄웠다면 모달 작업이 끝난 후에는 해당 뷰컨트롤러를 dismiss 해줘서 원래 있던 뷰컨트롤러로 돌아가야한다. 그런데 모달 작업이 끝난 후 dismiss를 안하고 아래 깔려 있는 뷰컨의 새로운 인스턴스를 만들어서 또다시 모달로 띄우는 플로우를 본 적이 있다.

마무리

거창한 개발 지식도 아니고 엄청난 내공이 담긴 내용도 아니고, 단지 신입 개발자보다 고작 한 단계 앞에 있는 개발자가 올챙이적 시절을 돌이켜보며 쓴 글이다.

Tags: ios, swift, readable code  

기술 부채도 자산인 이유

경영학과 전공자라면 반드시 들어야 하는 수업이 있다. 회계원리와 재무관리. 나는 이쪽 수업이 너무 재미 없어서 필수 과목만 최소한으로 수강했다. 비록 암기했던 것들은 다 사라졌지만 중요한 하나는 남아있다.

자산 = 부채 + 자본

기업은 소유하고 있는 경제적 자원을 관리하기 위해 재무상태표를 작성한다. 재무상태표란 간단히 말하자면 회사의 가계부라고 볼 수 있다. 다만 들어온 돈(수입)과 나간 돈(지출)만 기록하는 가계부와는 달리 재무상태표는 복식부기 방식으로 기록한다. 복식부기란 거래가 발생했을 때 상호대응 되는 두 개 항목을 동시에 기입하는 방식이다. 상태표의 왼쪽에는 자산에 해당하는 항목, 오른쪽에는 부채와 자본에 해당하는 항목을 기록한다. 그래서 항상 왼쪽의 총합과 오른쪽의 총합이 같게 유지되어야 한다. 따라서 회계적인 관점에서 보면 언제나 자산 = 부채 + 자본 이라는 등식이 성립한다.

기술 부채에 대한 생각이 바뀌다

기술 부채란 뭘까? 일명 스파게티 코드라고 부르는 구조화되어 있지 않은 코드 형태, 기능 수정이나 추가가 힘든 코드, 영향 범위를 파악하기 힘든 사이드 이펙트를 내재하고 있는 부분 등을 보면 개발자는 기술 부채가 있다고 느낀다. 이럴 때 보통 “기술 부채를 갚아야 한다”, “기술 부채가 너무 쌓였다”, “올해는 기술 부채를 좀 청산하자” 등의 표현을 사용한다. 이런 말을 종종 듣다보니 기술 부채는 무조건 없애거나 줄여야 하는 나쁜 대상으로만 인식하고 있었다.

그러던 어느날 팀원이 공유해준 블로그에서 ‘기술 부채가 발생하면서 남는 리소스를 다른 곳에 투자할 수 있다’는 문장을 봤다. 그때 회계 수업에서 배웠던 자산 = 부채 + 자본 등식이 생각났다. 부채에는 자산의 측면도 있다는걸 잊고 있었다. 그렇다면 기술 부채에도 자산의 측면이 있을까란 궁금증이 생겼다. 있다면 과연 어떤 종류의 자산일까. 그건 바로 시간이 아닐까란 생각을 했다.

부채가 무조건 나쁘기만 한 건 아니라는 마인드

현실 세계에서 부채가 없는 회사는 거의 없다. 그리고 더 중요한 사실은 부채가 없다는 것이 썩 좋기만 한 것도 아니라는 점이다. 회사에게 자산이란 생산 활동(돈 벌기)에 도움이 되는 것들을 의미한다. 자산이 많아야 생산도 많이 할 수 있다. 그래서 일반적으로 기업은 적절히 부채를 늘려 자산을 늘린다. 예를 들어 은행에서 대출을 받거나 회사채를 발행하여 현금을 확보한다. 물론 골목 가게처럼 규모가 작은 사업체는 빚이 아예 없을 수도 있다. 하지만 그런만큼 성장성도 낮다. 성장하기 위해 부채를 적절히 사용하면 좋은 것이다.

회사를 개발팀으로 치환해봐도 비슷하다. 개인 프로젝트가 아닌 이상 현실적으로 기술 부채를 만들지 않고 개발을 할 순 없다. 촉박한 마감일에 맞춰 개발을 하다보면 기술 부채가 쌓이게 되는데, 그 대신 사업적인 성과를 낼 수 있게 된다. 보통 연휴 기간에 매출이 높기 때문에 기술 부채가 생기더라도 연휴 시작 전에 출시하는 것이 좋을 것이다. 또한 확장의 시기에는 경쟁자보다 먼저 시장에 진입해 사용자를 확보하기 위해 빠르게 개발하는게 성장에 더 좋을 수 있다. 이런식으로 기술 부채를 짊어지는 대신 시간을 벌 수 있고, 그 시간으로 매출을 내거나 양적 성장을 이룰 수 있다.

스파게티 코드를 보면 찌푸려졌었고 어떻게든 빨리 없애야하는 나쁘기만한 존재라고 생각했다. 하지만 자산의 측면도 있다고 생각하니 적절한 관리감독이 필요한 대상으로 인식하기 시작했다. 다만 남이 진 부채를 내가 대신 상환하고 있는 느낌이 들 때도 있다. 또 그러나 내가 만든 기술 부채도 다른 누군가가 갚고 있겠지.

기술 부채는 어떻게 관리해야 하지?

“측정할 수 없는 것은 관리할 수 없다” - 피터 드러커

그렇다고 무작정 기술 부채를 늘리기만 할 수도 없다. 기술 부채를 갚지 않고 늘리기만 하면 팀 전체의 개발 속도가 느려지고 좀비처럼 되살아나는 버그로 인해 사용자와 개발자 모두 고통 받게 된다. 개발 생산성이 낮아지면 결국 사업도 부정적인 영향을 받는다. 다만 금융 부채와 기술 부채의 가장 큰 차이점은 기술 부채는 세는 단위가 없기 때문에 정확한 양을 알 수 없다는 점일 것이다. 근데 피터 드러커는 측정할 수 없는 것은 관리할 수 없다고 했다. 기술 부채를 관리하고 싶다면 어떻게든 수치로 나타내야 한다.

엉클밥은 애자일 포인트를 제시했다. 개발 업무별로 각각 예상되는 투입 리소스에 따라 포인트를 부여하고, 개발팀이 총 몇 포인트만큼의 일을 완료하는지 스프린트 단위로 그 추이를 보는 것이다. 스프린트마다 쌓는 포인트가 점점 줄기 시작하면 기술 부채로 인해 개발 속도가 느려지는 것이므로 코드 리팩토링을 해서 기술 부채를 청산해야할 타이밍이라고 한다. 애자일 포인트는 기술 부채로 인해 야기되는 개발 속도 저하를 추적하는 간접적인 지표인 것 같다. 좀 더 직접적으로는 코드 정적 분석을 통해 도출하는 지표들도 있다. 반복되는 코드가 얼마나 많은지, 클래스/프레임워크 간의 디펜던시가 얼마나 복잡한지 등등. 어떤 것을 쓰든 정답은 없으므로 아마도 상황에 맞게, 팀에 맞게 써야하지 않을까 싶다. 아직 관련 경험이 부족하여 상상만 할 뿐이다.

경영 ≈ 개발

기술 부채에 대해 부정적인 말만 듣다보니 무작정 안좋은 것이라고만 생각했었는데 기술 부채를 회계적인 부채랑 비교해보니 조금 다르게 바라보게 됐다. 또한 기업을 경영하는 것과 개발 팀을 운영하는 것이 비슷한 점이 많아 보인다. 부채 없이 사업을 할 순 없지만 부채가 너무 많이 쌓여서 상환하지 못하면 파산한다. 마찬가지로 기술 부채 없는 개발팀은 존재하지 않지만, 제대로 관리하지 못하면 주저 앉는다. 버그 투성이 프로그램 때문에 사용자가 고통받을 수도 있고 사용자가(또는 지친 개발자마저) 아예 떠나버릴 수도 있다. 도저히 부채 청산이 안되면 코드를 전부 버리고 아예 처음부터 다시 개발해야 할 수도 있다. 결국 경영이든 개발이든 부채를 잘 관리해서 조직에 유익한 방향으로 활용하는 것이 중요하다는 생각이 든다.

이 글의 초안을 읽어준 조소현, 김결에게 고마움을 전합니다.

Tags: technical debt