Slide 1

Slide 1 text

FRAMEWORK ORIENTED PROGRAMMING Pedro Piñera @pepibumur - IOS DEVELOPER AT SOUNDCLOUD NSBUDAPEST ⌚"#$

Slide 2

Slide 2 text

SZIASZTOK! ! Pedro IOS DEVELOPER AT SOUNDCLOUD @PEPIBUMUR TWITTER/FACEBOOK/YOUTUBE WWW.PPINERA.ES

Slide 3

Slide 3 text

CONTEXT Before 2008 OSX - 1 TARGET !

Slide 4

Slide 4 text

CONTEXT 2008 ! LAUNCHES IPHONE SOFTWARE DEVELOPMENT KIT " (Developers move to iOS. New platform, frameworks,... New exciting area)

Slide 5

Slide 5 text

CONTEXT After 2008 ! - 1 TARGET " ! - 1 TARGET"

Slide 6

Slide 6 text

CONTEXT 2011 COCOAPODS RELEASED Dependency Resolving + Integration + Community !

Slide 7

Slide 7 text

CONTEXT After 2011 ! - 1 TARGET " ! - 1 TARGET " X TARGETS (EXTERNAL) !!

Slide 8

Slide 8 text

CONTEXT 2015 ⌚ "

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

CONTEXT 2015 ! - 1 TARGET ! - 1 TARGET ! - 1 TARGET ⌚ - 1 TARGET

Slide 11

Slide 11 text

HOW TO REUSE CODE? (ACROSS PLATFORMS) Frameworks !

Slide 12

Slide 12 text

SWIFT ❤ DYNAMIC FRAMEWORKS

Slide 13

Slide 13 text

EMBEDDED RESOURCES (IMAGES, FONTS, ...)

Slide 14

Slide 14 text

DYNAMICALLY LINKED (NO DUPLICATED SYMBOLS)

Slide 15

Slide 15 text

SWIFT CODE

Slide 16

Slide 16 text

FRAMEWORK ORIENTED PROGRAMMING Reusable & platform independent code GITHUB

Slide 17

Slide 17 text

BEST PRACTICES PRINCIPLES ADVICES EXAMPLES

Slide 18

Slide 18 text

FRAMEWORKS STACK SoundCloud Approach

Slide 19

Slide 19 text

PRINCIPLES Some theory !

Slide 20

Slide 20 text

1. SINGLE RESPONSIBILITY SOLID INSPIRED

Slide 21

Slide 21 text

1. SINGLE RESPONSIBILITY SOLID INSPIRED

Slide 22

Slide 22 text

1. SINGLE RESPONSIBILITY START FROM A HIGH LEVEL

Slide 23

Slide 23 text

1. SINGLE RESPONSIBILITY SLICE THEM PROGRESSIVELY

Slide 24

Slide 24 text

1. SINGLE RESPONSIBILITY SLICE THEM PROGRESSIVELY

Slide 25

Slide 25 text

2. VERTICAL DEPENDENCIES (OVER HORIZONTAL)

Slide 26

Slide 26 text

3. LOWER IN THE STACK FEWER EXTERNAL DEPENDENCIES

Slide 27

Slide 27 text

4. ONE STEP DEPENDENCIES

Slide 28

Slide 28 text

4. ONE STEP DEPENDENCIES

Slide 29

Slide 29 text

5. INTERNAL BY DEFAULT

Slide 30

Slide 30 text

6. FINAL SOLID INSPIRED (OPEN/CLOSED)

Slide 31

Slide 31 text

6. FINAL SOLID INSPIRED (OPEN/CLOSED)

Slide 32

Slide 32 text

6. FINAL SOLID INSPIRED (OPEN/CLOSED)

Slide 33

Slide 33 text

6. FINAL SOLID INSPIRED (OPEN/CLOSED) final class Person { let name: String } class Alien: Person { // Compiler complains }

Slide 34

Slide 34 text

7. FRAMEWORK MODELS DON'T SHARE FRAMEWORKS' MODELS UPWARDS

Slide 35

Slide 35 text

7. FRAMEWORK MODELS DON'T SHARE FRAMEWORKS' MODELS UPWARDS

Slide 36

Slide 36 text

7. FRAMEWORK MODELS DON'T SHARE FRAMEWORKS' MODELS UPWARDS // Persistence class Author: NSManagedObjectModel { let name: String } class Track: NSManagedObjectModel { let author: Author } // ListenersKit struct StreamTrackEntity { let name: String let authorName: String }

Slide 37

Slide 37 text

7. FRAMEWORK MODELS DON'T SHARE FRAMEWORKS' MODELS UPWARDS struct StreamTrackEntityAdapter { func adapt(track: Track) -> StreamTrackEntity { return StreamTrackEntity(name: track.name, authorName: track.author.name) } }

Slide 38

Slide 38 text

8. PLATFORM ABSTRACTION SOLID INSPIRED (DI)

Slide 39

Slide 39 text

9. PROTOCOL ORIENTED INTERFACES SOLID INSPIRED (DI)

Slide 40

Slide 40 text

9. PROTOCOL ORIENTED INTERFACES SOLID INSPIRED (DI)

Slide 41

Slide 41 text

9. PROTOCOL ORIENTED INTERFACES SOLID INSPIRED (DI)

Slide 42

Slide 42 text

9. PROTOCOL ORIENTED INTERFACES SOLID INSPIRED (DI)

Slide 43

Slide 43 text

9. PROTOCOL ORIENTED INTERFACES SOLID INSPIRED (DI)

Slide 44

Slide 44 text

10. CORE/TESTING (AKA YOUR PROJECT FOUNDATION FRAMEWORKS)

Slide 45

Slide 45 text

10. CORE/TESTING (AKA YOUR PROJECT FOUNDATION FRAMEWORKS) ▸ Extensions ▸ Logging ▸ Analytics ▸ Architectural components (e.g. Reactive)

Slide 46

Slide 46 text

ADVANTAGES

Slide 47

Slide 47 text

MULTIPLATFORM APPS Only working on the UI ⌚"#$

Slide 48

Slide 48 text

MULTIPLATFORM APPS Only working on the UI ⌚"#$

Slide 49

Slide 49 text

EXPERIMENTATION ▸ Prototyping ▸ Playgrounds import MyAppKit requestFactory.request(path: "/myPath/").subscribeNext { response in // yai! }

Slide 50

Slide 50 text

NEW PRODUCTS With similar core needs BECAUSE YOU WANT TO REUSE CODE, RIGHT?

Slide 51

Slide 51 text

NEW PRODUCTS With similar core needs BECAUSE YOU WANT TO REUSE CODE, RIGHT?

Slide 52

Slide 52 text

OPEN SOURCE And benefit from the community BUILD PIECES OF CODE THAT YOU'D BE PROUD OF OPEN SOURCING

Slide 53

Slide 53 text

SPECIALIZED TEAMS From UI lovers to Core Data experts (CLEARLY DEFINED TEAM BOUNDARIES)

Slide 54

Slide 54 text

SPECIALIZED TEAMS From UI lovers to Core Data experts (CLEARLY DEFINED TEAM BOUNDARIES)

Slide 55

Slide 55 text

HOW TO? ! There are multiple options (I'LL SHOW YOU SOME)

Slide 56

Slide 56 text

CocoaPods

Slide 57

Slide 57 text

CocoaPods ▸ ✅ Easy setup (each Framework .podspec) ▸ ✅ Same setup for local/external dependencies ▸ ❌ It sucks if you don't version ▸ ❌ Fully frameworks approach (load time)

Slide 58

Slide 58 text

Manual ▸ ✅ More control over the workspace ▸ ✅ Custom setup (you design it) ▸ ❌ Cumbersome setup (Build Settings) External dependencies can be checked out with Carthage/Git Submodules

Slide 59

Slide 59 text

XCCONFIG AND MAKING YOUR FRAMEWORK MULTIPLATFORM

Slide 60

Slide 60 text

SUPPORTED_PLATFORMS = iphoneos iphonesimulator appletvsimulator appletvos macosx watchsimulator watchos TARGETED_DEVICE_FAMILY[sdk=iphone*] = 1,2 TARGETED_DEVICE_FAMILY[sdk=watch*] = 4 TARGETED_DEVICE_FAMILY[sdk=appletv*] = 3 VALID_ARCHS[sdk=macosx*] = x86_64 LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks LD_RUNPATH_SEARCH_PATHS[sdk=watch*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks LD_RUNPATH_SEARCH_PATHS[sdk=appletv*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks

Slide 61

Slide 61 text

Hybrid

Slide 62

Slide 62 text

Hybrid ▸ ✅ CocoaPods resolves/integrates app dependencies ▸ ✅ Carthage resolves frameworks dependencies ▸ ✅ Custom stack setup

Slide 63

Slide 63 text

OPEN QUESTIONS

Slide 64

Slide 64 text

VERSIONING? GIT REPO PER FRAMEWORK?

Slide 65

Slide 65 text

1. Keep it in the same repository (fast iterations) 2. Move it once it consolidates (sporadic changes) 3. Then version it! (snapshots in time)

Slide 66

Slide 66 text

EXTERNAL DEPENDENCIES? HOW TO FETCH THEM?

Slide 67

Slide 67 text

▸ If CocoaPods for local: Use it also for external ▸ If manual setup: Use Carthage or Git Submodules

Slide 68

Slide 68 text

STATIC OR DYNAMIC? !

Slide 69

Slide 69 text

▸ Objective-C & not shared - Static ▸ Objective-C && shared - Dynamic ▸ Swift - Dynamic

Slide 70

Slide 70 text

HOW MANY DYNAMIC FRAMEWORKS? THE MORE, THE WORSE LOADING TIME WILL ! IMPROVE IT? "

Slide 71

Slide 71 text

▸ No more than 6 - (WWDC2016:406) ▸ Group dependencies in Framework (Manual setup) Testing.framework Quick.{swift,h,m} Nimble.{swift,h,m} OHHTTPStubs.{swift,h,m} Core.framework RxSwift{.swift}

Slide 72

Slide 72 text

DOWNSIDES !

Slide 73

Slide 73 text

LACK OF DOCUMENTATION (TARGETS CONFIGURATION) Tip: Use CocoaPods and copy the configuration

Slide 74

Slide 74 text

STORYBOARDS/XIBS IN FRAMEWORKS Sucks ! TIP: KEEP THEM IN THE APPLICATION TARGET

Slide 75

Slide 75 text

FRAMEWORKS CODE RECOGNITION Sucks even more !

Slide 76

Slide 76 text

SOME EXTERNAL DEPENDENCIES ARE DISTRIBUTED AS PLATFORM BINARIES

Slide 77

Slide 77 text

## XCConfig LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) Fabric/OSX LD_RUNPATH_SEARCH_PATHS[sdk=appletv*] = $(inherited) Fabric/tvOS LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) Fabric/iOS

Slide 78

Slide 78 text

SOME EVEN DON'T PROVIDE BINARIES FOR ALL THE PLATFORMS

Slide 79

Slide 79 text

PROXY THEM USING MACROS

Slide 80

Slide 80 text

MACROS! #if !os(watchOS) import Fabric #end def log(message: String) { #if !os(watchOS) // Log using Fabric #end }

Slide 81

Slide 81 text

APIS MIGHT DIFFER BETWEEN PLATFORMS

Slide 82

Slide 82 text

▸ NSFetchedResultsController not for macOS ▸ NSIndexPath for watchOS has no row/section

Slide 83

Slide 83 text

PROXY THEM ALSO USING MACROS!

Slide 84

Slide 84 text

CONCLUSIONS

Slide 85

Slide 85 text

Very time-saver FOR MULTI-PLATFORM PROJECTS

Slide 86

Slide 86 text

AIMS LESS COUPLED CODE (defined boundaries) !

Slide 87

Slide 87 text

SETUP REQUIRES SOME Xcode Build Settings knowledge (UNLESS YOU USE COCOAPODS) !

Slide 88

Slide 88 text

MINIMIZE DEPENDENCIES 6 DEPENDENCIES (KISS)

Slide 89

Slide 89 text

USE YOUR COMMONSENSE WHEN DESIGNING YOUR STACK

Slide 90

Slide 90 text

USE YOUR COMMONSENSE Don't be a Javascript developer !!!!!!!!!!!

Slide 91

Slide 91 text

AND REMEMBER THE STACK DEPENDS ON YOUR NEEDS

Slide 92

Slide 92 text

IS IT A COMPANY OR A FREELANCE PROJECT?

Slide 93

Slide 93 text

IS IT A COMPANY OR A FREELANCE PROJECT? IS IT A NEW PROJECT?

Slide 94

Slide 94 text

IS IT A COMPANY OR A FREELANCE PROJECT? IS IT A NEW PROJECT? AM I USING ANY DEPENDENCIES TOOL?

Slide 95

Slide 95 text

IS IT A COMPANY OR A FREELANCE PROJECT? IS IT A NEW PROJECT? AM I USING ANY DEPENDENCIES TOOL? HOW MANY PEOPLE IN THE TEAM?

Slide 96

Slide 96 text

REFERENCES ▸ Library Oriented Programming: Justin Spahr-Summers ▸ The Unofficial Guide to xcconfig files ▸ WWDC: Optimizing App Startup Time ▸ Static & Dynamic libraries ▸ pepibumur/framework-oriented-programming

Slide 97

Slide 97 text

CREDITS ! FROM UNSPLASH

Slide 98

Slide 98 text

No content

Slide 99

Slide 99 text

SZIMPLA Network Testing in Swift GITHUB.COM/PEPIBUMUR/SZIMPLA

Slide 100

Slide 100 text

Köszönöm ! QUESTIONS? SLIDES (SPEAKERDECK) - HTTP://BIT.LY/29EKOCN pepibumur - [email protected]