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

Como aplicar la arquitectura de Elm en Swift

Como aplicar la arquitectura de Elm en Swift

Version reducida para https://char.la/ de mi presentación sobre Portal y como aplicar la aquitectura de Elm en Swift.

https://speakerdeck.com/guidomb/a-portal-from-elm-to-swift

Guido Marucci Blas

June 01, 2017
Tweet

More Decks by Guido Marucci Blas

Other Decks in Programming

Transcript

  1. A Portal from Elm to Swift 1 — A Portal

    from Elm to Swift by Guido Marucci Blas
  2. Guido Marucci Blas Co-founder & tech lead at Wolox CTO

    at Syrmo Twitter: @guidomb Blog: http://guidomb.blog GitHub: http://github.com/ guidomb 2 — A Portal from Elm to Swift by Guido Marucci Blas
  3. A Portal from Elm to Swift 4 — A Portal

    from Elm to Swift by Guido Marucci Blas
  4. MVC - Problems → Massive fat controllers → Hard to

    test → Highly coupled → Lots of boilerplate 9 — A Portal from Elm to Swift by Guido Marucci Blas
  5. MVC - Possible solutions → Extract business logic → Extract

    "side-effects" into services with protocols → Use dependency injection → Use notifications 10 — A Portal from Elm to Swift by Guido Marucci Blas
  6. MVVM - Problems → Requires a binding mechanisim → It's

    not clear who is responsable for view transitions → Forces you to use DI framework, singletons or propagate dependencies over the whole hierarchy 11 — A Portal from Elm to Swift by Guido Marucci Blas
  7. All this architectures still have the same problems 12 —

    A Portal from Elm to Swift by Guido Marucci Blas
  8. The application's state is spread over several components 13 —

    A Portal from Elm to Swift by Guido Marucci Blas
  9. Which means state is mutated all over the place 14

    — A Portal from Elm to Swift by Guido Marucci Blas
  10. Which also means that if state needs to be shared,

    it must be kept in sync 15 — A Portal from Elm to Swift by Guido Marucci Blas
  11. Shared mutable state is the root of all EVIL 16

    — A Portal from Elm to Swift by Guido Marucci Blas
  12. The other big issue is how this architectures manage side-effects

    17 — A Portal from Elm to Swift by Guido Marucci Blas
  13. What do we do next? 18 — A Portal from

    Elm to Swift by Guido Marucci Blas
  14. but what about Swift? 22 — A Portal from Elm

    to Swift by Guido Marucci Blas
  15. If you want the full power of the Elm architecture

    you need ... 24 — A Portal from Elm to Swift by Guido Marucci Blas
  16. But UIKit will make your life miserable 26 — A

    Portal from Elm to Swift by Guido Marucci Blas
  17. A (potentially) cross-platform, unidirectional data flow framework to build applications

    using a declarative and immutable UI API. 28 — A Portal from Elm to Swift by Guido Marucci Blas
  18. 100% written in Swift 29 — A Portal from Elm

    to Swift by Guido Marucci Blas
  19. The declarative API is NOT coupled to UIKit 30 —

    A Portal from Elm to Swift by Guido Marucci Blas
  20. enum Message { case like case goToDetailScreen } let component:

    Component<Message> = container( children: [ label( text: "Hello PortalView!", style: labelStyleSheet() { base, label in base.backgroundColor = .white label.textColor = .red label.textSize = 12 }, layout: layout() { $0.flex = flex() { $0.grow = .one } $0.justifyContent = .flexEnd } ) button( properties: properties() { $0.text = "Tap to like!" $0.onTap = .like } ) button( properties: properties() { $0.text = "Tap to got to detail screen" $0.onTap = .goToDetailScreen } ) ] ) 32 — A Portal from Elm to Swift by Guido Marucci Blas
  21. label( text: "Hello PortalView!", style: labelStyleSheet() { base, label in

    base.backgroundColor = .white label.textColor = .red label.textSize = 12 }, layout: layout() { $0.flex = flex() { $0.grow = .one } $0.justifyContent = .flexEnd } ) 33 — A Portal from Elm to Swift by Guido Marucci Blas
  22. button( properties: properties() { $0.text = "Tap to like!" $0.onTap

    = .like } ) 34 — A Portal from Elm to Swift by Guido Marucci Blas
  23. public indirect enum Component<MessageType> { case button(ButtonProperties<MessageType>, StyleSheet<ButtonStyleSheet>, Layout) case

    label(LabelProperties, StyleSheet<LabelStyleSheet>, Layout) case mapView(MapProperties, StyleSheet<EmptyStyleSheet>, Layout) case imageView(Image, StyleSheet<EmptyStyleSheet>, Layout) case container([Component<MessageType>], StyleSheet<EmptyStyleSheet>, Layout) case table(TableProperties<MessageType>, StyleSheet<TableStyleSheet>, Layout) case collection(CollectionProperties<MessageType>, StyleSheet<EmptyStyleSheet>, Layout) case carousel(CarouselProperties<MessageType>, StyleSheet<EmptyStyleSheet>, Layout) case touchable(gesture: Gesture<MessageType>, child: Component<MessageType>) case segmented(ZipList<SegmentProperties<MessageType>>, StyleSheet<SegmentedStyleSheet>, Layout) case progress(ProgressCounter, StyleSheet<ProgressStyleSheet>, Layout) case textField(TextFieldProperties<MessageType>, StyleSheet<TextFieldStyleSheet>, Layout) case custom(componentIdentifier: String, layout: Layout) case spinner(Bool, StyleSheet<SpinnerStyleSheet>, Layout) } 35 — A Portal from Elm to Swift by Guido Marucci Blas
  24. but what about state management and side- effects? 36 —

    A Portal from Elm to Swift by Guido Marucci Blas
  25. public protocol Application { associatedtype MessageType associatedtype StateType associatedtype CommandType

    associatedtype RouteType: Route associatedtype SubscriptionType: Equatable associatedtype NavigatorType: Equatable var initialState: StateType { get } var initialRoute: RouteType { get } func translateRouteChange(from currentRoute: RouteType, to nextRoute: RouteType) -> MessageType? func update(state: StateType, message: MessageType) -> (StateType, CommandType?)? func view(for state: StateType) -> View<RouteType, MessageType, NavigatorType> func subscriptions(for state: StateType) -> [Subscription<MessageType, RouteType, SubscriptionType>] } 37 — A Portal from Elm to Swift by Guido Marucci Blas
  26. public struct View<RouteType: Route, MessageType, NavigatorType: Navigator> { public typealias

    ActionType = Action<RouteType, MessageType> public enum Content { case alert(properties: AlertProperties<ActionType>) case component(Component<ActionType>) } public let navigator: NavigatorType public let root: RootComponent<ActionType> public let content: Content } 38 — A Portal from Elm to Swift by Guido Marucci Blas
  27. public indirect enum Action<RouteType: Route, MessageType> { case dismissNavigator(thenSend: Action<RouteType,

    MessageType>?) case navigateToPreviousRoute(preformTransition: Bool) case navigate(to: RouteType) case sendMessage(MessageType) } 39 — A Portal from Elm to Swift by Guido Marucci Blas
  28. public protocol Route: Equatable { var previous: Self? { get

    } } 40 — A Portal from Elm to Swift by Guido Marucci Blas
  29. public protocol CommandExecutor { associatedtype CommandType associatedtype MessageType func execute(command:

    CommandType, dispatch: @escaping (MessageType) -> Void) } 41 — A Portal from Elm to Swift by Guido Marucci Blas
  30. import UIKit import PortalApplication import PortalView let context = UIKitApplicationContext(

    application: Voices(), commandExecutor: VoicesCommandExecutor(), subscriptionManager: VoicesSubscriptionManager(), customComponentRenderer: VoidCustomComponentRenderer() ) context.registerMiddleware(TimeLogger()) PortalUIApplication.start(applicationContext: context) { message in switch message { case .didFinishLaunching(_, _): return .applicationLaunched default: return .none } } 42 — A Portal from Elm to Swift by Guido Marucci Blas
  31. Portal - Warning → Still very early stage → API

    will probably change → Still needs important features like UI diffing 44 — A Portal from Elm to Swift by Guido Marucci Blas
  32. Portal - Milestones → API stability → Improve performance →

    Cool tooling, like hot UI reload → Server side rendering? → Android support 45 — A Portal from Elm to Swift by Guido Marucci Blas
  33. TL; DR; → Decouple side-effects froms logic by describing effects

    using values → Avoid state sincronization, have a central place where state is mutated → Avoid deep view / object hierarchy, prefer wide hierarchies 46 — A Portal from Elm to Swift by Guido Marucci Blas