AYEONG.DEV
모든 글 보기

Project

졸업작품 하나 만들려다 풀스택 개발자가 되어버렸다

졸업 가능 할까요.

·
조회 0

01. 졸업작품? 주제부터 고르기 힘들었어요 엉엉

드디어 졸업작품을 만들어야 할 때가 왔는데 그동안 수업에서 배운 걸 활용해서 무언가 만들어야 한다니 살짝 설렜다.

이왕 만드는 거 단순한 CRUD 프로젝트보다는 누군가에게 실제로 도움이 되는 서비스를 만들어 보고 싶었다. (실제로 단순 CRUD 프로젝트는 교수님들이 싫어하기도 함.)

한동안 사회 뉴스를 엄청 챙겨봤었는데 유튜브에서 이런 영상을 봤다.

[ENG/JPN] 👨‍🦯시각장애인이 혼자 버스를 탈 수 있을까?🚌 사회실험 |실험카메라

평소 내가 아무렇지 않게 타고 다니는 버스가 누군가에게는 이렇게 어려운 일이 될 수 있다는 사실이 꽤 충격적이었다. 뭐랄까… 생각을 전혀 못하다가 망치로 머리 한 대 맞은 느낌?

버스가 오는지 확인해야 하고, 몇 번 버스인지 알아야 하고, 버스기사에게 탑승 의사도 전달해야 한다.

나에게는 이게 당연한 과정이었지만, 시각장애인에게는 이 모든 과정이 쉽지 않았다.

그때 든 생각은

"그럼 내가 앱으로 해결해 보면 되는 거 아냐?"

지금 생각하면 꽤 웃긴 발상이었다.

대학교 졸업작품으로 대중교통 이동권 문제를 해결해 보겠다니.

그렇게 시작한 프로젝트가 바로 시각장애인 이동권 개선을 위한 버스 애플리케이션이다.

처음에는 몰랐다.

이 프로젝트 때문에 내가 몇 번이나 밤을 새우게 될지.


02. 버스 예약 앱 하나 만들면 되는 거 아니야?

처음 기획했을 때 서비스 구조는 꽤나 단순해 보였다.

  • 현재 위치를 확인한다.
  • 주변 버스 정류장을 찾는다.
  • 음성으로 탑승할 버스를 예약한다.
  • 버스기사에게 예약 정보를 전달한다.
  • 목적지까지 이동한다.
  • 오? 생각보다 괜찮은데? 이 정도면 할 만하겠는데?

    ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ. 아니었다.

    막상 개발하려고 보니 문제가 하나둘씩 등장했다.

  • 사용자의 현재 위치는 어떻게 가져오지?
  • 주변 정류장은 어떤 기준으로 검색하지?
  • 실시간 버스 위치는 어디서 가져오지?
  • 버스기사에게 예약 정보는 어떻게 전달하지?
  • 음성인식이 버스 번호를 잘못 알아들으면?
  • 목적지가 실제 운행 노선에 있는지는 어떻게 확인하지?
  • 뭔가 복잡했다. 분명 앱 하나 만들면 끝이라고 생각했는데 어느새 개발해야 할 게 세 개로 늘어나있었다.

    Android 앱 + 웹 단말기 + 백엔드 서버. 거기에 DB까지…

    외부에서 버스 정보를 가져오기 위한 공공데이터 API 연동까지 필요했다.

    기술 스택은 다음과 같았다.

    이 때 깨달았다.

    기획 단계에서 '간단하겠는데?'라는 말은 함부로 하면 안 된다.


    03. 팀 프로젝트라고 했지, 같이 개발한다고는 안 했다.

    우리 팀은 2명이었다. 그리고 나는 팀장이었다.

    처음에는 역할을 나눠서 개발하면 될 거라고 생각했다.

    그런데 실제로는 기획부터 앱 개발, 웹 개발, 서버, DB까지 전부 내가 맡게 됐다.

    진짜 전부.

    아.

    팀장이라는 게 이런 거였나?

    분명 학교에서 배운 팀 프로젝트는 협업하는 거였는데 실제로는 혼자 풀스택 실습을 하고있는 나를 발견함.

    안드로이드 스튜디오에서 앱을 만들다가 API 연동이 안 되면 Node.js 코드를 열었다. 또 DB에 데이터가 이상하게 들어가면 MySQL을 확인하고, 웹 화면이 이상하면 React를 수정했다.

    프로젝트 하나를 개발하고 있는데 개발 환경은 계속 바뀌었다.

    그러다 새벽이 오면 '이것만 해결하고 자야지!!!' 했는데 어느새 해가 떠있는 걸 종종 봤다.

    물론 당시에는 꽤 힘들었다. 그런데 신기한 건 그렇게 고생하면서도 개발하는 게 싫지는 않았다는 것이다.

    오히려 막혔던 기능을 해결했을 때의 쾌감이 컸다. 특히 앱에서 입력한 데이터가 서버를 거쳐 웹 단말기에 정상적으로 표시되는 그 때는 진짜 기분이 말도 안되게 좋았다.

    다만 한 가지는 확실하게 배웠다.

    혼자서 할 수 있다는 것과 혼자서 해야 한다는 것은 전혀 다른 이야기다.

    다음 팀 프로젝트에서는 역할 분담부터 제대로 해야겠다고 다짐했다.


    04. 공공데이터 API? 그냥 호출하면 끝인 줄 알았다.

    버스 앱에서 가장 중요한 건 결국 버스 정보다. 근데 내가 경기도 전역의 버스의 위치를 어떻게 알 순 없다. 아무래도?

    당연히 공공데이터를 활용해야 했고 공공데이터포털에서 제공하는 경기도 버스 API를 사용했다.

    사용한 API는 크게 네 가지였다.

    plain text
    정류소 조회 API
     → 현재 위치 주변의 정류장 조회
    
    버스도착정보 조회 API
     → 정류장에 도착할 버스 정보 조회
    
    버스위치정보 조회 API
     → 버스의 현재 위치 조회
    
    버스노선 조회 API
     → 버스가 경유하는 정류장 조회

    처음에는 단순히 API를 호출하고 응답받으면 끝이라고 생각했다.

    plain text
    Request → API → Response

    이게 뭐 어렵겠어. 근데 실제 서비스에서는 그다음이 문제였다.

    사용자의 GPS 위치를 기반으로 주변 정류장을 조회해야 하고, 그 정류장에 정차하는 버스 목록을 가져와야 했다.

    그리고 사용자가 선택한 목적지가 해당 버스의 노선에 포함되어 있는지도 확인해야 했다. 하나의 기능을 위해 여러 API를 연결해야 했다.

    처음에는 각각의 API가 잘 동작하면 되는 줄 알았다.

    하지만 중요한 건 API를 호출하는 것 자체가 아니라, 서로 다른 데이터를 연결해서 사용자가 필요한 정보를 만들어 내는 일이었다.

    지금 생각하면 이때 처음으로 백엔드에서 데이터 흐름을 설계하는 재미를 느꼈던 것 같다.


    05. 08764를 왜 팔천칠백육십사라고 읽는 건데.

    이번 프로젝트에서 꽤 기억에 남는 버그가 있다.

    바로 정류소 ID 음성 안내 문제다.

    시각장애인을 위한 서비스이기 때문에 화면에 정보를 표시하는 것만큼 음성 안내도 중요했다.

    예를 들어 정류소 ID가 08764라면 다음과 같이 읽어야 했다.

    plain text
    기대한 결과
    "공, 팔, 칠, 육, 사"

    그런데 TTS가 읽어준 결과는?

    plain text
    실제 결과
    "팔천칠백육십사"

    ...?

    아니. 왜 이렇게 읽는 건데 ㅠㅠㅠㅠㅠㅠㅠㅠㅠ

    생각해 보면 프로그램 입장에서는 틀린 게 아니었다. 틀려도 내가 틀렸겠지. 숫자처럼 생긴 문자열을 숫자로 읽은 것뿐이다. 하지만 정류소 ID는 일반적인 수가 아니라 식별자였다.

    08764에서 앞자리 0이 사라지면 안 됐다. 그래서 문자열을 가공하는 방식으로 해결했다. 숫자 사이엔 공백을 추가하고, split()을 이용해 각 자릿수를 구분하도록 코드를 수정했다.

    plain text
    Before
    08764
    
    After
    0 8 7 6 4

    그 결과 정류소 번호를 각각의 숫자로 읽도록 만들 수 있었다.

    사실 뭐 엄청난 알고리즘을 구현한 건 아니었다. 그런데 이 작은 문제를 해결하면서 꽤 중요한 걸 배웠다.

    프로그램이 정상적으로 동작하는 것과 사용자가 원하는 방식으로 동작하는 것은 다르다.

    특히 시각장애인을 위한 앱에서는 이런 사소한 차이가 사용성에 직접적인 영향을 줄 수 있었다.


    06. "701번 버스 탈래"를 컴퓨터가 알아듣게 하기.

    음성인식 기능도 만만치 않았다. 처음에는 사용자가 말한 내용을 텍스트로 변환하면 끝이라고 생각했다.

    그런데 사용자가 항상 똑같은 문장으로 말하지는 않는다. 한국어의 비애. ㅠㅠ

    plain text
    "701번 버스"
    "701번 버스 탈래"
    "701번 버스 타고 싶어"

    결국 중요한 건 텍스트 자체가 아니라 사용자가 어떤 의도로 말했는지 파악하는 일이었다. 그래서 한국어 형태소 분석기인 Komoran을 사용했다. Komoran은 한국어 문장을 형태소 단위로 나누고 각각의 품사를 분석할 수 있게 도와준다.

    실제 테스트 문장은 다음과 같았다.

    plain text
    701번 버스 탈래

    분석 결과는 이랬다.

    plain text
    701   → SN   (숫자)
    번    → NNB  (의존명사)
    버스  → NNG  (일반명사)
    타    → VV   (동사)
    ㄹ래  → EC   (연결어미)

    오. 생각보다 신기했다. 문장을 입력했는데 숫자, 명사, 동사가 구분되어 나왔다.

    단순히 문자열을 비교하는 게 아니라 문장 안에 어떤 요소들이 존재하는지 분석할 수 있었다. 물론 형태소 분석이 모든 음성 명령을 정확하게 처리해 주는 마법은 아니다.

    하지만 이 과정을 통해 음성을 텍스트로 바꾸는 STT와 텍스트의 의미를 분석하는 과정은 서로 다르다는 것을 알게 됐다.

    모르는 기술을 직접 찾아보고 적용해 보면서 새로운 걸 배우는 재미도 있었다. 이래서 개발이 재밌나 보다.

    물론 에러 안 날 때만.


    07. 시각장애인을 위한 앱인데, UI가 왜 이렇게 어렵지?

    개발하면서 의외로 고민을 많이 했던 부분이 UI였다. 처음에는 화면을 최대한 예쁘게 만들고 싶은 욕심이 있었다.

    그런데 이번 프로젝트는 일반적인 앱과는 달랐다. 주 사용자가 시각장애인과 저시력자였기 때문이다.

    시각장애인이라고 해서 모두 동일한 방식으로 앱을 사용하는 것은 아니었다. 전맹 시각장애인에게는 음성 안내가 중요하고, 저시력자에게는 화면의 색상 대비와 정보 배치가 중요했다.

    그래서 최대한 직관적인 화면을 만들려고 했다.

  • 고대비 색상 사용
  • 불필요한 UI 요소 최소화
  • 버스 종류에 따른 배경색 구분
  • 큰 정보 표시 영역
  • 음성인식 버튼 중심의 화면 구성
  • 실제 메인 화면에는 출발 정류장, 탑승 버스, 도착 정류장 정보를 크게 배치했다.

    처음에는 디자인을 잘한다는 게 예쁜 화면을 만드는 일이라고 생각했다.

    그런데 이번 프로젝트를 하면서 생각이 달라졌다.

    좋은 UI는 예쁜 화면이 아니라, 사용자가 실제로 사용할 수 있는 화면이었다.


    08. 사회문제를 해결하는 서비스는 돈을 어떻게 벌어야 하지?

    졸업작품에서 가장 예상하지 못했던 난관 중 하나. 비즈니스 모델이었다. 개발이야 어떻게든 구현하면 되는 문제지만 서비스를 만들었으면 실제 운영 가능성도 고민해야 했다.

    문제는 이번 프로젝트가 사회적 가치를 목적으로 하는 서비스였다는 것이다.

    시각장애인의 이동권을 개선하겠다면서 무작정 사용자에게 돈을 받을 수도 없는 노릇이었다. 그렇다고 서버를 영원히 공짜로 운영할 수 있는 것도 아니었다.

    고민이 시작됐다.

    plain text
    서비스 운영 비용은 누가 부담하지?
    
    버스기사용 단말기는 어떻게 보급하지?
    
    실제 버스 운영기관과 어떻게 연결하지?
    
    서비스를 지속적으로 운영하려면?

    음. 이건 스택 오버플로우에서 해결 방법을 찾을 수 있는 문제가 아니었다. 기술적으로 구현할 수 있는 것과 실제 서비스로 운영할 수 있는 것은 또 다른 영역이었다.

    개발만 잘하면 끝일 줄 알았는데, 서비스의 지속 가능성까지 생각해야 했다. 결국 졸업작품에서 모든 문제를 해결하지는 못했다.

    하지만 좋은 개발자는 단순히 기능을 구현하는 사람이 아니라, 그 기능이 왜 필요하고 현실에서 어떻게 사용될 수 있는지까지 고민하는 사람이라는 생각을 하게 됐다.


    09. 개발 끝! 이제 배포만 하면 되겠네. (응 아니야.)

    드디어 앱이 완성됐다. Android Studio에서 정상적으로 실행됐고, 주요 기능도 구현했다.

    이제 Google Play 스토어에 올리기만 하면 끝이었다. 진짜 끝인 줄 알았다.

    그런데 앱 배포는 처음이었다.

    개발자 계정을 만드는 것부터 시작해서 앱을 등록하고 배포를 준비하는 과정까지 전부 처음 접하는 것들이었다.

    분명 개발은 끝났는데 또 공부해야 할 게 생겼다. '아니... 배포가 이렇게 귀찮은 일이었나?'

    웹을 배포하는 것과 Android 앱을 스토어에 등록하는 건 또 다른 경험이었다. 개발 환경에서 정상적으로 실행되는 것과 실제 사용자에게 배포하는 과정은 완전히 달랐다.

    그래도 하나씩 해결해 나갔다.

    그리고 결국.

    Google Play 스토어 배포 성공함.!!!!! 🎉

    그동안 작성한 코드가 실제로 설치 가능한 앱이 됐다는 게 신기했다.

    이때 처음으로 개발의 끝은 코드 작성이 아니라는 걸 실감했다.

    내 컴퓨터에서 잘 돌아가는 프로그램과 다른 사람이 실제로 사용할 수 있는 서비스는 다르다.


    10. 밤새 만든 졸업작품, 결과는?

    기획부터 개발, 디자인, 배포까지. 그리고 최종 발표 PPT까지. 정말 많은 시간을 쏟았다.

    버그를 해결하면 새로운 버그가 생겼고, 앱을 수정하면 서버도 수정해야 했다. 분명 하나의 졸업작품인데 할 일이 끝나지 않았다. 특히 발표를 앞두고는 개발한 내용을 정리하고 시연까지 준비해야 했다.

    그 와중에 PPT도 만들었다. 이쯤 되니 개발자가 아니라 1인 스타트업 대표가 된 기분이었다. 그래도 결국 완성했다.

    Google Play 스토어 배포까지 마쳤고, 캡스톤디자인 최종 발표도 무사히 끝냈다. 그리고 받은 결과는.

    캡스톤디자인 만점. 이건 좀 뿌듯했다.

    그동안 밤새웠던 시간이 조금은 보상받는 느낌이었다. 물론 가장 좋았던 건 점수보다도 내가 직접 기획한 서비스를 실제로 완성했다는 사실이었다. 앱, 웹, 서버, DB가 하나의 서비스로 동작한다는 게 신기했고, 처음부터 끝까지 직접 해냈다는 점에서 자신감도 생겼다.


    11. 그래서 개발자가 되고 싶어졌다.

    졸업작품을 만들기 전에는 개발을 잘한다는 게 코드를 잘 작성하는 일이라고 생각했다. 그런데 막상 하나의 서비스를 완성해 보니 그게 전부가 아니었다. 사용자가 겪는 문제를 이해해야 했고, 필요한 기술을 선택해야 했고, 예상하지 못한 오류를 해결해야 했다.

    처음 접하는 기술도 많았다. 어떤 문제는 몇 시간 동안 붙잡고 있어야 했는데 또 어떤 문제는 해결 방법을 찾고 나면 허무할 정도로 간단했다.

    그렇게 삽질을 반복하면서 알게 된게 있다!

    개발은 정답을 외우는 일이 아니라 문제를 해결하는 과정에 가깝다는 것. 모르는 게 생기면 찾아보면 된다. 지금 생각해보면 구글에서 검색했을 때 나오는 기술 블로그와 스택 오버플로우 덕에 많은 고비를 넘겼다. 나도 어려운 문제를 해결했을 땐 잘 기록해둬야지!

    물론 지금도 모르는 기술이 훨씬 많다. 그렇지만 새로운 걸 배워서 실제 기능으로 만드는 과정이 재미있다.

    앞으로 어떤 개발자가 될지는 아직 모르겠다. 프론트엔드든 백엔드든, 새로운 기술을 배우고 무언가를 만들어 내는 일은 계속하고 싶다. 졸업이 얼마 남지 않았지만 뭔가 실무에 한 발자국 가까워진 느낌? ㅋㅋㅋㅋ

    처음에는 그냥 졸업하려고 시작한 프로젝트였는데 끝나고 보니 얼른 개발자로 살아보고 싶다는 마음이 더 커졌다.

    2023년 졸업작품을 통해 배운 것.

    그리고 마지막으로 하나 더.

    다음 팀플은 제발 팀플이었으면 좋겠다.


    2023년 6월, 캡스톤디자인을 마치며.