Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Realm in real life

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →

Realm in real life

Avatar for Marcin Zbijowski

Marcin Zbijowski

October 21, 2017

Other Decks in Programming

Transcript

  1. App requirements • Collects attendees data • Enables contests •

    Easy (possibly live) preview of data • Works even when there is no network • Easy update without app recompilation
  2. Realm • is offline first solution • syncs as little

    as possible when possible • offers SDKs for iOS and JavaScript
  3. Realm class Attendee: Object { dynamic var firstName: String? }

    let attendee = Attendee() attendee.firstName = "Marcin" let realm = try! Realm() try! realm.write { realm.add(attendee) }
  4. iOS Setup private var authServerURL: URL { return URL(string: "https://\(self.syncServerURL)")!

    } private var realmServerURL: URL { return URL(string: "realm://\(self.syncServerURL):9080/~/\(self.realmName)")! }
  5. iOS Setup SyncUser.logIn(with: self.usernameCredentials, server: self.authServerURL, timeout: 5) { [weak

    self] user, error in guard let `self` = self else { return } var user = user if let error = error { // there could be an error, but maybe we can work offline? // in case previous login was success if user == nil { user = SyncUser.current } // if user is still not available, we have nothing to work with if user == nil { return } } // . . . }
  6. iOS Setup let config = Realm.Configuration(syncConfiguration: SyncConfiguration(user: user!, realmURL: self.realmServerURL))

    self.realmQueue.async { [weak self] in guard let `self` = self else { return } self.reactiveRealm.value = try! Realm(configuration: config) RealmSyncHandler.sharedInstance.startDownloadSync(realmUrl: self.realmServerURL) // . . . }
  7. Data models class Attendee: Object { dynamic var dateAdded: Date

    = Date() dynamic var email: String? dynamic var firstName: String? dynamic var lastName: String? var knownProgrammingLanguages = List<ProgrammingLanguage>() var takenSurveys = List<TakenSurvey>() }
  8. Data models class TakenSurvey: Object { dynamic var survey: Survey?

    = nil dynamic var startTime: Date = Date() dynamic var totalTime: Double = 0 var answers = List<AnsweredQuestion>() var attendees = LinkingObjects<Attendee>(fromType: Attendee.self, property: "takenSurveys") }
  9. Data population queue.async { [weak self] in guard let rules

    = rlm.objects(Rules.self).filter("id = \"currentSurveyTimeLimit\"").first, let survey = self?.activeSurvey else { return } self?.infoLabel.text = "\(rules.text) minutes | \(survey.questions.count) questions" }
  10. Data population func present(question: Question) { guard let container =

    self.formContainer, let questionLabel = container.viewWithTag(QUESTION_TEXT_TAG) else { return } // . . . questionLabel.text = question.text if let code = question.code { // create and position label } for answer in question.possibleAnswers { let currentView = self.createRadioButton(for: answer, /*. . .*/) // . . . } }
  11. Form validation func save() -> Bool { // . .

    . let isValid = self.validateForm(container: container) if isValid { let attendee = self.createAttendee(from: container) // . . . queue.async { try! realm.write { realm.add(attendee) } } self.clearForm(container: container) } else { let alert = UIAlertController(title: nil, message: NSLocalizedString("Please enter your name, surname and email", comment: ""), preferredStyle: .alert) // . . . presenter?.present(alert, animated: true) return false } RealmSyncHandler.sharedInstance.startUploadSync() return true }
  12. Realm Object Server $ cat ~/.bash_history curl -s https://packagecloud.io/install/repositories/realm/realm/script.deb.sh |

    sudo bash sudo apt-get update sudo apt-get install realm-object-server-developer sudo systemctl enable realm-object-server sudo systemctl start realm-object-server cat /etc/realm/admin_token.base64 vi /etc/realm/configuration.yml sudo vi /etc/realm/configuration.yml sudo service realm-object-server restart sudo systemctl restart realm-object-server sudo systemctl stop realm-object-server sudo systemctl start realm-object-server sudo systemctl stop realm-object-server sudo systemctl start realm-object-server sudo systemctl start codewise-con-admin sudo systemctl start codewisecon sudo systemctl status codewisecon sudo systemctl status realm-object-server sudo vi /etc/realm/configuration.yml tail -f /var/log/realm-object-server.log https://realm.io/docs/realm-object-server/#cloud-deployment
  13. App Transport Security • Introduced in iOS 9 • Forces

    you to do all communication over HTTPS
  14. App Transport Security Solution • Caddy Server to the rescue


    https://caddyserver.com • Super simple to configure and ready in no time private var authServerURL: URL { return URL(string: "https://\(self.syncServerURL)")! }
  15. Server side Swift? • Because it’s possible • Same models

    on both ends of the app • Possibly less code to write
  16. JavaScript approach • Ask colleagues for help • Node.js +

    some dependencies + Bootstrap $ ls -1 node_modules | wc -l 220
  17. JS Data models module.exports = { name: 'Attendee', properties: {

    dateAdded: { type: 'date', default: new Date()}, email: { type: 'string', optional: true}, firstName: { type: 'string', optional: true}, lastName: { type: 'string', optional: true}, knownProgrammingLanguages: { type: 'list', objectType: 'ProgrammingLanguage' }, takenSurveys: { type: 'list', objectType: 'TakenSurvey' } } }; class Attendee: Object { dynamic var dateAdded: Date = Date() dynamic var email: String? dynamic var firstName: String? dynamic var lastName: String? var knownProgrammingLanguages = List<ProgrammingLanguage>() var takenSurveys = List<TakenSurvey>() } JS Swift
  18. JS Data models module.exports = { name: 'TakenSurvey', properties: {

    survey: { type: 'Survey' }, totalTime: { type: 'double'}, answers: {type: 'list', objectType: 'AnsweredQuestion'} } }; class TakenSurvey: Object { dynamic var survey: Survey? = nil dynamic var startTime: Date = Date() dynamic var totalTime: Double = 0 var answers = List<AnsweredQuestion>() var attendees = LinkingObjects<Attendee>(fromType: Attendee.self, property: "takenSurveys") } JS Swift
  19. Where we used it • Geecon, Kraków, ~600 attendees •

    FrontTrends, Warszawa, ~300 attendees • Devoxx, Kraków, ~600 attendees • JS.Poland, Warszawa, ~100 attendees