+ All Categories
Home > Technology > Single Page Applications with CoffeeScript [Polish]

Single Page Applications with CoffeeScript [Polish]

Date post: 29-Jan-2018
Category:
Upload: andrzej-krzywda
View: 1,712 times
Download: 0 times
Share this document with a friend
110
Single Page Applications Andrzej Krzywda Use cases with CoffeeScript, DCI, AOP, TDD
Transcript
Page 1: Single Page Applications with CoffeeScript [Polish]

Single Page Applications

Andrzej Krzywda

Use cases with CoffeeScript, DCI, AOP, TDD

Page 2: Single Page Applications with CoffeeScript [Polish]

Kto lubi pisać w JavaScript?

Page 3: Single Page Applications with CoffeeScript [Polish]

Agenda

• Frontend - Zmiana sposobu myślenia

• Single Page Application

• Frontend - architektura

Page 4: Single Page Applications with CoffeeScript [Polish]

Zmiana sposobu myślenia

Page 5: Single Page Applications with CoffeeScript [Polish]

Dumny programista backendów

Page 6: Single Page Applications with CoffeeScript [Polish]

“JavaScript? My zajmujemy się

poważnymi projektami”

(2007 - 2008)

Page 7: Single Page Applications with CoffeeScript [Polish]

Rails consulting since 2007

Page 8: Single Page Applications with CoffeeScript [Polish]

“OK, zrobimy autocompletion”

Page 9: Single Page Applications with CoffeeScript [Polish]

“Znajdźmy jakiś plugin railsowy, który to

generuje i nie patrzmy do środka”

Page 10: Single Page Applications with CoffeeScript [Polish]

“Czy ceny mogą się zmieniać bez przeładowania?”

Page 11: Single Page Applications with CoffeeScript [Polish]

“Renderujmy JavaScript po stronie serwera”

Page 12: Single Page Applications with CoffeeScript [Polish]

“Pokazywanie słówek bez przeładowania”

Page 13: Single Page Applications with CoffeeScript [Polish]

Backendy - RubyFrontendy - Coffee

Page 14: Single Page Applications with CoffeeScript [Polish]

Social games for brands

(gierki i konkursy na FB i strony firmowe)

Page 15: Single Page Applications with CoffeeScript [Polish]

“Gra w kółko i krzyżyk, potem wybór

nagrody”

Page 16: Single Page Applications with CoffeeScript [Polish]

Hybryda

Page 17: Single Page Applications with CoffeeScript [Polish]

Pierwsza wersja naszej platformy tak działała.

Page 18: Single Page Applications with CoffeeScript [Polish]

Platforma GameBoxed==

jeden backend, wiele frontendów

market

Page 19: Single Page Applications with CoffeeScript [Polish]

Gdzie renderujemy html?

Page 20: Single Page Applications with CoffeeScript [Polish]

Cały html na frontendzie, serwer tylko zwraca JSON.

Page 21: Single Page Applications with CoffeeScript [Polish]

HTML na frontendzie nie różni się od HTML

na backendzie

Page 22: Single Page Applications with CoffeeScript [Polish]

<p>W tej sesji gry niesamowite umiejętności strzeleckie pozwolily Ci osiągnąć nowy rekord:<br> <b>{{playerMaxScore}} punktów.</b></p>

<a class="button ok_button">DALEJ</a>

handlebar

Page 23: Single Page Applications with CoffeeScript [Polish]

Rewolucja

Page 24: Single Page Applications with CoffeeScript [Polish]

Frontend to osobna aplikacja

Page 25: Single Page Applications with CoffeeScript [Polish]

Market 2.0

Page 26: Single Page Applications with CoffeeScript [Polish]

Pusher

web sockets

Page 27: Single Page Applications with CoffeeScript [Polish]

Pusher

Page 28: Single Page Applications with CoffeeScript [Polish]

Zmiana sposobu myślenia

• Faza 1: No JavaScript

• Faza 2: JQuery explosion

• Faza 3: Page/Widget object

• Faza 4: Single Page Application

W której fazie jest Twój projekt?

Page 29: Single Page Applications with CoffeeScript [Polish]

Single Page Application

Gmail, Twitter, Facebook, Trello

Page 30: Single Page Applications with CoffeeScript [Polish]
Page 31: Single Page Applications with CoffeeScript [Polish]

CoffeeScriptbetter JS

Class oriented language

Page 32: Single Page Applications with CoffeeScript [Polish]

Same zalety

Page 33: Single Page Applications with CoffeeScript [Polish]

JS == assembler

Page 34: Single Page Applications with CoffeeScript [Polish]

Coffee > Ruby

Page 35: Single Page Applications with CoffeeScript [Polish]

underscore.js

Page 36: Single Page Applications with CoffeeScript [Polish]

GameBoxed używa tylko Coffee do

frontend’ów

Page 37: Single Page Applications with CoffeeScript [Polish]

Polecamy!

Page 38: Single Page Applications with CoffeeScript [Polish]

Single Page Application

Architektura

Page 39: Single Page Applications with CoffeeScript [Polish]

Trygve

MVC, DCI

Page 40: Single Page Applications with CoffeeScript [Polish]

Zapomnijmy o MVC z backendu!

Page 41: Single Page Applications with CoffeeScript [Polish]

Nie ma MVC na backendzie

Page 42: Single Page Applications with CoffeeScript [Polish]

Nie ma View na backendzie

Page 43: Single Page Applications with CoffeeScript [Polish]

Prawdziwe MVC(w uproszczeniu - zmiana w modelu

powoduje automatyczną zmianę w GUI)

(Rails, Struts, Spring - nie są MVC!)

Page 44: Single Page Applications with CoffeeScript [Polish]

GUI - model

Page 45: Single Page Applications with CoffeeScript [Polish]

Modele• Game

• Player

• GameSession

• Round

• Prize

• Friend (Invitation)

• Life (LifeRequest...)

• Team

Page 46: Single Page Applications with CoffeeScript [Polish]

Views

• PrizeComponent

• FriendsComponent

• GameArea

• Popups

Page 47: Single Page Applications with CoffeeScript [Polish]

Pierwsze podejście

Page 48: Single Page Applications with CoffeeScript [Polish]

Popupy

• Wyświetl popup z zespołem gracza

• Po naciśnięciu OK, wyświetl popup z nagrodami

Page 49: Single Page Applications with CoffeeScript [Polish]

Callbacks

Page 50: Single Page Applications with CoffeeScript [Polish]

triggerActionsAfterMove: (move, callback) => @getBonusWhenStartCrossed(move) @getBonusWhenLandedOnCellWithFriends(@board.currentCell()) @pickCardAndNotifyIfAny(@board.currentCell(), callback)

Page 51: Single Page Applications with CoffeeScript [Polish]

pickCardAndNotifyIfAny: (cell, callback) => console.debug "pickCardAndNotifyIfAny #{cell.position}" card = @drawCard(cell) if not card console.debug "no card picked" callback?() return console.debug "card found: #{card.identifier}" card.onPicked(@) if card.onPicked? @eventBroker.trigger("player:picked_card:#{card.identifier}", card, callback) @eventBroker.trigger("player:picked_card", card)

Page 52: Single Page Applications with CoffeeScript [Polish]

class engine.monopoly.controllers.CardItemBargainContoller constructor: (@services, @game) -> @helper = new CardHelperForUsecases(@services)

setup: => @services.eventBroker.bind('player:picked_card:CardItemBargain', @execute)

execute: (card, callback) => @popup = @helper.showCardGenericPopupAndBindOnOK( (=> @applyFormDataToBargain(card, callback)), null) @popup.bind("popup:opened", => @popup.find('input').focus())

applyFormDataToBargain: (card, callback) => offer = @popup.find('input').val() new CardItemBargain(@services, @game).execute(card, offer, callback)

Page 53: Single Page Applications with CoffeeScript [Polish]

Eventy

Page 54: Single Page Applications with CoffeeScript [Polish]

class engine.shooter.components.StageResultWon

constructor: (@eventBroker) -> _.extend(@, Backbone.Events) super() @templateId = "stage_result_won"

addMeToScreen: (root, me) => $("#gameArea").append(me)

configureElement: (me) => me.find('.okButton').mousedown (event) => @hide() @eventBroker.trigger('stage:result:shown')

Page 55: Single Page Applications with CoffeeScript [Polish]

class engine.shooter.models.Game

constructor: (@serverSide, @eventBroker) -> super(@eventBroker) @levels = [] @guns = []

registerEvents: (eventBroker) => eventBroker.bind('game:start:requested', @start)

eventBroker.bind("player:clicked:inside-target", @playerTriggeredShotInsideTarget) eventBroker.bind("player:clicked:magazine:reload", @playerWantsToReload)

eventBroker.bind("stage:start:clicked", @startStageClicked) eventBroker.bind('countdown:stage:finish', @finishCurrentStage)

eventBroker.bind("stage:result:shown", @loadNextStageOrFinishGame)

Page 56: Single Page Applications with CoffeeScript [Polish]

Wymagana duża dyscyplina

Page 57: Single Page Applications with CoffeeScript [Polish]

Gdzie jest główne flow?

Page 58: Single Page Applications with CoffeeScript [Polish]

Use casesUsecaseController

DCI

Page 59: Single Page Applications with CoffeeScript [Polish]

Game Designer

Piotrek

Page 60: Single Page Applications with CoffeeScript [Polish]

Tomek - programista

(praca zdalna w praktyce)

Page 61: Single Page Applications with CoffeeScript [Polish]

class engine.invite_and_win.GameUseCase constructor: (@game, @player) -> ObjectHelper.addRole(@player, engine.shared.models.PlayerWithFriends)

@facebookHQ = new engine.invite_and_win.FacebookHQ()

tryToEnterGameArea: () => if @amIEnteringGameFirstTime() if @amICommingFromInvitation() @tellPlayerHeIsPartOfTeam(@facebookHQ.friendsInviting)

@teachPlayerHowToPlay()

else #n-th time... if @amICommingFromInvitation() @tellPlayerHeIsPartOfTeam(@facebookHQ.friendsInviting)

if not @playerLikesFanpage() @askPlayerToLikeFanpage()

if @haveNotYetPickedFavPizzaCountry() @askPlayerToDeclareHisFavCountry()

Page 62: Single Page Applications with CoffeeScript [Polish]

Use case używa dziedzinę

Page 63: Single Page Applications with CoffeeScript [Polish]

Ani use case, ani dziedzina, nie wiedzą

nic o GUI

Page 64: Single Page Applications with CoffeeScript [Polish]

Ani use case, ani dziedzina, nie wiedzą

nic o persistence

Page 65: Single Page Applications with CoffeeScript [Polish]

Use case’y mogą działać z innym GUI i innym

persistence

Page 66: Single Page Applications with CoffeeScript [Polish]

Gdzie jest DCI?

Page 67: Single Page Applications with CoffeeScript [Polish]

Data Context Interaction

Trygve

Page 68: Single Page Applications with CoffeeScript [Polish]

Dane pozostają w obiektach

Data

Page 69: Single Page Applications with CoffeeScript [Polish]

Obiekty są dosyć “cienkie”

Page 70: Single Page Applications with CoffeeScript [Polish]

class engine.shared.models.Player constructor: () -> @rank = null @maxScore = 0

Page 71: Single Page Applications with CoffeeScript [Polish]

Use case to zachowanieContext

Page 72: Single Page Applications with CoffeeScript [Polish]

Obiekty mają wstrzykiwane role

Interaction

Page 73: Single Page Applications with CoffeeScript [Polish]

Role są dodawane runtime!

Page 74: Single Page Applications with CoffeeScript [Polish]

class engine.invite_and_win.GameUseCase constructor: (@game, @player) -> ObjectHelper.addRole(@player, engine.shared.models.PlayerWithFriends)

tryToEnterGameArea: () => if @amIEnteringGameFirstTime() if @amICommingFromInvitation() @tellPlayerHeIsPartOfTeam(@facebookHQ.friendsInviting)

@teachPlayerHowToPlay()

else #n-th time... if @amICommingFromInvitation() @tellPlayerHeIsPartOfTeam(@facebookHQ.friendsInviting)

if not @playerLikesFanpage() @askPlayerToLikeFanpage()

if @haveNotYetPickedFavPizzaCountry() @askPlayerToDeclareHisFavCountry()

rola

Page 75: Single Page Applications with CoffeeScript [Polish]

OOP != COP

Page 76: Single Page Applications with CoffeeScript [Polish]

class engine.shared.models.PlayerWithFriends extends Mixin setup: => @friends = [] @invitedFriends = [] @acceptedFriends = []

setInvitedFriends: (facebookUids) => for facebookUid in facebookUids friend = new Friend({facebookUid: facebookUid}) @invitedFriends.push(friend)

setFriends: (friends) => @friends = friends

addFriend: (friend) => existing = @getFriendByFacebookUid(friend?.facebookUid) if not existing? @friends.push(friend)

Page 77: Single Page Applications with CoffeeScript [Polish]

class engine.invite_and_win.GameGuiConfiguration constructor: (@gameUseCase, @game, @gui, @services, @sharedComponents) -> execute: () => Around(@gameUseCase, 'tryToEnterGameArea', @checkFbInvitation) After (@gameUseCase, 'tryToEnterGameArea', @showTeamArea) After (@gameUseCase, 'tryToEnterGameArea', @showButtonInviteOrPostPicture) Around(@gameUseCase, 'tellPlayerHeIsPartOfTeam', @showTeamPopup) Around(@gameUseCase, 'askPlayerToLikeFanpage', @showLikePopup) Around(@gameUseCase, 'teachPlayerHowToPlay', @showTutorialPopup) Around(@gameUseCase, 'playerWantsToKnowWinnersWithPrize', @showWinnersPopup) Around(@gameUseCase, 'playerWantsToKnowPrizes', @showPrizesPopup) Around(@gameUseCase, 'askPlayerToDeclareHisFavCountry', @showDeclareCountryPopup) Around(@gameUseCase, 'iAcceptMyFriendInvitationToATeam', @onIAcceptMyFriendInvitationToATeam)

Page 78: Single Page Applications with CoffeeScript [Polish]

Around(@gameUseCase, 'tellPlayerHeIsPartOfTeam', @showTeamPopup)

Page 79: Single Page Applications with CoffeeScript [Polish]

showTeamPopup: (proceed, friendsInviting) => data = {inviting_friends: friendsInviting} popup = @popupsComponent.showPopup('team_popup', data) popup.bind('popup:closed', => proceed(friendsInviting))

Page 80: Single Page Applications with CoffeeScript [Polish]

Persistence

Page 81: Single Page Applications with CoffeeScript [Polish]

ServerSide

Page 82: Single Page Applications with CoffeeScript [Polish]

class engine.shared.server.ServerSide constructor: (@gameBasicDetails) -> @gameEngineUrl = "/engine/games/#{@gameBasicDetails.id}" @gameUrl = "/games/#{@gameBasicDetails.id}" @errors = []

gameDetailsLoaded: (gameDetails, callback) => callback(gameDetails)

fetchGameDetails: (callback, errback) => $.ajax( type: "GET" url: "#{@gameEngineUrl}.json" success: (gameDetails) => @gameDetailsLoaded(gameDetails, callback) error: errback )

Page 83: Single Page Applications with CoffeeScript [Polish]

My ładujemy dane na starcie

Page 84: Single Page Applications with CoffeeScript [Polish]

Można ładować w trakcie

Page 85: Single Page Applications with CoffeeScript [Polish]

Testowanie

Page 86: Single Page Applications with CoffeeScript [Polish]
Page 87: Single Page Applications with CoffeeScript [Polish]

scenario "player enters and has no friends", -> @player.enterGame(@playerWithNoFriends) @player.shouldSeeMainAreaWithInviteButton() @player.shouldSeeRemainingFriendsToCompleteTeam(4)

scenario "player enters and has collected part team", -> @player.enterGame(@playerWith3AcceptedFriends) @player.shouldSeeMainAreaWithInviteButton() @player.shouldSeeRemainingFriendsToCompleteTeam(1)

scenario "player enters and has collected whole team", -> @player.enterGame(@playerWith4AcceptedFriends) @player.shouldSeeMainAreaWithPostToWallButton()

Page 88: Single Page Applications with CoffeeScript [Polish]

TDD

Page 89: Single Page Applications with CoffeeScript [Polish]

Acceptance tests

with test.ServerSide

Page 90: Single Page Applications with CoffeeScript [Polish]

Reużycie?

Page 91: Single Page Applications with CoffeeScript [Polish]

Jak reużyć kod po obu stronach?

Page 92: Single Page Applications with CoffeeScript [Polish]

Nie wiem.

Page 93: Single Page Applications with CoffeeScript [Polish]

Czy Google spozycjonuje SPA?

Page 94: Single Page Applications with CoffeeScript [Polish]

Tak.Ale trzeba renderować

html po stronie serwera

Page 95: Single Page Applications with CoffeeScript [Polish]

Frameworks

Page 96: Single Page Applications with CoffeeScript [Polish]

My nie potrzebujemy

Page 97: Single Page Applications with CoffeeScript [Polish]

Ty prawdopodobnie też nie potrzebujesz.

Page 98: Single Page Applications with CoffeeScript [Polish]

Krytyka Backbone.js

Page 99: Single Page Applications with CoffeeScript [Polish]

powiązanie danych z widokami

Page 100: Single Page Applications with CoffeeScript [Polish]

a gdzie logika biznesowa?

Page 101: Single Page Applications with CoffeeScript [Polish]

Backbone Models

Page 102: Single Page Applications with CoffeeScript [Polish]

Przydatne do API, ale nie używajmy ich jako

dziedziny

Page 103: Single Page Applications with CoffeeScript [Polish]

Relations/objects mismatch

Page 104: Single Page Applications with CoffeeScript [Polish]

Resources/objects mismatch

Page 105: Single Page Applications with CoffeeScript [Polish]

Libraries - yesFrameworks - no

Page 106: Single Page Applications with CoffeeScript [Polish]

Bardzo ważne pytanie

Page 107: Single Page Applications with CoffeeScript [Polish]

A może Twój projekt powinien być

SinglePageApp?

Page 108: Single Page Applications with CoffeeScript [Polish]

Co jest lepsze dla użytkowników?

Page 109: Single Page Applications with CoffeeScript [Polish]

tl;dr

• Frontend to osobna aplikacja

• Używaj CoffeeScript

• Nie używaj frameworków

• Pisz use case’y w kodzie

• Poczytaj o DCI

• Twórz fajne frontendy

Page 110: Single Page Applications with CoffeeScript [Polish]

Dziękuję!@andrzejkrzywda

http://andrzejkrzywda.com

Pytania?

(ostatnio sporo bloguję o frontendach)


Recommended