HOME INFO PROJECT BLOG ESSAY
Article Projects Lab
한국어 English
article |

슬랙 봇에 Github App을 도입해보자

안녕하세요. 이번 글은 처음 써보는 언어로 슬랙봇 만들기에서 이어집니다.

코드는 역시나 Github에서 확인 가능합니다.


알고봇 프로토타입의 문제점

처음 개시한 슬랙봇은 다음과 같은 이슈가 있었습니다.

슬랙봇에서 명령어로 알고리즘 문제를 제출하게되면 제 소유의 Github 계정으로 PR과 Merge가 이뤄진다는 것입니다.

일반적으로 웹에서 PR을 생성할 때는 Fork한 레포지토리(downstream)에서 아카이빙 레포지토리(upstream)로 PR을 생성하는 과정은 write 권한이 없어도 가능한데, Github REST API는 약간 다르게 동작합니다.

이는 Github REST API 레퍼런스에 적혀있는 내용인데요, ‘한 레포지토리에서 다른 레포지토리의 base로 PR을 보낼 수 없다’는 것입니다.

내용에 의거하여 사용자가 등록한 Github 토큰으로 PR 생성을 시도하면 권한이 없음을 나타내는 403 에러가 발생하게 됩니다. 여기서 글또의 Organization에서 PR을 생성하려면 별도의 권한이 필요하다는 것을 알게되었습니다.

그래서 글또 Organization 토큰을 발급하여 PR 및 Merge를 수행하도록 작업하고 서비스를 개시했습니다.

시간이 지나며 사용자들이 문의주셨던 것 중 하나는 자신의 Github 계정으로 PR 및 Merge가 작동했으면 좋겠다는 의견이었습니다.

이 이슈는 알고봇을 서비스하기 전부터 고민하던 문제였으며 이에 대해 2가지 방법을 고려하게 됐습니다.

첫 번째 방법과 문제점

첫 번째 해결법은 사용자 별로 글또 Organization에 write 권한을 가진 토큰을 사용자마다 생성하는 방법입니다.

Organization 토큰을 사용자별로 발급받게되면 그 토큰을 사용함으로써 Organization에 접근할 권한을 갖게되고 이로써 사용자의 Github 계정으로 PR과 Merge가 가능하게 됩니다.

하지만 이 방법의 문제는 무엇일까요? 바로 운영 비용의 증가로 이어지게 됩니다.

최대한 타협하여 알고봇 사용자의 의견을 수렴하여 토큰을 한 번에 승인한다고 쳐도, 추후에 사용을 원하는 사용자들이 알고봇에 유입하게 된다면 그 별도의 토큰을 발급하기 위한 추가적인 운영비용이 늘어나게 됩니다.

그래서 이 방법은 우선 순위에서 밀려나게 되었습니다.

그래서 선택한 Github App

상기된 이유로 사용자 별로 토큰을 등록하는 방법은 채택되지 않았고 봇 계정이 PR과 Merge를 담당하도록 계획했습니다.

봇은 Github App을 사용해 제 계정으로 이루어지던 작업을 봇으로 대체하여 하나의 프로필 역할을 하게됩니다.

하지만 여전히 문제점은 사용자의 계정으로는 PR 및 Merge를 생성하지 못한다는 문제가 있었습니다.

기능을 요청한 사용자들의 의도는 자신의 Github에 PR을 남기기 위함이라는 것이었는데요, 알고봇 사용자 중 한 분인 ‘근호’님이 이에 대한 피드백을 주셨습니다.

바로 커밋 메시지에 공동 작성자(Co-authored)를 추가하는 것입니다. 이 방법이라면 PR을 직접 생성할 순 없지만 커밋 이력을 남김으로써 Github에 기록할 수 있게 됩니다.

이제 문제를 해결해보겠습니다.

먼저 기존 작업을 살펴보겠습니다.

주요 작업을 순서대로 살펴보면

  1. CSV 파일의 사용자의 GitHub 토큰을 읽기 - (csv.reader(file))
  2. 토큰에서 권한을 획득 - (Github(user_token))
  3. 사용자가 Fork한 아카이빙 레포지토리(글또 Organization의 레포지토리)에 접근 - (g_user.get_repo…)
  4. Fork한 브랜치에 알고리즘 풀이 브랜치를 생성 및 push - (user_fork.create_git_ref)
  5. 선택한 리뷰 유무에 따라 글또 Organization 토큰으로 PR 생성 및 Merge 실행 - (archive_repo.create_pull)

여기서 대체해야 할 작업은 5번 작업입니다.

글또 Organization 토큰으로 수행하던 작업을 Github App을 추가하여 작업을 대신하도록 해보겠습니다. 먼저 Github App을 추가하도록 해봅시다.

Organization에서 Github App 생성

먼저 Organization으로 이동합니다.

실제로는 글또 Organization에서 실행해야하지만 봇 작동을 위해서 테스트용 Organization을 만들었습니다. 상단 메뉴의 오른쪽 가장 끝에 있는 Settings를 선택합니다.

이어서 왼쪽 메뉴 최하단의 Developer settingsGithub Apps를 선택합니다.

오른쪽 상단의 New Github App을 선택합니다.

선택하면 위와 같은 화면을 볼 수 있습니다. 여기서

봇의 이름인 GitHub App nameHomepage URL을 입력해줍니다. 저같은 경우 아카이빙 레포지토리의 주소를 입력했습니다.

이 후 하단으로 내리다보면 Webhook를 볼 수 있는데, 사용하지 않기 때문에 Active를 비활성화 해줍니다.

가장 중요한 Permissions 입니다. 저장소 및 관련 리소스에 대한 액세스를 허용하는 설정인데요

봇에 필요한 권한은 다음과 같습니다.

Administration - ‘Read and write’ Contents - ‘Read and write’ Issues - ‘Read and write’ Metadata - ‘Read-only’ (자동으로 설정) Pull requests - ‘Read and write’

그리고 하단의 Organization permissions에서 Members를 ‘Read-only’로 설정합니다.

마지막으로, Github App의 설치 범위를 묻는 선택지가 나오는데요

Only on this account 를 선택하고 설치할 레포지토리를 지정한 뒤, Create Github App 으로 App을 생성하면 Github App 생성이 완료됩니다.

Github App에 필요한 리소스 가져오기

이제 코드에서 Github App을 사용하기 위한 세 가지 리소스가 필요합니다.

리소스는 App ID, Installation ID, PEM key(private key) 이 세 가지가 이에 해당합니다.

App을 생성하고 나면 다음과 같은 화면을 볼 수 있는데요

여기서 하단으로 내려서 Private keys 로 이동하여, Generate a private key를 선택하면 pem key가 로컬에 다운로드됩니다.

필요한 첫 번째 리소스를 얻었습니다!

이제 Github App을 설치해야합니다. 왼쪽 메뉴의 Install App 으로 이동해주세요.

위와 같이 Organization이 있는 것을 확인할 수 있습니다. Github App을 설치할 Organization 오른쪽의 install 을 선택합니다.

선택하면 Github App 설치화면이 나오는데요, Only select repositories 를 선택하고 Select repositories 에서 Github App을 설치할 저장소를 선택하고 install 합니다.

선택하고나면 위와 같은 화면을 볼 수 있는데요, 필요한 두 번째 리소스 Installation ID는 Github App 설치후에 나오는 화면의 url에서 확인 가능합니다.

저같은 경우 사진의 경우 URL의 끝 숫자인 ‘59003354’가 Installation ID에 해당합니다. 이것이 두 번째로 필요한 리소스입니다.

마지막 App Id. 이는 아까 생성했던 Github App에서 확인 가능한데요

Github App 페이지의 About에서 App ID를 확인할 수 있습니다.

위의 경우 ‘1099696’가 이에 해당합니다. 이것이 마지막으로 필요한 리소스입니다.

코드에 적용하기

Github App을 사용하기 위한 리소스는 모두 얻었습니다. 이제 코드에 적용해보겠습니다.

원래 코드에서 5. 선택한 리뷰 유무에 따라 글또 Organization 토큰으로 PR 생성 및 Merge 실행 작업만 Github App이 대체하도록하면 됩니다.

아까 얻은 리소스는 환경 변수로 사용하도록 하겠습니다. .env에 ID와 pem key를 넣고 사용하도록 하겠습니다.

이제 코드를 대체해봅시다.

Pygithub의 레퍼런스를 살펴보면 Github App을 Application ID와 private key로 인증합니다.

코드에서는 다음 작업을 실행합니다.

  1. GitHub App 인증에 필요한 환경변수 로드
  2. Private Key를 사용한 GitHub App 인증
  3. Installation 토큰 기반의 GitHub 클라이언트 생성
  4. 종합하여 GitHub App 인증에 필요한 모든 로직을 하나의 클래스로 관리하여 생성

이어서 획득한 권한으로 PR 생성을 진행합니다.

이 때, 요구하는 리소스를 환경변수에서 읽도록하고 테스트 환경에서 슬랙봇 명령어를 실행했는데, 디버깅 로그에서 다음과 같은 에러를 계속 마주했습니다.

번역해보면 ‘fork_collabo 권한이 없는 사람이 허락할 수 없습니다’는 것입니다. 이 에러의 의미를 하나씩 살펴봤습니다.

  • status: 422 - 서버가 요청의 콘텐츠 유형을 이해하지만 포함된 지침을 처리할 수 없음
  • resource: ‘PullRequest’ - 문제가 발생한 리소스 타입이 Pull Request
  • code: ‘custom’ - 커스텀 에러 타입
  • field: ‘fork_collab’ - fork된 레포지토리의 협업 권한(collaboration) 관련 필드에서 문제 발생
  • message: “fork_collab Fork collab can’t be granted by someone without permission” - 권한이 없는 사용자가 fork collaboration을 설정하려 시도

메시지로 추정하건대 GitHub의 권한 시스템에서 fork된 레포지토리에 대한 협업 권한을 설정하려 할 때 필요한 권한이 없어서 발생하는 문제라고 생각했습니다.

‘뭔가 Collaborlator 권한을 필요로하나?’ 라는 생각이 먼저 들어서 관련 키워드로 원인을 찾아보기로 했습니다.

키워드를 찾아봐도 원인을 못찾던 찰나에 하나의 글을 발견했습니다.

위 글에서 나타난 문제점은 다음과 같습니다.

GitHub App으로 조직 소유의 공개 레포지토리에 fork된 브랜치에서 PR을 생성하려고 했을 때 두 문제가 발생함

-> 사용자 계정으로 인증 시: 403 에러 (“Resource not accessible by integration”) -> 조직으로 인증 시: 422 에러 (“fork_collab Fork collab can’t be granted by someone without permission”)

이에 대한 해결책으로 PR 생성 요청에 "maintainer_can_modify": False 파라미터를 추가하면, GitHub App을 사용자 계정이 아닌 조직의 installation으로 인증하여 PR을 생성하도록 한다는 내용이었습니다.

결국 저 한 줄을 추가하고나서 의도하던대로 비즈니스 로직이 작동하게되었습니다!

코드가 추가해서 작동된 이유는 자세하게는 모르겠지만 작동 방식을 생각하여 상황을 재구성해봤습니다.

Fork & PR의 기본 동작은 일반적으로 PR을 생성할 때, 원본 레포지토리의 관리자(maintainer)가 PR의 코드를 수정할 수 있다 -> 이는 fork된 레포지토리에 대한 쓰기 권한이 필요함

여기서 'maintainer_can_modify=False'를 선언함으로써 원본 레포지토리 관리자의 PR 수정 권한을 비활성화하고 fork된 레포지토리에 대한 추가 권한 부여가 필요없게 되고

GitHub App이 fork된 레포지토리에대한 협업 권한(fork collaboration)을 설정하지 않아도 되는 흐름이 아닐까 생각합니다.

마지막으로 리뷰 유무에 따라 PR label을 설정하고, commit 메시지에 Co-authored를 추가했습니다.

코드 한 줄 때문에 4시간을 헤맸다는 것이 좀 머리 아팠지만, 결국 의도한 비즈니스 로직으로 업데이트하는 것을 성공했습니다!

맺음

24년에 마지막 날 업데이트를 마무리 할 예정이었는데 결국 다음 날까지 넘겨버렸습니다. 머리는 아팠지만 덕분에 새해를 산뜻하게 시작할 수 있었습니다. (이 맛에 코딩하지요)

하지만 여기서 끝이 아니라, 사용자 편의성을 위해 개선점을 찾아 계속 개선할 예정입니다.

새삼 서비스 하나를 만들고 운영하는 것이 이렇게 재밌는 일인지 느끼게 되는 하루입니다.

다소 긴 글인데 읽어주셔서 감사합니다. 다음은 회고글로 돌아오겠습니다.

출처

article |

처음 써보는 언어로 슬랙봇 만들기

안녕하세요. 이번 글은 슬랙 봇을 만들면서 겪었던 문제와 해결 과정에 대해 다루려고 합니다.

내용 이해에 필요한 코드만 다루고, 자세한 코드 내용은 다루지 않는 점을 미리 밝힙니다.

코드는 Github에서 확인 가능합니다.

개요

글또 커뮤니티의 소모임 중에는 ‘오늘도한문제풀었또’ 라는 채널이 있습니다.

채널 이름을 보면 알 수 있듯이 하루에 한 문제라도 알고리즘을 풀어 습관을 만들어가자는 취지로 만들어진 채널인데요, 평소처럼 알고리즘을 풀어서 제출하다가 필요한 점이 눈에 보였습니다.

채널 메시지를 보면 문제를 풀고 인증할 때 저렇게 메시지를 하나 남기는 것으로 문제를 풀었다는 것을 인증하고 있었는데요, 이러한 방식은 시각적으로도 좋지 않을 뿐더러 동기부여가 잘 안된다는 생각이 들었습니다.

마침 ‘오늘도한문제풀었또’ 채널의 4장 지한님이 제출된 알고리즘 코드를 아카이빙 레포지토리로 관리하겠다는 계획이 언급되었는데, 이를 ‘슬랙봇의 명령어로 알고리즘 문제를 제출하도록하면 편하지 않을까?’ 하여 슬랙봇 도입을 건의했습니다.

4장님의 반응도 긍정적이어서 앱의 핵심적인 기능만 추려서 봇 제작에 돌입했습니다.

초기 단계

먼저 MVP 기능은 명령어를 통해 다음 기능을 수행하도록 하는 것입니다.

  • 알고리즘 풀이: 명령어를 실행하면 코드를 제출하고 아카이빙 레포지토리에 저장
  • 알고리즘 조회: 작성했던 코드의 정보를 바탕으로 스트릭을 표시하도록하기.

처음엔 DB를 사용할까도 싶었는데 가벼운 작업이기 때문에 코드만 레포지토리에 저장하게 하고, 스트릭 생성을 위한 데이터만 CSV 파일로 저장하도록 계획했습니다.

프로그램 흐름을 그림으로 나타내면 다음과 같습니다.

먼저 유저는 슬랙 워크스페이스에서 명령어를 통해 서버와 통신합니다.

서버는 Slack Bolt SDK 프레임워크를 통해 동작하며, 유저가 전달한 정보를 CSV 파일을 저장하고 스트릭 생성 시 CSV 파일을 조회하여 보여줍니다. CSV 파일이 DB 역할을 대신하는 것이죠.

CSV 파일에 대해 간단하게 설명하면 다음과 같지 몇 가지 필드를 쉼표(,)로 구분한 텍스트 데이터 및 텍스트 파일입니다.

이 Slack Bolt를 사용하려면 앱을 등록해야 하는데요, Slack API로 이동하여 Create New App을 선택합니다.

선택하면 다음과 같이 앱 이름과 워크 스페이스를 지정해줘야 하는데요, 글또 워크스페이스에 도입하기 전이어서 새 워크스페이스를 생성하고 진행했습니다.

저같은 경우 ‘오늘도 한문제 풀었또’라는 워크스페이스를 만들어 지정했습니다.

이제 서버를 실행해야 하는데 방법은 공식문서에 아주 잘 나와있습니다.

서버를 실행하려면 slack_bolt가 필요합니다. 파이썬 작업 환경을 열고 pip install slack_bolt로 설치해줍니다.

코드를 보면 SLACK_BOT_TOKENSLACK_APP_TOKEN이 필요한데요 설명에 따르면 각각 ‘봇 사용자와 연결’, ‘앱에 대한 WebSocket 연결’을 생성하는데 사용됩니다.

Create New App으로 앱을 생성하고 나면 볼 수 있는 화면인데요, Enable Socket Mode를 활성화합니다.

여기서 Socket mode에 간단하게 설명하자면 앱에서 공개 HTTP 요청(Public HTTP Request)을 노출하지 않고 WebSocket 연결을 기반으로 간단하게 슬랙 앱을 구축할 수 있는 기능입니다.

활성화하면 위와 같이 토큰 명을 입력해야 하는데요, 원하는 이름으로 입력합니다.

이것이 위 코드에 필요한 SLACK_APP_TOKEN으로 설명을 보면 알 수 있듯이 웹소켓을 통해 앱의 상호작용과 이벤트 페이로드를 라우팅합니다.

이어서 Event-subscriptions로 이동합니다.

슬랙 앱에서 봇 사용자가 채널의 메시지와 같은 이벤트를 수신하도록 해야하는데요, 여기에 Add Bot User Event로 이벤트를 추가하면 필요한 OAuth 범위가 추가됩니다.

알고봇은 사용자의 메시지를 수신받아야하기 때문에 message.immessage.channels 를 선택했습니다. 앱에서 구현하고자 하는 기능에 맞춰 이벤트를 선택하여 추가하면 됩니다.

앱 생성 준비가 거의 다 끝났습니다. Features의 App Home에서 앱의 Bot 이름과 유저네임을 입력하고 저장합니다.

마지막으로 워크스페이스에 앱을 설치하면 완료됩니다.

앱 설치를 완료하면 서버 실행에 필요한 SLACK_BOT_TOKEN 값을 얻을 수 있습니다. 역시 복사해줍니다.

이제 Bolt 레퍼런스 대로 토큰을 등록하여 서버를 실행해봅시다.

토큰 같은 경우는 환경 변수로 관리하여 사용하면 좋은데, dotenv를 이용해 토큰을 불러와보겠습니다.

환경 변수로 토큰을 입력하고 ‘main.py’를 실행하면

Bolt App가 실행 중이라는 메시지를 확인할 수 있습니다.

이제 슬랙 봇에서 명령어로 계획했던 기능을 수행하도록 해보겠습니다.

주요 기능 추가하기

명령어로 기능을 수행하도록 하려면 슬랙 앱에 명령어를 등록해야 합니다.

앱의 Features에서 Slash Commands를 선택합니다.

앱에서 사용할 명령어는 ‘/알고토큰’, ‘/알고풀이’와 ‘/알고조회’ 명령어로 지정하겠습니다.

커맨드와 설명을 입력하고 Save를 선택하여 내용을 저장해줍니다.

등록을 마쳤으니 명령어로 실제 알고리즘 풀이를 제출하는 기능을 구현해야 합니다. 흐름은 다음과 같습니다.

  1. ‘/알고토큰’ 명렁어로 요청자의 Github의 접근할 수 있는 토큰을 등록한다.
  2. ‘/알고풀이’ 명령어를 앱에 입력한다.
  3. 알고리즘 풀이 정보를 입력할 수 있는 Modal을 띄운다.
  4. Modal에 값을 입력한 뒤에 스트릭 생성을 위한 데이터를 CSV 파일에 저장한다
  5. Github 아카이빙 레포지토리에 코드를 push하고 PR 및 Merge 한다.

2번과 3번 기능부터 구현해보도록 하겠습니다. 설명은 레퍼런스를 따릅니다.

먼저 @app.command 로 명령어를 입력받고, 그 아래 함수에서 modal 폼을 정의합니다. 앱에서 명령어를 실행하게 되면

그림과 같이 modal을 확인할 수 있습니다. 이후 스트릭 생성에 필요한 정보를 modal로 전달하고 CSV 파일에 저장합니다. (흐름 상 중요한 내용은 아니어서 코드는 생략합니다.)

이제 가장 중요한 기능인 Github에서 PR 및 Merge하는 기능을 구현해야하는데요 이 부분은 Github REST API에 액세스하는 라이브러리인 PyGithub를 사용하기로 결정했습니다.

GitHub REST API를 직접 다루는 것은 저에게 난이도가 있다고 생각했고 API 요청을 Python 객체로 추상화하여 쉽게 사용할 수 있어 채택했습니다.

먼저 패키지를 설치합니다.

pip install PyGithub

코드를 Push하거나 PR을 생성하는 기능은 다음의 흐름을 따르도록 계획했습니다.

공통적으로 사용자 요청을 받으면 요청자의 fork한 아카이빙 레포지토리 에서 브랜치를 생성하고 push합니다.

이 후, 리뷰 필요 유무에 따라 다음과 같이 분기됩니다.

  • 리뷰가 필요하다면 PR을 생성하고, PR 링크를 채널에 표시하여 리뷰를 받을 수 있도록 함

  • 리뷰가 필요없다면 PR을 생성하고, 아카이빙 레포지토리에 Merge

여기서 브랜치를 만들고 push하거나 PR 및 Merge 기능을 수행하려면 Github 권한이 필요한데 이는 토큰을 사용하기로 결정했습니다.

Github의 token을 이용하면 최소한의 권한을 지정한 토큰으로 API를 사용할 수 있습니다.

다음과 같이 PyGithub를 이용해 토큰을 다뤄 API에 접근할 수 있습니다.

CSV 파일에 저장되어 있는 유저의 토큰을 읽어들여 사용자 정보를 획득하고 이를 기반으로 fork 레포지토리에 접근하여 브랜치를 생성하고 Push하게 됩니다.

이어서 토큰으로 PR을 생성하고 리뷰 유무에 따라 리뷰를 생성하거나 Merge합니다.

여기서 겪은 문제가 있는데, 일반적으로 fork된 레포지토리에서 upstream에 PR을 올리는 것은 권한이 없어도 되는 것으로 인식하고 요청자의 토큰으로 PR을 수행하도록 했는데, 로깅을 해보니까 PR을 생성하는 부분에서 계속 403 Error를 내뱉었습니다.

REST API의 pull requests 문서를 참조해보니 다른 레포지토리의 베이스에 병합을 요청하는 PR은 한 레포지토리에 제출할 수 없다는 설명을 발견했습니다.

글또의 Organization 레포지토리에 접근하여 PR 및 Merge하려면 Organization의 아카이빙 레포지토리에 접근하기 위한 권한(토큰)이 필요하기 때문에 403 Error를 내뱉는 것 이었습니다.

결국 글또 Organization의 토큰을 따로 승인받고 생성 및 등록하여 이 토큰으로 PR 생성 및 Merge 하도록 변경하니 의도한대로 코드가 아카이빙 레포지토리로 저장됨에 동시에 채널의 메시지를 확인할 수 있었습니다.

이번 프로젝트에서 가장 시간을 많이 잡아먹은 부분으로 왜 문제점을 빨리 발견못했을까 하는 아쉬움이 남는 부분입니다.

추가적인 이슈

슬랙봇을 통해 알고리즘을 제출하고 아카이빙 레포지토리에 저장하고 스트릭을 조회할 수 있는 기능(이 글에서 코드로 다루진 않았지만)을 모두 구현했습니다.

하지만 여기에 골치아픈 문제가 하나가 있었는데

PR 생성과 Merge가 모두 제 Github 계정으로 이루어진다는 것입니다.

원인을 찾아보니 글또의 Organization 토큰을 Generate한 계정이 저의 계정이기 때문에 발생하는 일이었습니다.

그래서 해결 방법으로 크게 두 가지 방법을 생각해봤습니다.

  • 알고봇 사용을 원하는 사람들을 취합하여 글또 토큰을 한 번에 승인하여 저장하여 사용하기

이 방법은 알고봇을 사용하는 유저들에게 불편함을 주는 방법이어서 부적절하다는 생각이 들어 후순위로 밀려나게 되었고

  • Github App에 Algobot을 추가하고 PR 생성 및 Merge를 담당하도록 만들기

이 경우는 PR, Merge를 담당하던 제 계정의 토큰이 아닌 Github App의 봇이 작업을 대신하여 하나의 프로필 역할을 하게 됩니다.

사실상 가능한 방법이 이것밖에 없다고 생각하여 Github App에서 이를 테스트해보고 성공한다면 바로 운영 서버에 적용하도록 계획했습니다.

이 이슈는 다음에 글에서 다뤄보도록 하겠습니다.

맺음

현재 알고봇의 기능은 서버에서도 잘 돌아가고, 다들 관심가지고 심지어 피드백도 주셔서 계속 개선하고 있습니다.

작업을 하면서 느낀 점은 이렇게 작은 앱조차도 사용자들이 불편함을 느낄까봐 노심초사인데 ‘실제 회사의 큰 서비스라면 얼마나 부담감이 심할까’ 였습니다.

자고로 개발자면 ‘언어는 수단에 불과할뿐 아닌가?’ 라는 생각으로 시작하여 파이썬은 문법만 대충 아는 상태로 시작했는데, 좋은 서비스를 만드는 방향을 고민할 수 있는 유익한 시간이 되었고 무엇보다 작업하면서 너무 재밌었습니다.

나중에 더 심화된 기능의 봇도 만들어보고 싶네요.

글은 여기까지 입니다. 읽어주셔서 감사합니다.

출처