voyages-sncf.com : choix techniques et évolutions de l'application mobile

29

Upload: gwenn-guihal

Post on 16-Apr-2017

343 views

Category:

Engineering


1 download

TRANSCRIPT

Page 1: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile
Page 2: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Filiale privée de la SNCF + de 1100 collaborateurs 35 équipes de développement Paris, Lille, Nantes

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

Voyages-Sncf.com

Page 3: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Sites et applications mobiles Logiciel, middleware, moteur d’itinéraire Digital Factory de la SNCF - sncf.com - application SNCF - TGVPro, IDTGV, - …

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

VSC Technologies

Page 4: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Gwenn Guihal, 32 ans - 2008-2013 : Développeur Flash - depuis 2013: Développeur iOS

@_myrddin_

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

Page 5: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

14M de téléchargements 30% de l’audience 10 millions de visites/mois

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

V.

Page 6: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

6 devs iOS 6 devs android 2 dev back 1 architecte ui/ux 4 product owners

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

V.

Page 7: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

~100 écrans ios8 swift (~35%) iPhone, iPad, Apple watch, widget release tous les 2/3 mois version #32 en production depuis 2009

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

V.

Page 8: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

2009 ? 😱

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

Page 9: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile
Page 10: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile
Page 11: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Grossissement de l’équipe Refonte technique Refonte UI Refontes intégrées dans le delivery TU

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

Sortir du Legacy

Page 12: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

AFNetworking CocoaPods Repository privé Fastlane (intégration continue) Swift CollectionView

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

Quelques étapes

Page 13: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile
Page 14: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile
Page 15: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

CollectionView 😍

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

Page 16: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Layout personnalisé DecorationView Animations iPad Réutilisation des cellules UICollectionViewFlowLayout

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

versus TableView

Page 17: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile
Page 18: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Micro-architecture 😶

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

Page 19: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

UICollectionViewCell (affiche ce que lui done l’adapter)

Adapter (transforme, formate le

model)

Model (contient les données)

Page 20: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

class VSTransactionCardCollectionViewCell: UICollectionViewCell, VSCollectionCellProtocol {

@IBOutlet weak var label: UILabel! func updateWithAdapter(adapter aAdapter: VSCollectionAdapter) -> Void { guard let adapter = aAdapter as? VSTransactionCardAdapter else { fatalError("VSTransactionCardAdapter required") } label.attributedText = adapter.label } }

Cellule

Page 21: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

struct VSTransactionCardAdapter: VSCollectionAdapter {

let label:NSAttributedString init(order:Order) { let creditCardNumber = order.creditCardNumber() let sentence = String(format: trans(message_credit_card), creditCardNumber) label = NSAttributedString(string: sentence, attributes: [ NSFontAttributeName: UIFont.systemFontOfSize(14, weightFont:.Bold), NSForegroundColorAttributeName: UIColor.blackColor() ]) } func labelHeight(forWidth: CGFloat) -> CGFloat { let size = label.boundingRectWithSize(CGSize(width: forWidth, height: CGFloat.max), options: […], context: nil) return ceil(size.height) } }

Adapter

Page 22: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

class VSLabelCollectionViewCell: UICollectionViewCell {

@IBOutlet weak var label: UILabel! override func awakeFromNib() { super.awakeFromNib() // ... } static func computeHeight(forWidth:CGFloat, text:NSAttributedString) -> CGFloat { //... } }

Cellule Legacy

Page 23: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

class VSLabelCollectionViewCell: UICollectionViewCell {

@IBOutlet weak var label: UILabel! override func awakeFromNib() { super.awakeFromNib() // ... } static func computeHeight(forWidth:CGFloat, text:NSAttributedString) -> CGFloat { //... } }

extension VSLabelCollectionViewCell : VSCollectionCellProtocol { func updateWithAdapter(adapter aAdapter: VSCollectionAdapter) -> Void { guard let adapter = aAdapter as? VSCollectionLabelAdapter else { fatalError("VSCollectionLabelAdapter required") } label.attributedText = adapter.label } }

protocol VSCollectionLabelAdapter { var label:NSAttributedString! {get} }

Extension 😅

Page 24: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

cellForItemAtIndexPath…numberOfItemsInSection… shouldSelectItemAtIndexPath… sizeForItemAtIndexPath… insetForSectionAtIndex…

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

Delegate et Datasource

Page 25: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

Adapter (transforme, formate le

model)

CellDescriptor (représente la cellule pour le

delegate et datasource)

SectionDescriptor (contient un tableau de

cellDescriptors)

Page 26: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

class VSCardSectionDescriptor: VSCollectionSectionDescriptor { var cells = [VSCollectionCellDescriptor]() var backgroundColor : UIColor? = nil let backgroundPadding = UIEdgeInsetsZero var isExpanded: Bool = false func sectionInset(collectionView:UICollectionView) -> UIEdgeInsets { return UIEdgeInsets(top: 0, left: 15 + ipadInsetX(), bottom: 10, right: 15 + ipadInsetX()) } }

SectionDescriptor

Page 27: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

struct VSTransactionCardDescriptor: VSCollectionCellDescriptor { let identifier: String = "VSLabelCollectionViewCell" let className: String = "VSLabelCollectionViewCell" var selectable:Bool = false var adapter: VSCollectionAdapter { return _adapter } let _adapter: VSTransactionCardAdapter init(order:Order) { _adapter = VSTransactionCardAdapter(order:order) } func size(collectionView: UICollectionView, sectionDescriptor: VSCollectionSectionDescriptor) -> CGSize { let sectionInset = sectionDescriptor.sectionInset(collectionView) let width:CGFloat = collectionView.bounds.width - sectionInset.left - sectionInset.right return CGSize(width: width, height: max(_adapter.labelHeight(width), 24)) } }

CellDescriptor

Page 28: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

class VSCollectionDataSource: NSObject, UICollectionViewDataSource { var collectionDatas: VSCollectionDatas? func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { return collectionDatas?.sectionsCount() ?? 0 } func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return collectionDatas?.sections[section].cells.count ?? 0 } func collectionView(UICollectionView, cellForItemAtIndexPath NSIndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellDescriptor.identifier, forIndexPath: indexPath) as VSCollectionCellProtocol cell.updateWithAdapter(adapter: cellDescriptor.adapter) return cell }

func collectionView( UICollectionView, layout UICollectionViewLayout, sizeForItemAtIndexPath : NSIndexPath) -> CGSize { if let sectionDescriptor = collectionDatas?.sections[indexPath.section] { let cellDescriptor = sectionDescriptor.cells[indexPath.item] return cellDescriptor.size(collectionView, sectionDescriptor: sectionDescriptor) } return CGSizeZero }

}

UICollectionViewDataSource

Page 29: Voyages-sncf.com : Choix techniques et évolutions de l'application mobile

Gwenn Guihal - @_myrrdin_ - 19 Octobre 2016

Merci,

🤔