어느날 챗봇 Javascript SDK가 만들어졌다...?

Taesol Kwon·2023년 12월 12일
0
post-custom-banner

기존에 이전 회사에서 운영하던 챗봇 서비스의 경우, 챗봇을 운영하는 고객들마다 필요한 기능이 각각 달랐기 때문에 고객 별로 프로젝트를 운영하고 유지보수해야 했고, 저희가 고객들의 챗봇을 직접 설치하는 방식으로 불필요한 수작업을 걸쳤습니다. 이는 매우 비효율적적이고 많은 개발비용이 들어갔기 때문에 이러한 과정을 개편하기 위해서 누구나 쉽게 접근할 수 있도록 만들 필요가 있었습니다.

새롭게 진행된 프로젝트는 위의 개선사항들을 개편을 통해서 사용자가 챗봇 빌더를 이용해 직접 챗봇의 시나리오를 설정하고, 챗봇의 스타일을 커스텀하여 다른 브라우저에 챗봇을 서빙할 수 있는 서비스였습니다.

그리고 저는 그 중에서 챗봇을 서빙할 수 있는 방법 중에 가장 고민을 많이 했던 Javascript SDK 방식을 소개해 보고자 합니다.

먼저 Javascript SDK을 접했을때, 이거 뭐 어떻게 구현하라고...? 가 가장 먼저 든 생각이었습니다. 그만큼 SDK란 말은 많이 들었지만, 구현을 해야할 입장에선 새로운 도전이기도 했습니다.

그렇다면 먼저 SDK에 대해 간략히 알아볼 필요가 있습니다.

SDK란 Software Development Kit의 약자로, 개발자를 위한 플랫폼별 구축 도구 세트입니다.
SDK는 결제 연동, 챗봇 연동 등 복잡한 기능들을 간편하게 구축하도록 돕습니다.
예를 들자면, SDK는 밀키트에 비유할 수 있습니다. 초보자가 이를 사용하면 특정 요리를 더 쉽고 빠르게 만들 수 있도록 도와줍니다.

라이브러리와 비슷한거 아닌가요?
그렇게 느낄 수 있지만 라이브러리는 토마토 소스, 파스타 면 과 같이 독립적으로 사용할 수 있고, 여러군데 활용이 될 수 있는 요리 재료라고 생각해볼 수 있습니다.

어떻게 SDK를 사용해서 챗봇을 서빙할수 있을까?

먼저 저희는 사용자들이 가장 범용적으로 사용할 수 있도록 IE를 제외한 웹에 서빙할 목적을 가지고 있었습니다. 그렇기 때문에 Javascript SDK를 선정하게 되었고, 이를 활용하여 챗봇 서비스를 서빙하였습니다.

왜 NPM 방식이 아닌 임베딩 코드를 사용했는가?

Javascript SDK를 구현하는데는 npm 패키저 매니저와 임베딩 코드, 두 가지 방식을 고려했습니다.

임베딩 코드의 경우
[장점]

  • 간편성: 복잡한 설치 과정 없이 간편하게 코드를 몇 줄 추가하면 됩니다
  • 최신성: 사용자가 별도 업데이트를 할 필요 없이 최신 버전을 자동으로 사용할 수 있습니다.
  • CDN의 이점: CDN을 통해 스크립트를 제공받으면 로드 시간이 단축되고, 트래픽 분산 효과도 얻을 수 있습니다.

[단점]

  • 종속성: 웹 페이지가 외부 서버로부터 스크립트를 로드해야 하므로 외부 서버의 가용성에 의존합니다.
  • 보안문제: 외부 스크립트는 보안 취약점을 노출할 수 있습니다.
  • 버전 관리: 특정 버전의 SDK를 사용해야할 경우 , 버전 관리가 어려울 수 있습니다.

npm 패키지 방식의 경우
[장점]

  • 버전 관리: 특정 버전의 SDK를 설치할 수 있고, 의존성을 정확히 제어가 가능합니다.
  • 모듈 번들링: 프로젝트의 빌드 과정에서 모듈 번들러를 사용하여 SDK를 포함시킬 수 있습니다.
  • 보안: npm 패키지를 사용하면 소스 코드를 직접 검토하고, 필요한 보안 검사를 수행할 수 있습니다.

[단점]

  • 설치 과정: 사용자는 npm을 통해 패키지를 설치하는 과정을 거쳐야 합니다.
  • 업데이트 관리: 새버전이 출시 될때마다 수동으로 업데이트해야할 수 있습니다.
  • 환경제한: npm 패키지는 Node.js 환경이나 모듈 번들러가 필요합니다.

장단점을 비교해보았을때, 해당 서비스의 경우 손쉽게 챗봇 기능을 추가하고 사용자가 별도로 업데이트 할 필요없이 최신 버전을 사용할 수 있는 목적이 있었기 때문에, 그리고 회사코드의 유출을 원하지 않았던 저희는 임베딩 코드를 통해 서빙하는 방식을 택했습니다.

임베딩 코드 설계방법

이는 HTML 문서의 script 태그를 사용하여 외부 Javascript 파일을 직접 참조하는 방식입니다.


위의 그림을 보면 연동과정을 살펴 볼 수있습니다.
1. 챗봇을 이용중인 A 사이트 프론트엔드에 Chatbot.js 파일을 include하고 필요한 parameter를 설정합니다.
2. 사이트가 최초 실행(로드)
3. Chatbot.init() 메서드가 호출되면서 챗봇 플로팅 아이콘이 호출되게 됩니다.

이번에는 예시를 보도록 하겠습니다.

<!DOCTYPE html>
<html lang="en">
	...
	<body>
		<div
			id="chatbot-container"
			data-chatbot-id="u86j4ripEt8LRfPGzQ8f23fsdf" // AgentId
			data-margin-right="30px" // 아이콘의 스타일 설정값
			...
		/>
		
		<!-- React 컴포넌트가 이 div 안에 렌더링됩니다. -->
		<div id="root"></div>
		
		<script>
			(function (d, s, id) {
				var js,
				fjs = d.getElementsByTagName(s)[0];
				if (d.getElementById(id)) {
				return;
				}
				js = d.createElement(s);
				js.id = id;
				js.src ='https://ABC.com/chatbot.min.js'; // 
				fjs.parentNode.insertBefore(js, fjs);
			})(document, 'script', 'chatbot-embed');
		</script>
	</body>
</html>
  1. 챗봇을 설치하는데 필요한 고유한 고객의 chatbot-id와 커스텀한 스타일값을 전달할 수 있게 div 태그를 최상단에 위치시키게 됩니다. 데이터 속성을 통해서 원하는 값들을 chatbot.js 파일에서 접근할 수가 있습니다. 여기서 chatbot-id는 보안을 위해서 백엔드 서버에서 생성해준 암호화된 해쉬값을 사용하게 됩니다.

  2. script 태그를 HTML 마크업에 직접 삽입하는 대신 js를 통해서 동적으로 추가하는 방식을 이용해 즉시 실행 함수 표현식(IIFE)을 사용해 비동기적으로 로드하도록 합니다. 이렇게 되면 페이지 로딩과 동시에 실행되지만, 페이지의 파싱이나 다른 스크립트의 로딩을 차단하지 않게 됩니다.

<script src="https://ABC.com/chatbot.min.js" id="chatbot-embed"></script>

반대로 직접 삽입하는 방식을 사용하게 되면, 브라우저가 자동으로 해당 스크립트를 로드하고 실행하지만, 만약 스크립트가 크거나 서버 응답이 느릴 경우 페이지의 나머지 콘텐츠 로딩에 지연을 초래할 수 있습니다.

그렇다면 왜 async나 defer 속성을 사용하지 않았나요? 이 속성들도 비동기적으로 로드하도록 돕는 속성인데요?

script async

  • 스크립트가 병렬로 다운로드되기 시작하고, 다운로드가 끝나는 대로 실행됩니다.
  • HTML 파싱과 독립적으로 실행되며, 스크립트가 준비되는 즉시 중단할 수 있습니다.
  • 스크립트 간의 실행순서를 보장하지 않습니다.

script defer

  • 스크립트가 병렬로 다운로드 되고, HTML 파싱이 완전히 끝난 후 실행됩니다.
  • DOMContentLoaded 이벤트 전에 실행되며, 스크립트 간의 샐행 순서를 보장합니다.

IIFE를 사용한 동적 스크립트 삽입

  • 동적 스크립트를 생성하면 페이지 로딩에 영향을 주지 않고 필요한 시점에 스크립트를 로드할 수 있습니다.
  • 이미 로드된 스크립트의 중복 삽입을 방지할 수 있는 로직을 포함할 수 있습니다.
  • 스크립트를 로드하기 전후로 추가적인 사용자 로직을 실행할 수 있습니다. 예를 들면, 스크립트 로딩 실패 시에 대비한 콜백이 있습니다.

위의 특징들을 살펴볼때 챗봇의 경우 페이지 로딩에 영향을 주면 안된다 생각했었기에 동적 스크립트 삽입 방식을 선택했었습니다.

하지만 다시 만들게 된다면, 동적 스크립트의 방식의 경우 다른 스크립트의 로딩 상태에 따라 시점이 달라져야하거나, 추가적인 로직이 필요할 때가 더 적합한 상황이므로 해당 챗봇 서비스의 경우 고객의 브라우저 DOM에 의존성이 없기 때문에 좀 더 간편하고 빠르게 표시될 수 있는 async 속성을 이용해 작성할 것입니다.

  1. chatbot.js 파일의 용량을 줄이기 위해서 minify한 chatbot.min.js 파일을 CDN에서 호스팅 될 수 있도록 만들었습니다.

  2. 이후에 챗봇 플로팅 아이콘이 노출이 되게 되면 이를 클릭하면 body에 appened된 iframe을 통해서 챗봇이 실행되게 됩니다.

임베딩 코드를 사용해 작성을 해보니 향후에 데이터 속성을 추가하거나 스크립트 로직을 변경함에 있어서 확실히 유연성이나 확장성 면에서 간편한 이점이 있었습니다.
또한, Javascript SDK를 만들면서 사용자가 간편하게 이용할수 있게끔 문서화를 해두는게 필수적이라고 생각이 들었습니다. 개발자가 아닌 일반 고객이 봐도 쉽게 이해할 수 있을 정도로 말입니다. 하지만 보안적인 부분을 살펴보았을때 외부 스크립트가 다운로드 되는 과정에 악성코드가 심어진다거나 탈취될 위험성이 있기 때문에 보안 이슈들을 잘 체크해야할 것 같습니다.

profile
사진촬영을 좋아하는 프론트엔드 개발자입니다.
post-custom-banner

0개의 댓글