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

Dobry zwyczaj: nie odziedziczaj

Dobry zwyczaj: nie odziedziczaj

Slides for my conference talk from Mobilization 2015, 2015/10/17.

Polish only.

English title would be "Solely on merit: do not inherit"

Krzysztof Siejkowski

October 17, 2015
Tweet

More Decks by Krzysztof Siejkowski

Other Decks in Programming

Transcript

  1. Dobry zwyczaj
    nie odziedziczaj
    @_siejkowski
    siejkowski.net
    !

    View full-size slide

  2. BaseViewController
    BaseDataFetchingViewController
    :BaseViewController
    BaseFormPresentingViewController
    :BaseDataFetchingViewController

    View full-size slide

  3. Przepraszam, czy mogę
    przeciążyć?

    View full-size slide

  4. NSManagedObject
    https://github.com/rentzsch/mogenerator

    View full-size slide

  5. BaseViewController : UIViewController
    ThirdPartyBehaviorEnablingViewController
    : UIViewController
    UserAccountDetailsViewController : !

    View full-size slide

  6. struct SomeStruct {}
    enum SomeEnum {}
    typealias SomeFunction = (Int -> String)
    class C : SomeFunction
    ❗ Inheritance from non-protocol, non-class type
    'SomeFunction'

    View full-size slide

  7. agregacja
    protokoły
    funkcje

    View full-size slide

  8. ThirdPartyBehaviorEnablingService
    ThirdPartyBehaviorEnablingDelegate

    View full-size slide

  9. init(accountService: AccountService,
    transactionService: TransactionService,
    sessionService: SessionService,
    favouritesService: FavouritesService,
    locationService: LocationService,
    ...)

    View full-size slide

  10. class *-Utils
    class *-Helper

    View full-size slide

  11. UITableViewDataSource
    UITableViewDelegate

    View full-size slide

  12. code review
    TDD
    style guide
    clean code

    View full-size slide

  13. agregacja
    protokoły
    funkcje

    View full-size slide

  14. protocol SessionAware
    protocol LocationAware
    protocol FavouritesFetchable
    class MyViewController : UIViewController,
    SessionAware, LocationAware,
    FavouritesFetchable

    View full-size slide

  15. extension
    UIViewController
    : SessionAware

    View full-size slide

  16. protocol SessionAware {
    func login(username: String,
    _ password: String,
    _ callback: (UserDetails) -> ())
    }
    extension MyViewController : SessionAware {}
    extension SessionAware {
    func login(username: String,
    _ password: String,
    _ callback: (UserDetails) -> ())) {
    // domyślna implementacja
    }
    }
    ❗ http://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future

    View full-size slide

  17. protocol FavouritesDataSource : UITableViewDataSource {
    var state: [FavouriteDetails] { get } // "obietnica" stanu
    }
    extension FavouritesDataSource {
    func tableView(_ tableView: UITableView,
    numberOfRowsInSection section: Int) -> Int {
    return state.count
    // ...
    protocol FavouritesTableDelegate : UITableViewDelegate {
    var state: [FavouriteDetails] { get } // "obietnica" stanu
    }
    extension FavouritesTableDelegate {
    func tableView(_ tableView: UITableView,
    heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    // ...
    class MyViewController : NSObject, FavouritesDataSource, FavouritesTableDelegate {
    var state: [FavouriteDetails] = Array()
    init(newState: [FavouriteDetails]) {
    state = newState
    }

    View full-size slide

  18. ⬆ dziedziczenie ⬇
    ⬅ protokoły ➡

    View full-size slide

  19. agregacja
    protokoły
    funkcje

    View full-size slide

  20. func login(username: String,
    _ password: String,
    _ callback: (UserDetails) -> ())
    func update(view: HeaderView)
    (_ user: UserDetails) -> UserDetails
    func fetchFavourites(user: UserDetails)
    (_ callback: (FavouritesData) -> ())
    func update(source: FavoritesDataSource)
    (_ tableView: UITableView)
    (_ favourites: FavouritesData)

    View full-size slide

  21. class SomeViewController {
    let updateHeader = update(headerView)
    let updateFavourites = update(favouritesDataSource)(tableView)
    override func viewDidLoad() {
    // ..., m.in super.viewDidLoad()
    login("siejkowski","mobilization") { details in
    fetchFavourites(updateHeader(details))(updateFavourites)
    }
    }

    View full-size slide

  22. infix operator |> { associativity left }
    infix operator <| { associativity right }
    public func |> (a : A, f : A -> B) -> B {
    return f(a)
    }
    public func <| (f : A -> B, a : A) -> B {
    return f(a)
    }

    View full-size slide

  23. infix operator useFor { associativity left }
    details useFor updateHeader

    !

    View full-size slide

  24. login("siejkowski","mobilization") { details in
    fetchFavourites(updateHeader(details))(updateFavourites)
    }
    ⬇ ⬇ ⬇
    login("siejkowski","mobilization") { details in
    (details |> updateHeader |> fetchFavourites) <| updateFavourites
    }

    View full-size slide

  25. agregacja
    protokoły
    funkcje

    View full-size slide

  26. class SomeViewController {
    let updateHeader = update(headerView)
    let updateFavourites = update(favouritesDataSource)(tableView)
    override func viewDidLoad() {
    super.viewDidLoad()
    login("siejkowski","mobilization") { details in
    (details |> updateHeader |> fetchFavourites) <| updateFavourites
    }
    }
    !

    View full-size slide

  27. pure functions
    Swift functions

    View full-size slide

  28. struct FunctionUsingStruct {
    let func: String -> Bool
    init(_ injectedFunc: String -> Bool) {
    // funkcje można wstrzykiwać
    func = injectedFunc
    ...
    }
    }
    !

    View full-size slide

  29. class DIFactory {
    func realFunc(string: String) -> Bool { ... }
    // w produkcyjnym kodzie wstrzykujemy prawdziwą funkcję
    func functionUsingStruct() -> FunctionUsingStruct {
    return FunctionUsingStruct(realFunc)
    }
    class TestCase {
    func testFunc(string: String) -> Bool { return true }
    // w testowym kodzie używamy mockowej funkcji
    let testStruct = FunctionUsingStruct(testFunc)
    !

    View full-size slide

  30. func login(username: String,
    _ password: String,
    _ callback: (UserDetails) -> ())
    func fullLogin(loginManager: LoginManager)
    (_ username: String,
    _ password: String,
    _ callback(UserDetails) -> ()) -> () {
    loginManager.login(username, password, callback)
    }
    let login = fullLogin(actualLoginManager)
    let mockLogin = fullLogin(mockLoginManager)

    View full-size slide

  31. funkcje ❤ protokoły

    View full-size slide

  32. extension MyViewController : SessionAware {
    func login(username: String,
    _ password: String,
    _ callback: (UserDetails) -> ()) {
    // tutaj przekazany jest domyślnie self
    }
    }
    func login(username: String,
    _ password: String,
    _ callback: (UserDetails) -> ()) {
    // tutaj przekazane jest to co w sygnaturze
    }

    View full-size slide

  33. func root(double: Double) -> Double? { ... }
    func root(float: Float) -> Float? { ... }
    func root(int: Int) -> Int? { ... }
    protocol Rootable { func root() -> Self? }
    extension Double : Rootable { ... }
    extension Float : Rootable { ... }
    extension Int : Rootable { ... }
    func useRootable(rootable: Rootable) {
    rootable.root()
    }

    View full-size slide

  34. *-able
    protocol JSONDecodable {
    static func decode(json: JSON) -> Self
    }
    protocol Validatable {
    func validate(validator: Validator) -> Bool
    }
    protocol Hashable : Equatable {
    public var hashValue: Int { get }
    }

    View full-size slide

  35. Co jest problemem?
    nil
    ErrorType
    asynchroniczność
    logowanie
    sekwencja
    callback
    cokolwiek chcesz !

    View full-size slide

  36. func canCauseProblem(input: Int) -> ProblemHiding
    func possibleProblem(input: String) -> ProblemHiding
    func yetAnotherProblem(input: Double) -> ProblemHiding
    let input = 42
    ProblemHiding(input) // udajemy że wszystko gra
    .execute(canCauseProblem) // jakby nic się nie stało
    .execute(possibleProblem) // bez nerwów, bez ifów
    .execute(yetAnotherProblem) // jak kwiat lotosu
    .obtainValue() // sprawdzam!

    View full-size slide

  37. protocol Monad {
    typealias A
    typealias B
    typealias FB
    func bind(f: A -> FB) -> FB
    }
    !

    View full-size slide

  38. extension Optional : Monad {
    typealias A = Wrapped
    typealias B = Any // nil jest problemem
    typealias FB = B?
    func bind(f: A -> B?) -> B? {
    return self.flatMap(f)
    }
    }
    extension Array : Monad {
    typealias A = Element
    typealias B = Any // wiele wartości to problem
    typealias FB = Array
    func bind(f: A -> [B]) -> [B] {
    return self.flatMap(f)
    }
    }

    View full-size slide

  39. enum Result { // możliwy ErrorType to problem
    case Success(Value)
    case Failure(ErrorType)
    }
    extension Result : Monad {
    typealias A = Value
    typealias B = Any
    typealias FB = Result
    func bind(f: A -> Result) -> Result {
    switch self {
    case .Success(let value):
    return f(value)
    case .Failure(let error):
    return .Failure(error)
    }
    }
    }

    View full-size slide

  40. https://github.com/typelift
    Swiftx
    Swiftz
    https://github.com/thoughtbot
    Runes
    Argo
    https://github.com/robrix
    Prelude

    View full-size slide

  41. agregacja

    protokoły

    funkcje

    View full-size slide

  42. agregacja

    protokoły

    funkcje

    dziedziczenie

    View full-size slide

  43. Dziękuję!
    @_siejkowski
    !

    View full-size slide