반응형
요즘 들어서 실제 환경에서 내 연구분야와 관련된 지식이 확장되는 기쁨과 동시에 이걸 그동안 모르고 있었다는 절망, 곧이어 또다른 지식의 확장에 대한 경험의 연속이다. 한마디로 말해서 제정신이 아닌 상태다. (...) 전산학/컴퓨터공학의 세부 분야라면 어느 것이나 마찬가지일 것 같은데, 애초에 이론을 완벽하게 습득하지 않은 채로 계속 다음 단계로 전진하다 보면 실전에서 모래성과 같이 허술하게 쌓여 있던 그동안의 지식이 깨지게 되고, 결국 실전에서 문제를 해결하는 과정을 겪으면서 이론을 재정립하고, 실제 환경에서 어떻게 이론이 적용되는지도 배우게 된다. 물론 마지막 단계에 해당하는 '실전에서 문제를 해결하는 과정'이론 기반이 약할 경우 오래 걸릴 수밖에 없다.
내가 석사과정 2년차 때 자의반 타의반으로 무선 네트워크 분야의 연구주제를 선택하면서, 비교적 최근까지 얼마나 내가 이론이 약한 상태였는지를 뼈저리게 느끼고 있다. 달리 표현하자면, 이제서라도 네트워크를 실제로 운용할 때 필요한 일부 요소들(여전히 극히 일부인 것 같다.. 에휴)을 하나씩 재정립하는 것이 얼마나 다행인지 모르겠다. 학생이니까 실수하고 배우는 것이 용서가 되지, 만약 박사가 되어 세상에 나가서 똑같은 경험을 하고 살았다면 부끄러워서 고개를 들고 다니지 못했을 것이다. (뭐 사실 학생 신분도 이제 시한부가 되었다. 무한정 학생일 수는 없다.)
최근에 내 연구의 실험 환경인 와이파이(IEEE802.11) 기반의 멀티채널 무선 메쉬 네트워크(multi-channel wireless mesh network)를 구축하고 실제로 트래픽을 만들어서 보내면서, arp, route (커널 라우팅 테이블), iptables, hostapd, dhcp 등의 다양한 도구들의 역할과 그 중요성을 실감할 수 있었고, 커널에서 netlink를 통해서 패킷을 처리하는 절차, 패킷이 버퍼링되면서 발생하는 지연 문제, 그 원인을 제공하는 intra-flow interference, inter-flow interference 등에 대해서도 다시 살펴볼 수 있었다.

퀄넷(QualNet) 네트워크 시뮬레이터에서는 메쉬 네트워크 만드는 매뉴얼에 따라서 만들어 놓고 노드 몇번에서 다른 노드 몇번으로 패킷을 몇개 보내라고 시키면 위에 언급된 각종 도구들의 역할을 전혀 몰라도 실험하는 데 아무 이상이 없었고, 성능 측정 결과도 바로바로 나왔다. 그러면 나는 그저 next-hop으로 패킷을 전달하는 부분만 고쳐 가면서 실험해서 그래프를 만들어 내면 되었다.

그러나 현실 세계에서 무선 메쉬 네트워크가 서로 기본적인 "연결" 상태를 유지하도록 만드는 기본적인 것도 호락호락하지 않았고, 여기에 스마트폰이나 노트북을 연결해서 인터넷을 하거나 서로 통신이 되도록 만들기 위해서 이것저것 시도하면서부터는 더더욱 멘붕 상태에 빠져들 수밖에 없었다.

최근 들어서야 여러 앱들을 돌리고 네트워크 상태를 모니터링할 수 있게 되었는데, 이제 실제로 나만의 "라우팅"을 적용할 수 있겠다는 부푼 기대를 안고서 실험을 했으나, 근본적으로 라우팅만 가지고는 해결이 안되는 문제임을 인식한 직후에는 또 한번 절망할 수밖에 없었다. 아, 이래서 내가 저널에 투고한 논문이 reject 되었던 것일까?

------------------- 내가 다시 석사과정 2년차 또는 박사과정 1년차로 돌아간다면, 당장 노트북이든 보드PC든 라우터든 여러 개를 가져와서 실제로 돌아가는 무선 네트워크 실험 환경을 구축하는 것부터 시작할 것이다. 그것이 한 학기가 넘게 걸리든, 거의 일 년이 걸리는 한이 있더라도 반드시 테스트베드 환경 구축을 강행할 것이다. 그렇게 실제로 써먹을 수 있는 테스트베드를 만드는 작업 그 자체가 적어도 나에게는 이론을 동시에 습득하기에 가장 효과적이기 때문이다.

이렇게 무선 네트워크 환경에서 패킷이 머신 하나에 들어오고 나가기까지의 모든 세부 절차에 대한 총체적인 이해를 바탕으로, 그 다음에야 실제로 내가 해결하고 싶은 문제 상황을 상상해 보고, 매일매일 테스트베드 환경에 돌려볼 것이다. 만약 기존 환경에서 잘 해결이 안 된다면, 그것이 최소한의 research goal은 될 수 있다. 하지만 내가 단독으로 그 목표를 해결하면 아무 소용이 없으므로, 이제 기존의 논문들이 어떻게 했는지를 공부해서 그 개념을 실험 환경에 적용해서 돌려볼 것이다. 물론 너무나 당연한 소리지만, 기존 연구는 반드시 최고 수준의 학회/저널에서 최근에 발간된 논문들 중에서 찾을 것이다. 최근에 발간된 최고 수준의 학회/저널에 올라오지 않는 주제라면 사실 조심해야 한다. 모 아니면 도가 될 수 있기 때문이다. 정말로 해결이 필요한 실용적이고 중요한 문제인데 아무도 해결하지 않았거나, 해결할 가치가 없거나(공학적인 의미가 없거나) 둘 중 하나이기 때문이다. 하지만, 전자일 확률을 1%도 안 된다.

그런데 아마 내가 관심있어 하는 가장 최근의 핫한 연구분야는 내가 앞서 '이론의 실제화' 과정에서 구축한 테스트베드에 비해 이미 여러 단계 앞서 있을 것이다. 그리고 이미 어느 정도 오픈소스로 쉽게 구할 수 있게 되어 있을 가능성도 높다. 그럼에도 불구하고 위와 같이 기본적인 테스트베드를 구축하는 연습은 적어도 네트워크 분야에서는 안할 수가 없는 것 같다. 저 과정을 이해하지 못한 채로 신기술을 바로 적용하면 그 내부 작동 원리를 이해하기 위해서 결국 언젠가는 공부해야 하기 때문이다. 물론 최신 기술을 바로 설치해서 써 보는 것부터 시작해서 세부 개념과 원리를 익혀 가는 방법도 결코 나쁘지 않을 것이다. (예를 들면, 요즘 핫한 SDN 도구 중 하나인 OpenFlow나, 그 위에서 작동하는 ONOS 같은 컨트롤러 패키지부터 설치해서 써 보는 것.) 어쨌든 결국 최종적으로 얻게 되는 지식은 다를 바가 없을 테니까. 즉, 성향에 따라서 어느 방법이든 선택해서 열심히 익혀 나가는 수밖에 없다.

비록 많이 늦었지만, 이제서라도 이론을 다시 쌓아올리고, 실제 환경과 습득한 이론 사이의 간극을 줄여 가고 있으므로, 조금 더 노력해서 반드시 의미 있는 연구 결과를 만들어 내고 싶다. 남부끄럽지 않은 박사가 되어야겠다. 


반응형
블로그 이미지

Bryan_

,
반응형

OS: Raspbian Jessie

HW: Raspberry Pi 2 Model B

NIC: TP-LINK TL-WN722N (Atheros ath9k_htc)



라즈베리파이에 USB 무선랜 카드를 2개를 동시에 꽂아서 쓰면서, 편의를 위해서 각 인터페이스 이름(wlan0, wlan1, ...)에 네트워크 설정을 강제로 지정해 두었다. 예를 들어, wlan0은 hostapd를 돌려서 항상 AP가 되도록 하고, wlan1은 ad-hoc 모드로 다른 라즈베리파이와 네트워크를 구축하도록 하였다.



<문제 상황>


그런데 재부팅하고 나면 거의 매번 인터페이스 이름에 실제로 매핑되는 USB 무선랜카드가 달라지는 현상이 있었다. 인터페이스 이름에 할당되는 무선랜카드의 맥주소(물리적 주소, MAC address, HW address)가 재부팅할 때마다 랜덤하게 배정되는 것이다. 즉, ifconfig로 인터페이스 정보를 볼 때, 아래와 같은 출력 결과에서 HWaddr 영역이 서로 뒤바뀌는 일이 비일비재하게 나타났다.


wlan0     Link encap:Ethernet  HWaddr a0:f3:c1:2b:85:7b  

          inet addr:10.0.4.1  Bcast:10.0.4.255  Mask:255.255.255.0

          inet6 addr: fe80::a2f3:c1ff:fe2b:857b/64 Scope:Link

          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

          RX packets:1301 errors:0 dropped:0 overruns:0 frame:0

          TX packets:1379 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:1000 

          RX bytes:230487 (225.0 KiB)  TX bytes:539231 (526.5 KiB)


wlan1     Link encap:Ethernet  HWaddr a0:f3:c1:2a:ca:04  

          inet addr:192.168.3.4  Bcast:192.168.3.255  Mask:255.255.255.0

          inet6 addr: fe80::a2f3:c1ff:fe2a:ca04/64 Scope:Link

          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

          RX packets:89 errors:0 dropped:0 overruns:0 frame:0

          TX packets:122 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:1000 

          RX bytes:10699 (10.4 KiB)  TX bytes:14048 (13.7 KiB)

(라즈베리파이 기본 설정에서는 NIC가 여러 개일 경우, 

부팅할 때마다 빨간색 표시한 HWaddr 부분이 랜덤으로 계속 바뀐다.)



일반적인 상황에서는 별 문제가 아닐 수도 있겠지만, 내 경우에는 이렇게 맥주소가 뒤바뀌는 현상 때문에 애드혹 네트워크(ad-hoc network)를 구성할 때마다 여간 불편한 일이 아닐 수가 없었다. 애드혹 네트워크 설정을 /etc/network/interfaces 파일에 해 두더라도, 실제로 통신이 가능해지기 위해서는 서로 ping을 주고받는 과정과 어느정도의 시간을 거쳐서 각자 ARP 테이블을 구성해야만 한다.


pi@raspberrypi ~ $ arp -n

Address                  HWtype  HWaddress           Flags Mask            Iface

192.168.3.5              ether   a0:f3:c1:2b:85:e7   CM                    wlan1

192.168.5.1              ether   10:6f:3f:e7:e8:3e   C                     eth0

192.168.3.6              ether   a0:f3:c1:2a:ca:3b   CM                    wlan1

192.168.3.7              ether   00:26:66:4c:1c:1d   CM                    wlan1

(ARP 테이블 예시)


만약 모든 라즈베리파이의 wlan1 인터페이스를 애드혹 네트워크로만 쓰기로 하고, 각 wlan1 인터페이스의 맥 주소와 고정IP 주소를 가지고 수동으로 ARP 테이블에 등록하는 스크립트를 만들어서 부팅 때마다 자동으로 실행되게 한다면, 불편하게 ping을 여러 차례 날릴 필요 없이 애드혹 네트워크를 바로 사용할 수 있게 된다. 하지만 맥주소가 부팅할 때마다 뒤바뀌면 ARP 테이블을 수동으로 추가하더라도 엉뚱한 맥주소가 등록됨으로 인해서 통신을 할 수가 없다.




<해결 방법>


udev에 network rule을 추가하면 된다. [1]

참고로 우분투 데스크탑에는 기본으로 맥주소와 인터페이스 이름을 고정해서 기억하게 되어 있다.

아래와 같은 문법으로 파일을 수정하거나, 없으면 파일을 만들어서 추가한다.


#파일명: /etc/udev/rules.d/10-network.rules


SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="aa:bb:cc:dd:ee:ff", NAME="wlan0"

SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="ff:ee:dd:cc:bb:aa", NAME="wlan1


ATTR{address} 부분에 랜카드의 맥주소, NAME 부분에 강제 지정할 인터페이스 이름을 입력한다.




<참고자료>


[1] https://wiki.archlinux.org/index.php/Network_configuration#Device_names



반응형
블로그 이미지

Bryan_

,
반응형

테스트 대상 기기: 삼성 갤럭시 노트3 네오, LGU+ (SM-N750L)

Android 버전: 4.4.2


스마트폰을 통한 네트워크 실험을 하는 과정에서, 여러 차례 와이파이에 연결된 스마트폰에 ping을 날려야 하는 경우가 있었다. 화면이 꺼져 있더라도 옵션을 통해서 와이파이에 항상 연결되어 있게 할 수는 있는데, 유독 화면이 꺼져 있을 때에 ping 속도가 느린 것 같다는 느낌이 들어서 실제로 테스트를 해 보았다.

샘플 수가 20개라서 사실 많지는 않지만, 그래도 동일한 환경에서 주변에 다른 방해하는 기기가 거의 없는 새벽 시간대에 해 본 것이라서 어느 정도 의미는 있을 것으로 생각한다.


테스트 환경으로, 라즈베리파이 2B에 hostapd를 돌려서 가상 AP로 만들고, 스마트폰이 그 AP에 연결되도록 했다.

라즈베리파이는 Raspbian Jessie 운영체제에 Atheros ath9k-htc 기반의 USB 무선랜카드를 달고 있고, IEEE 802.11n 모드로 AP를 돌렸다.

테스트용 스마트폰 외에 무선으로 연결된 다른 연결된 기기는 없었다.


아래는 화면이 꺼져 있을 때, 의 ping 결과이다.

pi@raspberrypi ~/exp $ ping 10.0.5.10

PING 10.0.5.10 (10.0.5.10) 56(84) bytes of data.

64 bytes from 10.0.5.10: icmp_seq=1 ttl=64 time=289 ms

64 bytes from 10.0.5.10: icmp_seq=2 ttl=64 time=113 ms

64 bytes from 10.0.5.10: icmp_seq=3 ttl=64 time=344 ms

64 bytes from 10.0.5.10: icmp_seq=4 ttl=64 time=157 ms

64 bytes from 10.0.5.10: icmp_seq=5 ttl=64 time=204 ms

64 bytes from 10.0.5.10: icmp_seq=6 ttl=64 time=164 ms

64 bytes from 10.0.5.10: icmp_seq=7 ttl=64 time=188 ms

64 bytes from 10.0.5.10: icmp_seq=8 ttl=64 time=9.65 ms

64 bytes from 10.0.5.10: icmp_seq=9 ttl=64 time=237 ms

64 bytes from 10.0.5.10: icmp_seq=10 ttl=64 time=276 ms

64 bytes from 10.0.5.10: icmp_seq=11 ttl=64 time=80.7 ms

64 bytes from 10.0.5.10: icmp_seq=12 ttl=64 time=105 ms

64 bytes from 10.0.5.10: icmp_seq=13 ttl=64 time=126 ms

64 bytes from 10.0.5.10: icmp_seq=14 ttl=64 time=205 ms

64 bytes from 10.0.5.10: icmp_seq=15 ttl=64 time=220 ms

64 bytes from 10.0.5.10: icmp_seq=16 ttl=64 time=258 ms

64 bytes from 10.0.5.10: icmp_seq=17 ttl=64 time=254 ms

64 bytes from 10.0.5.10: icmp_seq=18 ttl=64 time=290 ms

64 bytes from 10.0.5.10: icmp_seq=19 ttl=64 time=312 ms

64 bytes from 10.0.5.10: icmp_seq=20 ttl=64 time=135 ms

^C

--- 10.0.5.10 ping statistics ---

20 packets transmitted, 20 received, 0% packet loss, time 19025ms

rtt min/avg/max/mdev = 9.658/198.845/344.289/84.791 ms



아래는 스마트폰 화면을 켜고, 바탕화면을 전환하거나 카카오톡 앱을 한번 켜 보는 등 화면을 켜져 있도록 유지했을 때의 ping 결과이다. 카카오톡을 켤 때 잠시 서버에 접속하는 경우를 제외하고는 스마트폰에서 별도로 트래픽을 발생시키지 않았다.


pi@raspberrypi ~/exp $ ping 10.0.5.10

PING 10.0.5.10 (10.0.5.10) 56(84) bytes of data.

64 bytes from 10.0.5.10: icmp_seq=1 ttl=64 time=146 ms

64 bytes from 10.0.5.10: icmp_seq=2 ttl=64 time=67.5 ms

64 bytes from 10.0.5.10: icmp_seq=3 ttl=64 time=81.2 ms

64 bytes from 10.0.5.10: icmp_seq=4 ttl=64 time=133 ms

64 bytes from 10.0.5.10: icmp_seq=5 ttl=64 time=128 ms

64 bytes from 10.0.5.10: icmp_seq=6 ttl=64 time=147 ms

64 bytes from 10.0.5.10: icmp_seq=7 ttl=64 time=175 ms

64 bytes from 10.0.5.10: icmp_seq=8 ttl=64 time=98.5 ms

64 bytes from 10.0.5.10: icmp_seq=9 ttl=64 time=109 ms

64 bytes from 10.0.5.10: icmp_seq=10 ttl=64 time=9.62 ms

64 bytes from 10.0.5.10: icmp_seq=11 ttl=64 time=66.1 ms

64 bytes from 10.0.5.10: icmp_seq=12 ttl=64 time=81.9 ms

64 bytes from 10.0.5.10: icmp_seq=13 ttl=64 time=108 ms

64 bytes from 10.0.5.10: icmp_seq=14 ttl=64 time=139 ms

64 bytes from 10.0.5.10: icmp_seq=15 ttl=64 time=146 ms

64 bytes from 10.0.5.10: icmp_seq=16 ttl=64 time=75.2 ms

64 bytes from 10.0.5.10: icmp_seq=17 ttl=64 time=5.52 ms

64 bytes from 10.0.5.10: icmp_seq=18 ttl=64 time=4.06 ms

64 bytes from 10.0.5.10: icmp_seq=19 ttl=64 time=4.30 ms

64 bytes from 10.0.5.10: icmp_seq=20 ttl=64 time=188 ms

64 bytes from 10.0.5.10: icmp_seq=21 ttl=64 time=78.3 ms

^C

--- 10.0.5.10 ping statistics ---

21 packets transmitted, 21 received, 0% packet loss, time 20028ms

rtt min/avg/max/mdev = 4.062/95.085/188.859/54.672 ms



최소값, 최대값, 평균 모두 차이가 남을 알 수 있다.

평균을 기준으로 대략 2배 가량 전송시간(round trip time)의 차이가 발생했다.

참고로 같은 증상이 삼성 갤럭시 넥서스(버전 4.1.1)에서도 나타났다.


무슨 연유로 어디에서 이러한 지연이 발생하는지는 정확하게 알 수 없다. 하지만 아마도 스마트폰에서 의도적으로 지연을 발생시켰을 것으로 예상되며, 그 이유는 여러가지가 있겠지만 에너지 절약 차원의 목표가 있을 것이라고 추측만 하고 있다.

네트워크 실험을 할 때에는 (물론 화면을 끄고서 실험할 일은 거의 없겠지만) 스마트폰 화면의 꺼짐 유무도 잘 확인하는 것이 좋겠다.



반응형
블로그 이미지

Bryan_

,
반응형

자바에서 DatagramSocket (UDP 소켓)을 파라미터 없이 생성하거나, 포트 번호만 파라미터로 지정하면 특정 네트워크 인터페이스에 지정되는 것이 아니고, 인터페이스에 상관 없이 포트 번호만 맞으면 패킷을 주고 받는 식으로 작동한다.


실제로 인터넷에 검색해 보면 UDP 소켓을 특정한 네트워크 인터페이스에 지정하고자 하는 요구가 상당히 많은 것을 알 수 있다. 하지만 컴퓨터에 네트워크 인터페이스가 여러 개 있을 경우에 UDP 소켓에서 특정 네트워크 인터페이스를 지정하는 것이 Java Virtual Machine (JVM) 입장에서는 자연스럽지 않을 수 있다. "패킷이 컴퓨터 밖으로 나갈 때, 이를 내보낼 가장 적합한 네트워크 인터페이스를 선택한다"는 보편적인 논리에서 보면 이것은 원래 운영체제(OS)에 내장된 라우팅 프로토콜의 역할이기 때문에, User mode에 있는 JVM 위에서 돌아가는 자바 어플리케이션이 이 역할에 일부분 끼어드는 것처럼 보이는 것이다. 아무튼 자바 어플리케이션 입장에서 불가능하지는 않지만, 바람직한 구성은 아닐 수도 있다.


어쨌든 패킷을 받는 서버 입장에서 DatagramSocket을 생성할 때, 생성자(constructor) 파라미터에 특정 IP 주소와 포트 번호를 모두 파라미터로 넘김으로써 특정 네트워크 인터페이스에서만 패킷을 받도록 지정할 수는 있다.


byte[] receiveData = new byte[1024];

String ip = "192.168.3.4"; // 현재 컴퓨터의 특정 네트워크 인터페이스에 할당된 IP 주소

String port = 54321; // 원하는 포트 번호

DatagramSocket socket = new DatagramSocket(new InetSocketAddress(ip, port));

DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);

socket.receive(receivePacket);


패킷을 보내는 클라이언트 입장에서는, 그냥 DatagramPacket을 보낼 때 destination IP 주소를 어떻게 지정하느냐에 따라서 특정 네트워크 인터페이스를 통한 전송 여부가 결정된다. 이것은 운영체제의 라우팅 테이블 설정을 따라간다.


byte[] sendData = new byte[1024];

// sendData에 대한 메세지 생성 작업 수행

String ip = "192.168.3.6";

int port = 54321;

DatagramSocket clientSocket = new DatagramSocket();

DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName(ip), port);

clientSocket.send(sendPacket);


예를 들어, 리눅스의 route 설정이 유선랜 eth0과 무선랜 wlan0 모두 활성화되어 있고, default (0.0.0.0)에 대한 게이트웨이가 유선랜(eth0) 게이트웨이로 설정되어 있다고 가정하자. 이 때, 로컬 네트워크 밖에 있는 인터넷 상의 어떤 기기에 UDP 패킷을 보내고자 한다면, 자바 어플리케이션은 eth0을 통해서 패킷을 보낼 것이다. 이런 경우에 반드시 무선랜 wlan0으로 패킷이 나가도록 하고 싶으면 리눅스에서 route 명령으로 wlan0을 통해서 인터넷으로 나가는 경로를 설정해 주어야 한다.


문제는 서버의 입장에서 DatagramSocket에 특정 IP 주소를 지정해 버리면, 브로드캐스트(broadcast) 메세지를 받지 못하는 문제가 생긴다. 상대편에서 정확하게 IP 주소를 지정해서 보내는 경우에만 패킷을 받을 수 있고, 테스트해 본 결과, 가령 192.168.3.255 와 같은 destination IP로 전송되는 패킷은 받지 못했다.


이 경우에는 서버의 입장에서는 특정한 IP 주소를 지정하지 말고 모든 인터페이스와 모든 주소에 대해서 받을 수 있도록 해 두고, 일단 패킷을 받고 나서 전송자의 IP 주소 대역을 보고 판단하는 루틴을 코드에 추가하는 것이 좋을 것 같다. (이것이 best solution인지는 알 수 없으나, 현재로써는 이것이 working solution이다.)


byte[] receiveData = new byte[1024];

String port = 54321; // 원하는 포트 번호

DatagramSocket socket = new DatagramSocket(port);

DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);

socket.receive(receivePacket);




반응형
블로그 이미지

Bryan_

,
반응형

전화상으로 진행하는 코딩 면접을 위해서 예상 문제들을 살펴보며 어떻게 해결할 수 있을지 머리속으로 그려 보고, 더러는 종이나 메모장에 바로 pseudo code를 작성해 보고 있다. 그런데, 내 생각을 정리해서 "깔끔하게" 문제를 해결하는 순서를 설명하기가 예상하는 것보다 쉽지 않다. 


주어진 문제를 보고 입력과 출력이 어떻게 되어야 하는지는 비교적 쉽게 정의할 수 있다. 문제는 입력으로부터 출력까지 도달하기 위해, 거시적인 안목에서 어떤 순서를 거쳐야 하는지를 단번에 나열하는 것은 쉽지 않다. 거시적인 안목, 즉 top-down approach로써 문제를 생각해 보려고 노력하는데, 일단 top-down 측면에서 옳다고 생각해서 나열한 순서를 다시 한번 자세히 따져 보면 비효율적인 방법임을 깨닫게 되는 것이다. 예를 들어, 일단 큰 그림에서 문제 해결의 순서를 plain text 형식의 코멘트로 써 놓고, 해당 코멘트에 대응하는 실제에 가까운 코드를 작성하다 보면 뒤늦게 지금 작성중인 이 방법이 결코 효율적이지 않다는 사실을 깨닫는 것이다.

Top-down 관점에서 큰 순서에 영향이 없이 세부적인 부분을 개선하는 방식으로 생각을 좁혀 가는 것이 문제를 해결하는 가장 이상적인 방법이지만, 충분히 고민하지 않은 채로 큰 그림을 얼른 대충 만들게 되면 나중에 top-down 측면의 순서를 모두 고쳐야 하는 불상사가 생기기도 한다. 즉, 근본적으로 방향을 잘못 짚는 경우에 해당한다.


그러면 어떻게 해야 할까? 가장 이상적인 방법은 두말할 것도 없이 처음부터 효율적인 해결책을 top-down 관점에서 설명하고, 그 순서대로 코드를 구체화시켜 가는 것이다. 하지만 그렇게 바로 생각해낼 수 없다면, 위와 같이 해결방법에 큰 수정이 발생하더라도 이를 감수하고 다시 차근차근 고쳐 가는 것이 안전할 것이다. 일단 간단한 해결책부터 먼저 제시해 놓고, 그것을 검토하면서 더 효율적인 방법으로 코드를 수정해 가겠다고 지속적으로 면접관들에게 설명하면서 멈추지 않고 진행하는 것이다.

적어도 이렇게 하는 것이 심리적 압박감으로 인해서 아무 것도 생각해 내지 못하고 머리가 하얗게 되어 버리는 것보다는 나을 것이다. 결국 어떤 상황에서도 평정심을 유지한 채 점진적이고 지속적으로 답을 발전시켜 나가는 마인드 컨트롤의 문제로 볼 수도 있다.

처음부터 조금 더 효율적인 알고리즘의 큰 그림부터 그려나갈 수 있도록 꾸준히 예상문제들의 해결 방법을 생각하고 코드로 연습하는 것 외에는 왕도가 없어 보인다. 조금 더 노력해 보자...


반응형
블로그 이미지

Bryan_

,