dimanche글 첫 등장! 첫 미션이었던 타임머신 에디터를 만들며 제대로 된 문서작성의 소중함을 깨닫는데…
과연 초보자들은 이번 미션에서 삽질을 덜 할 수 있을 것인가?!
오늘의 미션 : To Do List 프로그램 만들기
기나긴 추석 연휴를 지내고 돌아온 다음 날, 연휴 후유증에 시달릴까 걱정이 되었지만 그럴 새가 없었습니다. 새로운 미션이 떨어졌기 때문이죠. 오늘의 미션은To Do List관리 프로그램을 만드는 것입니다.
평소 계획 세우기를 좋아해서 저만의 퍼펙트한 플래너와 To Do List앱을 찾아해맸습니다. 매번 이건 마음에 안들어, 저건 별론데?하며 수많은 To Do List 앱을 깔았다 지웠다 했습니다.(그리고 결국엔 제가 직접 만든 플래너와 몰스킨노트에 정착) 이랬던 저인데 막상 제가 To Do List 프로그램을 만들려 하니 그동안 아무렇지도 않게 지웠던 앱들에게 미안한 마음이 들었습니다.
수많은 Task 관리 앱들. 무시(?)해서 미안했어..
오늘의 요구 사항은 다음과 같습니다.
- To do list에 항목을 추가할 수 있어야 한다. 항목을 추가하면 한줄로 되어있는 텍스트로 항목 내용을 기술한다.
- 할일을 입력하면 할일리스트 최상단에 추가된다
- 우선순위로 낮음/보통/중요 세가지중 하나를 부여할 수 있는데, 기본값은 보통이다.
- 할일 리스트는 두 부분으로 되어있다. 한부분은 체크하지 않은 리스트, 한부분은 체크된 리스트(완료된 목록). 각각 진행중인 할일, 완료된 할일이라 부른다.
- 진행중인 할일에서 체크를 누르면 완료된 할일로 넘어가고, 완료된 할일에서 체크를 해제하면 진행중으로 바뀐다.
- 리스트 바깥쪽엔 보여지지 않지만 할일이 만들어질 때 일련번호, 작성 시간이 같이 생성된다. 나중에 작성한게 위로, 먼저 생성한게 아래로 정렬된다.
- 완료목록, 진행목록이든 각 할일 항목에는 삭제 버튼이 있어서 삭제를 할 수 있다.
- 저장버튼은 현재 진행중인 할일 리스트, 완료된 리스트를 묶어서 textarea에 JSON 형식으로 출력해준다.
- textarea에 문자열 JSON을 붙여넣고 불러오기 버튼을 클릭하면 내용이 기존의 To do list 목록이 사라지고 입력한 목록으로 출력된다.
- JSON.parse() : 문자열을 넣으면 JSON object로 돌려준다.
- JSON.stringify() : JSON을 넣으면 문자열로 돌려준다.
뭐 부터 할 것인가…오늘은 생각조차 없다…
지난 미션 ‘타임머신 에디터’보다 복잡성이 한 층 더 높아져 멘붕에 빠졌습니다.
‘빨리코드를쓰고싶다’병
잠시 멘붕에 빠졌만 멍할 틈이 없습니다. 파워포인트를 켜고 문서부터 작성합니다. 지난시간 dimanche가 했던 것 처럼 저도 파워포인트를 이용해 테마정하기 > 줄거리 나누기 > 시나리오 작성하기 > 플로우차트 작성 순서로 문서를 작성했습니다.
위에서 길~~게 나열된 요구사항을 정리해 다음과 같이 줄거리로 작성했습니다.
그리고 줄거리에서 나뉜 번호를 세분화하여 시나리오를 작성했습니다.
문서와 어휘집도 작성하고, 플로우 차트도 그리고 많은 작업들을 했지만 그 중에서 가장 힘들었던 것은 저의 마음을 컨트롤하는 것이었습니다. 바로 시도 때도 없이 “빨리-코드를 작성하고-싶다”라는 생각이 들었기 때문이었죠.
“야 빨리 좀 작성하고 코드 짜자. 지금 시간 다 지나가고 있어.”
“이정도 썼으면 뭐 하는지 알잖아? 대충 마무리하고 빨리 짜봐.”
“짜봐야지 진짜 이렇게 돌아가는지 알지. 그게 진짜야.“
타임머신 에디터를 만들면서도 끊임없이 깨달은 것은 ‘기획’과 ‘문서 정리’의 중요성이었습니다 하…하지만 그 중요성을 알지만… 계속 해서 빨리 코드를 써내려가고 싶다는 생각이 들었습니다. (정말 병에 걸렸나 싶었습니다.) 그럴 때마다 <다함께 프로그래밍>에서 “프로그램이 멈추면 어차피 다시 시나리오 작업으로 돌아가야합니다.”라고 말한 것을 되뇌이며 ‘그래 어차피 제대로 해야해…’라고 마음을 다잡았습니다. 그 결과, 프로그램을 완성할 수 있었습니다. Todolist(버전1) 확인하기
단순함이 최고입니다.
완성의 뿌듯함은 잠시, 폭풍 피드백이 시작되었습니다. 우선 처음으로 지적받은 것은 저의 CSS코드였습니다. 나름 예쁘게(?) 만들어보고 싶어서, 그리고 얼마전에 배운 CSS 패턴을 써보고 싶어서 아주 신나게 CSS를 썼습니다. 그 결과 불필요한 HTML 구조의 중첩과 과도한 CSS 코드의 남용이 발생했습니다. (특히 웹사이트 ‘레이아웃’수준에서 쓰는 float과 clear패턴을 여기저기 남발…)
출근길의 공사장 벽면. 어디서 많이 봤다 했더니… 내 코드잖아! (덕지덕지…)
물론 아름다운 것은 좋습니다. 하지만 아름다운 것을 만들어 낼 지라도 이왕이면 적은 HTML 요소와 적은 CSS 코드로 화면을 구성하는 것이 진짜 실력! HTML, CSS는 쉽지 않습니다.
역할을 나눠봅시다.
제가 작성한 코드에서 가장 큰 문제점 중의 하나는 “역할이 잘 나눠져 있지 않다”는 점이었습니다. 프로그램의 종류는 크게 2가지로 나뉘는데 오늘 만든 To Do List 프로그램이나 지난 시간 만든 타임머신 에디터, 슬롯머신과 같은 프로그램은 ‘이벤트 기반 프로그램(event-driven program)’이라 합니다. 이 방식은 사용자가 버튼을 클릭한다든지, 키보드를 누른다든지와 같은 행동을 이벤트로 지정하고,이벤트가 발생하면 어떠한 행동을 해라라는 것을 정해두어 이벤트에 따라 프로그램이 실행되는 것을 말합니다. 그리고 이 방식에서는 역할을 나누는 것이 제일 중요합니다.
그럼 역할을 왜 나눠야 할까요? 사실 컴퓨터에게 어떠한 명령을 하려면 하고싶은 명령을 쭈우우우우우우욱 알려주면 됩니다. 심지어 똑같은 내용을 1000000000000번정도 시켜도 컴퓨터는 부담스러워 하지 않죠. (컴퓨터가 못하는 것은 인간처럼 정해지지 않은 상황에서 능동적으로 판단해 결정을 내리는 것…)
하지만 만약 클라이언트의 요구사항이 바뀌었다면? 프로그램을 만드는데 이렇게 하면 더 나을 것같아서 수정을 하게 된다면…? 프로그램은 계속 바뀌게 될텐데 그 때 마다 쭈우우우우우욱 나열되어있는 프로그램을 고쳐야한다면 어떻게 될까요? 프로그래머는 포기 하겠죠. 결국 역할을 나누는 건 프로그래머를 위해서입니다. 역할을 잘 나누면 프로그램의 유지 및 보수를 쉽게 할 수 있습니다.
그렇다면 역할은 어떻게 나눌 수 있을까요?
역할을 나누는 법 1 : 중복된 친구들을 찾아라!
역할을 나누는 가장 쉬운 방법은 ‘중복을 없애는 것’입니다. 프로그래밍에서 제일 나쁜 것은 중복…! 같은 내용을 계속 써야하는 것도 힘들지만 나중에 유지/보수 할 때를 생각하면 중복은 정말 나쁜 아이죠. 2번 이상 나오면 무조건 중복입니다.
중복을 발견하는데에 도움이 되었던 것은 플로우 차트였습니다. 시나리오 작성할 때는 잘 보이지 않았던 중복이 플로우 차트에서는 한눈에 보였기 때문이죠.
중복되는 부분은 같은 색깔로 묶어두었습니다. 한 눈에 보이는 중복!
플로우 차트에서 그린 대로 역할을 나누고, 역할을 함수로 구현했습니다. 또, 함수 이름은 맡은 역할을 잘 나타낼 수 있도록 붙이구요. 그 결과 줄거리에서 나눈 할 일을 등록해주는 역할의 writeTask 함수, 할 일을 삭제하는 역할을 맡은 del함수, 할 일의 완료 여부를 바꾸는 역할을 맡은 changeStatus 함수 등이 만들어졌습니다.
하지만 이것으로 충분하지 않았습니다. 저는 할 일 입력창이나 버튼처럼 화면에서 보이는 요소들이 가진 ‘기능’을 기준으로 역할을 나눴기 때문입니다.
역할을 나누는 법 2 : 격리시켜야 할 친구들을 찾아라!
시계를 고친다고 생각해봅시다. 시계의 건전지가 다 닳아서 건전지를 교체하는데 교체하는 과정에서 태엽의 위치가 바뀌도록 시계가 만들어져 있다면 좋은 시계일까요…? 딱 봐도 아니죠?
프로그램도 마찬가지입니다. A라는 부분을 고치는데 프로그램의 B부분이 연결되어 있어 영향을 받게 되어 있다면 유지보수의 지옥이 열리겠죠? 그러므로 역할을 나누는 다른 방법은 ‘격리되어야 하는 것이 무엇일까’를 고민하는 것입니다.
예를 들어 저는 코드에서 HTML의 요소를 가져오는데 document.getElementById() 함수를 이용했습니다. 이 함수를 이용하면 HTML 요소에 지정된 ID값을 괄호 안에 넣어 요소를 가져올 수 있습니다. Javascript에서 너무나도 많이 쓰이는 함수이기에 저는 저것이 더이상 쪼개질 수 없다고 생각했습니다. 하지만 피드백을 받는데, 제가 정해둔 HTML요소의 id 이름이 적절하지 않고, HTML 구조도 너무 복잡하다는 평을 받았습니다. 네…. HTML을 전부 엎게 되었습니다. Javascript와 연결된 부분도 전부 어그러져 프로그램이 작동하지 않게 되었습니다.
저는 인식하지 못했지만, HTML 요소와 Javascript를 연결해주는 요소를 정리하는 것도 하나의 역할이 될 수 있었습니다. 그래서 다음과 같이 역할을 나눴습니다.
//HTML 요소 ID와 Javascript에서 불러올 이름을 매칭 var _els = { textArea:'textArea', taskInput:'taskInput', taskCompleted:'taskCompleted', taskProgress:'taskProgress', msgDisplay:'msg', arrow:'arrow' }; //Javascript에서 정한 이름(key)를 넣으면 그와 매칭되는 ID를 가진 HTML 요소를 내놓음. var getEl = function(key){ return document.getElementById(_els[key]); };
이렇게 되면 _els이름을 가진 배열에서 어떤이름으로 HTML 요소 ID를 매칭했는지 알 수 있습니다. 후에 HTML 요소의 ID가 바뀌어도 _els의 내용만 바꿔주면 되기 때문에 코드 전체에 퍼져있는 getElementById()를 찾느라 헤매지 않아도 됩니다.
경고 메시지를 출력하는 부분도 다음과 같이 수정했습니다.
//기존안 //아래 4줄의 코드를 필요한 곳에서 메시지 내용만 바꿔가며 계속 반복. var display = document.getElementById('msg'); setTimeout(function(){ display.innerHTML = '내용이 비었습니다.'; },100); //개선안 //1. 메세지를 종류별로 정리 var _msgs = { saveSuccess:{ text:'성공적으로 저장했습니다.', color:'green' }, loadSuccess:{ text:'성공적으로 불러왔습니다.', color:'green' }, emptyList:{ text : '작성된 할 일이 없어요.', color : 'red' }, emptyInput:{ text:'할 일 내용을 입력해주세요.', color:'red' }, priorityMissing:{ text:'우선순위가 없습니다.', color:'red' }, priorityInvalid:{ text:'우선순위가 올바르지 않습니다.', color:'red' } }; //2. 메세지 키 값과 함께 호출. 1에서 정리된 메시지의 내용이 정해진 색깔로 화면에 등장하게 됨. var displayMsg = function(context){ var display; display = getEl('msgDisplay'); display.innerHTML ="&amp;amp;amp;amp;nbsp;"; setTimeout(function(){ display.innerHTML = _msgs[context].text; display.style.color = _msgs[context].color; },100); };
이렇게 역할을 분리함으로써 코드들이 격리 되었습니다. 코드가 격리되었다는 것은 유연성이 높아진다는 말이기도 한데, 코드가 딱 한가지 역할만 맡게 하여 어디서든 쓰일 수 있다는 의미입니다.
물론 처음에는 역할을 구분하는 것이 어렵습니다. 하지만 자꾸 연습하고 쪼개보면서 역할을 인식하게 되는 센스를 발전시킬 수 있습니다.
역할을 나누는 법 3 : 역할에도 수준이 있다.
역할을 구분하는 것에서 끝나지 않습니다. 코드를 체계적으로 쓰고, 정리하는데에는 역할의 수준을 구분하는 것도 필요합니다.
예를 들어 카레를 만든다고 생각해봅시다. 카레를 만들려면 우선 재료를 사오고 요리 기구를 준비해둡니다. 그것이 되어야 재료를 손질하고, 물을 끓이고, 재료를 섞어 카레를 만들 수 있습니다.
코드도 마찬가지입니다. 역할에도 수준이 있어서 프로그램이 돌아갈 수 있게 기본 환경을 조성하는 역할에서부터, 그 환경을 바탕으로 삭제라든지, 화면 출력이라든지 여러 기능을 실행하는 역할을 맡은 친구들도 있습니다. 위에서 나온 _els, _msg 배열을 준비해둔 것은 마치 요리의 기본 재료인 소금, 설탕을 사온것과 같고, 배열 정보를 바탕으로 HTML 요소를 가져올 수 있는 getEl()함수, 알림 메시지를 출력할 수 있는 displayMsg()함수는 사온 재료를 통에 담아두어 필요하면 언제든 소금을 뿌리고, 설탕을 칠 수 있도록 준비해 둔 것과 같다고 할 수 있습니다.
이렇게 코드에도 수준이 있으며, 수준별로 코드를 쭉 정리해 써내려갈 수 있습니다. 코드의 수준을 알아채는데에는 탄탄하고 섬세한 시나리오 작성이 도움이 되는 것 같습니다.
제품의 수준을 높여주는 ‘한걸음 더’
저희는 ‘제품’을 만드는 전문 개발사입니다. 요구사항을 충족하는 것 뿐만이 아니라 어떡하면 더 좋은 제품이 될 수 있을지 고민을 해봐야합니다.
요구사항중에는 “완료한 항목은 다시 진행중인 항목으로 바꿀 수 있다”라는 것이 있습니다. 진행중인 항목에서 체크박스를 클릭하면 완료 중으로 바뀌니까, 반대도 체크박스를 풀면 된다고 생각을 했습니다. 그래서 별 생각없이 그렇게 UI를 짜고, 기능을 구현했습니다. 하지만 사용자의 입장에서 생각했다면 체크된 체크박스를 푸는 방식으로 상태를 바꾸는것이 아니라 [진행중으로 변경하기]버튼을 만들어서 보여줬어야 합니다. 그리고 완료된 항목에는 상대적으로 비중을 적게 주기 위한 다른 장치도 있어야 했습니다.
하지만 저는 그에 대해 고려를 하지 않았습니다. 당장의 미션을 완료해야한다는 생각에 첫편에서 언급한 가장 기초, “나는 좋은 제품을 만드는 좋은 개발자가 될꺼야”라는 자세를 잊었던 것이었습니다. 기본 자세를 잃다니, 정말 저는 초보였습니다.
초심을 잃었던 점을 반성하며 다음과 같이 프로그램을 고쳐보았습니다. >>확인하기
문서도, 코드도 여러번 고치니 한결 나아진 것 같습니다. 하지만 여전히 부족한 점이 보이는 건… 그래도 포기하지 않고 계속 노력합니다. 개발왕이 될 그날을 향하여!
summer| bsidesoft 신입사원
디자인을 공부했던 섬머는 개발까지 해버리겠다는 욕심으로 개발자의 세계에 입문하게 되었습니다. 개발왕이 되어 멋진 제품을 만들어내는 꿈을 꾸고 있습니다. 코드, 디자인을 포함한 세상의 모든 아름다운 것들과 미드, 그리고 달리기를 좋아합니다.
recent comment