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"

43d2bef703ec7165166f161f137ac54f?s=128

Krzysztof Siejkowski

October 17, 2015
Tweet

Transcript

  1. 2.
  2. 6.
  3. 7.
  4. 10.

    struct SomeStruct {} enum SomeEnum {} typealias SomeFunction = (Int

    -> String) class C : SomeFunction ❗ Inheritance from non-protocol, non-class type 'SomeFunction'
  5. 20.

    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
  6. 21.

    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 }
  7. 24.

    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)
  8. 25.

    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) } }
  9. 26.

    infix operator |> { associativity left } infix operator <|

    { associativity right } public func |> <A, B>(a : A, f : A -> B) -> B { return f(a) } public func <| <A, B>(f : A -> B, a : A) -> B { return f(a) }
  10. 30.

    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 } } !
  11. 32.

    struct FunctionUsingStruct { let func: String -> Bool init(_ injectedFunc:

    String -> Bool) { // funkcje można wstrzykiwać func = injectedFunc ... } } !
  12. 33.

    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) !
  13. 34.

    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)
  14. 36.

    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 }
  15. 37.

    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() }
  16. 38.

    *-able protocol JSONDecodable { static func decode(json: JSON) -> Self

    } protocol Validatable { func validate(validator: Validator) -> Bool } protocol Hashable : Equatable { public var hashValue: Int { get } }
  17. 40.

    func canCauseProblem(input: Int) -> ProblemHiding<String> func possibleProblem(input: String) -> ProblemHiding<Double>

    func yetAnotherProblem(input: Double) -> ProblemHiding<Int> 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!
  18. 42.

    extension Optional : Monad { typealias A = Wrapped typealias

    B = Any // nil jest problemem typealias FB = B? func bind<B>(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<B> func bind<B>(f: A -> [B]) -> [B] { return self.flatMap(f) } }
  19. 43.

    enum Result<Value> { // możliwy ErrorType to problem case Success(Value)

    case Failure(ErrorType) } extension Result : Monad { typealias A = Value typealias B = Any typealias FB = Result<B> func bind<B>(f: A -> Result<B>) -> Result<B> { switch self { case .Success(let value): return f(value) case .Failure(let error): return .Failure(error) } } }