LINE Corporation이 2023년 10월 1일부로 LY Corporation이 되었습니다. LY Corporation의 새로운 기술 블로그를 소개합니다. LY Corporation Tech Blog

Blog


LINE 메신저 앱의 공유 모듈 통합 개발기 - 2

들어가며

지난 1편에서 LINE iOS 공유 기능 모듈을 개발하면서 겪었던 어려움과 이를 해결해 나간 방법을 아래 여섯 가지로 나눈 뒤 '1. 데이터 모델 규약 통합'과 '2. 데이터 공유 로직 통합'의 내용을 먼저 설명드렸습니다.

  1. 데이터 모델 규약 통합
  2. 데이터 공유 로직 통합
  3. 사용 가능한 서비스 목록 판단
  4. 커스텀/추가 액션 제공
  5. 예외 처리 일반화
  6. UI/UX 개선

이어서 이번 글에서는 '3. 사용 가능한 서비스 목록 판단'부터 '6. UI/UX 개선'까지 설명드리면서, 공유 모듈을 사용하는 LINE 내 여러 서비스의 다양한 요구 사항을 만족하면서 유지 보수가 편하고 확장 가능한 구조로 구현하기 위해 저희가 어떤 고민을 했는지 공유하겠습니다.

3. 사용 가능한 서비스 목록 판단

아래와 같이 공유 화면의 하단에는 대화방 이외에 콘텐츠를 공유할 수 있는 서비스 목록이 나타납니다. 

그림 5. 공유 가능한 서비스 목록

공유를 시작한 화면의 종류에 따라 달라질 수 있고, 선택된 콘텐츠의 유형에 따라서도 달라질 수 있는 목록입니다. 사용할 수 있는 서비스를 필터링해서 보여주기 위해 내부 구조를 어떻게 설계했는지 소개하겠습니다.

문제점

공유 화면을 열었을 때 노출되는 공유 가능한 서비스 목록은 아래와 같은 두 가지 이유로 각 상황에 따라 다르게 결정됩니다.

  • 진입 서비스에 따라 목적 서비스로 선택할 수 있는 서비스의 종류가 다름
    • 예) 앨범과 노트는 대화방에서만 사용할 수 있는 서비스임 → 대화방에서 공유 모듈을 열었을 때만 노출되어야 함
  • 목적 서비스에 따라 처리할 수 있는 콘텐츠의 종류가 다름
    • 예) 앨범은 이미지만 처리할 수 있음 → 텍스트나 비디오 등을 선택하면 전송이 제한되어야 함

LINE에서 지원하는 서비스와 콘텐츠의 유형은 다양합니다. 그래서 이러한 조건을 한곳에 정리해보면 아래 그림 6과 같이 다소 복잡한 형태가 됩니다. 표 가장 왼쪽의 Area 열은 공유를 시작하는 서비스 종류를 의미하고 Source type은 사용자가 선택하여 공유하려고 하는 콘텐츠의 종류를 나타냅니다. 각 Area와 Source type에 따라 공유 화면에 나타날 수 있는 서비스의 종류가 오른쪽에 표시되어 있습니다.

그림 6. 진입 서비스, 콘텐츠 유형별 공유 가능한 서비스 목록

표에는 한 가지 유형의 콘텐츠를 선택했을 때 공유 가능한 서비스의 목록이 정리되어 있습니다. 하지만 실제로는 다양한 유형을 가진 여러 개의 콘텐츠를 선택하는 것이 가능하기 때문에 표에 정리된 것보다 훨씬 다양한 경우가 발생할 수 있습니다.

이전에는 이런 복잡한 제한 사항이 한곳에 정리되어 코드로 구현되어 있지 않았습니다. 따라서 각 서비스나 콘텐츠마다 사용 가능한 서비스가 무엇인지 코드에서 파악하고 관리하는 게 어려웠습니다.

해결책

서비스 목록을 결정하는 두 가지 요인인 진입 서비스의 종류와 콘텐츠의 종류에 따라 사용 가능한 서비스 목록을 도출해서 교집합을 계산하기로 했습니다.

1. 진입 서비스의 종류

각 서비스가 공유 모듈을 호출할 때 희망하는 서비스의 목록을 입력할 수 있도록 했습니다. 예를 들면 앨범에서 공유 모듈을 호출할 때 includedShareActivityTypes 파라미터를 통해서 '킵, 타임라인 그리고 다른 앱으로도 공유하고 싶다'라고 포괄적으로 지정하는 것입니다. includedShareActivityTypes에 지정한 서비스는 아래에서 소개할 공유 콘텐츠의 종류를 참고해서 필터링됩니다. 따라서 공유 모듈에 항상 노출되는 것이 보장되지는 않으며, 공유 모듈에서 표시할 수 있는 서비스의 후보라고 생각할 수 있습니다. includedShareActivityTypes에 희망하는 서비스의 목록을 명시함으로써 서비스 간의 연결 관계가 궁금할 때 공유 모듈을 호출하는 코드를 확인하여 쉽게 파악할 수 있고, 각 진입 서비스에서 공유를 추가하고 삭제하는 것이 쉬워지는 효과를 얻을 수 있습니다.

iOS의 시스템 공유 기능도 진입 서비스가 공유 가능한 서비스의 목록을 제어할 수 있습니다. iOS에서 다른 앱으로 공유하는 기능을 담당하는 UIActivityViewController 클래스는 excludedActivityTypes라는 배열을 가지고 원치 않는 서비스를 목록에서 제외하는 방식을 사용합니다. iOS에서 excludedActivityTypes를 이용해 공유 가능한 서비스 목록에서 서비스를 배제하는 방식을 취한 것과 다르게 LINE에서는 includedShareActivityTypes를 이용해서 원하는 서비스의 목록을 포함적으로 선언하는데요. 그 이유는 iOS 공유 시스템과 LINE 공유 모듈의 특성이 다르기 때문입니다. 

iOS의 공유는 서비스들이 목록에 노출될 것인지, 숨겨질 것인지를 결정하는 권한이 각 서비스 자체에 있습니다. 게다가 iOS 공유 화면에 표시되는 서비스 종류의 범위는 사용자가 설치한 앱에 따라 달라지기 때문에 서비스 종류가 매우 다양하고 빈번하게 변경됩니다. 이 두 가지 특성 때문에 목록에 어떤 서비스가 나타날 수 있는지는 진입 서비스의 코드에서는 예상할 수 없습니다. 따라서 iOS 공유 화면을 실행하는 주체에서는 '어떤 서비스를 표시하고 싶은가'가 아닌 '어떤 서비스를 제외하고 싶은가'를 고민하는 것이 훨씬 효율적입니다. 만약에 iOS 공유 화면을 실행하는 쪽에서 '어떤 서비스를 표시하고 싶은지'를 지정해야 한다면, 코드에서 iOS 앱 생태계의 수많은 서비스를 일일이 명시해야 하고, 새로 출시된 앱 또한 빈번하게 추가해야 하는 비효율적인 상황이 될 것입니다. 

반면에 LINE의 경우 공유 화면의 목록에 어떤 서비스가 나타날 수 있는지는 공유 모듈에 유형이 정의되어 있어서 진입 서비스 코드에서 명확하게 알 수 있습니다. 또한 LINE의 공유는 iOS 공유와 비교했을 때 선택할 수 있는 서비스의 수가 적고, 새로운 공유 서비스가 개발되는 일도 잦지 않습니다. 따라서 LINE 공유 모듈에서는 '어떤 서비스를 표시하고 싶은지'를 고려하는 것이 효율적입니다. 이렇게 하면 어떤 서비스에서 어떤 서비스로 공유가 가능한지 스펙 문서를 따로 확인하지 않아도 코드를 통해서 명확하게 확인할 수 있습니다. 또한 새로운 공유 서비스가 개발되었을 때 기존 서비스에 영향을 주지 않고 필요한 곳에만 새로운 공유 서비스를 추가할 수 있다는 장점이 있습니다.

2. 콘텐츠의 종류

대화방, 킵, 타임라인 등 공유가 가능한 서비스의 종류는 Swift enum 유형의ShareActivityType로 정의됩니다.

ShareActivityType enum의 값에 따라 공유할 수 있는 서비스의 목록이 결정되기 때문에, 위와 같이 ShareActivity에 유형에 맞는 서비스의 배열을 반환하는 함수를 추가했습니다. 진입 서비스별 사용 가능한 목적 서비스의 목록을 한곳에 정리했기 때문에 위 1. 진입 서비스의 종류에서와 마찬가지로 코드를 통해 스펙을 확인하는 게 한결 쉬워졌고 수정이 간편해졌습니다.

3. 커스텀 서비스

대부분은 위에서 설명한 두 조건을 확인하면 충분하지만, 때에 따라 공유 모듈에서 지원하지 않는 커스텀 액션이 별도로 필요할 때가 있습니다. 이런 경우에는 위에서 얻은 목록에 서비스를 추가해 주어야 합니다.

진입 서비스와 콘텐츠의 종류에 따라서 결정된 서비스 목록에 항상 표시하고 싶은 서비스를 추가하고 싶다면, 위와 같이 진입 서비스에서 customShareActivityTypes에 추가 액션을 명시할 수 있습니다. customShareActivityTypes에 명시된 서비스는 공유하려는 콘텐츠의 종류와 관계없이 언제나 서비스 목록에 나타나도록 구현했습니다.

사용 가능한 서비스 목록 최종 결정

위 1, 2, 3에서 얻은 목록을 기반으로 상황에 따라 아래 그림과 같이 서비스 목록을 결정할 수 있습니다. 

그림 7. 서비스 목록 구성 흐름

먼저 사용자가 공유할 콘텐츠를 선택해서 공유 화면에 진입하면, 기본적으로 아래 두 개 목록의 교집합이 반영됩니다. 

  • 진입 서비스에서 지정한 서비스 목록
  • 선택한 콘텐츠 각각의 유형에 따른 서비스 목록의 교집합

위 그림을 보면, 사용자가 일반 대화방에서 텍스트와 이미지 콘텐츠 여러 개를 선택해서 공유 버튼을 눌렀습니다(a 단계). 오픈챗이 아닌 일반 대화방에서는 오픈챗 노트를 제외한 킵이나 타임라인, 앨범, 노트 혹은 다른 앱으로 공유할 수 있습니다. 텍스트는 앨범을 제외한 모든 서비스에 공유할 수 있고, 이미지는 모든 서비스에 공유할 수 있습니다. 결과적으로 이 세 서비스 목록의 교집합인 킵, 타임라인, 노트, 다른 앱으로의 공유가 공유 화면에 나타납니다(b 단계). 만약 진입 서비스가 커스텀 서비스를 추가 지정했다면 위 결과에 지정된 추가 서비스를 더해줍니다. 

화면 안에서 각 서비스 아이콘이 놓이는 순서는 상대적으로 정해져 있습니다. 예를 들면 액션별 아이콘의 배치는 항상 킵이 타임라인보다 왼쪽에, 타임라인이 링크 복사보다 왼쪽에 놓여야 합니다. 따라서 ShareActivityType은 Comparable 프로토콜을 준수하여 Enum에 정의된 서비스 순서대로 간단하게 정렬할 수 있도록 구현했습니다.

결과적으로 그림 7에서 b 단계의 결과에 커스텀 액션을 더한 후 서비스 목록을 규칙에 맞게 정렬하면, 그림 7의 c 단계와 같은 결과를 얻게 됩니다.

4. 커스텀 액션 제공

서비스마다 다른 요구 사항을 충족하기 위해서 제공하는 커스텀 액션을 소개합니다.

 문제점

다양한 서비스에서 사용하는 공유 기능을 한 모듈로 통합 구현하여 중복되는 로직을 여러 군데 두지 않아도 된다는 장점을 얻었지만, 새롭게 발견된 문제도 있었습니다. 때때로 같은 목적 서비스를 선택하더라도 진입 서비스에 따라 요구 사항이 달라서 공유 모듈에서 제공하는 기본 기능만으로는 충분하지 않을 때가 있다는 점이었습니다.

예를 들어, 링크 복사 액션은 서비스에 따라 다르게 동작해야 할 때가 있습니다.

  • 일반적인 경우: 사용자가 선택해서 공유하는 URL을 다른 작업 없이 복사
  • 킵: 사용자가 선택해서 공유하는 텍스트에서 URL만 추출해서 복사
  • 타임라인 포스트: 선택된 포스트의 링크를 서버에서 받아온 후 복사

공유 모듈에서 같은 아이콘을 누르더라도 진입 서비스의 종류에 따라 다른 코드를 수행해야 하는 경우를 처리할 수 있는 방법이 필요했습니다.

해결책

현재 다양한 서비스가 공유 모듈을 사용하고 있습니다. 또한 언제든 추가되거나 없어질 수 있습니다. 그러므로 공유 모듈 내부에서 진입 서비스의 종류에 따라 동작을 다르게 하는 방식은 지양했습니다. 대신 필요하다면 진입 서비스에서 공유 액션을 커스터마이즈할 수 있는 방법을 제공하기로 했습니다.

진입 서비스에서 희망하는 서비스 목록을 지정할 때와 같은 방식으로, customShareActivityTypes 파라미터를 이용해서 커스터마이즈할 서비스를 지정할 수 있습니다. 공유 화면에서는 customShareActivityTypes에 지정된 서비스를 선택된 콘텐츠 종류와 관계없이 항상 표시합니다. 커스텀 서비스가 선택되었을 때 동작할 코드는 Swift의 코드 블록인 클로져(closure)를 통해 지정할 수 있습니다. 공유 모듈을 호출할 때 전달하는 completionHandler라는 클로져는 공유 작업이 완료된 후 실행되는데, 이 클로져에 커스텀 서비스가 선택되었을 때 동작할 코드를 넣어줄 수 있습니다. customShareActivityTypes에 지정된 서비스가 선택되면, 공유 모듈에서는 모듈 내부에 정의된 기본 공유 코드를 실행하지 않고 곧바로 completionHandler를 호출하기 때문에, 각 진입 서비스 별로 원하는 코드를 실행할 수 있습니다. 위 코드의 completionHandler를 보면 선택된 서비스의 유형이 copyLink 또는 otherApps일 때 실행할 코드를 진입 서비스에서 지정한 것을 볼 수 있습니다.

이로써 공유 모듈에서 통일된 공유 기능을 사용하되 서비스별로 다르게 처리해야 하는 부분을 보충할 수 있게 되었고, 콘텐츠의 종류에 관계없이 각 진입 서비스에서 어떤 공유 서비스든 추가해서 사용할 수 있게 되었습니다.

현재는 커스텀 공유 액션을 사용해야 하는 경우가 많지 않습니다. 하지만 나중에 이러한 경우가 늘어난다면 지금처럼 completionHandler 한곳에서 여러 가지 커스텀 공유 액션을 처리하는 대신에, 커스텀 공유 액션의 유형과 해당 유형의 서비스가 선택되었을 때 실행할 클로져를 멤버로 가지는 자료 구조를 만들어서 공유 모듈에 전달하는 방식으로 개선할 수 있습니다.

5. 예외 처리 일반화

공유 모듈은 다양한 서비스를 다루고 있으며 사용 패턴 또한 매우 다양해서, 기존 서비스에서 각자 구현했던 예외 처리를 그대로 사용하는 건 어려웠습니다. 이에 모든 예외 상황을 고려하면서도 개발과 유지 보수가 쉽도록 예외 상황을 단계별로 일반화했는데요. 그 방법을 말씀드리겠습니다.

문제점

여러 가지 서비스에서 텍스트와 이미지, 연락처, 위치 정보 등 다양한 유형의 콘텐츠를 주고받다 보면 종종 콘텐츠를 공유할 수 없는 상황이 생기기도 합니다. 아래는 공유를 시도할 때 모듈에서 고려해야 할 점입니다.

  • 공유하려는 콘텐츠를 사용할 수 없는 경우가 있음 
    • 이미지, 비디오 등의 파일이 만료된 경우
    • 상대방이 메시지를 취소한 경우
    • 네트워크에 오류가 발생한 경우
  • 서비스마다 처리할 수 있는 콘텐츠의 유형과 최대 개수가 다름
  • 서비스마다 연결된 서비스의 종류가 다름
    • 대화방 -> 노트, 앨범, 타임라인, 다른 앱
    • 타임라인 -> 대화방
    • 킵 -> 대화방, 타임라인

위와 같은 요소를 점검한 후 공유가 불가능하다고 판단되면 사용자에게 알림(alert)을 통해 해당 내용을 알기 쉽게 전달해야 합니다. 하지만 기존에 각 서비스에서 각각 처리했던 여러 가지 경우가 합쳐지며 양이 방대해지면서 예외를 보다 체계적으로 처리할 방법이 필요해졌습니다.

해결책

앞서 살펴봤던 예외 케이스를 자세히 생각해보면, 공유 전체 과정 중 여러 시점에서 예외 처리가 필요한 것을 알 수 있습니다.

  • 공유하려는 콘텐츠가 사용 가능한지 확인 -> 공유 모듈을 열기 전에 확인할 수 있음
  • 사용자가 선택한 목적 서비스가 사용 가능한지 확인 -> 공유 모듈에 진입할 때 확인할 수 있음
  • 사용자가 선택한 목적 서비스가 콘텐츠를 처리할 수 있는지 확인 -> 사용자가 목적 서비스를 선택하는 시점에 확인할 수 있음

일찍 알려줄 수 있는 예외 상황을 늦은 시점에 확인해서 알려준다면, 공유를 하기 위해 차례차례 단계를 밟아온 사용자가 불편함을 겪을 수 있습니다. 또한 알림에서 예외 상황의 여러 가지 이유를 복잡하게 설명해야 하기 때문에 사용자가 알림 내용을 쉽게 인지하기 어려워집니다. 게다가 복잡한 내용의 알림을 구성하기 위해 복잡한 코드를 작성해야 하고, 테스트도 어려워집니다. 

따라서 어떤 시점에 어떤 예외를 처리할지 구별하는 것이 가장 중요하다고 판단, 발생할 수 있는 모든 케이스의 특징을 추려내어 예외 처리 프로세스를 크게 네 단계로 분류했습니다. 각 단계에서 고려해야 하는 요소를 최소화하기 위해서 어떤 단계에서 처리해도 상관없는 예외 상황이 있다면 최대한 이른 시점에 처리했습니다.

단계 언제 예외 처리
1 공유를 시작하기 전
  • 콘텐츠가 공유 가능한 상태인지 확인
    • 서버나 기기 캐시에 파일이 남아 있는지 확인
    • 접근 권한이 있는지 확인
  • 서비스 특성에 따라 콘텐츠를 선택하는 시점에 미리 유효하지 않은 콘텐츠를 선택하지 못하게 처리
    • 콘텐츠를 선택하지 못하게 처리하지 않았다면, 공유 모듈에 진입하기 전에 선택된 콘텐츠의 상태를 확인해서 사용할 수 없는 콘텐츠가 있다면 알림 표시
  • 서비스 목록 구성
    • 진입 서비스에서 원하는 서비스 목록 지정
    • 필요한 경우 서비스 이용 권한 확인(오픈챗 노트 또는 공식 계정에서)
2 공유 화면에 진입할 때
  • 서비스 목록 구성
    • 선택된 콘텐츠의 종류에 따라 서비스 목록을 추려냄
  • 대화방 목록 구성
    • 최근 대화방, 최근 공유 대화방 구성
    • 공유가 가능한 대화방 필터링
    • 화면 크기에 따라 공유 가능한 대화방 개수 결정
3 공유하려는 서비스를 선택했을 때
  • 콘텐츠 유형별 개수 확인
    • 선택된 서비스에서 처리할 수 있는 개수를 만족했는지 확인(메시지 100개, 이미지 20개 등..)
  • 필요한 경우 네트워크 상태 검사
  • 필요한 경우 콘텐츠 다운로드 진행
4 공유가 취소 또는 완료됐을 때
  • 공유 성공 시 각 서비스에서 필요한 후처리 진행
  • 공유 취소 시 이전 화면에서 사용자가 선택한 콘텐츠 목록을 유지하여 수정 후 다시 공유할 수 있도록 함
  • 공유가 실패했을 때 에러에 따라 적절한 처리

6. UI/UX 개선

각 서비스의 공유 기능 UX에서 불편했던 점이 무엇인지 고민하고 개선했습니다.

새로운 UI 도입 및 공유 화면 통합


그림 8. 공유 화면 UI
그림 8. 공유 화면 UI

기존에 LINE 내부의 다양한 서비스에서 제공하고 있던 공유 기능은 모두 UI/UX가 달랐습니다. 예를 들면 공유 버튼이 아닌 저장 버튼을 눌러야 앨범으로 사진을 전송할 수 있는 화면도 있었고, 공유 버튼을 눌렀을 때 나타나는 대화방, 킵, 타임라인 등의 서비스 순서가 각각 다른 경우도 있었습니다. 이렇게 서비스마다 제공하는 공유 기능의 UI/UX가 달라서 혼란스러운 경우가 많았습니다. 이런 불편함을 해소하여 사용자가 어떤 서비스에서든 공유 기능을 익숙하게 사용할 수 있도록, 모든 서비스에 통일된 화면을 도입했습니다. 

그리고 기존에는 대부분의 서비스에서 공유 버튼을 누르면 공유할 수 있는 서비스를 고르는 액션 시트(sheet)가 나타났습니다. iOS의 기본 UI 컴포넌트를 사용했기 때문에 간편하게 개발할 수 있고 사용자에게도 익숙한 UI여서 사용성에 큰 문제는 없었지만, 사용자가 더욱더 쉽고 편리하게 공유할 수 있도록 몇 가지를 개선한 새로운 UI를 적용했습니다.

먼저, 킵이나 타임라인 등의 다른 서비스에 비해서 공유 빈도가 높은 대화방 공유를 최적화하는 방향으로 개선했습니다. 가장 많은 사람들이 자주 사용하는 서비스의 사용 단계를 조금이라도 단축하고자 했습니다. 새로운 공유 UI에서는 화면 상단에 최근에 공유한 대화방과 최근에 대화했던 방이 순서대로 나타납니다. 대화방을 선택하면 하단에 추가 메시지를 입력할 수 있고, 공유 버튼을 누르면 다른 화면으로 넘어가지 않고 바로 전송을 마칠 수 있습니다. 원래 보고 있던 화면에서 벗어나지 않고 전송을 마칠 수 있어서 사용자가 공유 기능을 사용할 때 부담이 덜하다는 장점이 있습니다.

기존의 대화방 공유는 사용자의 대화방 목록이 전부 표시되는 화면이 나타났기 때문에 대화방이 많은 사용자는 화면을 로딩하는 데 오랜 시간이 걸린다는 단점이 있었는데요. 새로운 공유 UI에서는 최근에 사용자가 사용했던 대화방 일부만 보여줍니다. 따라서 로딩 시간이 줄어드는 효과도 얻을 수 있었습니다.

또한 공유할 수 있는 서비스 목록을 아이콘과 텍스트 형식으로 제공하도록 변경하여, 기존의 액션 시트에서 텍스트만으로 공유 기능을 표현할 때보다 좀 더 직관적으로 사용자가 서비스를 인식할 수 있게 되었습니다.

마지막으로 기존에는 서비스마다 액션 시트의 순서가 달라서 사용자가 혼란스러웠는데요. 아이콘 정렬 순서를 정해서 모든 서비스에서 항상 같은 순서로 나타나도록 변경, 개선했습니다.

 공유 완료 알림(notification)

 
그림 9-1. 기존 공유 완료 알림

기존에는 각 서비스별로 공유가 완료되고 난 후의 동작이 다양했습니다.

  • 원래 사용자가 보던 화면을 그대로 유지하며, 화면 상단에 공유가 완료되었다는 것을 알리는 알림이 나타나고 알림을 누르면 결과 화면으로 이동
  • 원래 사용자가 보던 화면을 그대로 유지하며, 결과를 확인하기 위해서는 직접 결과 화면을 찾아가야 함
  • 콘텐츠가 공유된 화면으로 자동 전환
 
그림 9-2. 통일된 공유 완료 알림

공유 모듈에서는 서비스마다 다른 UX의 차이를 없애기 위해 공유 후 동작을 '공유가 완료되면 알림을 표시하는 방식' 한 가지로 통일했습니다. 기존의 알림 UI는 대화방에서만 사용하고 있었으므로 대화방과 관련된 데이터만 처리할 수 있었는데요. 모든 서비스에서 사용할 수 있도록 왼쪽 아이콘 영역과 가운데 텍스트 영역을 자유롭게 조작할 수 있는 구조로 변경하여 개발했습니다. 

최종적으로 알림을 사용하여 공유가 끝난 후에도 사용자가 원래 보고 있던 화면에 그대로 머무를 수 있게 되어 기존에 진행하고 있던 작업에 방해받지 않게 되었습니다. 또한 사용자가 원할 때는 알림 영역을 눌러서 결과 화면으로 쉽게 이동할 수 있다는 장점도 얻었습니다.

공유 모듈 도입 전후 구조 비교

공유 모듈을 도입하면서 앱 내 공유 기능의 구조는 아래와 같이 달라졌습니다. 

그림 10-1. 공유 모듈 도입 전
그림 10-2. 공유 모듈 도입 후

기존에는 서비스별 공유 기능을 모아 놓으면 그림 10-1과 같은 구조였습니다. 각 서비스가 서로 복잡하게 연결되어 있는 것을 확인할 수 있습니다. 공유 모듈을 도입한 후에는 그림 10-2처럼 모든 서비스의 공유 기능이 InAppSharing과 InAppShareContext라는 클래스를 반드시 거쳐가고, SharableObject라는 단일 데이터 모델을 이용하게 되었습니다. 결과적으로 공유와 관련된 코드를 한곳에서 쉽게 확인할 수 있게 되었고, 공유 기능을 통제하고 싶을 때 수정해야 할 지점이 줄어들어서 코드를 관리하기 쉬워졌습니다.

이번 프로젝트를 통해 LINE 내의 대부분의 공유 기능이 이 모듈로 대체되었고, 이를 통해 크게 두 개의 이점을 얻었습니다. 먼저 프로젝트를 시작하게 된 이유였던 UX 측면에서는, 사용자가 공유 버튼을 눌렀을 때 어떤 화면에서든 일관된 경험을 제공할 수 있게 되었습니다. 동시에 개발자 입장에서는 모든 공유 모델과 로직이 공용화되어 유지 보수 비용을 줄일 수 있게 되었습니다. 또한 향후 공유 서비스나 새로운 콘텐츠 유형이 추가되더라도 공유 모듈에서 쉽게 추가할 수 있는 구조가 되었습니다. 

마치며

LINE iOS 프로젝트 전체에 많은 영향을 미치는 작업을 하다 보니 본문에서 이야기했던 것과는 조금 다른 종류의 어려움도 겪었습니다. 공유 모듈 개발과 동시에 LINE iOS 프로젝트 구성 방식이 새롭게 바뀌어 코드 충돌이 발생하기도 했고, 다른 서비스도 계속 병렬로 개발이 진행되었기 때문에 변경되는 사양에 맞춰 코드를 여러 번 수정하는 일도 있었습니다. 또한 같은 UI지만 다른 전송 로직을 가진 공유 기능을 iOS Share Extension에 함께 적용해야 했고, iOS 13에서 새롭게 소개된 기능인 다크 모드나 Siri 제안도 함께 고려해야 했습니다. 하지만 초반에 설계와 리팩토링에 많은 노력을 기울였던 덕분에, 여러 가지 어려움을 잘 이겨내며 안정적으로 개발을 마무리할 수 있었습니다. 프로젝트 구조와 설계의 중요성을 많이 느낀 프로젝트였습니다.