Skip to main content

· 6 min read

웹 접근성 관련 작업을 할 일이 생겨서 AChecker라는 서비스를 살펴보게 되었다.

AChecker는 사용자가 입력한 URL에 대해서 지정한 웹접근성 Guideline(이하 WAG)을 준수하고 있는지 검사를 해주는데, 기본으로는 HTML 형태로 출력해주지면 감사하게도 REST API 역시 제공하고 있다. REST API를 사용할 경우 Output type은 XML 뿐이다.

1. 문제점에 대한 인지

사용해보면서 기능에 대해 몇가지 검토를 하는 도중에 검사 대상이 되는 페이지에 한글이 포함되어 있는 경우 XML 이 깨지는 문제를 발견하게 되었고 좀 더 명확한 문제의 원인을 알기 위해 소스코드를 살펴보기로 했다. AChecker의 소스코드는 Github에 등록되어 있어서 브라우저로 소스를 살펴보기가 나름 편하다. 깔끔하기도 하고.

PHP로 되어있는 코드를 이리저리 살펴보니 (난 PHP를 잘 모른다. 하지만 상세한 문법과 함수들을 모르더라도 훑어보고 문제가 될만한 부분을 찾는데에는 문제가 없다고 생각했다) REST API에 대한 클래스의 인코딩이 조금 이상하다는 걸 발견할 수 있었다. (ISO-8859-1 이었음) EUC-KR이나 UTF-8이 아니라면 한글 표시에 문제가 발생할 수 있겠다 생각을 하면서 REST 말고 HTML 생성하는 부분도 살펴보니 HTML은 UTF-8로 생성하고 있었다. 문제가 되는 URL에 대한 검사 결과를 비교해보니 역시나 HTML로 output을 받을 때에는 전혀 문제가 발생하지 않았고 최종적으로 encoding이 원인이라는 것을 확신하게 되었다. 또 어디를 수정해야 하는지도... (PHP를 몰라도 검색을 좀 해보니 해결책을 찾기가 어렵진 않았음)

2. Contribution을 하자

내가 업무에 쓸거니 그냥 나만 수정해서 쓸까 했는데, 예전부터 마음먹고 있던 Open source 활동을 시작하는 기회로 만들면 어떨까하는 생각이 들었고 별 고민없이 진행하기로 했다. 어차피 수정할 내용이 많지도 않아서 시간 소모가 작을 것 같다는 생각이 마음을 좀 더 편안하게 해주었다.

3. Fork

우선은 AChecker 저장소를 fork 하기로 했다. Github에서 fork는 원래의 저장소를 따와서 내 계정에 동일한 저장소를 만드는 과정을 의미한다. Fork를 하니 아래의 그림처럼 내 계정에 동일한 저장소가 만들어진다.

스크린샷 2014-02-04 오후 12.51.50

4. 작업

Fork한 저장소를 clone해야 내가 수정할 수 있다. 물론 원래의 저장소를 clone해서 수정해도 되겠지만 pull request를 할 것이므로 fork한 저장소를 clone 해야 한다. SSH로 clone도 하고 push 하는게 편하기 때문에 미리 github에 public key를 등록해 주었다. 그 이후엔 내가 쓰는 환경에서 코드를 수정했고, 테스트를 해봤다. 잘 된다. 문제가 해결되었다. 그 다음엔 commit. 내가 등록하는 commit message가 그대로 남기 때문에 혹시나 AChecker만 가지고 있는 commit message rule 같은게 없는지 살펴봤는데 제약사항이 없는 것 같았으므로 적당히 알아볼 수 있도록 message를 등록했다. 그리고 push해서 fork한 내 저장소에 commit이 제대로 올라갔는지 확인.

스크린샷 2014-02-06 오후 7.07.29

5. Pull request

Fork한 저장소에는 반영되었으니 이제 pull 해가라고 요청해야 한다. AChecker 저장소 페이지로 이동해 Pull Requests 메뉴로 가보니 새로 등록하는 버튼이 있다. (아래 그림 오른쪽 상단 녹색 버튼) 버튼을 누르니 fork한 저장소에 등록된 commit message가 title에 입력되어 있다. 적당히 제목과 내용 적어서 완료.

스크린샷 2014-02-06 오후 7.07.07

등록하고 나면 Pull Requests list에 표시되고 Issues에도 함께 나타난다.

이제 결과만 기다리면 되겠다.

· 5 min read

1. Adapter pattern

Wrapper pattern 혹은 단순히 wrapper 로도 불리우는 디자인 패턴으로 서로 호환성이 없는 상황에서 하나의 인터페이스를 다른 인터페이스로 변환하는 과정을 거쳐 사용이 가능하도록 만들어준다. 호환성이 없어서 한 인터페이스를 구현한 클래스들을 사용하지 못할 때 가능하게 만들어주는 역할을 하는 것을 Adapter라고 부르며, Adapter에 맞춰서 변환하는 대상을 Adaptee로 한다. (아래 그림 참조)

300px-ObjectAdapter

 

위 UML에서는 인터페이스와 구현 클래스에 대한 구분이 없지만 유연성을 위해 일반적으로 인터페이스와 인터페이스 간의 composition을 많이 활용하는 것 같다. 쉽게 실제 사물을 이용한다고 가정해보자. Macbook 사용자들은 외부 디스플레이 출력을 위해서 Mini Display Port만 사용해야 한다. 반면에 일반적인 모니터들은 HDMI, DVI, RGB(VGA) 입력만을 받는다. 그 중 DVI를 사용해 연결하겠다 마음을 먹었다면 Mini Display Port to DVI adapter를 시중에서 구매해야만 가능하다. 둘의 인터페이스가 다르기 때문이다. UML상에서 보면 Mini Display Port는 Client가 되고 DVI는 Adaptee가 된다. 그리고 Mini Display Port to DVI adapter는 이름대로 Adapter의 역할이다. Adapter의 구현은 Mini Display Port의 인터페이스를 그대로 구현하되 내부에서는 Adaptee인 DVI의 객체를 갖고 DVI 객체가 갖고 있는 함수를 호출하는 방식으로 진행하면 된다. 실제 Mini Display Port 변환 adapter가 내부에서 함수를 호출하지는 않겠지만...

 

2. Facade pattern

Facade의 의미는 Wikipedia를 인용하자면 앞면, 얼굴 등을 의미하는 프랑스어에서 넘어온 단어로 일반적으로 빌딩의 외형을 의미한다고 되어있다. 의미 그대로 facade pattern은 여러 라이브러리를 사용할 때나 많은 양의 코드에 대해 간단한 인터페이스를 제공하기 위한 디자인 패턴으로 facade는 그러한 인터페이스를 제공할 수 있는 object를 말한다. Facade는 간단한 함수들을 제공함으로써 라이브러리나 코드들에 대해 깊이 알지 못해도 사용을 쉽게 하고자 하는데 의의가 있다. 또 Adapter pattern과 마찬가지로 여러 API들을 wrapping 하는 역할을 할 수도 있다.

FacadeDesignPattern

 

예를 들어 로봇을 만드는데 '잔다' 기능을 구현한다고 하자. 자기 위한 절차만 간단히 정리하자면 욕실에 가서 씻고 (치약을 짜서 양치질을 하고, 세수를 하거나 경우에 따라서는 화장을 지워야 할 수도 있고 샤워를 한다) 이부자리를 정리한 후, 물을 한모금 마시고, 현관문이나 창문이 열려있지는 않은지 검사하고, 불을 끈 후에 눕는다. 이 모든 세부 기능들이 각각의 버튼으로 제공되고는 있지만 (매번 누를 수는 없으니) 버튼 하나로 '잔다' 기능을 수행하도록 만들고 싶다면 Facade pattern을 사용해 Facade 클래스와 sleep 함수를 구현하면 되겠다.

 

3. 참고자료

Adapter Pattern : http://en.wikipedia.org/wiki/Adapter_pattern

Facade Pattern : http://en.wikipedia.org/wiki/Facade_pattern

· 4 min read

Strategy pattern은 간단히 생각하면 strategy를 runtime에 결정할 수 있도록 만드는 pattern으로 생각하고 있다.

개인적으로는 pattern 공부하면서 가장 인상적이고 재미있는게 strategy pattern 이었다.

 

1. Strategy pattern의 특징과 구조

Strategy pattern을 사용하면 알고리즘(또는 strategy)의 행위를 runtime에 변경하는 것이 가능하다. Strategy pattern을 적용한다는 것은 알고리즘군을 정의해서 캡슐화하며 서로 교환할 수 있게 만드는 과정이라고 생각할 수 있는데, 알고리즘과 알고리즘을 사용하는 객체나 기능과의 독립성을 유지하고 좀 더 쉽게 다양화할 수 있다. 아래의 구조를 바탕으로 설명하면,

Strategy_Pattern_in_UML

 

Strategy interface를 사용함으로써 하나의 알고리즘군을 따로 정의해서 캡슐화하며, 각각의 알고리즘들은 별개의 Concrete class에 구현한다. 알고리즘을 사용하는 객체와의 독립성 유지는 interface로 분리된 알고리즘 자체만으로도 어느정도 가능하지만 핵심은 Context에서 상속대신 composition (UML은 composition으로 표기되어 있지만 aggregation 이어도 문제없다고 생각함)으로 알고리즘과의 관계를 구성한다는 사실이다.

아래의 구조로 strategy pattern을 사용하지 않을 때와 비교를 해보자.

400px-StrategyPattern_IBrakeBehavior.svg

 

Accelerate와 Brake라는 행위가 가능한 Car class를 만든다고 했을 때 자동차 모델에 따라 Accelerate와 Brake도 다양하게 늘어날 것임을 예상할 수 있다. 이 부분이 변경될 가능성이 높은 부분인데 일반적인 경우처럼 상속을 받아 subclass로 구현을 해버리면 행위가 늘어날수록 변경해야 하는 소스가 늘어나게 된다. 그러므로 이런 경우 변경 가능성이 높은 부분 (Accelerate, Brake)을 따로 분리해서 캡슐화를 해버리고, 행위를 사용하는 Car class에서 각각의 행위를 composition (위 UML에서는 dependency 관계로 되어있지만) 관계로 연결을 하면 행위와 주체와의 결합도를 낮추고 독립성을 높일 수 있다. 위와 같은 구조에서 행위는 그것을 사용하는 class와 관계없이 변경하는 것이 가능하다.

 

2. Dependency injection과 strategy pattern

Wikipedia에서는 dependency injection과 strategy pattern을 별개의 design pattern으로 분류하고 있지만 runtime에서 dependency 있는 부분의 변경을 위해 결합도를 낮추기 위해 strategy pattern을 확장한 사례라고 생각한다. Dependecy injection은 SW testing에도 종종 사용되는 기법이다.

 

3. 참고자료

Strategy Pattern : http://en.wikipedia.org/wiki/Strategy_pattern

Dependency Injection : http://en.wikipedia.org/wiki/Dependency_injection

· 7 min read

시간이 지날수록 스트레스가 심해지는 것 같아서 GTD를 사용해 보기로 했다.

스트레스는 마음의 병이라 치유하지 않으면 그게 곧 말이나 행동에 반영이 되는 것처럼 느껴졌다.

그럼 나의 스트레스는 주로 무엇때문에 발생하는가? 를 생각해보니 보통 이런 것들에 기인했던 것 같다.

(1) 기대(이상)와 현실의 괴리

(2) 업무와 사생활의 불균형

(3) 복잡한 상황의 누적

 

(1)은 개인마다 차이가 있겠지만 나의 경우에도 스스로에게 거는 기대치가 실제 내 역량이나 상황보다 높았다고 생각된다.

이렇다보니 업무와 사생활이 비대칭을 이루게 되었는데 여기서 오는 스트레스도 상당했는데 가족들에게 소홀하니 미안함에 스스로를 더 피곤하게 만들었고 그게 나 자신에게 또 하나의 과부하를 거는 요소로 작용했다. 이런 환경에서는 대부분의 일과 상황들이 복잡하게 엉켜서 한꺼번에 닥치곤 하는 것 같다. 여기에 스트레스를 해소하기 위한 나만의 어떤 방법들, 예를 들면 취미 같은 것들이 마땅치 않아서 상황은 더 좋지 않았다.

 

나의 경우를 봤을 때 스트레스가 누적되면 처음엔 짜증이 생기고, 연이어 불안, 우울이 동반되는 것 같다.

그래서 이런 상황을 개선하기 위해서 몇가지를 스스로에게 테스트해 보기로 했고 그 중에 하나가 GTD 활용이다.

 

1. GTD의 개념

GTD(Getting Things Done)는 David Allen이라는 사람이 주장한 관리 방법이라고 한다.

유명한 Franklin Covey의 관리 기법과의 차이를 가지고 풀어보면, Franklin의 방법은 본인이 추구하는 가치가 더 높은 것에 집중할 수 있도록 하는데 반해 GTD는 먼저 할 수 있는 것부터 처리하라고 장려하고 있다. GTD가 스트레스를 줄여줄 수도 있겠다고 생각한 이유는 아래와 같다.

(1) Franklin의 방법을 사용했을 때에는 좀 더 가치있는 일을 먼저 해야 했는데 이런 종류의 일은 보통 시간을 오래 투자해야 하기 때문에 중간에 어떠한 이유로든 방해를 받기 쉬웠다. 훈련이 되면 좀 나아질 수도 있겠지만, 사람 일이라는게 예측이 쉽지 않아서 예상대로 흘러가지 않는 경우 다음으로 미루어야 하는 경우가 종종 발생했고 여기에서 오는 스트레스는 최소한 줄일 수 있을 것 같았다. 빨리 끝날 것 같은 것부터 하면 되기 때문에 그만큼 방해를 받을 여지가 줄어들 것이다. GTD는 좀 더 유연하게 계획하고 실행하기 쉬울 것 같다는 생각이 든다.

(2) GTD는 생각나는대로 할 일을 Inbox에 집어넣고(수집), 다음 단계로 넘어가 분류한 후에 일정 등을 세우고 검토하도록 되어있다. 이런 일련의 과정이 한 번 끝나고 나면 조건과 상황 (Context)에 따라 리스트대로 보고 마음대로 골라서 실행하면 된다. 즉 장기적인 관점에서 복잡하게 고민할 것이 없다. 내가 이해한 내용이 맞다면 그냥 생각나는대로 넣고 보이는대로 하면 되는 것이다.

 

GTD에서 일의 단위를 처리하는 과정은 아래와 같다.

gtd

 

 

2. GTD의 단점을 극복하기 위한 방안

GTD에 대한 자료를 찾아보니 단점들도 있다. 가장 눈에 띄는 것은 개인의 창의성을 저해할 수도 있다는 내용이었다. 분류를 하기는 하지만 가치에 대한 평가가 덜 한 상태에서 할 일 리스트를 무작정 넣어두고 실행만하는 방법이기 때문에 효율성은 높을 수 있지만 고민을 상대적으로 덜고 (장점이기도 하지만) 진행하는 것이므로 충분히 그럴 수 있겠다는 생각이 든다. 그래서 GTD를 좀 응용해서 해 볼 계획인데, 실행하는 절차는 GTD의 방법대로 하되 무엇을 실행할지는 장기적인 관점에서 고민해서 결정하면 어떨까 싶다. Franklin의 방법처럼 더 높은 가치를 갖는 일들을 많이 배정하는 식으로 해도 괜찮을 것이다.

 

3. 참고했던 자료

(1) David allen의 page : http://www.davidco.com/about-gtd

(2) GTD의 기본 내용을 살펴봤던 자료 : http://www.slideshare.net/phploveme/gtd-how-to-start-gtd

(3) Omnifocus를 활용한 GTD 관리 방법

· 3 min read

Eclipse plugin 중에 node.js를 위한 nodeclipse를 사용하고 있다.

초기에는 다른 경로를 사용하다가 언젠가부터 update site가 아래 경로로 바뀌었는데

New update site : nodeclipse.org 참조

http://dl.bintray.com/nodeclipse/nodeclipse/0.7.0/

좀 더 좋아지긴 했다. (Windows 용만 봤을 때에는)

가장 큰 개선점이라고 한다면 windows에서의 "express project 생성 가능" 이라고 개인적으로 생각한다.

(Coffee script 지원 등은 어차피 내가 아직은 사용하지 않는 기능)

제대로 설치가 안되서 애를 먹었는데 아래와 같은 일을 겪고 진행해서 해결했다.

 

1. node.js core / 기타 plugin 설치 불가

Helios를 사용중이었는데 update site가 변경되기 전에는 잘 썼던건데 update site 변경해서 새로 설치해보니

포함된 일부 플러그인이 설치가 안되는 걸 발견했다.

나머지는 대충 넘어갈 수 있는데 core가 설치가 안되서 어쩔 수 없이 해결하고 넘어가야 했다.

공식페이지에 설치 조건 등에 언급이 되어있었으면 좋았는데 알아보니 Eclipse Indigo 이상 가능하다.

http://stackoverflow.com/questions/17418747/nodeclipse-org-eclipse-wst-jsdt-core-not-found-when-installing-into-eclipse

최신인 Luna 설치한 후 plugin을 제대로 설치했다. (내 신발도 luna eclipse 인데...뭔가 잘 풀리려나)

 

2. Terminated, terminated, terminated, ...

설치 후 기존 project들 실행했는데 실행하자마자 로그도 없이 곧바로 terminated 되는 현상이 있었다.

알아보니 JDK 문제인 듯 싶었다. (왜 jdk version을 타는지 알 수 없다. 이해가 안된다)

http://stackoverflow.com/questions/19689501/togglebreakpointstargetfactory-specified-id-is-already-registered

 

3. JDK7 설치 후 eclipse 실행 불가

이런 일은 version up 하면 가끔 생기는 문제라 어느 정도 익숙하다.

JDK7 설치 후 Eclipse 실행시 아래와 유사한 형태의 팝업이 등장한다.

Could not create the java virtual machine

eclipse.ini에 vm 경로를 명시하고 memory를 너무 과하게 잡지 않으면 실행이 되는 걸 발견할 수 있다.

나의 경우엔

-vm C:\Program Files\Java\jdk1.7.0_45\bin\javaw.exe

을 ini에 추가하고 Xmx를 1024m으로 했다가 안되서 512로 변경했더니 정상 실행.

 

4. 행복한 결말

제대로 실행된다. 문제없다. 하지만 이런 종류의 dependency는 사실 좀 귀찮은 문제다.

· 7 min read

1. BullseyeCoverage?

BullseyeCoverage (이하 Bullseye)는 bullseye.com에서 판매하고 있는 C/C++ code의 coverage를 측정할 수 있는 툴로 C/C++이 동작하는 여러 환경에 따라 분석이 용이하게 되어있다.

Code coverage는 Wikipedia에 설명된 대로 어느 정도로 테스트 되었는지를 나타내는 지표 중 하나로 실제 현업에서는 function coverage, condition/decision coverage, statement coverage를 주로 사용하게 되는 것 같다. 사실 SW testing이 개발 단계에서의 프로세스로 잘 자리잡고 있다면 coverage 라는게 여러 측면에서 활용도가 높을 수 있겠지만 경험상 많은 곳에서 활용되고 있는 것 같지는 않다. 또 그렇기 때문에 이런 툴을 담당하는 사람들 역시도 많지 않아 보인다. Google에서 검색을 하더라도 Bullseye에 대한 설정이나 troubleshooting에 대한 자료를 찾기가 쉽지 않은데 무언가를 개발하거나 어떤 툴을 사용할 때 보다 많이 애를 먹게 되었다. 사실 제일 도움이 많이 된 자료는 Bullseye.com의 help page와 개발자로 알려져 있는 Steve Cornett과 주고 받은 email 이었다.

2. 환경변수를 설정해야 한다

Bullseye는 어찌보면 간단한 원리를 사용하고 있는데 C/C++ 소스를 컴파일할 때 컴파일러 이전에 Bullseye가 가지고 있는 covc란 파일을 실행함으로써 소스코드에 계측코드를 심은 후에 컴파일을 수행한다. 이렇게 컴파일된 소스들은 실제 runtime시에 계측코드를 호출하게 되고 계측코드는 cov라는 coverage 초기 정보를 담고 있는 파일 내부에 기록을 한다.

Coverage 측정 후에도 cov 파일의 크기에는 변함이 없는데 이는 이미 컴파일 단계에서 초기 정보를 기록한 cov 파일 내부의 data를 단순히 변경하기 때문이다.

Bullseye를 사용해서 컴파일(빌드)을 하고 나서 측정 전에 해야하는 중요한 일 중에 하나가 runtime 환경에서 계측코드가 읽어들일 수 있는 환경변수를 설정하는 것이다.

환경에 따라 차이는 있겠지만 보통 필수로 지정하게 되는 환경변수로 COVFILE이 있는데 이 변수에 계측코드가 호출되면서 기록할 cov 파일 경로(파일명 포함)를 지정하면 된다. (만약 COVFILE 환경변수가 없으면 기본적으로 /test.cov를 읽도록 되어있다.)

3. libcov를 수정하자

가장 최근에 경험한 환경에서는 측정을 방해하는 몇가지 문제가 있었는데

(1) 환경변수 설정은 가능하지만 계측코드가 인식하지 못함

(2) 특정 경로 이외에는 쓰기 금지

(1)의 문제는 제공하는 환경변수 지정 방법 몇가지를 사용해 봤으나 계측코드가 절대 인식하지 못하는 상태였다. 왜 계측코드가 환경변수를 읽어들일 수 없었는지는 명확한 원인을 알 수는 없었는데 환경변수를 제대로 읽어들이고 있는지 로그를 추가해서 읽어들이지 못한다는 현상 자체는 파악할 수 있었다.

(2)의 문제는 여유없는 자원과 기타 보안을 이유로 만들어진 상황으로 내가 해결할 수는 없는 문제였고 다행히 쓰기가 가능한 경로를 파악하는 것 만으로 만족할 수 밖에 없었다.

테스트할 환경에서 환경변수 지정을 하지 못한다면, 하더라도 무의미하다면 어떤 방법을 사용할 수 있을까?

대략적인 원리만 알고 있는 상태였지만 Bullseye 설치 후 각 환경에 맞게 컴파일해서 라이브러리로 만들어야 하는 libcov 소스를 수정해 보기로 했다.

linux 환경이었기 때문에 정확히는 libcov-posix.c 파일이다. (Bullseye 설치 경로의 run 디렉토리 아래에 있음)

libcov-posix.c 파일을 열어보면 아래와 같은 함수를 볼 수 있다.

static char* Libcov_genenv(const char* name)
{
char* value = getenv(name);
const int errnoSave = errno;
if (value == NULL) {
value = getenvFile(name, "/tmp/BullseyeCoverageEnv.txt");
}
if (value == NULL) {
value = getenvFile(name, "/etc/BullseyeCoverageEnv.txt");
}
errno = errnoSave;
...
...

다른 함수들을 포함해서 보면 Bullseye는 환경변수에 등록된 COVFILE을 읽어들인 후에 유효하지 않으면 /tmp/BullseyeCoverageEnv.txt 파일을 읽어서 COVFILE 등의 환경변수를 읽는다. 이것 역시 유효하지 않으면 /etc 경로에 있는 같은 이름의 파일을 읽게 된다. 역시나 환경적인 이유로 /tmp나 /etc 경로를 사용할 수는 없었다. (/tmp는 reboot 시에 추가한 파일이 삭제되고, /etc는 쓰기 금지 영역)

그래서 결국은 쓰기가 가능한 경로를 지정해서 먼저 읽어들이도록 libcov-posix.c 파일을 수정해버렸고 측정시 정확히 COVFILE을 인식하는 걸 확인할 수 있었다.

(참고 : 실제 수정해서 사용한 Libcov_getenv 함수는 별도 환경변수를 설정하지 않는 이상 초당 1회씩 호출되는 함수이다. Bullseye는 별도 설정이 없다면 초당 1회씩 COVFILE에 기록하려고 시도함)

· 4 min read

1. Disable session

구현중인 REST API에서 SNS 연동이 필요한 부분이 있다. (API server에서 SNS 연동까지 해야하는지는 고민중이지만)

REST API는 session 유지를 해서는 안된다고 많은 참고자료들에서 언급이 되고 있는데 (인증에 대한 정보를 API 호출시 넘기도록 함)

SNS와의 OAuth를 위해 살펴본 node.js의 passport 모듈에도 관련 내용이 기술되어 있다.

참고 링크 : http://passportjs.org/guide/authenticate/

스크린샷 2013-11-06 오후 11.35.11

Passport는 인증과 관련된 기능을 좀 더 쉽게 처리하고자 만들어진 모듈인데, 인증 기능을 다룬 부분에 session이 필요없을 경우 disable이 가능하도록 옵션을 제공하고 있는 것을 알 수 있다. 그리고 굳이 API server와 같은 상황을 예로 들고 있다.

2. Passport를 활용한 strategy의 구현부 (Session 강제)

Passport를 활용하고 있는 모듈들이 몇가지 있는데 주로 passport의 API만 가지고 구현하기 번거로우니 특화된 기능을 사용하기 쉽게 정리해놓고 있다. passport-oauth, passport-twitter, passport-facebook 등이 그 예인데, twitter와 연동해보려고 간단히 사용해보니 session을 사용하지 않으면 오류가 발생하는 걸 확인했다. passport-twitter가 포함하고 있는 passport-oauth1 (OAuth 1.0을 구현, 링크 : https://github.com/jaredhanson/passport-oauth1)의 strategy.js (실제 대부분의 기능을 담고 있는 구현부)를 보니 120번째 라인에서 request에 session이 없는 경우 오류를 리턴하도록 구현되어 있었다.

스크린샷 2013-11-06 오후 11.39.59

passport-oauth1은 passport-oauth와도 관계가 있는 모듈로 passport 자체는 session을 disable 할 수 있도록 되어있지만 passport를 활용한 다른 모듈들은 사실 session을 강제하고 있다. 실험삼아 session disable이 가능한 authenticate 함수에서 disable option을 담아서 호출해 봤는데 결국 마지막에 호출되는 passport-oauth1에서 오류가 발생하는 걸 확인할 수 있었다.

3. 결국 oauth 구현

passport.js만을 이용해서 SNS 연동을 할 수도 있겠지만 passport 자체가 OAuth만을 위해 만들어진게 아니라서 작업이 번거로울 것 같다는 생각이 들었다. 어찌되었든 비슷한 기능을 하는 다른 모듈을 찾거나 결국은 내가 직접 구현을 해야하는 상황. node-oauth (npm에서는 oauth라는 이름, 링크 : https://github.com/ciaranj/node-oauth) 라는 모듈을 passport 대신 사용해서 직접 구현할 생각이다.

· 3 min read

원격지에서 samba로 공유되고 있는 파일이 존재하는지를 확인하기 위해서 smbclient를 이용해봤다.

아래와 같은 command를 shell에서 호출하고 나서

smbclient //${server}/${service} ${password} -c "ls ${dir}/${file}"

exit code를 $?로 판단하면 파일이 존재유무를 손쉽게 확인할 수 있다.

고생을 했던게 ${service}.

단순히 알고 있는게 samba 경로였기 때문에 전체 경로를 다 넣어보니 연결이 안되었었다.

samba로 공유된 파일들에 대해서 나처럼 경로에 대한 정보만 알고 있다면 첫번째 디렉토리만 service 항목에 넣으면 된다.

패스워드 유출 문제가 불안하면 authentication file을 만들어서 입력하는 방법도 옵션으로 제공하고 있다.

-c는 접속 후 전송할 command를 추가할 때 사용하는 옵션.

나머지는 smbclient의 man page를 참조하면 되겠다.

man page에도 나오지만 authentication file은 아래의 형태로 생성해서 -A 옵션으로 파일명을 명시해야 한다.

username = <value>
password = <value>
domain = <value>

난 왜 이 것을 시도했는가?

자동화 시스템에서 파일을 scp로 전송 후 파일이 제대로 전송되었다면 특정 사이트에 경로를 기록해야 하는 상황이었다.

scp를 사용했으면 ssh로 command 전송해서 하면 되지 않나? 라는 생각이 들지만

문제는 파일이 쌓이는 서버쪽 정보는 내가 전혀 알지도 못하고 알게 두지도 않았다.

scp로 전송시 필요한 ssh password도 내가 아닌 알고 있는 제3자가 입력해서 암호화되어 저장된 그런 상태...

원격지에 파일이 전송되는 경로가 사실은 Samba 뿐 아니라 FTP로 운영되는 경로이기도 했는데, 역시나 FTP 정보를 알 수도 없었다.

어디까지나 일반 사용자 입장에서 서버 요구사항을 해결해야 했던 경험.

· 3 min read

Git을 사용하면서 여러명의 사용자가 하나의 저장소에 push를 할 때 종종 오류와 함께 push가 안되는 상황이 발생한다.

(fatal: failed to write object 와 같은 오류가 발생하는 경우임)

원인은 push할 원격 저장소(.git)의 objects에 파일을 써야 하는데 권한이 없기 때문인데

이미 objects를 A라는 사람의 이름으로 생성을 했는데 B라는 사용자가 같은 파일에 대한 쓰기를 시도(A가 이전에 만든 파일을 수정해서 push)하게 되고

이 때 objects의 파일들이 group이나 others에 대한 쓰기 권한이 없는 상태인 경우이다.

Linux에서 umask를 적절히 변경해서 사용하고 있고 사용자에 대한 기본그룹이 사용자 계정이 아닌 공통으로 사용하는 그룹으로 지정되어 있다면 문제가 없다.

이와 관련한 git의 config가 있는데 바로 core.sharedRepository이다. (참조 : http://git-scm.com/docs/git-config)

옵션에 대한 값은 group (true), all (world, everybody), umask (false) 까지 제공되는데 group이나 true로 했을 경우 저장소 내에 파일 생성시 그룹 쓰기 권한을 세팅하게 되고, all은 모든 사용자가 읽기 가능 + 그룹쓰기 권한, umask나 false로 설정시 umask 값에 따라서 권한 설정을 하게 된다. Default는 umask (false).

 

이 옵션을 설정하지 않았다 하더라도 umask와 기본 그룹 설정만 하면 되니 별 문제가 없는게 일반적인데 가끔 신규 서버 구축시 기본그룹 설정을 잊어버렸다면 써먹을만 하다.

git 자체가 사용자 관리에 대한 제대로 된 기능이 없다보니 그래도 가장 좋은 방법은 사용자 관리가 손쉬운 다른 tool을 함께 사용하는 방법이라고 본다.

· 2 min read

Ubuntu 설치를 하면 apt-get으로 package를 받아오는 서버가 기본적으로 kr.archive.ubuntu.com으로 설정된다.

kr.archive.ubuntu.com에 어떤 이슈가 있는지는 모르겠지만 가끔씩 연결이 안되는 경우가 발생하곤 한다.

게다가 속도도 느리다. (내 환경에서는 다운로드 속도가 초당 100 ~ 200KB 정도)

느리고 불안정한데 바꿔주자.

/etc/apt/sources.list 파일을 열어 kr.archive.ubuntu.com들을 모두 ftp.daum.net으로 변경한다.

변경한 이후에는 sudo apt-get update를 꼭 실행해야 이후 package install에 문제가 없다.

ftp.daum.net으로 변경한 이후 속도는 초당 약 3MB 정도로(나의 경우) 과거보다는 좋아짐.

 

난 왜 바꿨는가?

kr.archive.ubuntu.com을 아무 생각없이 사용하는데 install이 안되는 경우가 발생했고 ftp.daum.net으로 변경하니 잘 되서. 빠르고.