코규리
article thumbnail

 

🧚🏿‍♀️: 이번에도 IOT 프로젝트를 하셨다구요! 어떤 프로젝트예요?


🍊 한 문장으로 하면, 자율주행 Device를 통해 신축 건물의 시공 결함을 파악하는 서비스를 위한 플랫폼
크게 개발 부분을 세 가지로 나누면 다음과 같아요.
1️⃣ ROS상에서 자율주행 및 결함 탐지 AI가 탑재된 Device개발
2️⃣ 해당 Device를 조작할 수 있는 (가상의 하자 탐지 서비스 직원이 이용하는) Application
3️⃣ 해당 서비스를 신청/결제할 수 있는 (고객이 이용하는) Web

 

🧚🏿‍♀️: 어떤 부분을 맡았나요?


🍊 팀 구성에 따라 Device팀이 ROS관련 AI 알고리즘을 전면 담당했고 Front팀은 React기반 고객 전용 Web 화면과 직원 전용 Application 화면 구현을 맡았어요. 그리고 이 두 팀간의 데이터 송수신을 위한 비즈니스 로직 구현을 하는 Backend가 제가 맡은 부분이에요.
Backend팀은 2명으로 구성되었고, 그 중 한 명인 제가 세부적으로 구현한 사항은 다음과 같아요.

  • SpringSecurity & JWT 기반 회원 보안
  • Session & Redis & Naver SMS 인증을 통한 비회원 보안
  • IoT기기와 App 사이의 Socket통신 구현

 

🧚🏿‍♀️: 보안이 두 종류네요! 왜 그렇게 나누었나요?


🍊Application과 Web은 서로 다른 보안을 가지고 있어요. 그 이유는 해당 서비스 이용자의 성격이 달랐기 때문이죠.

Application은 빈번한 접근이 기대되는 직원이 사용한다

우선, Application의 경우 직원이 사용해요. 직원은 프로젝트 설계상 Application을 하루동안 굉장히 많이 접근할 것으로 기대하고 있어요. 더불어서 '기업'의 입장에서 따지자면 직원이 수집하는 정보들은 사내에서 관리해야 할 정보이기에 접근 보안성이 필요할 것 같았구요. 그래서 JWT기반의 보안을 수행하되, _Access/Refresh Token_을 적용하여 일정 기간 내에 재접속을 한다면 별도의 로그인 과정을 생략할 수 있으니 사용자 경험을 향상시킬 수 있도록 하기 위해 사용하였습니다.

Web은 일회성이자 이용시간이 짧을 것으로 기대되는 고객이 사용한다

반대로 Web에서 JWT 토큰 인증 방식을 유지 하지 않았던 이유는, 이 또한 해당 프로젝트 설계상 Web을 이용하는 고객은 '비회원'이었기 때문이에요. Web의 일회성 사용이 기대되면서 이용시간이 굉장히 짧은 비회원은 DB에 저장되지 않을 것이고, 때문에 해당 비회원의 식별값을 JWT담아 인증/인가를 하는 것보다 더 낮은 레벨의, 최소한의 보안을 가지는 것을 고려했어요. 따라서 해당 비회원의 SessionID를 Redis에 저장하도록 CustomFilter를 만들어 일정 시간동안의 접근을 허용했습니다. 마치, 제가 구직을 위해 자소서를 쓰면 로그인 이후 제한시간 내에서만 이용할 수 있는 것처럼요.

 

🧚🏿‍♀️: 왜 IoT기기와 Application은 Socket 통신을 하게 되었나요?


🍊 사실 IOT기기 통신 기법으로 보다 적합한 MQTT를 고려해봤어요. 그런데 전문분야 컨설턴트님께 자문을 구해본 결과, Socket 속에서도 MQTT 규격을 맞추는 것으로도 해결될 것이며 또한 해당 프로젝트에서 'MQTT'를 고집하는 것 자체를 목표로 삼으면 러닝커브로 인한 구현 지연이 우려된다고 하셨어요. 또한 프로토콜 특징상, 경험도 없는 상황에서 예측 불가한 문제 발생 시의 대처 가능성을 배제할 수 없었구요. 따라서 Socket을 통한 해결 방법을 모색하게 되었습니다.

그래서 Socket에서 자체적인 JSON타입의 Message 통신규약을 만들어 데이터 송수신 및 제어, JWT인증까지 할 수 있도록 구현했습니다. 다만.. 뒤늦게 알았지만 WebSocket에서 STMOP를 통해 MQTT처럼 Subscribe/Publish 모델을 구현하면 보다 용이하게 개발할 수 있었겠더라구요. 개발 과정 중 늦은 시점에 알았기에, 이 부분이 아쉽네요.

 

🧚🏿‍♀️: 가장 신경 쓴 부분이 있나요?


🍊 네! 앞서말한 Socket Message 처리가 가장 신경 쓴 부분이에요. 당시 Device가 어떤 정보까지 수집할 수 있을지 확정이 나지 않았기에, 최대한 다양한 종류의 Message 종류를 JSON형태로 정의하고 이에 따른 비즈니스 로직을 각각 처리할 수 있게 해야했어요. 그러다 보니 다음과 같은 추가 작업이 있었죠.

디자인패턴을 통한 Message 별 비즈니스 로직 수행

약 8개가 넘는 Message 종류가 있었어요. 예를 들어 JWT를 통해 Device인지 직원인지 식별하고, 어떤 Device를 제어하고 싶은지 확인하여 기기를 가동하고, Device의 메시지에 따라 정보를 DB에 저장할지, S3를 통한 이미지 처리가 필요할지, 또 바로 직원에게 발신해야할지 등이 있었어요. 이러한 비즈니스 로직이 추가될 때마다 저의 코드는 굉장히 난잡했고 정리해야 할 시기가 필요했습니다.
결과적으로 Strategy 디자인 패턴을 개선법으로 찾았습니다. 이 패턴으로 다양한 비즈니스 로직을 교체할 수 있으며 새로운 전략 추가시의 확장성을 갖추며 각 전략이 자신만의 알고리즘을 수행할 수 있도록 할 수 있었죠.

복잡한 통신 순서와 오류에 대한 Response 남기기

설계상, 각 메시지는 순서가 요구되는 작업들이 있었어요.
예를 들어 인증 -> 통신 상대 지정 -> 데이터 수신 -> 통신 상대 종료 등, 선 작업이 일어나지 않으면 통신이 정상적으로 수신할 수 없었어요. 통신 수행 과정의 이해를 최대한 돕고자 Sequence Diagram 을 그리며 팀원들에게 전달해 봤지만, 여전히 개발과정에서는 어디서부터 잘못된 건지 원인을 찾기 어렵더라구요. 그래서 최대한 어떤 것이 문제인지를 응답하는 메시지를 작성하는 데 주의를 기울였습니다. 관련해서 생각나는 것이 Socket 통신 전용 오류 메시지 코드도 있어서 적용하려다가, 다같이 하는 팀 작업에 이 오류 상태코드를 익히는 것도 남은 시간대비 러닝커브가 커서 보류했었네요.

 

🧚🏿‍♀️: 아쉬운 점이 있다면 무엇인가요?


'알면서도 못한 일'인 것 같아요.
문제점 혹은 개선점을 찾았음에도 시간과 업무의 효율성을 위해서 포기해야 하는 일이 있었어요. 앞서 말한 것처럼 Socket의 Stomp는 사실 안 쓰던 이유 중 하나가 러닝커브 이외에도 현재의 요구사항이 Publish/Subscribe 모델과 맞지 않을 수 있다는 생각이 있었거든요. 하지만 다시 찾아보니 해당 모델을 써도, 조금 더 탐구하면 더 용이한 방법이 있을 것 같더라구요.
또.. 다 하고 보니, 필요하지 않은 일을 했다라는 자각도 있었어요. 각 API에 대한 Response를 보낼 때 응답코드를 이미 보내면서도 문장으로 "성공적으로 처리되었습니다. "와 같이 불필요한 문구를 함께 내보냈거든요.
이런 점들을 프로젝트 마무리 이후 팀원(🐶)과 함께 얘기했었는데, 다음 번 프로젝트에는 개선해보려고 합니다.

라구 인터뷰할 날이 오길.

[이게MO징 Github]