[회고] Viber ChatBot Service (w. ShareTreats )

da__ell·2023년 7월 25일
0

ShareTreats-Viber

목록 보기
2/2
post-thumbnail

2023년 6월부터 7월까지 쉐어트리츠에서 진행한 Viber ChatBot Project에 대한 전반적인(조금은 구체적일 수 있는) 회고이다.

프로젝트 시작

팀원은 총 4명으로 구성되었고 제공할 서비스는 Viber라는 메신저 서비스에서 제공되기 때문에 해당 API에 대한 이해가 필요했다.

기존 웹 개발과 달랐던 점

기존에는 Front 개발자와 API 명세서에 대해서 함께 논의하면서 어떤 식으로 데이터를 제공해주고 클라이언트에 어떻게 띄워줄 것인지 논의하는 과정을 거쳐왔다.
하지만 Viber 서비스를 활용한 개발은 아래와 같이 Viber 사용자 - Viber 서버 - Backend 서버의 구성으로 데이터 송수신이 이뤄진다. 그래서 Viber 사용자가 텍스트를 입력하게 되면 Viber 서버에서 이를 수신하고 해당 메시지를 Callback 형태로 Backend 서버에 제공해주는 방식이다.
반대로 이러한 Callback 메시지가 서버가 들어왔을 때 팀에서 구축한 비즈니스 로직에 따라 반대로 응답 메시지를 보내주고자 한다면 Viber가 원하는 Message의 형태로 Json 데이터를 가공하여 Viber 서버에 보내면 Viber에서 그에 맞춰서 사용자에게 보여주는 과정이이었다.

따라서 이러한 구성에 대해 이해하고 Callback 메시지의 형태와, Viber에서 지원하는 메시지 형태를 알아야 했다.

ALB, ACM 선택 이유

Viber 공식문서에서는 송수신이 HTTPS환경에서 이뤄져야 한다고 명시한다. 따라서 팀에서 HTTPS 통신이 가능하도록 인프라를 구축하여야 했다.

HTTPS통신을 위해서 ALB와 ACM을 선택한 이유는 ALB에서 HTTPS 인증을 수행하기 때문에 SSL 인증서를 인스턴스에 설치할 필요가 없다는 점이다.
ALB는 SSL 인증서를 관리하고 SSL 통신을 종료함으로써, EC2 인스턴스가 SSL 인증서를 관리하거나 SSL 통신을 직접 처리할 필요가 없게 된다.
또한 이러한 방식은 EC2 인스턴스의 보안 부담을 줄이고, 애플리케이션 서버를 직접 인터넷에 노출시키지 않도록 하기 때문에 AWS 환경에서 보안을 향상시키는데 효과적이라고 판단했다.

백엔드 기술스택 선택 이유 (Java, SpringBoot)

첫 번째로 비즈니스 측면에서 사측에서 요청한 기술스택이 Java, SpringBoot였다.
두 번째로 협업적 측변에서 적절하다고 생각한다.
먼저 Java가 TypeSafe하다는 점이 장점이라고 생각했다. 리팩토링하거나 확장 할 때 IDE를 이용해서 수정할 점을 빠르게 확인할 수 있다. 각자 구현한 코드를 합쳐서 완성된 프로젝트를 만든다는 점에서 기존부터 함께 일해온 팀원들이 아니었기 때문에 이런 점도 이유였다.
또한 팀원들 모두 Java와 SpringBoot를 활용한 개발 경험이 있었다는 점에서 기간내에 완수하기 위한 측면에서도 적절한 판단이었다.
세 번째는 활용할 수 있는 라이브러리의 규모였다. Spring에 있는 대규모의 라이브러리는 개발하는데 있어서 큰 이점이라고 생각했다. 일례로 데이터 관리 측면에서 어려움을 겪을 수 있는 데이터베이스 관리도 스프링부트에서는 JPA라는 라이브러리를 통해 간소화 해둬서 손쉽게 다룰 수 있다.

이런 이유들을 통해 기술스택을 설정하게 되었다.
버전 선택은 Java 11로 선택했고 그 이유는 현재 기업을 보면 Java 8 혹은 Java 11을 주로 채택하여 사용하고 있고, 성능이 개선된 G1 GC를 사용하는 Java 11을 사용하는 편이 좋다고 생각했다. 또한 Java 11은 LTS 버전이므로 장기적인 지원이 보장된 버전인 점도 고려 대상이었다.
그리고 이전에 팀원들이 Java 11로 개발해왔다는 점도 하나의 이유였다.

플로우 구성

팀에서는 2가지의 이유로 유저, 시스템 2가지 플로우를 먼저 구성하기로 결정했다. 그 이유는 다음과 같았다.

  1. Viber 서비스에 대한 이해 부족
    Viber 챗봇의 개발은 기존 웹 개발과 달랐기 때문에 사용자의 입장에서 어떻게 동작하는지, 그리고 그에 따라 서버에서는 어떻게 요청을 받고 응답을 보낼지에 대해서 함께 논의해야 했다. 이를 위해 전반적인 플로우를 함께 논의하면서 구성하였다.
  1. 팀 프로젝트에서 원활한 협업의 목적
    Viber 서비스의 통신 과정은 사용자가 요청을 보내면 Viber 서버를 거쳐서 백엔드 서버에 도달하는 방식이다. 서버에서 응답을 보내는 것은 그의 역순이다. 따라서 모든 로직의 과정이 순차적으로 이루어져야 했고, 역할 분담을 하더라도 모든 팀원들이 전체적인 시스템 플로우를 이해할 필요성을 느꼈다.

유저플로우

시스템 플로우

프로젝트 진행

프로젝트를 구현하면서 어떻게 구현했고 어떤 고민을 했는지에 대한 내용을 작성해보았다.

Viber 서버로 부터 들어오는 Callback data를 어떻게 구분하여 처리할 것인가?

Viber의 공식 문서에서 따르면 Viber에서 챗봇을 생성한 후 서버와 webhook을 연결하면, 연결한 webhook url 하나로 모든 통신이 이뤄지는 방식이다.

    @PostMapping("/viber/bot/webhook")
    public ResponseEntity<?> webhook(@RequestBody String callback) 

이전 웹 개발의 경우 각 API마다 별도의 URL들을 지정하여 통신하는 방식이지만, 이번 개발은 하나의 url로 모든 요청을 받아야한다.

따라서 하나의 Controller에서 하나의 메서드에서 모든 요청들을 받고 응답을 해줘야하기 떄문에 이러한 요청들의 Type을 구분하기 위한 분기들을 나누는 것에 대해서 고민했다.

이를 위해 Callback data를 확인해보았다.

{
   "event":"conversation_started",
   "timestamp":1457764197627,
   "message_token":4912661846655238145,
   "type":"open",
   "context":"context information",
   "user":{
      "id":"01234567890A=",
      "name":"John McClane",
      "avatar":"http://avatar.example.com",
      "country":"UK",
      "language":"en",
      "api_version":1
   },
   "subscribed":false
}

Viber의 통신 방식은 사용자가 어떠한 요청을 하든 그 요청은 callback data의 형태로 서버에 전송된다.
따라서 우리는 Callback Data에 따라 요청의 종류를 나누고 그에 따른 로직을 처리하는 것으로 결정했다.

해당 챗봇에서 처리하는 요청의 유형(event)은 크게 4가지였다.

  1. 채팅창에 입장하여 대화를 시작 (conversation_started)
  2. 사용자가 챗봇을 구독 (subscribed)
  3. 사용자가 메시지를 보냄 (message)
  4. 사용자가 챗봇의 구독을 해제 (unsubscribed)

이를 각 이벤트 타입에 따라 분기를 나누고 타입에 따라 로직을 처리하는 메서드를 호출하도록 구현했다.

String event = getEventValueToCallback(callback);

if (event.equals(CONVERSATION_STARTED))
	return sendWelcomeMessage.execute();
if (event.equals(MESSAGE))
	return sendResponseByTextInMessage(callback);
if (event.equals(UNSUBSCRIBED))
	manageSubscription.unsubscribe(callback);
if (event.equals(SUBSCRIBED))
	manageSubscription.validateReSubscription(callback);

기능 구현에 대하여

해당 글 참고 - 담당한 기능들에 대한 정리

프로젝트를 마치고

한 달이 조금 넘는 짧은 시간동안 회사에서 제공한 간략한 요구사항을 바탕으로 하나의 프로젝트의 구현을 완료한 경험은 뜻깊었다.

1. 커뮤니케이션의 중요성을 다시 한 번 느끼다

이전 프로젝트에서 현직자와의 커뮤니케이션을 했던 경험이 없었던 것은 아니었다. 다만 이번 프로젝트와 달랐던 점은 이전의 프로젝트는 모든 기획부터 팀에서 진행했다는 점이고, 이번 프로젝트는 회사에서 제공한 간략한 요구사항을 바탕으로 정해진 주제에서 시작했다는 점이다.

프로젝트를 진행하면서 현직자와 소통이 필요하게 되었고, 슬랙을 사용한 글을 통한 커뮤니케이션, Zoom을 통해 실시간으로 대화로 이루어진 커뮤니케이션을 진행하게 되었다.

이를 통해 보다 구체적이고 명확하게 소통을 진행하는 법을 배우게 되었다.

글을 통해 소통을 진행할 때는 주요한 사항에 대해서는 볼드체를 통해 강조하였고, 질문하고 싶은 사항에 대해 구체적인 문제 상황과 문제 상황에 대한 팀에서의 생각을 논리적으로 정리하는 것이 필요하였고 그 과정을 통해 나의 생각을 설명하고 질문하는 방법에 대해 배울 수 있었다.

또한 4명의 팀원들과 1달 동안 함께 하면서 초반에 개발 방향과 플로우에 대한 싱크를 맞추기 위해 오랜 시간 회의를 한 것은 큰 도움이 되었다. 초반에 소통에 많은 시간을 투자하였고 이후 개발을 하는 데 있어 혼선을 줄일 수 있었다.

2. 다른 환경에서 개발을 경험해보다.

이전의 웹 개발과 다르게 챗봇을 개발하는 것은 해당 메신저의 API에 대한 이해가 1순위로 중요했다. 개발의 기술적 난이도가 높았던 프로젝트는 아니었지만, API 문서를 읽고 문서를 바탕으로 기능을 구현하는 것은 다른 난이도였다. 이 경험을 통해 앞으로 개발을 진행하는데 있어서 필요한 공식문서나 영어 문서를 활용하는 역량을 향상시킬 수 있었다.

3. 다시 한 번 느낀 개밥 먹기의 중요성...

Play-Dance-Live때도 느꼈지만, 실무에서 새로운 기능의 도입을 검토할 때 빠르게 테스트 할 수 있는 프로토타입을 빠르게 개발하는 이유에 대해 느꼈다. 클린 코드, 유지보수하기 편한 코드를 작성하면서 빠르게 개발을 하는 것이 좋지만, 실무에서는 빠르게 기능을 구현하고 그 기능이 돌아가는지 만들어 보는 것이 나쁜 개발이라고 단정할 수 없다고 느꼈다.

이번 프로젝트에서 사실 CTO님과 팀장님께 코드에 대한 피드백, 즉 코드 리뷰를 기대했었다.
하지만 스타트업에서 프로젝트를 진행하면서 느낀 것은 빠르게 비즈니스를 확장시켜 나가는 환경에서는 빠르게 새로운 프로젝트를 진행하는 경우가 있는 만큼, 당장에 돌아가는 코드를 일단 기간 내에 작성하는 것이 이번 프로젝트의 1차적인 목표의 달성이라는 말씀을 들었다.

새로운 기술의 도입이나, 개선은 이후에 공부를 하면서 문제점을 확인하고 개선하는 것으로 앞으로의 학습을 생각해보려고 한다.

profile
daelkdev@gmail.com

1개의 댓글

comment-user-thumbnail
2023년 7월 25일

좋은 글 감사합니다. 자주 올게요 :)

답글 달기