brunch

You can make anything
by writing

C.S.Lewis

[RxJava] #3 구구단을 Rx적으로 코딩하기

들어가는 글: 추석 연휴도 후반전입니다. 1화, 2화에 보내주신 성원으로 힘이 납니다. 이왕이면 댓글도 달아주시면 더욱 힘이 날 듯 합니다. 이번엔 'Rx적으로 생각'하는 것은 무엇일까? 몇자 적어보겠습니다. 


1. Rx적인 생각? 


우리 강좌의 목적은 Rx가 안드로이드 개발자에게 정말로 필요한가?를 같이 고민해보고

어떻게 활용할 수 있는지를 알아보는 것입니다. 


Rx적인 생각은 무엇일까요? 

기술을 걷어내고 개념적으로 생각해보시길 바랍니다. 


제가 1화, 2화에서 소개드렸던 내용을 다시 적어보겠습니다. 


#1 [본문 링크]  

"반응형 프로그래밍은 명령형(imperative) 프로그래밍의 반대말이다." 

"반응형 프로그래밍은 함수형 프로그래밍을 활용한다." 

"반응형 프로그래밍은 데이터의 흐름에서 시작된다." 

반응형 프로그래밍은 함수형 프로그래밍 언어의 도구들을 가지고 데이터 흐름을 composable하게 구현하는 것이다. 


#2 [본문 링크] 

반응형 프로그래밍은 크게 3부분으로 구성되어 있습니다. 

1. input 부분: 이벤트가 시작되는 부분 

2. operators 부분: 이벤트를 가공하고 조합(compose) 하여 결과를 만드는 부분

3. output 부분: 가공한 결과를 출력하는 부분 


Rx적인 생각은 위에서 나온 것들로 현실의 문제를 풀어보는 것입니다. 

그동안 우리가 프로그램을 짜던 방식은 명령형 프로그래밍이라고 생각하면 됩니다. 


거기에서 벗어나 새로운 시각으로 프로그래밍 해보는 것을 의미합니다. 

아주 단순한 사례에서 천천히 연습을 해봅시다. 


2. 구구단을 위한 Rx 프로그래밍 


구구단을 명령형 프로그래밍으로 짜봅시다. 

워낙 간단해서 객체를 쓸 필요도 없습니다. 


편의상 3단을 출력해보겠습니다. 


코드의 내용은 너무도 쉬우니 설명을 생략합니다.  

위아래 @Test 와 assertTrue(true)라는 부분이 어색하게 보이시는 분은 아래 토막글을 읽어보세요.


<토막글> 
안드로이드를 개발할 때 간단한 java 테스트 코드를 짤 일이 있다면 기존에는 java 프로젝트를 별도로 만들어야 했습니다. (귀찮으신 분들은 이클립스로 만들기도 했습니다.) 그런데 이제는 '로컬 유닛 테스팅'이 가능하니 굳이 그럴 필요는 없습니다. 관련되는 간단한 코드를 짤 때 @Test 하고 간단히 작성하면 됩니다. 테스트 코드에는 assert 문이 적어도 1개는 필요한데요, 마지막에 assertTrue(true) 이런식으로 붙여주면 됩니다. 

만약 assert문을 한 개도 안 넣어주면 No tests were found 라는 에러가 발생합니다. 

 

이제 이것을 안드로이드 앱에서 Rx적으로 코딩을 해보겠습니다. 

음.. 이게 아무리 간단한 것을 짜보려고 해도 잘 안되더라구요.. 

저도 1시간정도 해맸습니다 T_T Rx 프로그래밍이 진입장벽이 높습니다.


구구단 3단을 출력하는 Rx 코드 


실행결과는 아래와 같습니다. 


음.. 간단한 것인데요, Rx 적으로 생각한다는 것이 상당히 어렵습니다. 

제가 느끼는 것도 무언가 '사고방식'이 다른 것 같습니다. 


참고로 위의 guguEdit 은 EditText로 3 단을 표시하는 영역이고 , 

guguResult는 구구단의 결과를 표시하는 EditText 입니다. 



3. 구구단 코드를 뜯어보자 


UI 코드를 제외한 로직 코드입니다. 

int dan = 3;
Observable.range(1, 9)
        .map(row -> dan + " * " + row + " = " + (dan * row))
        .map(row -> row + '\n')
        .subscribe(guguResult::append);


일단 for문이 없습니다. 

for 문 없이 어떻게 반복적인 동작을 수행할 수 있을까요? 


여러가지 방법이 있지만 (저는 아직 다른 방법은 잘 모르겠습니다 ^^;;;) 

이번엔 range(X, N)을 활용하였습니다. 

range(1,9) 는 1부터 9개의 숫자를 나열합니다. 우리가 원하는 데로 {1,2,3,4,5,6,7,8,9}에 해당합니다. 


이 각각에 대해서 map()이 호출됩니다. 첫번째 map에서는 출력할 라인을 만들고 그 다음 map()에는 newline을 추가합니다. 앞서 composable이라고 말씀드렸듯이 여러개의 map()을 추가로 붙일 수 있습니다. 


마지막 결과를 출력하기 위해서 subscribe()을 활용하였습니다. 

Java8에서 추가된 문법으로 람다 표현식의 인자를 생략할 수 있습니다. 

원래의 코드는 

subscrible(text -> guguResult.append(text)) 

입니다. 


앞서 말씀드린 inputs / operators / outputs 에서 두번째 부분인 operators를 잘 조합하면 나머지 코드를 간결하게 유지할 수 있습니다. 


4. 함수형으로 생각하는 것은 어렵다? 


갑자기 왠 함수형으로 생각하는 것이 나왔을까요? 

우리는 지금 Rx적인 사고방식에 대해서 얘기하고 있는데요..


그 이유는 Rx라는 방식이 결국 함수형 프로그래밍을 지향하기 때문입니다. 

그렇게 생각을 해야 Rx적인 코드를 짤 수 있습니다. 


Java는 함수형 언어가 아닙니다. 객체지향 언어이고 Java8에 와서야 람다 표현식같은 함수형 프로그래밍 도구가 추가되었습니다. 


또 Rx적으로 사고를 하려면 Rx에서 제공하는 수많은 기초 operators를 섭렵해야 합니다. 

대부분의 문서가 그것을 먼저 가르쳐주기 때문에 .. 문서를 읽어봐도 '이걸 어디에 써먹지?' 이렇게 생각하게 되는 것 같습니다. 제가 그랬으니까요. 


차근차근 사례를 들어가며 Rx적인 사고방식 / 선언형 프로그래밍 / 함수형 프로그래밍을 

연습해봅시다. 


우리에겐 연습이 필요합니다. 


2016.9.16 @Home 

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari