Teamwork

Teamwork는 이상적으로 분산된 고객 서비스 애플리케이션을 보여주는 Realm의 데모 앱입니다. 전력 회사나 케이블 회사, 모바일 세일즈 포스 등에서 사용할 수 있습니다. 중앙의 “매니저” 사용자가 작업을 생성해서 다양한 작업을 수행하는 현장의 팀원이나 독립 에이전트에게 작업을 배정하는 시나리오로 제작됐습니다.

Teamworks 모델

Teamwork의 목표는 다중 사용자, 다중 Realm을 사용하는 애플리케이션의 설계 원칙을 보여주는 것으로 온전한 현장 서비스 애플리케이션까지 지원하지는 않습니다. 하지만 Teamwork는 이런 시스템의 기본을 구성하는 모든 요소를 포함하므로 본격적인 현장 서비스 애플리케이션의 기초로 사용할 수 있습니다.

Teamwork에는 4가지 기본 모델이 있습니다.

Person

사실상 사용자 프로필 객체로, 애플리케이션이 사용자 신원을 보여주는 문자열 이상의 데이터를 저장하거나 보여줄 수 있도록 합니다. 성, 이름, 아바타/프로필 이미지, 매니저/작업자 등 시스템상의 역할 등의 기본 데이터를 관리합니다.

Task

작업은 시스템의 중심 객체입니다. 실제로 수행할 수 있는 현장의 작업자가 수행하거나 배정받을 작업 단위를 나타냅니다. 작업의 속성은 아래처럼 단순한 내용을 포함합니다.

  • 작업 이름
  • 작업 설명
  • 생성일, 마감일
  • 팀 이름 (선택 사항)
  • 작업자 (Teamwork 사용자)
  • 작업을 수행할 위치에 대한 참조

작업은 두 가지 형태로 TeamWork에 존재합니다. 하나는 어드민 사용자가 소유하고 관리하는 마스터 작업 리스트로 어드민이 작업을 만들고 상세 항목을 넣어서 이를 개인이나 팀에 배정합니다. 특정 사용자에게 할당하지 않거나 할당될 수 있습니다.

팀 모델의 두 번째 용도는 특정 팀에 할당된 작업의 복사본인 팀 작업 목록을 만드는 것입니다. 이 형태는 각 팀마다 특정 작업 Realm으로 저장됩니다. 이를 Teamwork 앱에서는 “TaskTeamRealms”라고 부릅니다.

Team

팀은 사용자의 컬렉션을 나타냅니다. 사용자는 하나 이상의 팀에 속할 수 있고, 작업은 팀에 할당되거나 특정 팀 내의 특정 사용자에게 할당될 수 있습니다.

팀은 다음과 같은 속성을 가집니다.

  • 팀 이름
  • 팀 설명
  • 생성일, 마감일
  • 팀원
  • 해당 팀에 배정된 모든 작업을 포함하는 팀 작업 Realm에 접근하는 URL

팀 작업 Realm

어드민 사용자가 특정 팀에 배정한 작업의 사본을 포함할 독립형 Realm입니다. 각 팀은 각각 팀 작업 Realm을 가지며, 이 Realm은 팀원이 열 수 있도록 Realm 오브적트 서버로 팀원들의 기기에 동기화됩니다.

팀원은 Teamwork 앱에서 자신의 Realm에 접근하고 자신이나 팀 전체에 할당된 작업을 볼 수 있습니다. 작업이 “완료됨”으로 표시되면 백엔드 Realm 이벤트 리스너는 팀 작업 Realm의 항목 업데이트를 확인하고 작업의 마스터 복사본을 “완료됨”으로 표시하고 다른 관련 메타 데이터를 업데이트합니다.

Locations

위치 모델은 앱 내부의 지도에서 보여줄 사람들의 위치와 작업이 수행될 위치를 저장하는 두 가지 역할을 합니다.

위치는 다음과 같은 속성을 가집니다.

  • 위도/경도 및 다양한 거리 주소 구성 요소
  • 생성일, 마지막 업데이트일
  • person ID - Teamwork 사용자의 마지막 위치를 나타내는 경우 사용
  • Task ID - 작업 수행 위치를 나타내는 경우 사용
  • Team ID - 특정 팀에게 배정된 작업의 위치를 나타내는 경우 사용

위치 객체가 작업을 나타내는 경우 작업이 배정된 팀이 있는 경우 해당 팀을 포함합니다. 이에 따라 지도와 팀 구성요소가 작업의 위치를 표시하고 팀을 기준으로 지도의 표시를 필터링할 수 있습니다.

Realm 설계

Realm은 데이터베이스이지만 모바일 컨텍스트에서는 정보 접근 및 배포를 관리하는데 사용할 수 있는 정보 그룹을 나타내기도 합니다.

Teamwork에는 세 가지 정보 출처가 있습니다.

  • 모든 사용자에게 동기화될 공통 정보
  • 어드민 사용자만 생성하고 접근하는 정보
  • 개인 작업자 팀이 사용하는 정보

위에서 설명한 사용 가능한 모델은 명확한 그룹으로 구분됩니다.

  1. People, Teams, Locations 등 모두에게 필요한 공통 정보
  2. 매니저 전용 정보: 마스터 작업 리스트
  3. 팀원 전용 정보: 팀에 배정된 작업의 사본을 저장하는 팀별 독립형 Realm으로 표시되는 소속 팀의 작업 등

이렇게 그룹화하면 다음과 같은 다중 사용자 모바일 앱의 설계상 문제를 해결하는 데 도움이 됩니다.

  • 사용자가 필요한 정보만 제공
  • 접근을 분리해서 유지함으로써 명료한 데이터와 보안 유지
  • 데이터 모델 클러스터링 - 일반적으로 접근되는 모델을 Realm에 그룹화해서 주어진 작업을 합리적인 횟수로 수행하기 위해 프로그래머가 상호작용해야 하는 Realm의 숫자를 유지

다중 Realm 관리 및 접근

대부분의 앱은 하나의 Realm을 사용하는 것만으로 충분하며, 단일 동기 Realm에는 다음처럼 한 줄의 코드로 접근할 수 있습니다.

let defaultRealm = try! realm()

다중 Realm을 사용하는 앱에서 Realm에 접근하는 법은 조금 더 복잡하지만, 두 가지 간단한 패턴으로 요약할 수 있습니다.

  1. 데이터 모델이 일반적인 데이터 사용 클러스터링을 형성하는 방법을 결정하기
  2. 해당 클러스터를 포함하는 Realm 설정을 위한 접근자를 생성하기

모델 클러스터링

모델 사이의 잠재적인 연계를 이해하고 특정 연계의 필요성을 파악해야 하므로 실제로 가장 어려운 부분입니다.

필수 링크는 앱이 Realm 리스트 참조나 백링크를 따라 다른 모델에서 한 세트의 모델 오브젝트를 참조해야 하는 애플리케이션에서 사용합니다.

Teamwork의 경우, Teams, Persons, Locations는 서로 강하게 결속됩니다. 따라서 모든 사용자는 팀 작업 Realm이나 마스터 작업 리스트를 각각 열 필요 없이 하나의 공유 Realm에서 팀과 팀을 참조하는 사람, 팀과 작업을 보여주는 지도를 볼 수 있습니다. 참조 요소인 작업 ID를 리터럴 외래 키로 사용해서 마스터 작업 목록이나 사용자에게 적합한 팀 작업 Realm에서 객체를 찾을 수 있습니다.

접근자 생성

여러 Realm에 접근하는 것은 레이아웃 코드와 Realm으로 모델을 연결하는 방식을 반영합니다. 여러 테이블이나 어떤 프레임워크의 DB를 다루는 것은 어려운 일이지만, Teamwork는 접근 메커니즘을 Realm 인스턴스에 전달할 수 있는 정적 속성으로 압축해서 이를 쉽게 만들었습니다.

다음은 Apple의 Swift 예제이지만 Realm이 지원하는 언어 바인딩 모두에서 같은 원칙을 적용할 수 있습니다. 매크로와 같은 다양한 요소를 생성하는 코드입니다.

static let syncHost               	= "127.0.0.1"
static let ApplicationName         	= "TeamworkMR"
static let syncRealmPath          	= "teamwork"
 
 
// RMP 인증 시스템과 통신하기 위한 URL
static let syncAuthURL = NSURL(string: "http://\(syncHost):9080")!
    
// 애플리케이션 대신 관리하는 동기화 서비스 및 Realm과 통신하기 위한 URL
static let syncServerURL = NSURL(string: "realm://\(syncHost):9080/\(ApplicationName)-\(syncRealmPath)")
    
// 주의: Realm 파일이란 Realm 안의 전체 모델 / 스키마 컬렉션을 의미합니다.
// 따라서 Realm이 나타내는 모델을 명시해야 합니다.
// 다음 예를 확인하세요.
    
// People, Teams, Locations 마스터 리스트로 누구나 열 수 있습니다.
static let commonRealmURL = URL(string: "realm://\(syncHost):9080/\(ApplicationName)-CommonRealm")!
func commonRealmConfig(user: SyncUser) -> Realm.Configuration  {
    let config = Realm.Configuration(syncConfiguration: SyncConfiguration(user: SyncUser.current!, realmURL: TeamWorkConstants.commonRealmURL), objectTypes: [CommonModel_1.self, CommonModel_2.self, ..., CommonModel_N.self])
    return config
}
 
func managerRealmConfig(user: SyncUser) -> Realm.Configuration  {
    let config = Realm.Configuration(syncConfiguration: SyncConfiguration(user: SyncUser.current!, realmURL: TeamWorkConstants.managerRealmURL), objectTypes: [Task.self])
    return config
}
// 온디멘드로 열리는 개인별 TeamTaskRealms의 부분 경로입니다.
// 사용자가 "Red Team", "Team Bonzai!" 등 자신이 속한 팀의 특정 뷰를 열 때 사용합니다.
static let TeamTasksPartialPath = "realm://\(syncHost):9080/\(ApplicationName)-TeamTaskRealms/"

이 접근자 메커니즘을 사용하면 모든 Realm을 여는 대신 필요한 Realm만을 열 수 있습니다.

어드민이 아닌 사용자가 로그인한 경우 공용 Realm만이 열립니다. 이는 사용자에게 지도에서 미해결 상태인 작업을 표시하는 데 사용됩니다. (주의: 위치는 사용자와 작업을 모두 추적합니다)

사용자는 기본 팀을 선택해서 열거나, Teams 탭으로 이동해서 사용 가능한 팀을 확인하고 이 중 하나로 전환할 수 있습니다.