Search
🌉

Firebase Emulator 개발 환경 분리

생성일
2020/12/28 05:20
태그
Firebase
속성
속성 1
속성 2
2021/07/18 12:25

Why?

개발 환경을 분리하는 것은 현재 라이브 중인 서비스에는 영향이 없으면서도 효율적으로 안전한 테스트/개발을 하기 위함을 목적으로 합니다.
고객이 서비스를 사용하는 환경에서 개발/테스트를 진행하게 되면 고객에게 Dummy data 가 노출되거나, 최악의 경우 DB가 망가져 서비스를 문 닫아야 하는 상황까지 올 수 있습니다.
서비스/회사의 규모에 따라 개발 환경을 다르게 가져가기도 합니다.
NHN 재직중에는 Dev - Alpha - Beta - Release
뱅크샐러드 재직중에는 Staging - Production
그렇다면 Firebase 플랫폼을 이용해 1인 서비스 환경에서는 어떻게 구성하는 것이 바람직 할까요?

Firebase 플랫폼에서 개발 환경을 분리하는 방법

2가지 전략이 존재하며, 팀 구성과 서비스 운영환경에 따라 선택할 수 있습니다.

1. [Required] Firebase Deploy

Firebase Deploy 에 배포되는 코드입니다. 외부에서 접근 가능한 API 로 실제 사용자가 이용하는 환경입니다. Release 라고 부르겠습니다.

2. [Optional] Firebase Deploy for Debug (2인 이상의 팀에 추천)

구체적인 구현 방법은 아래 포스팅에서 설명합니다.
별개의 Firebase project 를 생성합니다.
현재 iOS에서 제공하고 있는 '퇴근요정' 서비스 LeaveFairy 입니다. 개발 환경을 구분하기 위해 별개의 프로젝트로 'LeaveFairy-Debug' 를 생성해서 사용중입니다.
개발 환경만을 위해 1개의 프로젝트를 추가로 생성하는게 투머치로 느껴질 수 있습니다.

장점

개발환경과 운영환경을 절대적으로 분리할 수 있습니다. (DB, 유저, Analytics, Crashlystics). 실수로 인해 발생할 위험성이 적습니다

단점

프로젝트가 2개가 된다는 것은 GoogleService-info.plist 등 Firebase 를 위한 코드, 환경들이 분리되어 관리 포인트가 증가됩니다.

3. [Required] Firebase Emulator

장점

코드의 수정내용을 저장 하면 바로 Emulator 로 배포되므로 개발 생산성을 높일 수 있습니다. 때문에 개발자는 local 에 firebase emulator 를 이용한 개발환경을 구축해야 합니다.

단점

에뮬레이터를 실행하지 않으면 Firebase Emualtor 를 바라보고 있는 앱은 동작하지 않습니다. (무조건 1인 개발 환경에서만 적용 가능)

개발 환경 분리의 구현

수업지구대 서비스에서 사용하고 있는 코드를 소개합니다.
수업지구대는 현재 1인 개발로 서비스하고 있어서 Firebase Deploy, Firebase Emulator 로 2개 환경으로 구분하여 사용하고 있습니다.

1. [Client] Cloud function End-point 환경 분리

extension NEISServiceAPI: TargetType { #if DEBUG var host: String { "http://localhost:5001/mosi-ac123/us-central1/api/" } #else var host: String { "https://us-central1-mosi-ac123.cloudfunctions.net/api/" } #endif var domain: String { "neis" } var baseURL: URL { switch self { case .searchSchool, .classInfo, .meal, .schedule, .timetable: return URL(string: "\(host)\(domain)")! } } }
Swift
복사
#if DEBUG macro 를 사용해 API host 를 분기처리 합니다. DEBUG (local) 환경에서는 Emulator 의 cloud function 을 바라보도록 구성하고, Release scheme 으로 앱을 빌드하는 경우에는 firebase cloud function 을 직접 호출하도록 합니다.

2. [Client] Authentification 환경 분리

public class KLAuthentification: NSObject, GIDSignInDelegate, LoginButtonDelegate { public func iniitalize(debugMode: Bool = false, debugHost: String = "localhost", debugPort: Int = 9099) { if debugMode { Auth.auth().useEmulator(withHost: debugHost, port: debugPort) } } }
Swift
복사
유저 인증을 담당하는 KLAuthentification 클래스를 초기화 할 때 debugMode 에 따라 환경을 구분합니다.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let _ = (scene as? UIWindowScene) else { return } self.window?.rootViewController = UIStoryboard.init(name: "LaunchScreen", bundle: nil).instantiateInitialViewController() self.window?.makeKeyAndVisible() FirebaseApp.configure() #if DEBUG KLAuthentification.shared.iniitalize(debugMode: true) #else KLAuthentification.shared.iniitalize() #endif }
Swift
복사