[토이 프로젝트] 깃허브 프로필에 최신 포스트 자동 업데이트하기
😆 시작 계기
깃허브 프로필을 어떻게 꾸밀까 고민하다가 블로그의 최신 글 목록을 올려놓기로 다짐했다. 다만 포스팅 할때마다 매번 리드미를 수정하는건 너무너무 귀찮은 일이니까 알아서 자동으로 갱신해주는 작은 프로젝트를 만들었다. (GitHub Repository: https://github.com/yeon-06/github-posting-box)
😉 프로젝트 흐름
매일 특정 시간에 GitHub Action이 동작한다. GitHub Action은 아래 흐름과 같은 로직을 실행한다.
- 블로그에서 필요한 정보들을 가져온다. (미리보기 이미지, 포스팅 제목, 포스팅 날짜 등)
- 1의 정보를 바탕으로 파일을 생성한다.
- 2에서 생성한 내용으로 리드미를 업데이트한다.
조금 더 구체적으로 살펴보자. (repository: https://github.com/yeon-06/github-posting-box)
- Jsoup을 이용해 블로그에서 필요한 데이터 가져오기
- 제목, 미리보기 사진, 미리보기 글, 날짜 가져오기
- 새로 올라온 포스트가 없다면 API 호출 종료
- 1의 정보를 이용해 포스팅 목록을 보여줄 table 스크립트 생성
- GitHub API 호출 (디렉토리는 repository 내의 폴더를 의미함)
- 브랜치 생성
- img 디렉토리 삭제
- 1에서 가져온 미리보기 이미지를 원하는 크기로 변경 후 img 디렉토리에 업로드
- 2에서 생성했던 정보를 이용해 리드미 갱신
- PR을 생성하고 squash merge 진행
이미지 디렉토리를 삭제하고, 파일을 업로드하고, 리드미를 갱신하는 등 3번의 모든 작업을 하나의 커밋으로 만들 수 있다면 좋겠지만, 아쉽게도 지원하지 않는 듯했다. 따라서 브랜치를 생성하고 PR을 생성하고 squash merge를 진행하는 방법을 선택했다.
🤓 기술 스택
- Java 11
- GitHub Action
기술 스택은 나에게 익숙한 것으로 골랐다. 낯선 언어를 선택하면 개발 시간이 너무 길어질 것 같았다. GitHub Action을 이용한 이유는 서버 비용이 제거하기 위함이다. 항상 서버를 켜둘 필요 없이 필요할 때만 아주 잠깐 실행해도 충분해서 가능한 일이었다.
🥸 개발 일지
💛 Spring 제거하기
처음에는 Spring Boot를 이용해 API를 하나 만들었다. GitHub Action은 해당 API를 호출하기만 하면 됐다. 그런데 로직 하나만 실행하면 되는데 스프링을 꼭 써야할까? 꼭 REST API 형식으로 만들어야할까? 라는 의문이 들었다. 그래서 더 간소하게 만들어보자! 라는 취지로 스프링을 제거했다. 이 과정 속에서 정말 많은 일이 벌어졌다. 아 이것도 스프링이 지원하는 기능이었지... 하고 리마인드 할 수 있는 계기가 되었다^ㅡ^... 전체 기능을 개발한 기간보다 스프링을 제거하면서 삽질한 기간이 더 길었기에 다시 스프링을 도입할까.. 라는 고민도 했지만 오류로부터 도망가지 않기 위해 어떻게든 해냈다.
까먹고 있었던, 스프링에서 지원해주는 일
- 외부 라이브러리 의존성 관리
- yml 파일의 값 편하게 가져오기 (@Value 지원)
- yml 파일에서 환경 변수 사용
더 자세히 보기 👉 https://yeonyeon.tistory.com/296
💛 변경된 계획
처음에는 gist로 만든 뒤에 핀으로 고정하고 싶었다. 만들다가 알게 된 사실인데 gist에는 링크를 못건다.😰 파일이 마크다운이든 html이든 형식과는 상관없이 문자열/코드 그대로 보여준다. 그래서 gist는 포기하고 리드미 하단에 추가하기로 계획을 변경했다.
💛 ChatGPT 첫이용
이번 토이 프로젝트에서 가장 반성할 점은 도구에 너무 많은 의존을 했다. 나는 이번에 처음으로 ChatGPT라는 신문물을 이용해보았다. 내가 궁금한 것을 친구한테 물어보듯 편하게 물어봐도, 이런 코드에 저걸 적용하고 싶으면 어떻게 해야할까? 같은 모호한 질문을 물어봐도 훌륭한 답변이 돌아왔다. 이 편리함에 이끌려 적극적으로 이용해보았으나 내 문제는 잘 해결되지 않았다. ChatGPT의 제안이 자꾸 실패해고, 다시 물어봐도 똑같은 제안만 하는 상황에 이르자, ChatGPT를 뒤로 미루고 직접 구글링+공식 문서를 뒤적거렸다. 해당 이슈는 두어시간 만에 바로 해결됐다. 물론 내 ChatGPT 사용 방법이 미숙했을수도 있다. 하지만 도구에 너무 의존하면 안된다는 깨달음을 얻었다.
🧐 개선점
💛 html 코드 가져오기
현재 Jsoup이라는 라이브러리를 통해 html 코드를 직접 가져와 필요한 부분의 텍스트를 가져오고 있다. 특정 속성 값이나 특정 클래스명을 통해 찾은 태그의 텍스트 값 등. 그리고 클래스명 같은건 application.yml에서 관리하게끔 만들었다. 아래 사진으로 예를 들자면 포스팅의 제목을 가져오고 싶다고 가정할 때, 클래스명을 'post-item'인 태그를 먼저 찾고, 그 안에서 'title'이라는 클래스명을 가진 태그의 텍스트 값을 구해온다. 이와 같은 방식을 선택하다 보니 번거로운 점이 많았다. 만약 티스토리 스킨이라도 변경하면 해당 클래스명이 달라지므로 매번 application.yml을 수정해야할 수도 있다. 어떤 블로그에서는 메인 화면에 글 목록이 아니라 가장 최신 글 내용이 보일수도 있다. 그래서 가능하다면 티스토리 REST API를 이용해 정보를 가져올 수 있도록 수정할 예정이다.
blog:
url: https://yeonyeon.tistory.com
contents-class-name: post-item
title-class-name: title
summary-class-name: excerpt
date-class-name: date
💛 구멍이 많은 더러운 코드
초기 예상 구성은 정말 간단했기 때문에 돌아가는 것만 확인했다. 클래스도 controller, service, domain 기껏해야 3개 뿐이었고 원하는 문자열이 만들어졌는지만 확인하면 되는 수준이라 테스트 코드를 짤 필요도 없었다. 코드를 되는대로 아무렇게나 짰고 하드 코딩도 많고 예외 처리도 안되어있다. 미리보기 이미지를 추가하면서 좀 더 복잡한 작업이 추가되며 커다란 쓰레기 더미가 되었다. 코드를 다듬고 책임 분리도 확실히 해줄 필요성을 느끼게 되었다. 무엇보다 exception에 대한 처리가 하나도 되어있지 않다. 보다 자세한 에러 로그를 남겨주고 싶다.
💛 글자수로 문자열 자르기
포스팅 목록에는 위와 같이 글 내용을 미리볼 수 있는 부분이 있다. 지금은 해당 부분을 substring을 통해 글자수대로 자르고 있다. 이 부분을 byte 단위+글자 단위로 자르도록 수정하고 싶다. 단순하게 byte[] 바꾼 뒤 특정 크기만큼 String으로 다시 변환하면 끝 글자가 깨지는 현상이 발생해 어떤 식으로 로직을 짤지는 아직 고민중에 있다. (ex: 한글은 한 글자에 3byte인데 2byte까지만 자르는 경우)
💛 다른 사람 블로그에서는 사용 불가
꼭꼭 개선하고 싶은 부분인데 일단 내 블로그에서는 돌아가도록 만들다보니 다른 사람 블로그에는 적용되지 않을 가능성이 크다. 변경될만한 값은 github secrets 또는 application.yml에서 가져다쓰도록 만들긴했지만 아마 어딘가 하드 코딩으로 박힌 부분도 있을거라 예상된다. 유동적으로 바꿀 수 있는 값은 한 곳에 분리하고 변경해야하는 값을 최소화하면 더 편할 것 같다. 그리고 해당 레포지토리를 이용하는 방법이 정리된 리드미도 추가할 예정이다.