[생활코딩] 아침에 갑자기 생각난김에 yes24 api server 만들기

어제 저녁 이동국님과 토비님을 만나서 이런 저런 얘길 하다보니 자연스래 책 얘기에 빠졌다. 그러다가 서로의 판매지수와 순위를 이야기하며 이런 정보를 push 받고 싶다는 이야기가 나왔고, 토비님이 “생활코딩좀 해~”라고 하시길래.. 번뜩…

그래 예스24에서 API 서버 안만들어주면 그냥 HTML 긁어서 내가 서버를 만들어도 되겠구나… 이 서버 정보 조회해서 푸쉬하는건 따로 만들고.

아침에 일어났는데 다행히 어젯밤 대화가 기억났고, 12시반까지 광화문으로 가야하는 일정에 맞추려면 남은 시간은 대략 4시간. 그런데 이걸 어쩌나 서연이가 일어났다. 스프링 세팅하기는 귀찮고 play 처럼 명령어 하나만 치면 스캐폴딩을 다 만들어주는 뭔가가 있음 좋겠지만 플레이로 만들기는 죽어도 싫고.

그래서 그레일즈 선택! 했으나.. 지금와서 생각해보니 왜 노드.js를 기억하지 못했나 아쉽. 하지만 그레일즈 재밌었다. 짧은 시간이었지만 플레이보다 100배 좋다고 감히 말할 수 있다.

어쨌든 모니터 80%는 서연이한테 호비와 트니트니를 틀어주고 난 20% 구석에서 그레일즈 어떻게 쓰는지와 HTTP Client 찾기 시작해서 슬슬 대충 HTML 조회 끝. 이제 정규식으로 필요한 부분만 긁으면 되는데 기억이 잘 안나서 윤군한테 물어봤지만 왠지 복잡하게 푸는것 같아서. 그냥 자바 정규식 검색해서 글좀 봤더니 의외로 엄청 단순하게 해결.

이제 다 만들었으니 배포를 해야겠는데… 이제는 서은이가 일어났다.

서연이는 어린이집으로 데려다 주러 유진이가 데리고 나가고 나는 서은이 안고서 서버 세팅 시작. 자바는 다행히 지난번에 깔아놨고, 톰캣, 그레일즈, Git 설치 시작. Git 설치가 젤 힘들었다. yum 기본 저장소엔 왜 git이 없는거야.. 아 귀찮게 rpm 설치하고 어쩌고..

아무튼 서은이 안고서 서버 세팅 거의다 맞추니까 유진이가 돌아왔다.

서은이 얼른 안기고 배포까지 끝내고 구플에 자랑글 하나 올리고 난 이제 나가야겠다.

https://github.com/keesun/yes24-api-server

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
package yes24.api.server
 
import groovyx.net.http.HTTPBuilder
 
import static groovyx.net.http.ContentType.TEXT
 
class BookController {
 
def info() {
def bookId = params.id
def mainHttp = new HTTPBuilder('http://www.yes24.com/24/Goods/' + bookId)
def mainResponse;
mainHttp.get(contentType: TEXT) { resp, reader ->
mainResponse = reader.text
}
 
def rankHttp = new HTTPBuilder('http://www.yes24.com/24/addModules/bestsellerrank/' + bookId + '/?categoryNumber=001001003016001012')
def rankResponse;
rankHttp.get(contentType: TEXT) { resp, reader ->
rankResponse = reader.text
}
 
def salesPointMatcher = mainResponse =~ /판매지수 [0-9]* /
def titleMatcher = mainResponse =~ /<title>.*<\/title>/
def computerRankMatcher = rankResponse =~ /컴퓨터와 인터넷 [0-9]*/
 
render(contentType: "text/json") {
title = titleMatcher[0].encodeAsHTML().replace("&lt;title&gt;", "").replace("&lt;/title&gt;", "")
salesPoint = salesPointMatcher[0]
rank = computerRankMatcher[0]
}
}
}

막 짠거라서 예외처리나 테스트 그런거 모르겠다.

아 재밌었다!!!

http://nullpe.com/yes24-api-server-0.1/book/info?id=8069226

yes24에서 관심있는 책 id만 바꿔가면서 조회해보면 된다.

끝!

[Play] 테스트 로그도 영…

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
@Test
public void buildCloneRepository() throws GitAPIException, IOException {
// Given
Project original = createProject("keesun", "test");
CloneAndFetchTemplate template = createTemplate(original);
new GitRepository("keesun", "test").create();
 
// When
Repository repository = template.buildCloneRepository();
 
// Then
assertThat(repository).isNotNull();
assertThat(template.getDirectory()).isNotNull();
String clonePath = "resources/test/repo/git-merging/keesun/test.git";
assertThat(template.getDirectory()).isEqualTo(clonePath);
assertThat(new File(clonePath).exists()).isTrue();
assertThat(new File(clonePath + "/.git").exists()).isTrue();
}
view raw PlayTest.java This Gist brought to you by GitHub.

이런 테스트 코드 실행했을 때 아래와 같은 에러가 났다면 대체 13줄이 문제라는거야 14줄이 문제라는거야…

도통 알수가 없어… 왜 라인수를 알갈쳐주는거야… 장난 치는거야 지금? 이게 어디서 났는지 찾아봐라? 머 그런거야? 지금 나랑 한번 해보자는거지? 재미없으니까 테스트 assert  실패한곳 라인수 찍어놔.. 당장 찍어 내라고!!!

[Git/JGit] PullRequest 구현하기

코드를 주고 받는 방법엔 크게 두가지가 있는것 같다. 프로깃이라는 책에서도 두가지를 설명하는데 하나는 고전적인 방법으로 패치 파일을 주고 받을 수 있겠고, 나머지 하난 상대방 브랜치를 merge하거나 rebase하는 식으로 코드를 직접 합치는 방법이 있겠다.

나는 후자를 선택했는데 그전까진 패치 파일 주고 받는 방법을 미처 생각하지 못했었고, pull request가 주는 어감때문에도 왠지 “코드 가져가라는 요청”이니까 merge로 코드를 받아가면 되겠군? 이라고 생각해서 이쪽으로 발상을 한것 같다.

암튼, 그래서 어떻게 하기로 했냐면.. 요청 보내는 쪽에서 가져갈 브랜치가 그 브랜치에 있는 코드를 어느 브랜치에 보낼지 선택하게하고 무슨 코드를 보낸다고 대충 적는다.

그럼 서버에 데이터가 하나 저장되는데 그게 PullRequest라는 도메인으로 저장된다. 그 안에는 어떤 Project(역시 도메인)에서 어떤 Project로 어떤 Branch에서 어디로 보내는지 누가 보내는지 누가 받았는지 등의 정보를 가지고 있다.

그럼 코드를 받는 프로젝트의 “코드 주고받기”라는 메뉴에 가보면 열려있는 풀리퀘 메뉴쪽에 하나가 표시되고 거길 열어보면 누군가 요청 보낸걸 볼 수 있다.

거기서 클릭해서 들어가면 이제 두가지를 할 수 있는데.. 하나는 “수락” 하나는 “거절”.

“수락”을 하면 다음과 같은 일이 발생한다.

일단 Git 저장소는 전부 bare모드로 만들어져있기 때문에 Git  저장소에서 직접 브랜치를 옮기거나 checkout을 받는다거나 하는 작업을 할 수 없다. 그래서 요청을 받아줄 프로젝트의 저장소를 bare모드가 아닌 non-bare 모드로 clone을 한다. 다음으로 ‘요청 받을 브랜치’와 ‘요청 보낸 브랜치’를 두개 만들고 각각을 ‘요청 보내온 저장소’와 ‘요청 받아줄 저장소’의 브랜치에서 fetch 해온다. 그런다음 ‘요청 받을 브랜치의 코드를 받아온 브랜치’로 이동해서 ‘요청 보내온 브랜치의 코드를 받아온 브랜치’의 코드를 머지 한다.

머지가 잘 되면 요청 받을 프로젝트의 브랜치로 ‘요청 받을 브랜치의 코드를 받아와서 요청 보낸 브랜치의 코드를 받아온 브랜치와 머지한 코드’를 푸쉬한다.

이렇게하면 풀리퀘가 된다. 그리고 머지 커밋이 항상 남도록 하려면 merge할때 NO_FF 옵션을 주면 된다.

이제부터 다듬기로, 머지하기 전에 머지가 잘되는지 확인해보고(사실 확인이라기보다 그냥 한번 해보면 되는데.. 암튼) 미리 머지가 잘 될 상황인지 아닌지 알려줄 수 있겠고, 잘 안되는 상황이면 직접 콘솔로 머지하고 컨플릭트 해결하라고 안내해 줄 수 있겠다.

그리고 풀리퀘를 만들어 보낼 시점에도 위와 같이 머지가 잘 되는 상황인지 체크해서 알려줄 수 있겠다. 어디서 하는게 좋을지 생각해 봤는데 어차피 보내느 시점과 받는 시점 사이에 받는 브랜치의 코드가 바뀌면서 처음 보낼 땐 머지가 잘 될것 같아도 나중에 안된느 시점이 있을 수 있으니까 그냥 두번 다 해주는게 좋을 것 같다고 결정했다.

그 다음 다듬기로는 풀리퀘가 어떤 커밋을 보내는 건지 커밋 목록과 브랜치 간의 파일 DIff 정보를 보여주는건데.. 후자는 금방 찾았는데 브랜치간에 차이나는 커밋 목록 만드는게 생각처럼 쉽게 안찾아진다. git show-branch와 비슷한 명령어가 jgit에 없는것 같다. 어떻게 해야할런지.. 흠… 좀 더 고민하거나 팀원에게 도움을 받아야겠다.

갈 길이 멀지만… 일단 포크/풀리퀘 구현은 가능하단걸 알았으니까 끝.

[Play] routes가 그지 같은 이유

리팩토링에 존나 취약하다. 컨트롤러를 리팩토링 할 수가 없어.

예를 들어,  MainController라는 컨트롤러에다가 핸들러 10개를 만들고 쓰다보니 그 중에 5개는 별도의 컨트롤러 클래스로 떼어내는게 좋겠다는 생각이 들었다고 치자고. 충분히 그럴 수 있자나? 이런 상황을 처음부터 알 수 있는 사람이 어딨어. 다 하다보면 많아지고 많아지면 비슷한거끼리 쪼개서 모으고 싶고 그런거지.

스프링이면 해당 핸들러 메서드만 별도의 컨트롤러 클래스로 옮겨버리면 된다고. 뷰에다가 컨트롤러 클래스이름 적어준것도 아니고 routes 같은 파일에다 URL 매핑하지 않고(물론 비슷하게 흉내낼 순 있지만 요즘 누가 그렇게 써..) 핸들러 메서드 위에 @RM으로 되어있으니까 메서드 옮기면서 URL 매핑 정보도 같이 옮겨지는거라고 다른거 수정할께 없이 그냥 그게 끝이야.

그런데 플레이는… 하아… 이런 그지 같은게.. 일단 routes 파일에 적어둔 매핑 정보를 바꿔주려면 들어가서 졸라 많은 URL 매핑 정보중에서 내가 고친 컨트롤러 이름 찾아가지고 바꿔줘야되겠지. 그다음에 그 핸들러 쓰던 뷰 파일 다 찾아가서 @routes.MainController.핸들러이름 이딴식으로 박아둔거 다 바꿔줘야된다고 그걸 어떻게 다 찾아서 고치냐고 아.. 씨바… 더러워서 진짜.

후아…. 진정하고 스프링 코딩이나 해야지..

개발자에게 채용당하고 싶다면…

빗버켓이나 깃헙 공개 저장소에 자기 코드를 올리는게 좋겠다. 도무지 글만 보고서는 이 분이 어떤 코딩이 가능하다는건지 어떻게 코딩을 하시는건지 알수가 없다.

이런 시점에 자기 코드로 어필한다면 개발자를 채용하는 개발자에게 참 잘 어필할 수 있을텐데 드물어 보인다.

나나 잘 하자.