74
Always give one hundred percent Jakub Turek 26th June, 2018

Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Always give one hundred percent

Jakub Turek26th June, 2018

Page 2: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

About me

Jakub Turek

https://jakubturek.com @KubaTurek turekj EL Passion

1

Page 3: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Motivation

Retrospective of a recent project:

▶ Team of 3 focused on unit testing & TDD.▶ 9 months of work.▶ 186 865 lines of Swift code.▶ 4 960 files.▶ 6 internal frameworks.▶ 6 768 test cases.

2

Page 4: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Agenda

1. Introduction to unit-testing & TDD.2. Engineering for testability.3. Common obstacles:

▶ view controllers,▶ views,▶ global functions.

4. Refactoring test code.5. Test code generation.6. Metrics.

3

Page 5: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Introduction to testing

Page 6: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Unit testing

A unit test is an automated piece of code that invokesa unit of work in the system and then checks a singleassumption about the behavior of that unit of work.

— Roy Osherove, The art of unit testing

4

Page 7: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Good unit test

Traits of a good unit test:

▶ automated,▶ fast,▶ tests a single logical concept in the system,▶ trustworthy,▶ readable,▶ maintanable.

5

Page 8: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

TDD

TDD is a programming technique which combines wri-ting a test before writing just enough production codeto fulfill that test and refactoring.

— Kent Beck, Test-Driven Development by example

6

Page 9: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Typical response to TDD

We don’t do TDD because:

1. We are not allowed to.2. We don’t have enough time.3. It didn’t work for us*.

* Might indicate feedback loop problems.

7

Page 10: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

TDD workflow

1. Red - write a failing test.2. Green - write minimal amount of code to pass.3. Refactor.

8

Page 11: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

3 laws of TDD

1. You can’t write any production code until you writea failing unit test.

2. You can’t write more of a unit test than is sufficient to fail.Not compiling is failing.

3. You can’t write more production code than is sufficient topass currently failing unit test.

9

Page 12: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Demo

10

Page 13: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Engineering for testability

Page 14: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Pure functions

How to write testable code?

1. Pass values to functions.2. Return values from functions.

— @mdiep, Matt Diephouse, Twitter

11

Page 15: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Boundaries

Boundaries by Gary Bernhardt

This talk is about using simple values (as opposed to complexobjects) not just for holding data, but also as the boundariesbetween components and subsystems.

https://destroyallsoftware.com/talks/boundaries

12

Page 16: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Imperative shell, functional core

Imperative shell:

▶ real worlddependencies,

▶ side-effects,▶ stateful operations.

Functional core:

▶ decisions,▶ purely functional

transformations.

13

Page 17: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Demo

14

Page 18: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Resources

Controlling Complexity in Swifthttps://academy.realm.io/posts/andy-matuschak-controlling-complexity/

Enemy of the Statehttps://speakerdeck.com/jspahrsummers/enemy-of-the-state

Imperative Shell, Functional Core Gisthttps://tinyurl.com/y9cxblm8

Imperative Shell, Functional Core on iOShttps://jakubturek.com/imperative-shell-functional-core/

15

Page 19: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Dealing with massive controllers

Page 20: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Metrics (1/5)

Examine the largest files:

find Sources -name '*.swift' \| xargs wc -l \| sort -r

16

Page 21: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Metrics (2/5)

Output:

??? AllAssemblies.generated.swift??? ContentController.swift??? PickerController.swift??? MapController.swift??? ClassCell.swift??? CalendarController.swift??? ContactController.swift??? AuthorizeController.swift

17

Page 22: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Metrics (3/5)

Actual line counts:

148 AllAssemblies.generated.swift140 ContentController.swift139 PickerController.swift138 MapController.swift138 ClassCell.swift138 CalendarController.swift137 ContactController.swift135 AuthorizeController.swift

18

Page 23: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Metrics (4/5)

Examine the average controller size:

cloc Modules \--include-lang=Swift \--match-f='.+Controller\.swift'

19

Page 24: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Metrics (5/5)

▶ Controllers in total: 164.▶ Screens in total: 38.▶ Average 4.32 controller per screen.▶ Lines in total: 12 327.▶ Average 75.16 lines of code per controller.

20

Page 25: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

More View Controllers

Page 26: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

How to decouple controllers?

▶ Never Subclass as a last resort.▶ Use child controllers for composition.▶ Use protocols for controllers’ boundaries.▶ Refer to controllers using compound types

(UIViewController & ControllerProtocol).

21

Page 27: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Adding a child controller

func embed(child: UIViewController,inside view: UIView) {

addChildViewController(child)view.addSubview(child.view)

child.snp.makeConstraints {$0.edges.equalToSuperview()

}

child.didMove(toParentViewController: self)}

22

Page 28: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Decoupling controllers (1/2)

protocol ChildControllerType: class {var productSelected: ((String) -> Void)? { get set }

}

class ChildController: UIViewController,ChildControllerType {

init(/* dependencies */) { /* ... */ }

var productSelected: ((String) -> Void)?

override func viewDidLoad() {/* implementation */

}}

23

Page 29: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Decoupling controllers (2/2)

typealias ChildControlling =UIViewController & ChildControllerType

class ParentController: UIViewController {init(factory: () -> ChildControlling) {self.factory = factory

}

override func viewDidLoad() {super.viewDidLoad()embed(child: child, inside: view)

}

private lazy var child = factory()private let factory: () -> ChildControlling

} 24

Page 30: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Stubbing a child controller (1/2)

class ChildControllerStub: UIViewController,ChildControllerType {

var productSelected: ((String) -> Void)?}

25

Page 31: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Stubbing a child controller (2/2)

class ParentControllerTests: XCTestCase {var childStub: ChildControllerStub!var sut: ParentController!

override func setUp() {super.setUp()childStub = ChildControllerStub()sut = ParentController(factory: { childStub })

}

func testThatSelectedProductNameIsDisplayed() {childStub.productSelected?("Water")XCTAssertEqual(sut.view.label.text, "Water")

}}

26

Page 32: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Child view controller examples

▶ Buttons:▶ side-effects,▶ error handling,▶ interaction toggling.

▶ Forms:▶ user input validation,▶ complex presentation,▶ error handling.

▶ API data coordination. Immutable children:▶ data,▶ empty state,▶ error.

27

Page 33: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Views

Page 34: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

iOSSnapshotTestCase

iOSSnapshotTestCase

iOSSnapshotTestCase takes preconfigured view andrenders its snapshot. It compares snapshot to a “referenceimage” stored in repository and fails if the two images don’tmatch.

https://github.com/uber/ios-snapshot-test-case

28

Page 35: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

iOSSnapshotTestCase diff

Expected Actual

Diff

29

Page 36: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Instant feedback for views

Page 37: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Red phase (1/3)

Note down the size from design (≈ 300 × 40).

30

Page 38: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Red phase (2/3)

override func setUp() {super.setUp()recordMode = true

sut = GradientLabelView(text: "Academia Gorila")sut.frame = CGRect(width: 300, height: 40)

}

func testLabelMatchesSnapshot() {FBSnapshotVerifyView(sut)

}

class GradientLabelView { // ... implementation }

31

Page 39: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Red phase (3/3)

Build the view in iterations:

1. Change the code.2. Run the tests.3. Compare a reference image to the design:

▶ Repeat the cycle if needed.

32

Page 40: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Green phase

override func setUp() {super.setUp()recordMode = false

sut = GradientLabelView(text: "Academia Gorila")sut.frame = CGRect(width: 300, height: 40)

}

func testLabelMatchesSnapshot() {FBSnapshotVerifyView(sut)

}

33

Page 41: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Refactor phase

▶ Move the view to a production target.▶ Refactor the view.

34

Page 42: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Testing global methods

Page 43: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Global method example (1/2)

extension UIImage {static func with(color: UIColor) -> UIImage? {let origin = CGPoint(x: 0, y: 0)let size = CGSize(width: 1, height: 1)let rect = CGRect(origin: origin, size: size)

return CGContext.drawImage(of: size) { ctx inctx.setFillColor(color.cgColor)ctx.fill(rect)

}}

}

35

Page 44: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Global method example (2/2)

static func drawImage(of size: CGSize,using drawer: (CGContext) -> Void)-> UIImage? {

UIGraphicsBeginImage...(size, false, 0.0)

defer { UIGraphicsEndImageContext() }

guard let ctx = UIGraphicsGetCurrentContext() else {return nil

}

drawer(ctx)

return UIGraphicsGetImage...()}

36

Page 45: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Swift namespace resolution (1/2)

Shipping your own controller type:

class UIViewController {func theTimeHasComeToLoadAView() {myOwnPersonalView = SomeView()

}}

let controller = UIViewController()controller.theTimeHasComeToLoadAView() // works

37

Page 46: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Swift namespace resolution (2/2)

Shipping your own controller library:

# Podfilepod 'MyOwnController', '~> 0.1'

// SourceFile.swiftimport MyOwnControllerimport UIKit

UIViewController() // compilation error

38

Page 47: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Testing global methods (1/2)

import UIKit

func UIGraphicsGetImageFromCurrentImageContext()-> UIImage? {

return imageFromContext()}

var imageFromContext: () -> UIImage? =UIKit.UIGraphicsGetImageFromCurrentImageContext

39

Page 48: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Testing global methods (2/2)

override func setUp() {imageFromContext = { UIImage.catMeme }

}

override func tearDown() {imageFromContext = UIKit.UIGraphicsGetImage...

}

func testThatDrawImageReturnsImageFromContext() {let image = CGContext.drawImage(of: .zero) { _ in }

XCTAssertEqual(UIImagePNGRepresentation(image),UIImagePNGRepresentation(imageFromContext())

)} 40

Page 49: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Refactoring test code

Page 50: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Testing models (1/2)

struct User {let id: Intlet born: Date

}

41

Page 51: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Testing models (2/2)

func testThatUsersBornInJanuaryGetAPrize() {let u1 = User(id: 3,born: Date(timeIntervalSince1970: 631886400)

)let u2 = User(id: 6,born: Date(timeIntervalSince1970: 634233600)

)let u3 = User(id: 8,born: Date(timeIntervalSince1970: 727466400)

)

XCTAssertEqual(sut.winners([u1, u2, u3]), [3, 8])} 42

Page 52: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Test data

extension User {static var bornJanuary1990: User {return User(id: 3, born: "1990-01-09 12:00".date())

}

static var bornFebruary1990: User {return User(id: 6, born: "1990-02-05 16:00".date())

}

static var bornJanuary1993: User {return User(id: 8, born: "1993-01-19 18:00".date())

}}

43

Page 53: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Refactored tests

func testThatUsersBornInJanuaryGetAPrize() {let winnerIDs = sut.winners([.bornJanuary1990,.bornFebruary1990,.bornJanuary1993

])

XCTAssertEqual(winnerIDs, [3, 8])}

44

Page 54: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Test code generation

Page 55: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Sourcery

Sourcery

Sourcery is a code generator for Swift language, built on top ofApple’s own SourceKit. It extends the language abstractions toallow you to generate boilerplate code automatically.

https://github.com/krzysztofzablocki/Sourcery

45

Page 56: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Problem: required initializers

0% code coverage when not using inteface builder

required init?(coder aDecoder: NSCoder) {return nil

}

46

Page 57: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

AllViews.stencil

extension UIView {

static var allInitializers: [(NSCoder) -> UIView?] {return [{% for view in types.classes where view.based.UIView %}{% set spacer %}{% if not forloop.last %},{% endif %}{% endset %}{% for initializer in view.initializers %}{% if initializer.selectorName == "init(coder:)" %}{{ view.name }}.init(coder:){{ spacer }}{% endif %}{% endfor %}{% endfor %}]

}

}

47

Page 58: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

AllViews.generated.swift

extension UIView {

static var allInitializers: [(NSCoder) -> UIView?] {return [

ActionBarView.init(coder:),AuthorizeErrorView.init(coder:),BlurView.init(coder:),BorderedButtonView.init(coder:),FilterView.init(coder:),HeaderView.init(coder:),/* ... */

]}

}

48

Page 59: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

AllViewsTests.swift

func testThatAllViewsAreNonCodable() {UIView.allInitializers.forEach { initializer inXCTAssertNil(initializer(NSCoder()))

}}

49

Page 60: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Other usages

▶ Automatic synthesizing of Equatable conformance inextensions.

▶ Mock object generation.▶ Complex assertions:

▶ There is a factory class for every Route.▶ There is an integration test for every request.

50

Page 61: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Metrics

Page 62: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Metrics

Measured on every pull request:

▶ Project size:▶ lines of code,▶ files count,▶ average file size.

▶ Static analysis:▶ SwiftLint: consistent coding style,▶ jscpd: automatic copy-paste detection.

▶ Code coverage.

51

Page 63: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Metrics - visualization

Danger

Danger runs during your CI process, and gives teams thechance to automate common code review chores.

http://danger.systems/js/swift.html

52

Page 64: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Danger

53

Page 65: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Automatic copy-paste detection

JSCPD

jscpd is a tool for detect copy/paste ”design pattern” inprogramming source code.

https://github.com/kucherenko/jscpd

54

Page 66: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

JSCPD + Danger = (1/3)

55

Page 67: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

JSCPD + Danger = (2/3)

cpd.yaml:

languages:- swift

files:- "Sources/**"

exclude:- "**/*.generated.swift"

reporter: jsonoutput: jscpd_report.json

56

Page 68: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

JSCPD + Danger = (3/3)

Dangerfile:

def find_duplicates`jscpd`

rep = JSON.parse(File.read('jscpd_report.json'))clones = rep["statistics"]["clones"]

if clones > 0warn("JSCPD found #{clones} clone(s)")

endend

Full version: https://tinyurl.com/yc23t4mb

57

Page 69: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Code coverage

Code coverage is a percentage of code which is covered byautomated tests.

Test coverage is a useful tool for finding untested partsof a codebase. Test coverage is of little use as a numericstatement of how good your tests are.

— Martin Fowler, TestCoverage

58

Page 70: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

danger-xcov (1/2)

danger-xcov

danger-xcov is the Danger plugin of xcov, a friendlyvisualizer for Xcode’s code coverage files.

https://github.com/nakiostudio/danger-xcov

59

Page 71: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

danger-xcov (2/2)

60

Page 72: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Thank you!

61

Page 73: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Additional resources

Jakub TurekAlways give one hundred percenthttps://jakubturek.com/talks/

Jon ReidQuality Coding - Bloghttps://qualitycoding.org/blog/

Kasper B. GraversenGist: functional core, imperative shellhttps://tinyurl.com/y9cxblm8

62

Page 74: Always give one hundred percent - Jakub Turek · Always give one hundred percent Jakub Turek 26th June, 2018. About me Jakub Turek @KubaTurek turekj EL Passion 1. Motivation Retrospective

Feedback

@elpassion

63