[go: up one dir, main page]

<블로그 원문은 이곳에서 확인하실 수 있으며, 블로그 번역 리뷰는 전태균(Machine Learning GDE)님이 참여해 주셨습니다.>

게시자: Jonathan Shen, Ruoming Pang(소프트웨어 엔지니어, Google 두뇌 및 기계 인지 팀을 대표하여 작성)

텍스트로부터 매우 자연스러운 음성을 생성하는 과제(텍스트-음성, TTS)는 수십 년 묵은 연구 목표였습니다. 지난 몇 년 동안 TTS 연구에서 많은 진전이 있었으며 완전한 TTS 시스템의 많은 개별적인 부분들이 크게 개선되었습니다. TacotronWaveNet 같은 이전 작업에서 얻은 아이디어를 통합하여 더 많은 개선 사항을 추가함으로써 새로운 시스템인 Tacotron 2가 탄생했습니다. 우리의 접근 방식에서는 복잡한 언어 및 음향 기능을 입력 수단으로 사용하지 않습니다. 대신, 음성 예시와 해당 텍스트 대화 내용만으로 교육받은 신경망을 사용하여 텍스트에서 인간과 유사한 음성을 생성합니다.

우리가 선보이는 새로운 시스템에 대한 자세한 설명은 'Natural TTS Synthesis by Conditioning WaveNet on Mel Spectrogram Predictions'라는 제목의 논문에서 찾아볼 수 있습니다. 간단히 말하자면 다음과 같이 작동합니다. TTS에 최적화된 시퀀스-시퀀스 모델을 사용하여 오디오를 인코딩하는 기능 시퀀스에 문자 시퀀스를 매핑합니다. 이 기능은 12.5밀리초마다 계산된 프레임을 포함하는 80차원 오디오 스펙트로그램으로, 단어의 발음뿐 아니라 음량, 속도 및 억양을 비롯한 사람의 음성이 지닌 다양하고 미묘한 부분을 포착합니다. 마지막으로 이러한 기능은 WaveNet과 유사한 아키텍처를 사용하여 24kHz 파형으로 변환됩니다.


Tacotron 2의 모델 아키텍처에 대해 자세히 알아보기. 이미지의 아래쪽 절반은 문자 시퀀스를 스펙트로그램에 매핑하는 시퀀스-시퀀스 모델을 나타냅니다. 기술적인 세부 사항은 논문을 참조하세요.


최첨단 TTS 시스템의 결과를 보여주는 Tacotron 2 오디오 샘플 몇 가지를 들을 수 있습니다. 인간 청취자에게 생성된 음성이 얼마나 자연스러운지 점수를 매겨달라고 요청한 평가에서 성우와 같은 전문가들이 녹음한 음성에 대해 매긴 점수와 비슷한 점수를 얻었습니다.

샘플이 훌륭한 것 같지만 아직 해결해야 할 어려운 문제가 몇 가지 남아 있습니다. 예를 들어, 우리의 시스템은 복잡한 단어(예: decorum, merlot)를 발음하는 데 어려움이 있으며 극단적인 경우에는 이상한 소리를 랜덤하게 생성할 수도 있습니다. 또한, 아직은 실시간으로 오디오를 생성할 수 없습니다. 게다가 아직은 생성된 음성을 제어할 수도 없습니다(예: 행복하거나 슬픈 음색을 내도록 지시). 이들 각각은 그 자체로 흥미로운 연구 과제입니다.

감사의 말

Jonathan Shen, Ruoming Pang, Ron J. Weiss, Mike Schuster, Navdeep Jaitly, Zongheng Yang, Zhifeng Chen, Yu Zhang, Yuxuan Wang, RJ Skerry-Ryan, Rif A. Saurous, Yannis Agiomyrgiannakis, Yonghui Wu, Sound Understanding 팀, TTS Research 팀 및 TensorFlow 팀에 감사의 마음을 전합니다.

<블로그 원문은 이곳에서 확인하실 수 있으며, 블로그 번역 리뷰는 양찬석(Google)님이 참여해 주셨습니다.>
게시자: Jason St. Pierre, 제품 관리자
Fabric과 Firebase 팀이 협력 관계를 체결한 후, 우리의 목표는 최고로 멋진 플랫폼을 만드는 것이었습니다. 이를 위한 첫 번째 이정표로 Firebase Crashlytics 베타 버전이 출시되었습니다.

Firebase Crashlytics는 앱 품질을 저해하는 안정성 문제를 추적하고 수정하는 데 도움을 줄 수 있는 실시간 오류 보고 도구(Crash Reporting Tool)입니다. 개발자는 기존에 사용하던 Firebase 콘솔을 통해 업계 최고의 오류 보고 솔루션을 사용할 수 있습니다. 이 시점 이후로는 Crashlytics가 Firebase용 오류 보고 도구로 권장되며, 기존 Firebase 오류 보고를 사용하고 계신 분은 대시보드의 배너를 클릭하여 업그레이드를 진행할 수 있습니다. 또한, 신규 Firebase 개발자는 g.co/firebase/optin을 방문하여 Crashlytics 사용을 시작하실 수 있습니다.

업그레이드함으로써 얻게 되는 기능과 혜택을 설명해드리겠습니다. Crashlytics가 모든 모바일 앱 개발자가 꼭 확보해야 할 도구라는 점을 알 수 있을 것입니다.

더욱 빠른 문제해결

Crashlytics는 스택 트레이스(Stack Trace)의 유사성을 기반으로 비정상 종료를 그룹화하고 그 영향력을 표시해줍니다. 따라서 실시간 비정상 종료 데이터를 통해 추세를 손쉽게 파악하고, 버전 필터링을 사용하여 가장 중요한 특정 릴리스에서 발행하는 문제에 집중할 수 있습니다. 문제 개요 및 문제 세부 정보 페이지는 문제해결을 위한 소요시간 단축할 수 있도록 디자인되었습니다.



개요 페이지에서는 비정상 종료가 발생하지 않은 사용자 비율이 두드러지게 표시되므로 어떤 빌드가 안정성 측면에서 향상되고 있는지를 측정할 수 있습니다.


또한 유의성 배지 도 확인할 수 있습니다. 이 배지가 강조 표시되어 있을 때는 앱 작동을 비정상적으로 만들 수 있는 두드러지는 요소가 있음을 나타냅니다. 예를 들어, 유의성 배지를 통해 특정 문제가 특정 기기, OS 또는 탈옥된 휴대폰에서만 발생하는지를 알 수 있습니다.


이러한 통찰력 있는 정보에 힘입어 문제를 효과적으로 분류하고, 긴급한 문제에 신속하게 대응할 수 있습니다. 탈옥된 기기에서만 일반적으로 발생하는 문제는 우선 순위를 낮출 수 있습니다. 아니면 최신 OS 릴리스로 인해 발생한 문제를 수정하는 데 더 집중할 수도 있습니다. 유의성 배지는 문제를 해결할 때 더욱 현명한 결정을 내리는 데 도움이 됩니다.


사용자설정 키 및 로그

Crashlytics를 사용하면 비정상 종료가 발생한 이유와 어떠한 일이 발생하여 비정상 종료에까지 이르게 되었는지에 대한 추가 정보와 그에 대한 컨텍스트를 제공하는 로그와 키를 계측할 수 있습니다.

구체적으로 말하면, 로그를 사용하여 비정상 종료가 발생하기 바로 전에 사용자가 어떠한 작업을 하고 있었는지에 대한 세부 정보를 수집할 수 있습니다(예: 사용자가 다운로드 화면으로 이동하고 다운로드 버튼을 클릭함). 또한, 로그를 사용하여 사용자 작업에 대한 세부 정보를 얻을 수도 있습니다(예: 이미지 다운로드 크기). 로그는 비정상 종료 전에 발생한 이벤트의 타임라인을 보여 줍니다. 비정상 종료가 발생하면 더욱 신속하게 디버그하는 데 도움이 되도록 로그 내용을 취하여 이를 비정상 종료 보고에 추가합니다.

상황에 따라 사용자 앱의 마지막 상태를 아는 것이 작업 순서만큼 중요한 경우도 있습니다. 키는 사용자가 앱을 탐색함에 따라 덮어 쓰이는 항목에 대해 마지막으로 알려진 값을 기록하는 키 값 쌍입니다. 예를 들어, 키를 사용하면 게임 앱에서 사용자가 마지막으로 이룬 레벨이나 맞춤 설정의 최신 구성 등 디버그 작업에 유용할지 모르는 컨텍스트를 나타낼 수 있는 정보를 추적할 수 있습니다.

로그와 키는 세션 메타데이터에서 단서를 찾고 버그를 재현하기 위해 사용자가 수행한 단계를 되짚어 갈 수 있는 아주 훌륭한 방법입니다.


실시간 알림

안정성 문제는 워크스테이션을 사용하지 않을 때도 언제든지 나타날 수 있습니다. 새로운 문제가 발생하면 Crashlytics 대시보드에 실시간으로 우선순위에 따라 표시될 뿐만 아니라 새로운 문제가 발생할 때, 문제로 인해 성능이 저하되는 경우, 그리고 문제의 영향이 갑자기 커지는 경우 이메일 알림도 전송됩니다. 여러분 뒤에 Crashlytics가 있으므로 안심하시고 잠시 물러나 여유롭게 커피 한잔 드셔도 됩니다. Crashlytics는 최근 제공한 앱과 관련하여 문제가 발생하면 알림을 전송해주므로 중요한 비정상 종료를 절대로 놓치지 않을 것입니다.


Firebase Crashlytics와 Cloud Functions for Firebase의 통합

Crashlytics의 많은 강력한 기능을 Firebase에 도입한 것 외에, 우리는 플랫폼의 다른 부분에도 Crashlytics를 통합하는 작업도 진행하고 있습니다. 이제, Cloud Functions for Firebase를 트리거하기 위한 이벤트 소스로 Crashlytics 데이터를 활용할 수 있습니다. 이번 통합을 통해 중요한 앱 흐름(예: 구매 흐름)에 영향을 미치는 문제를 팀의 엔지니어나 Slack 채널에 직접 전달하는 워크플로를 자동화할 수 있습니다. 이런 식으로 긴급한 문제가 즉각적이고도 적절하게 모니터링되고 에스컬레이션되도록 할 수 있습니다.


또한, 안정성 데이터를 새로 디자인된 Firebase 콘솔의 다양한 영역에서 함께 노출합니다. 개발자 여러분은 최고 수준의 안정성을 유지하기 위해 여러 페이지 사이에서 탐색할 필요가 없습니다. 이제는 Crashlytics 데이터를 프로젝트 개요 페이지, Firebase용 Google 애널리틱스 대시보드는 물론, 최신 릴리스 섹션에서도 볼 수 있습니다.

앞으로 예정된 더욱 흥미로운 업데이트

Crashlytics의 이번 베타 출시는 최고의 Fabric과 Firebase의 기능을 결합하는 단계의 시작에 불과합니다. 고객은 이미 Google의 플랫폼을 함께 사용하여 놀라운 결과를 달성하고 있습니다. 일례로, 만남을 갖기에 최고의 날짜와 시간을 찾는 데 도움이 되는 앱인 Doodle을 살펴보도록 하겠습니다. Doodle은 Crashlytics 및 원격 구성을 사용해 앱을 새롭게 디자인하고 사용자 유지율과 참여율을 높였습니다.


이제부터 신규 및 기존 Firebase 고객은 Crashlytics를 사용해야 합니다. Crashlytics가 최고의 Firebase용 오류 보고 도구이기 때문입니다. 신규 Firebase 고객은 g.co/firebase/optin을 방문하여 Crashlytics 사용을 시작할 수 있으며, 기존 오류 보고 고객은 오류 보고 대시보드의 배너를 클릭하시면 됩니다. 우리는 계속해서 Crashlytics를 발전시켜 나갈 것이며 여러분의 피드백을 손꼽아 기다리고 있습니다!

이미 Fabric에서 Crashlytics를 사용하고 계시다면 현재 조건으로 충분하십니다. 따라서 아직은 마이그레이션할 필요가 없습니다. Fabric 앱에서 Firebase Crashlytics를 이용할 수 있는 방법에 대한 흥미로운 소식을 곧 알려드릴 예정입니다.

<블로그 원문은 여기에서 확인하실 수 있으며, 블로그 번역 리뷰는 양찬석(Google)님이 참여해 주셨습니다.>
Google Play Services SDK 11.6.0에서는 API 구조가 변경되었습니다. GoogleApiClient 클래스 대신, 각 기능별로 별도의 클라이언트가 제공됩니다. 이에 따라 Play Games Services API를 사용하는데 필요한 상용구 코드의 양이 줄어들었습니다.

API는 사용하기 더욱 쉽고, 스레드 안전(thread-safe)하고 메모리를 효율적으로 사용할 수 있도록 변경되었습니다. 새로운 API는 Task 모델을 활용하여 activity와 API의 비동기 결과 처리 사이에 발생하는 문제를  효과적으로 분리합니다. 이 방식은 Firebase에서 처음 등장했으며 외부 개발자 커뮤니티에서 좋은 평가를 받았습니다. Task 모델은 장점에 대해 더욱 자세히 알아보려면 Task에 대한 블로그 시리즈Task API 개발자 가이드를 확인해 보시기 바랍니다.

개발자 문서는 새로운 API는 물론, 개발자를 위한 그 외 모든 Google 리소스에 대한 정보를 얻을 수 있는 신뢰할 수 있는 출처입니다. Play Games Services API 안드로이드 기본 샘플 프로젝트와 클라이언트 서버 골격 프로젝트 모두 새로운 API를 사용하도록 업데이트되었습니다. 샘플 프로젝트는 새로운 API를 사용하면서 발생하는 문제를 제보할 수 있는 최상의 장소이기도 합니다.

많은 변화가 이루어진 것 같지만, 두려워하지 마세요! Play Services API 클라이언트 사용법은 무척 간단하고 코드 상 불필요한 내용을 많이 줄일 수 있습니다. API 클라이언트 사용은 다음 세 부분으로 나뉩니다.
  1. 인증이 이제 Google 로그인 클라이언트를 사용하여 명시적으로 수행됩니다. 이로 인해 인증 프로세스 제어 방법과 Google 로그인 ID 및 Play Games Services ID 간의 차이가 더 명확해집니다.
  2. 모든 Games.category 정적 메서드 호출을 해당 API 클라이언트 메서드로 변환합니다. Task 클래스를 사용하도록 변환하는 것도 포함됩니다. Task 모델은 코드에 있는 문제의 분리에 큰 도움이 되며 작업 리스너가 UI 스레드에서 콜백되므로 멀티스레드 복잡성을 줄여줍니다.
  3. 멀티플레이어 invitation 처리는 턴 방식 및 실시간 멀티플레이어 API 클라이언트를 통해 명시적으로 이루어집니다. GoogleApiClient가 더 이상 사용되지 않으므로 멀티플레이어 invitation을 포함하는 '연결 힌트' 객체에 액세스할 수 없습니다. 이제는 명시적 메서드 호출을 통해 invitation에 액세스할 수 있습니다.

인증

인증 프로세스의 세부 정보는 Google Developers 웹사이트에서 확인할 수 있습니다.

가장 일반적인 인증 사용 사례는 DEFAULT_GAMES_SIGN_IN 옵션을 사용하는 것입니다. 이 옵션을 사용하면 게임에서 사용자의 게임 프로필을 사용할 수 있습니다. 사용자의 게임 프로필에는 이름, 이미지 아바타와 같이 게임이 표시할 수 있는 게이머 태그만 포함되므로 사용자의 실제 ID가 보호됩니다. 따라서 사용자가 추가적인 개인정보 공유에 동의할 필요가 없으므로 사용자와 게임 간의 마찰이 줄어듭니다.

참고: 게임 프로필만 사용하는 것으로 요청할 수 있는 Google 로그인 옵션은 requestServerAuthCode()뿐입니다. requestIDToken()과 같은 다른 모든 옵션의 경우 사용자가 추가 정보를 공유하는 것에 대해 동의해야 합니다. 또한, 이 옵션은 사용자에게 탭이 없는 로그인 환경이 제공되지 않도록 하는 효과도 있습니다.

한 가지 더 참고할 사항은 Snapshots API를 사용하여 게임 데이터를 저장하는 경우 로그인 옵션을 생성할 때 Drive.SCOPE_APPFOLDER 범위를 추가해야 한다는 점입니다.

private  GoogleSignInClient signInClient;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // other code here
   
   GoogleSignInOptions signInOption = new GoogleSignInOptions.Builder(
        GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
        // If you are using Snapshots add the Drive scope.
        .requestScopes(Drive.SCOPE_APPFOLDER)
        // If you need a server side auth code, request it here.
        .requestServerAuthCode(webClientId)
        .build();
    signInClient = GoogleSignIn.getClient(context, signInOption);
}

한 번에 하나의 사용자 계정으로만 로그인할 수 있으므로 activity가 재개될 때 자동 로그인을 시도하는 것이 좋습니다. 그렇게 해도 유효한 경우 사용자를 자동으로 로그인하는 효과가 있습니다. 또한, 사용자가 다른 activity에서 로그아웃하는 것처럼 변경 사항이 있는 경우 로그인된 계정이 업데이트되거나 무효화됩니다.

private void signInSilently() {
  GoogleSignInOptions signInOption =
    new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
                   .build();
  GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOption);
  signInClient.silentSignIn().addOnCompleteListener(this,
           new OnCompleteListener<GoogleSignInAccount>() {
               @Override
               public void onComplete(@NonNull Task<GoogleSignInAccount> task) {
                  // Handle UI updates based on being signed in or not.
                  enableUIButtons(task.isSuccessful());
                 // It is OK to cache the account for later use.
                 mSignInAccount  = task.getResult();
               }
           });
}
    @Override
    protected void onResume() {
        super.onResume();
        signInSilently();
    }

대화식 로그인은 별도의 인텐트를 실행하는 방법으로 이루어집니다. 대단하죠! 오류 해결책이 있는지 확인하고 올바른 API를 호출하여 오류를 해결하려고 시도할 필요가 더 이상 없습니다. 그저 간단히 activity를 시작하고 onActivityResult()에서 결과를 가져오기만 하면 됩니다.

  Intent intent = signInClient.getSignInIntent();
  startActivityForResult(intent, RC_SIGN_IN);
    @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
      super.onActivityResult(requestCode, resultCode, intent);
      if (requestCode == RC_SIGN_IN) {
        // The Task returned from this call is always completed, no need to attach
        // a listener.
        Task<GoogleSignInAccount> task = 
              GoogleSignIn.getSignedInAccountFromIntent(intent);

          try {
            GoogleSignInAccount account = task.getResult(ApiException.class);
            // Signed in successfully, show authenticated UI.
              enableUIButtons(true);
           } catch (ApiException apiException) {
                // The ApiException status code indicates the
                //  detailed failure reason.
                // Please refer to the GoogleSignInStatusCodes class reference
                //  for more information.
                Log.w(TAG, "signInResult:failed code= " +
                    apiException.getStatusCode());
                new AlertDialog.Builder(MainActivity.this)
                        .setMessage("Signin Failed")
                        .setNeutralButton(android.R.string.ok, null)
                        .show();
            }
    }
}

GoogleSignIn.getLastSignedInAccount() 메서드를 호출하여 사용자가 로그인되었는지 여부를 확인할 수 있습니다. 이 메서드는 로그인된 사용자에 대한 GoogleSignInAccount를 반환하고, 로그인된 사용자가 없는 경우에는 null을 반환합니다.

if (GoogleSignIn.getLastSignedInAccount(/*context*/ this) != null) {
  // There is a user signed in, handle updating the UI.
  enableUIButtons(true);
} else {
  // Not signed in; update the UI.
  enableUIButtons(false);
}

로그아웃은 GoogleSignInClient.signOut()을 호출하는 방식으로 수행됩니다. 따라서 더 이상 게임을 위한 특정한 로그아웃이 없습니다.

signInClient.signOut().addOnCompleteListener(MainActivity.this,
        new OnCompleteListener<Void>() {
            @Override
             public void onComplete(@NonNull Task<Void> task) {
                enableUIButtons(false);
             }
         });
);

Games Services API 클라이언트 사용

이전 버전의 Play Games Services에서는 API를 호출하는 일반적인 패턴이 다음과 같았습니다.
    PendingResult<Stats.LoadPlayerStatsResult> result =
            Games.Stats.loadPlayerStats(
            mGoogleApiClient, false /* forceReload */);
    result.setResultCallback(new
            ResultCallback<Stats.LoadPlayerStatsResult>() {
        public void onResult(Stats.LoadPlayerStatsResult result) {
            Status status = result.getStatus();
            if (status.isSuccess()) {
                PlayerStats stats = result.getPlayerStats();
                if (stats != null) {
                    Log.d(TAG, "Player stats loaded");
                    if (stats.getDaysSinceLastPlayed() > 7) {
                        Log.d(TAG, "It's been longer than a week");
                    }
                    if (stats.getNumberOfSessions() > 1000) {
                        Log.d(TAG, "Veteran player");
                    }
                    if (stats.getChurnProbability() == 1) {
                        Log.d(TAG, "Player is at high risk of churn");
                    }
                }
            } else {
                Log.d(TAG, "Failed to fetch Stats Data status: "
                        + status.getStatusMessage());
            }
        }
    });

이 API는 Games 클래스의 정적 필드에서 액세스가 이루어지고 결과를 얻기 위해 개발자가 리스너에 추가한 PendingResult를 반환했습니다.

그런데 이제는 여기에 약간 변화가 생겼습니다. Games 클래스에서 API 클라이언트를 가져오는 정적 메서드가 있으며 PendingResult 클래스가 Task 클래스로 바뀌었습니다.

그 결과, 새로운 코드는 다음과 같습니다.
GoogleSignInAccount mSignInAccount = null;
Games.getPlayerStatsClient(this, mSignInAccount).loadPlayerStats(true)
        .addOnCompleteListener(
            new OnCompleteListener<AnnotatedData<PlayerStats>>() {
              @Override
              public void onComplete(Task<AnnotatedData<PlayerStats>> task) {
                try {
                    AnnotatedData<PlayerStats> statsData =
                        task.getResult(ApiException.class);
                    if (statsData.isStale()) {
                        Log.d(TAG,"using cached data");
                    }
                    PlayerStats stats = statsData.get();
                    if (stats != null) {
                        Log.d(TAG, "Player stats loaded");
                        if (stats.getDaysSinceLastPlayed() > 7) {
                            Log.d(TAG, "It's been longer than a week");
                        }
                        if (stats.getNumberOfSessions() > 1000) {
                            Log.d(TAG, "Veteran player");
                        }
                        if (stats.getChurnProbability() == 1) {
                            Log.d(TAG, "Player is at high risk of churn");
                        }
                    }
                } catch (ApiException apiException) {
                    int status = apiException.getStatusCode();
                    Log.d(TAG, "Failed to fetch Stats Data status: "
                            + status + ": " + task.getException());
                }
            }
        });

여기서 볼 수 있듯이, 크게 변한 것은 아니지만 Task API의 이점을 모두 활용할 수 있으므로 GoogleApiClient 수명 주기 관리에 대해 염려할 필요가 없습니다.

이러한 변경 패턴은 모든 API에서 동일합니다. 추가 정보가 필요한 경우 개발자 웹사이트에서 확인할 수 있습니다. 예를 들어, 예전에 Games.Achievements를 사용했다면 이제는 Games.getAchievementClient()를 사용해야 합니다.

Play Games Services API에 대한 마지막 주요 변경 사항은 새로운 API 클래스인 GamesClient가 추가되었다는 점입니다. 이 클래스는 setGravityForPopups(), getSettingsIntent()와 같은 지원 메서드를 처리하며 게임이 알림에서 실행된 경우 멀티플레이어 invitation 객체에 대한 액세스도 제공합니다.

이전에는 연결 힌트와 함께 onConnected() 메서드가 호출되었습니다. 이 힌트는 시작 시 activity로 전달된 invitation을 포함할 수 있는 Bundle 객체입니다.

이제는 GamesClient API를 사용하는 경우 invitation이 있으면 게임에서 signInSilently()를 호출해야 합니다. 이 호출은 사용자가 invitation에서 확인되었기 때문에 성공할 것입니다. 그런 후 GamesClient.getActivationHint()를 호출하여 활성화 힌트를 가져오고 invitation이 있는 경우 이를 처리합니다.

Games.getGamesClient(MainActivity.this,  mSignInAccount)
        .getActivationHint().addOnCompleteListener(
        new OnCompleteListener<Bundle>() {
            @Override
            public void onComplete(@NonNull Task<Bundle> task) {
                try {
                    Bundle hint = task.getResult(ApiException.class);
                    if (hint != null) {
                        Invitation inv = 
                           hint.getParcelable(Multiplayer.EXTRA_INVITATION);
                        if (inv != null && inv.getInvitationId() != null) {
                            // retrieve and cache the invitation ID
                            acceptInviteToRoom(inv.getInvitationId());
                            return;
                        }
                    }
                } catch (ApiException apiException) {
                    Log.w(TAG, "getActivationHint failed: " +
                        apiException.getMessage());
                }
            }
        });

오류 처리

메서드 호출이 실패하면 Task.isSuccessful()이 false가 되고 이 오류에 대한 정보는 Task.getException()을 호출하여 액세스할 수 있습니다. 경우에 따라서는 이러한 예외가 API 호출에서 성공 이외의 값이 반환되는 단순한 형태로 나타나기도 합니다. 다음과 같이 ApiException로 캐스트하여 이를 확인할 수 있습니다.
if (task.getException() instanceof ApiException) {
                    ApiException apiException = (ApiException) task.getException();
                    status = apiException.getStatusCode();
}

다른 경우, MatchApiException이 반환될 수 있으며 여기에는 업데이트된 일치 데이터 구조가 포함됩니다. 이러한 예외도 비슷한 방법으로 검색할 수 있습니다.
if (task.getException() instanceof MatchApiException) {
                    MatchApiException matchApiException =
                        (MatchApiException) task.getException();
                    status = matchApiException.getStatusCode();
                    match = matchApiException.getMatch();
} else if (task.getException() instanceof ApiException) {
                    ApiException apiException = (ApiException) task.getException();
                    status = apiException.getStatusCode();
}

상태 코드가 SIGN_IN_REQUIRED이면 플레이어를 다시 인증해야 함을 나타냅니다. 이를 위해 GoogleSignInClient.getSignInIntent()를 호출하여 플레이어를 대화식으로 로그인합니다.

요약


기존 GoogleApiClient 방식 대신, 더욱 느슨하게 결합된 API 클라이언트 사용으로 변경됨에 따라 상용구 코드가 줄어들고 사용 패턴이 더욱 명확해지고 스레드 안전성이 확보되는 이점이 있습니다. 현재 게임을 API 클라이언트로 마이그레이션하는 경우 다음 자료를 참고하시기 바랍니다.

게임에 대한 로그인 모범 사례:
https://developers.google.com/games/services/checklist

Play Games Services 샘플:
Android 기본 샘플
클라이언트 서버 골격

StackOverflow:
https://stackoverflow.com/questions/tagged/google-play-games

<블로그 원문은 여기에서 확인하실 수 있으며, 블로그 번역 리뷰는 김태호(Google)님이 참여해 주셨습니다.>

게시자: John Shriver-Blake, 제품 관리자


올해 초 Fabric 구성원들이 Firebase와 함께 하기로 했을 때, 우리는 앱을 개발하는 과정에서 일반적으로 발생하는 문제를 해결하는 플랫폼을 제공함으로써 여러분과 같은 개발자들이 멋진 사용자 환경을 만드는데 집중하게 하자는 공통된 목표를 달성하는 것에 뜻을 모았습니다.

많은 영역 중에서도 Fabric이 뛰어난 한 가지는 바로 콘솔과 대시보드였습니다. 우리는 지난 몇 달 동안 Fabric과 협력하여 Fabric과 Firebase에서 가장 뛰어난 부분을 하나로 합치려는 노력을 해왔습니다. 오늘, 우리는 Firebase 콘솔에 대한 몇 가지 개선 사항을 알려드리고자 합니다.


새롭게 설계된 탐색 기능

우리는 먼저 개발팀이 작업하는 방식을 더욱 정확히 반영하기 위해 탐색 기능을 새로 설계하는 작업부터 시작했습니다. 그래서 Firebase 제품을 네 개 그룹, 즉 개발, 안정성, 분석 및 성장으로 묶었습니다. 기존에 Firebase 콘솔에 표시되었던 제품들은 모두 그대로 표시되며, Firebase 플랫폼에서 제공하는 여러 제품들을 더욱 간단히 탐색할 수 있게끔 각 항목들을 재구성했습니다.

새로운 프로젝트 홈

몇 가지 중요 측정항목을 전면과 중심에 표시하도록 Firebase 콘솔의 프로젝트 홈 화면도 다시 설계했습니다. 이제는 Firebase에서 프로젝트를 처음 열 때 네 개의 주요 측정항목, 즉 30일간 비정상 종료가 발생하지 않은 사용자 비율, 30일간 비정상 종료 발생 횟수, 일일 활성 사용자 수 및 매월 활성 사용자 수와 함께 시간 경과에 따라 이러한 추세를 표시하는 그래프가 표시됩니다. 연구 조사를 수행한 결과 개발자는 이 네 가지 측정항목 중 하나를 찾는 데 대부분의 시간을 쓰고 있다는 사실을 확인했으므로 프로젝트 홈 방문 페이지에서 이러한 측정항목에 손쉽게 액세스할 수 있게 했습니다.

Latest Release

많은 사랑을 받은 또 다른 Fabric 콘솔 기능은 Latest Release 섹션입니다. 이 대시보드에서는 최신 앱 출시에서 가장 중요한 통계 정보 일체를 제공하므로 무엇이 잘 진행되고 있는지, 무엇을 롤백해야 하는지 빠르게 파악할 수 있습니다. Latest Release 섹션은 새로 설계된 Firebase 콘솔의 Analytics 섹션 하위에서 찾아볼 수 있습니다. 

업데이트된 Analytics 대시보드

오늘부터 Analytics 대시보드가 궁금한 사항을 쉽게 이해할 수 있도록 단순한 카드로 구성된 것을 볼 수 있을 것입니다. 'DAU' 또는 '사용자 유지 집단(코호트)'과 같은 용어를 기준으로 데이터를 구성하면 탐색하기 어렵기 때문에 "내 사용자가 어디에 참여하는가?" 또는 "사용자를 얼마나 잘 유지하고 있는가?"와 같이 앱과 관련하여 궁금해하는 사항을 기준으로 대시보드를 다시 구성했습니다. 연구 조사 결과 사용자 중 90%가 이 설계를 선호하는 것으로 확인되었으며 여러분도 이 설계가 유용하다는 점을 확인하시게 되기를 바랍니다!


실시간 정보

Fabric의 동료들과 여러 개발자들로부터 들은 의견을 통해 실시간 정보 확보가 중요하다는 점을 알게 되었습니다. 새로운 앱 출시 여부를 추적하거나 버그 수정 상태를 모니터링하는 것과 관계없이 앱에서 어떤 일이 일어나고 있는지 실시간으로 파악할 수 있어야 하며,  이에 따라 변경사항을 반영하거나 작업의 우선 순위를 지정할 수 있어야 합니다.

이를 위해, 새로운 Analytics 대시보드에 표시되는 카드와 콘솔의 Latest Release 섹션에 비정상 종료 및 활성 사용자에 대한 실시간 데이터를 추가되었습니다. 이는 단지 첫 시작일 뿐입니다. 앞으로 계속해서 Firebase 콘솔의 나머지 부분에서도 실시간 데이터를 더 많이 확인할 수 있도록 지원할 계획입니다.

늘 그렇듯이 https://firebase.google.com/support/를 방문하여 피드백을 남기고 궁금한 사항을 질문하실 수 있습니다.

<블로그 원문은 여기에서 확인하실 수 있으며, 블로그 번역 리뷰는 곽동현(Machine Learning GDE)님이 참여해 주셨습니다.>
게시자: Sujith Ravi, Google Expander 팀 연구원
올해 초, 우리는 스마트 메시징을 위한 '온디바이스' 기계 학습 기술을 최초로 적용한 Android Wear 2.0을 출시했습니다. 이를 통해 이전에는 Gmail, InboxAllo에서 사용할 수 있었던 Smart Reply 같은 클라우드 기반 기술을 클라우드에 연결할 필요 없이 타사 메시징 앱을 비롯한 애플리케이션 내에서 최초로 직접 사용할 수 있게 되었습니다. 이에 따라 이동 중에 스마트워치에서 바로 수신되는 채팅 메시지에 응답할 수 있습니다.

저희는 오늘 모바일 및 내장형 기기용 TensorFlow 경량 솔루션인 TensorFlow Lite를 발표합니다. 이 프레임워크는 작은 메모리 사용 공간 및 신속한 성능에 중점을 두고 기계 학습 모델의 짧은 시간 내 추론에 맞게 최적화되었습니다. 우리는 개발자와 연구자들이 온디바이스 추론으로 구동되는 새로운 머신 인텔리전스 기능을 더욱 쉽게 빌드할 수 있도록 하기 위해 온디바이스 대화형 모델과 함께, TensorFlow Lite로 구동되는 자연어 애플리케이션의 사례를 제공하는 데모 앱을 라이브러리의 일부로 출시했습니다. 이 모델에서는 채팅 애플리케이션에 쉽게 플러그인할 수 있는 효율적인 추론 기능을 통해 대화형 채팅 메시지 입력에 대한 회신 제안을 생성함으로써 온디바이스 대화형 인텔리전스를 구동합니다.

우리가 출시한 온디바이스 대화형 모델에서는 ProjectionNet: 신경 프로젝션 기술을 사용한 효율적인 온디바이스 딥 네트워크 학습(Learning Efficient On-Device Deep Networks Using Neural Projections)에서 처음 제시된 결합 최적화 프레임워크를 기반으로 컴팩트 신경망(및 기타 기계 학습 모델)을 훈련하는 데 새로운 ML 아키텍처를 사용합니다. 이 아키텍처는 컴팩트 비트 벡터 표현으로 입력을 변환하는 효율적인 '프로젝션' 작업을 사용하여 컴퓨팅 성능과 메모리가 제한적인 상황에서도 휴대기기에서 효율적으로 실행될 수 있습니다. 유사한 입력은 프로젝션 유형에 따라 조밀하거나 희소성을 띠는 가까운 벡터로 프로젝션됩니다. 예를 들어, "안녕, 어떻게 지내?""친구야, 어떻게 지내니?"라는 메시지는 동일한 벡터 표현으로 프로젝션될 수 있습니다.

대화형 모델은 이 아이디어를 바탕으로 적은 계산 및 메모리 사용 공간에서 이러한 효율적인 작업을 결합합니다. 우리는 두 가지 모델 유형을 결합으로 훈련하는 ML 프레임워크(즉, 컴팩트 프로젝션 모델(위 설명)과 트레이너 모델 결합)를 사용하여 이러한 온디바이스 모델을 완벽하게 훈련했습니다. 이 두 모델은 결합 방식으로 훈련되며, 여기서 프로젝션 모델은 트레이너 모델로부터 학습합니다. 트레이너는 전문가라는 특징을 띠고 더욱 크고 복잡한 ML 아키텍처를 사용하여 모델링되는 반면, 프로젝션 모델은 전문가로부터 학습하는 학생과 유사합니다. 훈련 중에 양자화 또는 증류와 같은 다른 기법을 추가로 적용하여 더욱 밀도 높은 압축을 구현하거나 선택적으로 목적 함수의 특정 부분을 최적화할 수도 있습니다. 훈련을 마치고 나면 기기에서 추론을 위해 더 작은 프로젝션 모델을 직접 사용할 수 있습니다.

추론을 위해, 모바일 플랫폼에서 신속하게 실행할 수 있도록 최적화된 TensorFlow Lite 작업 세트로 훈련된 프로젝션 모델이 컴파일된 후 기기에서 바로 실행됩니다. 온디바이스 대화형 모델에 대한 TensorFlow Lite 추론 그래프는 다음과 같습니다.
온디바이스 대화형 모델에 대한 TensorFlow Lite 실행.
오늘 출시되는 오픈소스 대화형 모델(코드와 함께 출시)은 위에서 설명한 결합 ML 아키텍처를 사용하여 완벽히 훈련된 모델입니다. 오늘 출시에는 데모 앱도 포함되어 있으므로 휴대기기에서 원터치 스마트 회신 기능을 쉽게 다운로드해 사용해 보실 수 있습니다. 이 아키텍처를 통해 애플리케이션 요구 사항을 기준으로 모델 크기와 예측 품질을 손쉽게 구성할 수 있습니다. 여기서 이 모델이 올바른 효과를 발휘하는 샘플 메시지 목록을 확인할 수 있습니다. 시스템에서는 채팅 대화에서 관찰된 인기 있는 응답 인텐트에서 학습되고 컴파일된 고정된 세트를 통해 회신 제안을 폴백할 수도 있습니다. 기본 모델은 Google이 해당 앱에서 Smart Reply 응답에 사용하는 모델과 다릅니다1.

대화형 모델 이외의 옵션

흥미롭게도, 위에서 설명한 ML 아키텍처에서는 기본 모델을 유연하게 선택할 수 있습니다. 우리는 이 아키텍처를 여러 기계 학습 접근 방식과도 호환되도록 설계했습니다. 예를 들어, TensorFlow 딥 러닝에 사용하는 경우 기본 모델에 대해 경량 신경망(ProjectionNet)을 학습하는 반면, 다른 아키텍처(ProjectionGraph)는 신경망 대신 그래프 프레임워크를 사용하는 모델을 나타냅니다.

결합 프레임워크는 여러 가지 ML 모델링 아키텍처를 사용하는 작업에 대해 경량의 온디바이스 모델을 훈련하는 데 사용할 수도 있습니다. 일례로서, 우리는 동적 프로젝션 작업으로 구성된 단순한 프로젝션 아키텍처 및 완전히 연결된 몇 가지 좁은 계층이 결합된 트레이너 모델에 대해 복잡한 피드 전달 또는 반복 아키텍처(예: LSTM)를 사용하는 ProjectionNet 아키텍처를 도출했습니다. 전체 아키텍처는 TensorFlow에서 역전파를 사용하여 완벽하게 훈련되며 훈련을 마치고 나면 간결한 ProjectionNet이 추론에 직접 사용됩니다. 우리는 이 방법을 사용하여 모델 크기를 상당히 축소시키고(최대 몇 자릿수 이상 축소) 여러 시각적 및 언어 분류 작업(몇 가지 예는 여기를 참조)에 대한 정확성과 관련하여 높은 성능을 실현하는 소형 ProjectionNet 모델을 성공적으로 훈련했습니다. 마찬가지로 반지도학습 설정에서도 그래프 학습 프레임워크를 사용하여 다른 경량 모델을 훈련했습니다.
온디바이스 모델 훈련을 위한 ML 아키텍처: 딥 러닝을 사용하여 훈련된 ProjectionNet(왼쪽)과 그래프 학습을 사용하여 훈련된 ProjectionGraph(오른쪽).
우리는 앞으로도 계속해서 TensorFlow Lite 모델을 향상하고 업데이트된 모델을 오픈소스로 출시할 예정입니다. 이러한 ML 아키텍처를 사용하여 학습된 출시 모델(및 향후 모델)은 많은 자연어 및 컴퓨터 버전 애플리케이션에 재사용하거나 머신 인텔리전스 실현을 위해 기존 앱에 연결할 수 있을 것입니다.  기계 학습 및 자연어 처리 커뮤니티에서 이를 바탕으로 우리가 아직 생각하지 못한 새로운 문제 및 활용 사례를 처리할 수 있게 되기를 바랍니다.

감사의 말
Yicheng Fan 씨와 Gaurav Nemade 씨가 이 작업에 막대하게 기여했습니다. Rajat Monga, Andre Hentz, Andrew Selle, Sarah Sirajuddin과 TensorFlow 팀의 Anitha Vijayakumar, 그리고 Robin Dua, Patrick McGregor, Andrei Broder, Andrew Tomkins과 같은 분들은 물론 Google Expander 팀에게도 감사의 인사를 전합니다.



1 출시된 온디바이스 모델은 휴대폰 및 웨어러블 기기에서 지연 시간이 짧은 소규모 애플리케이션에 최적화할 목적으로 훈련되었습니다. 하지만 Google 앱의 Smart Reply 예측은 그보다 크고 복잡한 모델을 사용하여 생성되었습니다. 또한, 프로덕션 시스템에서는 부적절한 콘텐츠를 감지하도록 훈련된 여러 분류자를 사용하며 추가 필터링 및 조정을 적용하여 사용자 환경 및 품질 수준을 최적화하고 있습니다. 오픈소스 TensorFlow Lite 버전을 사용하는 개발자는 최종 애플리케이션에 이와 같은 방법도 따를 것을 권장합니다.

<블로그 원문은 여기에서 확인하실 수 있으며, 블로그 번역 리뷰는 최성준(Machine Learning GDE)님이 참여해 주셨습니다.>
게시자: Chris Olston(TensorFlow Serving 연구원) 및 Noah Fiedel(TensorFlow Serving 소프트웨어 엔지니어)

2016년 2월 TensorFlow Serving이 처음으로 오픈소스로 제공된 이후 우리는 몇 가지 주요 기능을 대폭 개선했습니다. 우리가 처음 시작한 때를 되돌아보고, 그동안의 진행 상황을 다시 짚어보고, 앞으로 나아갈 방향에 대해 얘기해 보도록 하겠습니다.

TensorFlow Serving이 출시되기 전, Google 내 TensorFlow 사용자는 자신만의 서비스 제공 시스템을 처음부터 새로 생성해야 했습니다. 서비스 제공은 얼핏보면 쉬운 것처럼 보이지만, 일회성 서비스 제공 솔루션은 빠르게 그 복잡성이 증가합니다. 기계 학습(ML) 서비스 제공 시스템은 모델 버전 관리(롤백 옵션을 포함한 모델 업데이트용) 및 다중 모델(A/B 테스트를 통한 실험용)을 지원해야 하면서, 동시에 동작하는 모델들이 하드웨어 액셀러레이터(GPU 및 TPU)를 통해 짧은 지연 시간으로 높은 처리량을 달성하도록 보장해야 합니다. 따라서 우리는 범용적인 단일 TensorFlow Serving 소프트웨어 스택을 만들기로 했습니다.

우리는 이를 처음부터 오픈소스로 제공 가능하도록 만들기로 결정했으며 2015년 9월에 개발을 시작했습니다. 몇 달 후 우리는 완벽하게 작동하는 초기 시스템을 제작했으며 2016년 2월에 오픈소스 릴리스를 했습니다.

지난 1년 반 동안 우리 회사 내외부의 사용자와 파트너의 도움 덕분에 TensorFlow Serving은 성능, 모범 사례 및 표준 측면에서 다음과 같은 발전을 이루었습니다.
  • 최적화된 서비스 제공 및 사용자설정 기능 기본 제공: 우리는 이제 AVX 지원 최신 CPU에 맞게 최적화되어 미리 빌드된 표준 서비스 제공 바이너리를 제공하므로 개발자가 특별한 요구 사항이 없는 한 Google 라이브러리에서 자체적인 바이너리를 어셈블할 필요가 없습니다. 그와 동시에, 레지스트리 기반 프레임워크를 추가하여 라이브러리를 사용자설정(또는 TensorFlow 이외) 서비스 제공 시나리오에 사용할 수 있도록 했습니다.
  • 다중 모델 서비스 제공: 한 모델에서 동시에 서비스가 제공되는 여러 모델로 전환하면 성능과 관련하여 여러 가지 장애물이 발생합니다. 우리는 (1) 격리된 스레드 풀에 로드하여 트래픽이 발생시키는 다른 모델에서 지연 시간의 급증이 발생하지 않도록 하고, (2) 서버 시작 시 모든 모델의 초기 병렬 로드를 가속화하며, (3) 다중 모델 배치 인터리빙을 통해 하드웨어 액셀러레이터(GPU/TPU)를 다중화함으로써 다중 모델을 원활하게 제공합니다.
  • 모델 형식 표준화: 우리는 SavedModel을 TensorFlow 1.0에 추가하여 훈련 및 서비스 제공 간에 제대로 작동하는 단일의 표준 모델 형식을 커뮤니티에 제공했습니다.
  • 사용이 간편한 추론 API: 우리는 일반적인 추론 작업(분류, 회귀)에 사용할 수 있는 사용이 간편한 API를 출시했으며, 이는 광범위한 Google 애플리케이션에서 올바르게 작동하는 것으로 확인되었습니다. 더욱 발전된 사용을 지원하기 위해 더 low-level tensor 기반 API(predict)와 멀티태스킹 모델링을 사용하는 새로운 다중 추론 API를 지원합니다.
이 모든 작업은 (a) 우리가 내실을 기하고 내부 SLA를 충족하도록 하는 데 도움을 주는 Google의 ML SRE 팀, (b) 광고 서비스 제공 및 TFX를 포함한 기타 Google 기계 학습 인프라 팀, (c) Google Play 등의 애플리케이션 팀, (d) Clipper 서비스 제공 시스템과 관련한 상호 보완적인 연구 문제를 탐구하는 UC 버클리 RISE Lab 파트너, (e) Google 오픈소스 사용자 기반 및 기고자와의 긴밀한 협업을 바탕으로 이루어졌습니다.

TensorFlow Serving은 현재 Google의 Cloud ML Prediction을 비롯하여 1,100개 이상의 Google 자체 프로젝트에 대해 초당 수천만 개의 추론을 처리하고 있습니다. Google의 핵심 서비스 제공 코드는 오픈소스 릴리스를 통해 모두에게 제공됩니다.

앞으로 계속해서 우리가 하는 작업은 무궁무진할 것이며 혁신을 꾀할 수 있는 여러 방안을 모색 중입니다. 오늘 우리는 두 가지 실험 영역에서 초기 진행 상황을 알려드리고자 합니다.
  • 세분화된 일괄 처리: 특수화된 하드웨어(GPU 및 TPU)를 통한 높은 처리량을 달성하기 위해 우리가 택한 핵심 기술은 여러 사례를 공동으로 처리하여 효율성을 높이는 기술인 '일괄 처리'입니다. 우리는 (a) 효율성을 극대화하기 위해 일괄 처리가 계산에서 GPU/TPU 부분만 대상으로 삼을 수 있도록 하고, (b) 텍스트 및 이벤트 시퀀스와 같은 시퀀스 데이터를 처리하는 데 사용되는 순환적 신경망 내에서 일괄 처리가 가능하도록 하는 것을 목표로 일괄 처리를 향상할 수 있는 기술과 모범 사례를 개발하고 있습니다. 우리는 일괄 처리/일괄 처리 해제 작업 쌍을 사용하여 임의의 부분 그래프를 일괄 처리하는 것을 실험하고 있습니다.
  • 분산 모델 서비스 제공: 우리는 하나의 서버 노드에 맞추기에는 너무 큰 모델을 처리하거나 메모리 효율적인 방식으로 하위 모델을 공유하는 수단으로서 모델 분할 기술을 연구하고 있습니다. 최근에 프로덕션 환경에서 1TB 이상의 모델을 출시하고 좋은 결과를 내고 있으며, 이 기능을 곧 오픈소스로 제공하기를 바라고 있습니다.
다시 한 번 피드백, 코드, 그리고 아이디어를 주신 모든 사용자와 파트너 여러분께 감사 말씀을 올립니다. github.com/tensorflow/serving에서 프로젝트에 참여해 주시기 바랍니다.

구글코리아가 글로벌 혁신 제품 개발에 참여할 소프트웨어 엔지니어를 채용합니다. 이번 채용 모집분야는 검색, 안드로이드, 사물인터넷(IoT), 구글 어시스턴트 등 현재 개발 중인 구글 서비스 전 분야에 걸쳐 신입 및 경력, 인턴 등 다양한 개발자를 모집합니다.

구글코리아 엔지니어링팀은 그동안 글로벌 혁신 제품 개발에 참여해 왔으며, 특히 검색 서비스 중 금융 및 엔터테인먼트 분야, 안드로이드 부문 멀티미디어 및 시스템 분야, 사물인터넷(IoT) 플랫폼 및 구글 어시스턴트의 검색 연동 기능 개발 등에 집중해왔습니다.

특히 구글의 소프트웨어 엔지니어는 한국 뿐 아니라 전세계 수십억 명의 사용자가 정보를 연결하고, 탐색하며, 상호작용하는 방식을 바꿀 수 있는 차세대 테크놀로지를 개발하게 됩니다. 따라서 이번 채용에서는 해결해야 하는 문제를 탐색하여 잘 정의하고 이를 주도적으로 풀어나가는 적극적 자세와 새로운 기술에 대한 지속적인 관심과 더불어 빠른 학습 능력을 가진 역량있는 지원자를 눈여겨 볼 계획입니다.

구글은 포춘(Fortune)에서 6년 연속 ‘일하기 좋은 100대 기업’ 1위를 기록하고 있습니다. 특히 한국에서는 ‘2017 대한민국 일하기 좋은 100대 기업’에서 국가 간 우호 교류 및 신뢰 경영 문화 조성에서 괄목할 성과를 낸 기업 및 기관, 개인에 시상하는 특별상을 수상하는 등 기업 문화 발전에 노력하고 있습니다. 또한, 엔지니어링 업계 다양성 활성화를 위해 여성 소프트웨어 캠프 및 장학금 제도를 비롯하여 컴퓨터 전공 여학생을 대상으로 다양한 프로그램을 진행하는 등 국내 여성 개발자 육성에도 힘쓰고 있습니다.

각 분야별 구체적인 모집 분야와 자격 요건 등에 대한 상세한 내용은 아래 표와 구글 채용 페이지를 통해 확인하실 수 있습니다. 구글의 차세대 기술을 이끌 국내 엔지니어들의 많은 관심과 지원을 기대하겠습니다!
모집 직군
모집 분야
인원
소프트웨어 엔지니어 경력
(00명)
Engineering Manager, Android Media
(안드로이드 미디어, 엔지니어링 매니저)
0명
Software Engineer, Pixel Camera
(카메라 분야 소프트웨어 엔지니어)
00명
Software Engineer, Android OS
(안드로이드 OS, 소프트웨어 엔지니어)
0명
Software Engineer, Tools and Infrastructure
(툴과 인프라스트럭처, 소프트웨어 엔지니어)
0명
Software Engineer - Seoul (소프트웨어 엔지니어)
00명
소프트웨어 엔지니어 신입
(00명)
Software Engineer, University Graduate (소프트웨어 엔지니어)
00명
소프트웨어 엔지니어 인턴
(00명)
2018 소프트웨어 엔지니어 인턴(공지 예정)
00명

<블로그 원문은 여기에서 확인하실 수 있으며, 블로그 번역 리뷰는 정승욱(Android GDE)님이 참여해 주셨습니다.>

게시자: Marc Stogaitis 및 Tajinder Gadh, 소프트웨어 엔지니어


운전은 우리의 일상 활동에 있어 필수적인 부분입니다. 따라서 Google에서는 어떻게 하면 Android 기기를 Google 사용자가 사용하기에 더 적합하고 안전하게 만들 수 있을지 고심하는 데 많은 시간을 할애합니다. 운전에 방해가 되지 않도록 하고 개방적인 에코시스템을 빌드하여 안전이 최우선인 스마트폰 환경을 구현할 수 있을까 하는 고심 말입니다.

우리는 최근에 새로 발표한 Pixel 2세대 기기에서 운전 중 알림 일시중지 기능을 선보였습니다. 운전 중 알림 일시중지 기능을 사용하면 운전할 때 기기가 자동으로 알림 일시중지 모드로 전환됩니다. 이 모드에서는 수신 메시지와 알림이 무음 처리되지만 수신 전화, 내비게이션 안내 및 음성 상호작용은 연결된 차량 블루투스를 이용해 계속 받을 수 있습니다. 이 제품은 운전 중 주의를 산만하게 할 요소를 최대한 줄이는 동시에 사용자가 계속해서 원활하게 내비게이션 또는 이와 유사한 다른 앱은 방해받지 않고 사용할 수 있도록 설계되었습니다.

이면을 살펴보면, 이 제품은 여러 센서, 블루투스 및 와이파이에서 저출력 신호를 사용하여 사용자가 운전 중일 때를 감지하는 AI 기반 온디바이스 동작 인식을 사용합니다. 동작 인식 기능은 Android 센서 허브를 사용하여 짧은 지연 시간, 낮은 전력 및 정확한 운전 감지를 보장합니다.

이것이 바로 우리가 나아가야 할 다음 단계이지만 앞으로도 갈 길이 멉니다. 내년 초에는 산만한 요소가 없는 운전 환경을 빌드하기 위해 운전 중 알림 일시중지 기능에서 사용되는 동일한 API인 Activity Recognition Transition API를 출시할 예정입니다.

보내주신 피드백에 감사드리며, 제품의 진화에 따라 계속 여러분의 의견을 경청할 것입니다.

운전 중 알림 일시중지 기능 설정에 관해 궁금한 사항이 있으시면 고객센터를 통해 확인하시기 바랍니다.

<블로그 원문은 여기에서 확인하실 수 있으며, 블로그 번역 리뷰는 도창욱(Web Technologies GDE)님이 참여해 주셨습니다.>

Firebase Predictions 베타 출시를 기쁜 마음으로 발표합니다! 이를 통해 우리는 Firebase를 사용하는 모든 개발자에게 뛰어난 성능의 Google 기계 학습 시스템을 제공할 수 있게 되었습니다. Predictions는 기계 학습 모델을 사용하여 결정되는 예측 동작을 기반으로 동적 사용자 그룹을 생성할 수 있는 제품으로, Firebase 클라우드 메시징, 원격 구성 및 기타 기술을 사용하여 이러한 사용자 그룹을 타겟팅할 수 있습니다. 예측 내용이 항상 최신 상태로 유지하도록 사용자 그룹은 매일 업데이트됩니다.

기본적으로 다음과 같이 네 가지 예측 그룹이 제공됩니다.
  • Churn은 소프트한 이탈, 즉 앞으로 7일 내에 앱 사용을 중단할 것으로 예측되는 사용자 그룹입니다.
  • Not_Churn은 앞으로 7일이 지나도 앱을 계속 사용할 것으로 예측되는 사용자 그룹입니다.
  • Spend는 앞으로 7일 내에 인앱 구매를 할 것으로 예측되는 사용자 그룹입니다.
  • Not_Spend는 앞으로 7일 내에 인앱 구매를 할 것으로는 예측되지 않는 사용자 그룹입니다.

Firebase 콘솔의 왼쪽 탐색 모음에서 Predictions를 선택하면 바로 이 네 가지 그룹이 표시됩니다.

이들 카드에서 각 경우에 따라 취할 수 있는 조치 사항을 알 수 있습니다.

Tolerance: 이 허용치 슬라이더를 통해 허용되는 오차 정도를 낮음, 보통 또는 높음으로 지정할 수 있습니다. 낮은 허용치에서는 사용자 모집단이 더 작아지지만 오차에 대한 위험도 낮아집니다. 이와 유사하게, 높은 허용치에서는 사용자 모집단이 더 커지지만 오차 위험도 높아집니다. 'churn' 경우에는 이탈할 것으로 예측되지만 실제로는 앱을 계속 사용하는 사용자를 오차의 예로 들 수 있습니다.

Target Users: 이 작업에서는 해당 사용자 그룹에 대해 Remote Config 또는 Notifications 를 선택할 수 있는 드롭다운이 제공됩니다. 이 옵션은 인앱 인센티브를 제공하기 위한 몇 가지 유용한 지침을 보여주는 링크도 제공합니다.



Remote Config를 선택하면 해당 모집단에 대해 설정하고 싶은 원격 구성 매개변수를 지정하고 그에 대한 값을 지정할 수 있는 새 화면이 표시됩니다. 예를 들어, 게임을 빌드했는데 많은 사람들이 이탈한데다 게임 플레이가 너무 어렵다는 피드백이 온다면 난이도에 대한 원격 구성 변수를 설정할 수 있을 것입니다. 그러면 이탈할 가능성이 높은 사용자라도 기본값을 낮게 설정하여 좀 더 쉽게 게임을 즐기도록 유도할 수 있습니다.

Notifications를 선택하면 Firebase 클라우드 메시징을 사용하여 전송할 메시지를 작성할 수 있는 익숙한 작성기가 표시됩니다. 더불어 타겟 잠재고객을 선택할 수 있는 일반적인 옵션 외에도, 사용자 세그먼트로서 예측된 사용자 그룹도 미리 채워지게 됩니다.



이를 통해 해당 사용자 그룹으로 알림이 전달되도록 할 수 있습니다. 예를 들어, 이탈 위험이 있는 사용자에 대해 앱을 계속 사용하도록 유도하는 알림을 보낼 수 있습니다.

자신만의 예측 생성. 기본 제공되는 예측 카드로만 제한되지 않습니다. 당연히 앱에서 설정하는 사용자설정 이벤트를 기반으로 자신만의 예측을 생성할 수도 있습니다. 이 경우, 예측을 생성할 수 있는 카드가 표시됩니다.

이 카드를 선택하면 이벤트가 발생할 시기 또는 발생하지 않을 시기에 대한 예측을 생성할 수 있습니다. 이는 해당 전환 이벤트에 참여할 가능성이 큰 사용자의 식별에 도움이 됩니다.

예를 들어, 위 사례에서는 사용자가 게임에서 레벨이 올라갈 때마다 level_up 전환 이벤트가 기록됩니다. 따라서 레벨이 올라갈 수 있는 플레이어에 대한 예측을 생성하고 그들에게 게임을 계속할 수 있도록 인센티브를 제공할 수 있습니다.

그러면 예측을 저장한 후 시간이 지남에 따라 기본 제공되는 카드와 같은 방식으로 Firebase 콘솔에서 카드에 데이터가 채워집니다.

알림과 원격 구성으로 사용자를 타겟팅하는 옵션을 포함하여 다른 카드와 같은 방법으로 이 카드를 사용할 수 있습니다.

Firebase Predictions는 베타 제품이며 우리는 계속해서 이에 대한 작업을 하고 향상해 나갈 것입니다. 궁금한 점이나 피드백이 있으면 알려주시기 바랍니다. 버그 및 제품과 관련한 제안 사항은 firebase.google.com/support로 알려주시기 바랍니다.

firebase.google.com/products/predictions/에서 Firebase Predictions에 대한 자세한 사항을 알아보거나 여기서 Google 문서를 직접 확인해 보실 수 있습니다.

<블로그 원문은 여기에서 확인하실 수 있으며, 블로그 번역 리뷰는 양찬석(Google)님이 참여해 주셨습니다.>

게시자: Steven Soneff, 신원 확인 제품 관리자
전화번호를 활용하는 앱을 만들 때, 사용자가 전화번호를 소유하고 있는지 인증할 필요가 있습니다. 하지만 전화 번호 인증은 여러가지 면에서 까다로올 수 있습니다. UX 관점에서 여러 로케일의 전화번호 형식을 지원해야 하고, 간편한 사용자 인증을 위해 사용자의 SMS를 확인하기 위해서 위험한 등급의 사용자 권한을 요구해야합니다.

Firebase 전화 인증과 같이 미리 구현된 전화 인증 라이브러리가 있지만, 이러한 기능을 직접 만들어야 하는  경우, Google Play Service에서 새롭게 제공하는 두 가지 API인 Phone SelectorSMS Retriever를 활용할 수 있습니다. 이를 활용해, 추가 적인 기기 권한 요청 없이 SMS를 통해 사용자 전화 번호를 확인하고 바로 인증을 진행할 수 있습니다. Flipkart와 같은 앱에서는 이 방법을 사용하여 전화번호 가입 과정 성공률을 12% 높일 수 있었습니다.

서버에서 이러한 API를 활용하기 위한 단계는 다음에서 확인할 수 있습니다.

그럼 전화번호 선택기를 제공하는 방법과 이 후 SMS Retriever API를 활용해, 서버로부터 인증 코드를 요청하는 방법을 살펴보겠습니다. 결과적으로 안드로이드 디바이스 상에서 사용자 입력 과정 없이 자동으로 인증 코드를 수신하여 파싱할 수 있습니다.

참고: 시작하기 전에 전화 번호가 있고, SMS를 수신할 수 있으며, Google Play Service 10.2.x 이상이 설치된 기기에서 아래 기능을 테스트할 수 있습니다.

Phone Selector를 사용하여 전화번호 가져오기

첫 번째 단계에서는 사용자가 앱 내에서 SMS 인증을 시작하도록 합니다. 앱에서 전화번호를 입력하라는 메시지를 사용자에게 표시합니다. 다음과 같이 Phone Selector를 사용해  이 기능을 쉽게 구현할 수 있습니다.

// Construct a request for phone numbers and show the picker
private void requestHint() {
    HintRequest hintRequest = new HintRequest.Builder()
           .setPhoneNumberIdentifierSupported(true)
           .build();

    PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent(
            apiClient, hintRequest);
    startIntentSenderForResult(intent.getIntentSender(),
            RESOLVE_HINT, null, 0, 0, 0);
}

HintRequest 빌더는 전화번호 식별자가 필요하다는 사실을 Play Service에 알립니다. 그 후, 사용자가 전화번호를 선택할 수 있는 Play Service 대화상자를 표시하기 위한 인텐트를 만듭니다. 이 API는 어떠한 사용 권한도 요구하지 않고, 휴대폰 또는 Google 계정에서 얻을 수 있는 번호를 사용자가 선택할 수 있도록 표시합니다.


사용자가 전화번호를 선택하면 최신 버전의 Play Service를 실행하는 기기에서 E164 형식으로 onActivityResult에서 애플리케이션에 이 전화번호가 반환됩니다. 어떤 경우에는 휴대폰에 따라 전화번호를 가져오지 못할 수도 있으므로 자격 증명이 null이 아닌지 여부를 확인해야 합니다. 전화번호가 없으면 사용자가 수동으로 입력할 수 있는 방법을 제공할 필요가 있습니다.

// Obtain the phone number from the result
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (requestCode == RESOLVE_HINT) {
      if (resultCode == RESULT_OK) {
          Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
          // credential.getId(); <-- E.164 format phone number on 10.2.+ devices
      }
  }
}

이제, 사용자 전화번호를 확인했습니다. 이 방법이 유용하기는 하지만, 개발자는 해당 사용자가 이 전화번호를 소유하고 있는지 인증해야합니다. 예를 들어, 이 번호를 사용하여 다른 사용자와 메시지를 주고받거나 이 번호로 사용자 자신의 신원을 확인할 수 있는지 여부를 확인하고 싶을 것입니다.


SMS Verification API를 활용하여 전화번호 인증

전화번호 소유 여부를 확인하는 간단한 방법은 일회성 인증 코드를 포함한 SMS를 해당 번호로 보내고 앱에 입력하도록 하는 것입니다. SMS Verification API는 앱이 들어오는 SMS를 수신할 수 있는 기능을 제공합니다. 그러면 앱이 이렇게 이 SMS에서 자동으로 코드를 파싱할 수 있습니다.

앱은 다음과 같이 SmsRetrieverClient 를 구현합니다..
SmsRetrieverClient client = SmsRetriever.getClient(this /* context */);

Task<Void> task = client.startSmsRetriever();

task.addOnSuccessListener(new OnSuccessListener<Void>() {
  @Override
  public void onSuccess(Void aVoid) {
    // successfully started an SMS Retriever for one SMS message
  }
});

task.addOnFailureListener(new OnFailureListener() {
  @Override
  public void onFailure(@NonNull Exception e) {
  });
);

그 후, 작업을 시작하기만 하면 됩니다. on Success 리스너뿐만 아니라, 문제가 발생한 경우 이를 처리하기 위한 on Failure 리스너도 포함되어 있습니다. SMS Retriever를 시작한 후에는 사용자의 전화번호를 서버로 보내고 메시지를 생성하여 해당 번호로 보내기 위한 워크플로를 시작해야 합니다.

이 메시지는 특정 방식으로 구성되어야 합니다. 메시지는 SMS 메시지 크기에 맞아야 하므로, 140바이트를 초과할 수 없습니다. '<#>' 또는 두 개의 연속되고 폭이 없는 공백 문자(U + 200B)를 특정 접두사로 사용하여 시작해야 합니다. 자세한 내용은 해당 문서를 참조하세요. 아래의 설명과 같이 앱을 식별하는 11자 길이의 해시로 끝나야 합니다.

예:

<#> Use 123456 as your verification code in Example App!
FA+9qCX9VSu

일회성 인증 코드는 어떠한 문자열이든 가능하며, 단순하게 임의의 숫자를 생성해도 됩니다. 메시지는 여기에 제시된 절차에 따라 판별되는 해시로 끝나야 합니다. Google Play Service는 이 해시를 사용하여 인증 메시지에 해당하는 앱을 결정합니다. 앱 패키지 및 서명 인증서용으로 이 해시를 한 번만 생성하면 됩니다. 이 해시는 변경되지 않으며 클라이언트 앱에서 제공되지 않습니다.

그러면 서버가 기존에 구축한 SMS 인프라 또는 서비스를 사용하여 휴대폰으로 메시지를 보낼 수 있습니다. 이 메시지가 수신되면 Google Play Service가 메시지의 텍스트를 포함하는 인텐트를 브로드캐스트합니다. 코드는 다음과 같습니다.

public class MySMSBroadcastReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
    if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
      Bundle extras = intent.getExtras();
      Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);

      switch(status.getStatusCode()) {
        case CommonStatusCodes.SUCCESS:
          String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
          break;
        case CommonStatusCodes.TIMEOUT:
          break;
      }
    }
  }
}

브로드캐스트 리시버의 onReceive에서 추가 항목을 얻고 그곳에서 상태를 확인합니다. 메시지가 성공적으로 수신된 경우, 추가 항목에서 메시지를 확인 할 수 있습니다. 여기에서 인증 코드를 파싱하고 서버로 다시 전송하여 전화번호 소유 여부를 확인할 수 있습니다.

자세한 내용은 전체 문서와 올해 진행된 Google I/O 세션을 확인하시기 바랍니다.

얼리 어답터의 사용 후기

이 API를 일찍 사용해 본 파트너들은 긍정적인 반응을 보이고 있습니다. 다음은 이들 파트너의 사용 후기를 일부 발췌한 내용입니다.

Twilio는 안드로이드 SMS 인증이 그 어느 때보다도 쉬워졌다는 사실을 확인하고는 이에 대한 내용을 블로그에 올렸습니다.

"전화번호를 사용해 사용자 계정을 등록하고 식별하는 안드로이드용 모바일 앱을 빌드하는 개발자라면 안드로이드용 Twilio Verification SDK를 꼭 사용해 보세요. 그러면 매끄럽고 안전하고 쉬운 가입 절차 제공 문제를 그 어느 때보다도 빠르게 해결하실 수 있을 겁니다." - Simil Thorpe, Twilio의 제품 소유자

Authy는 이러한 API가 많은 변경 사항을 수행할 필요 없이 기존의 SMS 인프라와 잘 연동된다는 사실에 만족감을 표시했습니다.

"Phone Selector와 SMS Retriever를 Authy 2FA 앱에 추가하면 애플리케이션에 필요한 높은 수준의 보안을 유지하는 동시에 사용자에게 놀라울 정도로 뛰어난 UX를 제공할 수 있습니다." - Serge Kruppa, Authy 엔지니어링 책임자

Telesign은 동일한 백엔드 프레임워크에서 UX가 향상되고 보안이 강화되며 전환율이 증가한다는 점을 확인했습니다.

"번거로운 부분이 줄어든 이러한 인증 모드를 통해 얻을 수 있는 유의미한 장점 중 하나는 고객이 사용자 가입 및 등록 과정에서 전환율이 증가하는 것을 눈으로 볼 수 있다는 점입니다.

Google Play Service는 SMS 메시지를 해당 메시지 내의 애플리케이션 해시를 기반으로 대상 애플리케이션만 액세스할 수 있도록 허용하므로, 이를 통해 보안 강화라는 이점도 얻을 수 있습니다."- Priyesh Jain(게시물 작성자)

<블로그 원문은 여기에서 확인하실 수 있으며, 블로그 번역 리뷰는 정승욱(Android GDE)님이 참여해 주셨습니다.>
게시자: Lukas Bergstrom, Android 개발자 프레임워크 팀 제품 관리자

Android는 고급 휴대폰에서 비행기 좌석 시스템에 이르기까지 수십억 개의 기기에서 실행되고 있습니다. Android OS는 이처럼 광범위한 기기에서 제대로 작동하도록 리소스를 공격적으로 관리하는데, 이로 인해 때로는 견고한 앱을 빌드하기가 어렵고 복잡해질 수 있습니다. 이 작업을 좀 더 쉽게 하기 위해, 우리는 Google I/O에서 Architecture Components의 미리보기를 선보임으로써 수명 주기 관리 및 데이터 지속성과 같은 일반적인 작업을 위한 라이브러리와 함께 앱 아키텍처에 대한 지침을 제공했습니다. 이와 함께, 이러한 기본 구성 요소를 통해 더 적은 상용구 코드로 모듈식 애플리케이션을 작성할 수 있으므로 개발자가 쓸데없이 시간을 낭비하는 대신 혁신을 꾀하는 데 집중할 수 있으며, 우리는 앞으로도 이러한 기반을 기초로 앱 빌드가 계속 이루어지기를 바랍니다.

오늘 우리는 Room 및 Lifecycle Architecture Components 라이브러리가 1.0 Stable에 도달했음을 기쁜 마음으로 알려드립니다. 이러한 API는 프로덕션 앱 및 라이브러리에 바로 사용할 수 있으며 앱 아키텍처 및 로컬 저장소와 관련하여 도움을 구하는 개발자들에게 권장합니다(단, 권장 사항일 뿐이지 필수 사항은 아님). Lifecycle은 이제 지원 라이브러리에도 통합되었으므로 AppCompatActivity와 같은 표준 클래스와 함께 사용할 수 있습니다.

우리는 오늘 Stable 버전을 선언하지만 베타 구성 요소가 이미 앱에서 함께 사용되고 있으며 설치 건수가 수십억 건에 이릅니다. Zappos와 같은 주요 개발업체는 다음과 같이 Architecture Components 덕분에 중요한 문제에 더 많은 시간을 할애할 수 있었습니다.

Android Architecture Components 출시 전에는 자체적으로 ViewModel을 구현했었습니다. 로더와 종속성 주입을 사용하여 구성이 변경되는 과정에서 ViewModel을 유지했습니다. 최근에 우리는 Architecture Components ViewModel 구현으로 전환했으므로 이러한 상용구 코드를 더 이상 사용하지 않게 되었습니다. 우리는 설계, 비즈니스 로직 및 테스트에 더 많은 시간을 소비하고 상용구 코드를 작성하거나 Android 수명 주기 관련 문제를 걱정하는 데는 시간을 덜 낭비할 수 있게 되었다는 사실을 확인했습니다.

또한, Activity 수명 주기에 직접 후크되는 LiveData를 사용하기 시작했습니다. LiveData를 사용하여 네트워크 데이터를 검색하고 표시하므로 네트워크 호출 구독 관리에 대해 더 이상 염려할 필요가 없게 되었습니다.

- David Henry, Zappos의 Android 소프트웨어 엔지니어

Architecture Components는 개발자들이 뛰어난 사용 환경을 빌드하는 데 집중할 수 있도록 몇 가지 일반적인 문제를 없애주는 단순하고 유연하며 실용적인 접근 방식을 제공합니다. 이는 앱 아키텍처에 대한 지침에 따라 함께 연결되는 핵심 구성 요소를 기반으로 합니다.

Lifecycle

모든 Android 개발자는 Activity를 시작, 중지 및 제거할 때 운영체제 문제를 다루어야 합니다. 즉, 수명 주기를 거치면서 UI를 업데이트하는 데 사용되는 observable과 같은 구성 요소의 상태를 관리해야 합니다. Lifecycle을 사용하면 자체적인 수명 주기를 관리하는 수명 주기 인식 구성 요소 를 생성할 수 있으므로 누수나 비정상 종료 문제가 발생할 가능성이 줄어들게 됩니다. Lifecycle 라이브러리는 LiveData와 같은 다른 Architecture Components의 기반입니다.

LiveData

LiveData는 데이터를 유지하고 업데이트를 제공하는 수명 주기 인식 observable입니다. UI 코드는 변경 사항을 구독하고 LiveData에 해당 Lifecycle에 대한 참조를 제공합니다. LiveData는 수명 주기를 인식하므로 해당 Lifecycle이 시작되거나 재개될 때 업데이트를 제공하지만 LifecycleOwner가 제거될 때 업데이트 제공을 중지합니다. LiveData는 더욱 안전하고 성능이 좋은 반응형 UI를 간단하게 빌드할 수 있는 방법입니다.

ViewModel

ViewModel은 Activity 및 Fragment와 같은 수명 주기와 연결된 엔터티로부터 로직 및 뷰 데이터에 대한 소유권을 분리합니다. ViewModel은 연결된 Activity 또는 Fragment가 영구적으로 제거될 때까지 유지됩니다. 즉, 회전으로 인해 Fragment가 다시 생성되는 등의 이벤트가 발생해도 뷰 데이터가 유지됩니다. ViewModel은 일반적인 수명 주기 관련 문제를 해결할 뿐만 아니라 더욱 모듈화되고 테스트하기가 더욱 쉬운 UI를 빌드하는 데에도 도움이 됩니다.

Room

거의 모든 앱이 데이터를 로컬 위치에 저장할 필요가 있습니다. Android에서는 버전 1부터 플랫폼에 SQLite를 번들로 포함해 제공하고 있지만 이를 직접 사용하기란 무척 어려울 수 있습니다. Room은 더 적은 상용구 코드로 SQlite의 기능을 완벽히 활용할 수 있는 단순한 객체 매핑 계층입니다. 컴파일 시간 쿼리 검증 및 기본 제공 마이그레이션과 같은 기능을 통해 더욱 쉽게 강력한 지속성 계층을 빌드할 수 있는 동시에, LiveData와의 통합을 통해 Room은 데이터베이스가 지원되고 수명 주기가 인식되는 observable을 제공할 수 있습니다. Room은 로컬 저장소를 관리하는 데 필요한 단순성, 강력한 기능 및 견고성을 모두 아우르고 있으므로 꼭 한번 사용해 보시기를 바랍니다.

앱 아키텍처에 대한 가이드 및 기타 등등

마지막으로, 모든 개발자에게 적용되는 핵심 원리와 Architecture Components를 함께 사용하기 위한 구체적인 지침을 제공하는 앱 아키텍처에 대한 가이드를 작성했다는 점도 알려드립니다. 우리는 개발자들로부터 명확하고 일관된 지침이 중요하다는 의견을 많이 들어왔기 때문에 현재 해당하는 경우 Architecture Components를 참조하도록 개발자 문서를 업데이트하고 있습니다. 또한, Architecture Components 사이트를 통해 풍부한 동영상, 코드랩 및 샘플 앱도 제공하고 있으며 앞으로 더 많은 것들을 제공할 예정입니다.

계속 지켜봐 주세요.

첫 번째 Architecture Components 세트가 이제 Stable 버전으로 제공되지만 할 일이 더 있다는 것을 알고 있습니다. 지난 몇 달 동안 우리는 개발자 여러분의 피드백을 들어왔으며 이에 따라 기능을 개선했습니다. 또한, RecyclerView를 사용하여 대규모 데이터세트를 처리하기가 너무 어렵다는 내용의 피드백에 따라 최근에 PagedList라고 하는 새로운 Architecture Components를 알파 버전으로 출시했습니다. 이는 시작에 불과합니다. 우리는 더 많은 주요 구성 요소를 개발 중에 있으며, 향후 몇 달 내에 발표할 계획입니다.

Architecture Components와 관련하여 우리가 바라는 바는, 개발자가 휴대기기를 위한 독창적이고 새로운 환경을 제공하는 데 집중할 수 있도록 해드리는 것입니다. 마침내 프로덕션용 Stable 버전으로 이들 Architecture Components를 발표할 수 있게 되어 기쁘게 생각합니다. 우리는 그 과정에서 이처럼 유용한 피드백을 제공해 주신 커뮤니티에 감사하다는 인사를 드리고 싶으며 이 게시물의 댓글을 통해 계속해서 논의가 활발하게 이루어지기를 기대합니다. 끝으로, 이 Stable 버전 출시를 기다려 주신 개발자 여러분, 지금 바로 시작해 보시기 바랍니다.

<블로그 원문은 여기에서 확인하실 수 있으며, 블로그 번역 리뷰는 김소영(Google)님이 참여해 주셨습니다.>

구글 로컬라이제이션팀 게재

구글의 아랍어 랭귀지 매니저인 크리스티나 하예크는 사랑하는 할머니가 팔순이 되셨을 때 자매들과 함께 할머니와 더욱 가까워질 수 있는 선물을 드리고 싶었습니다. 할머니가 사시는 곳은 레바논이지만, 자녀와 손주들은 세계 곳곳에 흩어져 살고 있었기 때문이죠. 이러한 지리적 거리를 조금이나마 좁히고자 크리스티나 자매는 할머니께 안드로이드 스마트폰을 선물했습니다. 할머니는 상자에서 새 스마트폰을 꺼내자마자 바로 아랍어로 사용할 수 있다는 사실에 깜짝 놀랐습니다.

마법이 일어난 것이 아닙니다. 구글 로컬라이제이션팀이 열심히 일한 덕분입니다. 30여 개국에 흩어져 있는 로컬라이제이션팀은 70개가 넘는 언어로 모든 구글 제품을 쉽고 재미있게 사용할 수 있도록 하는 일을 담당합니다. 로컬라이제이션이란 번역만을 의미하는 것이 아닙니다. 일례로 야구와 도넛의 비유가 미국에서는 잘 통할지 몰라도 다른 문화권에서는 통하지 않을 수도 있습니다. 그래서 이탈리아의 경우 축구로, 프랑스라면 크루아상으로 바꾸는 것이죠. 로컬라이제이션팀의 사명은 모든 언어와 문화에 어울리는 다양한 사용자 경험을 제공하는 것입니다. 이를 위해 유능한 번역사들과 감수자들이 그룹을 이루어 구글 제품이 전 세계 어디서든 자연스럽게 느껴지도록 로컬라이제이션 작업을 하고 있습니다.

인터넷을 사용하는 세계 인구가 점점 늘면서, 로컬라이제이션 산업도 성장을 거듭하고 있습니다. 이에 따라 훌륭한 실력을 갖춘 번역사, 감수자, 로컬라이제이션 전문가 수요도 늘고 있죠. 따라서 모두를 위한 제품을 만들고 전 세계 어디에 있든 인터넷을 사용할 수 있도록 하겠다는 구글의 사명을 달성하기 위한 노력의 일환으로, 로컬라이제이션 에센셜이라는 이름의 온라인 공개 수업(MOOC)을 진행합니다. 피터 루버스(Peter Lubbers) 구글 개발자 교육팀장은 다음과 같이 말합니다.

“언어 산업은 오늘날 세계에서 가장 빠르게 성장하는 분야 중 하나입니다. 전직 인터내셔널라이제이션 프로덕트 매니저(겸 네덜란드어 번역사)로서 이번에 ‘로컬라이제이션 에센셜’을 구글·유다시티(Udacity) 교육 과정으로 개설하게 되어 기쁩니다. 이 과정은 전 세계 누구든 지금 바로 무료로 수강할 수 있습니다. 이 강의는 다양한 직군을 망라하는 대규모 프로젝트로 개발되었으며, 구글의 수많은 로컬라이제이션 전문가들이 모여 심혈을 기울였습니다. 모두가 열과 성을 다해 참여하는 모습이 보기 좋았고, 덕분에 대단히 완성도 높은 강의를 만들 수 있었습니다.”

로컬라이제이션 에센셜’은 유다시티와 공동으로 개발한 무료 강의로 글로벌 제품을 개발하기 위해 필요한 로컬라이제이션의 기본을 모두 다룹니다. 베르트 반데르 미른(Bert Vander Meeren) 구글 로컬라이제이션 디렉터의 설명을 들어보시죠.

“오늘날 로컬라이제이션은 갈수록 더 중요해지는 분야입니다. 인터넷 사용자층이 특히 비영어권 국가에서 급속히 성장하고 있기 때문입니다. 그러나 이 분야에 대한 교육 기회는 충분하지 않습니다. 저희 팀뿐만 아니라 대규모 로컬라이제이션 인력이 필요한 모든 기업에게 바람직한 상황이 아닙니다. 그래서 저희가 앞장서서 문제를 해결해 보기로 했습니다. 다년간의 실무 경험을 갖춘 로컬라이제이션 전문가들보다 이 분야를 더 잘 아는 사람이 있을까요? 이전에도 유다시티와 협력하여 안드로이드 개발자들을 위한 교육 과정을 개발하여 제공한 적이 있기 때문에 이번 협업도 자연스럽게 결정했습니다. 이 강의는 로컬라이제이션 분야의 지식과 기술을 익히고 싶은 분이면 누구에게나 좋은 기회가 될 것입니다. 로컬라이제이션은 여전히 잘 알려져 있지 않은 분야이지만 전 세계에 서비스할 제품을 개발하기 위해 대단히 중요한 분야입니다. 학생에게도, 직장인에게도, 기업가에게도 시야를 넓힐 수 있는 좋은 기회가 될 것입니다.”

이번 기회를 통해 구글이 가진 로컬라이제이션에 대한 지식을 공유함으로써, 전 세계 사용자들이 자신의 문화에 좀 더 잘 어우러지는 제품을 사용할 수 있고 새로운 기회를 얻을 수 있기를 희망합니다.

이번 강의가 전 세계 사용자들에게 어떤 영향을 미칠지 기대됩니다.