Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

ヘルスケアサービスを実現する最新技術 〜HealthKit・GCP + Goの活用〜

29,448 views

Published on

DeNA TechCon 2018の登壇資料です。

Published in: Technology
  • Be the first to comment

  • Be the first to like this

ヘルスケアサービスを実現する最新技術 〜HealthKit・GCP + Goの活用〜

  1. 1. 

  2. 2. 2
  3. 3. 3
  4. 4. 4
  5. 5. 5
  6. 6. 6
  7. 7. 7
  8. 8. 8
  9. 9. 9
  10. 10. 11
  11. 11. 12
  12. 12. 13
  13. 13. 14
  14. 14. 15
  15. 15. 16
  16. 16. 17
  17. 17. 18
  18. 18. 20
  19. 19. 21
  20. 20. import UIKit import HealthStore class ViewController: UIViewController { private let healthStore = HealthStore() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } } 22
  21. 21. guard let healthStore = healthStore else { return } guard let type = HKQuantityType.quantityType(forIdentifier: .stepCount) else { return } let builder = DailyQueryBuilder(quantityType: type) healthStore.requestSources(from: Date.startOfToday(), to: Date(), builder: builder) { (sources: [StepSource]?) in if let sources = sources { print("sources: (sources)”) } else { print("step sources are not found.”) } } 23
  22. 22. guard let healthStore = healthStore else { return } guard let type = HKQuantityType.quantityType(forIdentifier: .stepCount) else { return } let builder = DailyQueryBuilder(quantityType: type) healthStore.requestSources(from: Date.startOfToday(), to: Date(), builder: builder) { (sources: [StepSource]?) in if let sources = sources { print("sources: (sources)”) } else { print("step sources are not found.”) } } 24
  23. 23. guard let healthStore = healthStore else { return } guard let type = HKQuantityType.quantityType(forIdentifier: .stepCount) else { return } let builder = DailyQueryBuilder(quantityType: type) healthStore.requestSources(to: Date(), builder: builder) { (sources: [StepSource]?) in if let sources = sources { print("sources: (sources)”) } else { print("step sources are not found.”) } } 25
  24. 24. guard let healthStore = healthStore else { return } guard let type = HKQuantityType.quantityType(forIdentifier: .stepCount) else { return } let builder = DailyQueryBuilder(quantityType: type) healthStore.observeSourceUpdates(from: Date(), builder: builder, handler: { (sources: [StepSource]?) in if let sources = sources { print("sources: (sources)") } else { print("step sources are not found.") } }) 26
  25. 25. guard let healthStore = healthStore else { return } guard let type = HKQuantityType.quantityType(forIdentifier: .stepCount) else { return } let builder = RestrictedSourceQueryBuilder(quantityType: type) healthStore.requestSources(from: Date.startOfToday(), to: Date(), builder: builder) { (sources: [StepSource]?) in if let sources = sources { print("sources: (sources)”) } else { print("step sources are not found.”) } } 27
  26. 26. 28
  27. 27. import HealthKit public protocol HealthStoreQueryBuildable { var quantityType: HKQuantityType { get } var typesToWrite: Set<HKSampleType>? { get } var typesToRead: Set<HKObjectType>? { get } var options: HKStatisticsOptions { get } var anchorDate: Date { get } var intervalComponents: DateComponents { get } var predicates: [NSPredicate] { get } func build() -> HKStatisticsCollectionQuery? func build(completion: @escaping (HKStatisticsCollectionQuery?) -> Void) } 29
  28. 28. public extension HealthStoreQueryBuildable { var typesToWrite: Set<HKSampleType>? { return nil } var typesToRead: Set<HKObjectType>? { return nil } func build() -> HKStatisticsCollectionQuery? { let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates) return HKStatisticsCollectionQuery( quantityType: quantityType, quantitySamplePredicate: predicate, options: options, anchorDate: anchorDate, intervalComponents: intervalComponents) } func build(completion: @escaping (HKStatisticsCollectionQuery?) -> Void) { completion(build()) } } 30
  29. 29. public struct DailyQueryBuilder: HealthStoreQueryBuildable { public let quantityType: HKQuantityType public var typesToRead: Set<HKObjectType>? { return [quantityType] } public let options: HKStatisticsOptions = .cumulativeSum public let anchorDate: Date public let intervalComponents: DateComponents = DateComponents(day: 1) public let predicates: [NSPredicate] = [] public init(quantityType: HKQuantityType, anchorDate: Date = Date.startOfToday()) { self.quantityType = quantityType self.anchorDate = anchorDate } } 31
  30. 30. public class RestrictedSourceQueryBuilder: HealthStoreQueryBuildable { public func build(completion: @escaping (HKStatisticsCollectionQuery?) -> Void) { guard let provider = HealthSourceProvider() else { completion(nil) return } provider.appleSources(sampleType: quantityType) { (sources, error) in if let error = error { print(error) } guard let sources = sources else { completion(nil) return } // update predicates let metadataPredicate = HKQuery.predicateForObjects(withMetadataKey: HKMetadataKeyWasUserEntered, operatorType: .notEqualTo, value: true) let sourcePredicate = HKQuery.predicateForObjects(from: sources) self.predicates = [metadataPredicate, sourcePredicate] // build query completion(self.build()) } } } 32
  31. 31. 33
  32. 32. 34
  33. 33. 35
  34. 34. 36
  35. 35. 38
  36. 36. 39 🤖 🚀
  37. 37. 40 💗 👀
  38. 38. 41
  39. 39. 42
  40. 40. 43
  41. 41. 44
  42. 42. 45
  43. 43. 46
  44. 44. 47 var ( ErrNoSuchUser = errors.New("...") ) type Repository interface { Get(id string) (*User, error) } var NewRepository func(context.Context) Repository domain/user/repository.go
  45. 45. 48
  46. 46. 49 type userRepository struct { Ctx context.Context } func NewUserRepository(ctx context.Context) user.Repository { return &userRepository{ Ctx: ctx, } } func (r *userRepository) Get(id string) (*user.User, error) { // ... } infrastructure/persistence/datastore/user_repository.go
  47. 47. 50 func init() { user.NewRepository = datastore.NewUserRepository } func main() { repo := user.NewRepository(ctx) // datastore.userRepository }
  48. 48. 51 type userRepository struct { Ctx context.Context } func NewUserRepository(ctx context.Context) user.Repository { return &userRepository{ Ctx: ctx, } } func (r *userRepository) Get(id string) (*user.User, error) { // ... } infrastructure/persistence/mock/user_repository.go
  49. 49. 52 func TestMain(m *testing.M) { user.NewRepository = mock.NewUserRepository m.Run() }
  50. 50. 53 👍 👍 👍
  51. 51. 58
  52. 52. 59 func Namespacer(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // treat an error! ctx, _ := appengine.Namespace(r.Context(), "Namespace-a") h(w, r.WithContext(ctx)) } } Middleware
  53. 53. 63
  54. 54. 64 👍 👍 👍
  55. 55. BigQuery App Engine Datastore Data Studio
  56. 56. BigQuery App Engine Datastore Data Studio
  57. 57. App Engine Task Queue BigQuery Access Enqueue
  58. 58. BigQuery App Engine Datastore Data Studio
  59. 59. Cron Export Backup Load
  60. 60. 71 Cron Export Backup
  61. 61. 72 Create Load Job Backup Trigger Load
  62. 62. Cron Export Backup Load
  63. 63. BigQuery App Engine Datastore Data Studio
  64. 64. BigQuery Data Studio
  65. 65. 76
  66. 66. 77 👍 👍 👍

×