10/09/15A-stad meetup
Kris Waelkens
Analyst
Dries Droesbeke
Architect
Jan-Bart Vervoort
Back-end Dev
Mante Bridts
Front-end Dev
Charlie Misonne
Testing
■wifi: ‘DigAnt Free Wifi’■hashtag: #digantcafe■instagram: @digipolis_antwerpen■twitter: @dgplsantwerpen■slideshare:
http://www.slideshare.net/digipolisantwerpen
■linkedin: https://www.linkedin.com/company/digipolis
■facebook: https://www.facebook.com/Digipolis/
Some info
What? Why?A-stad
Centrale Referentie Systemen
burger / medewerker
...
So it begins...
Concept
mei ‘14: release beta.antwerpen.be
Centrale Referentie Systemen
burger
Centrale Referentie Systemen
A-profiel (user app)
meldingene-loket notificati
on redactie ... helpcenter
cart(betalen) search stadspla
n
burger
no comment
Centrale Referentie Systemen
A-profiel (user app)
e-loket notification redactie ... helpcent
ercart
(betalen) search stadsplan
burger
meldingen
navoor
Centrale Referentie Systemen
A-profiel (user app)
meldingene-loket notificati
on redactie ... helpcenter
cart(betalen) search stadspla
n
burger
Centrale Referentie Systemen
A-profiel (user app)
meldingene-loket notificati
on redactie ... helpcenter
vacatures
contact-boek
Onboarding
medewerker
Centrale Referentie Systemen
A-profiel (user app)
meldingene-loket notificati
on redactie ... helpcenter
cart(betalen) search stadspla
n
burger
API’s
Work in progress:
■API’s & SDK: developer portal■Challenge: zero downtime deployment■Reusable backend “engines”-> Antwerp City Platform as a Service (AcPaaS)-> Check http://antwerpen.digipolis.be!!!
Work in progress...
Overview architectureA-stad
Overview
Frontend
Backend
Databases
Integrations
Infrastructure
ALM
Tips■ automate everything from day 1■ use vagrant with production cookbooks■ create a skeleton with separate
packages(npm,bower,NuGet,composer)■ version your api’s/packages with semver■ code review with pull requests■ Write tests■ separation by isolation #(micro)services■ no agile excuses!
Backend@janbart
A-stad
vagrant up
vagrant up
pm2 start processes.json
pm2 start processes.json
Favorite
app.put('/srv/overzicht/d/items/:itemId/favorite', function(req, res) { var overviewItemId = req.params.itemId; var favorite = req.body.favorite; app.astad.acl.requireLogin(app, req, res, function() { var user = req.adata.user; var context = users.hasContext(req, "employee") ? "employee" : "user"; favorites.favoriteItem(user, context, overviewItemId, favorite, function(err, data) { if (err) {
return res.status(500).json(getError(err.message)); } else if (data == null) { return res.status(404).json(getError('Kon favoriet niet
vinden.')); } else { return res.json(getResponse(data)); } }); }, function() { return res.status(401).json(getNoPermission()); });
});
app.put('/srv/overzicht/d/items/:itemId/favorite', access.canFavorite(app), function(req, res) { var overviewItemId = req.params.itemId; var favorite = req.body.favorite; var user = req.adata.user; var context = users.hasContext(req, "employee") ? "employee" : "user"; favorites.favoriteItem(user, context, overviewItemId, favorite, function(err, data) { if (err) { return res.status(500).json(getError(err.message)); } else if (data == null) { return res.status(404).json(getError('Kon favoriet niet vinden.')); } else { return res.json(getResponse(data)); });});
/*** Save an item as favorite*/function favoriteItem(user, context, overviewItemId, favorite, callback) { var userId = user.id; async.waterfall([ function getOverviewObject(cb) { OverviewItem.findById(overviewItemId, cb); }, function userHasFavorites(overviewObject, cb) { if (overviewObject == null) { return cb(new Error('OverviewItem bestaat niet.')); } Favorite.findOne({userId: userId, context: context}, cb); }, function createFavoritesObjectIfNeeded(favoriteObject, cb) { if (favoriteObject == null) { if (favorite) { // Create favorite object for user return saveFavorite(userId, context, overviewItemId, function saved(err, data) { return favoriteSaved(err, data, overviewItemId, cb); }); } else { return cb(new Error("Dit item behoort nog niet tot je favorieten.")); } } else { var foundId = favoriteObject.overviewItemIds.indexOf(overviewItemId) !== -1; if (foundId) { if (favorite) { return cb(new Error("Je hebt dit item al toegevoegd aan je favorieten.")); } else { favoriteObject.overviewItemIds.pull(mongoose.Types.ObjectId(overviewItemId)); return favoriteObject.save(function saved(err, data) { return favoriteSaved(err, data, overviewItemId, cb); }); } } else { if (favorite) { favoriteObject.overviewItemIds.push(mongoose.Types.ObjectId(overviewItemId)); return favoriteObject.save(function saved(err, data) { return favoriteSaved(err, data, overviewItemId, cb); }); } else { return cb(new Error("Je moet dit item toevoegen aan je favorieten voordat je het kan verwijderen uit je favorieten.")); } } } } ], callback);}
/*** Save an item as favorite*/function favoriteItem(user, context, overviewItemId, favorite, callback) {
async.waterfall([ function getOverviewObject(cb) {}, function userHasFavorites(overviewObject, cb) {}, function createFavoritesObjectIfNeeded(favoriteObject, cb) {} ], callback);}
Test it.™
Node Package Manager
NPM
NPM-modules
Hi, I'm Betty.
Developer x
Developer x
Developer y
Developer z
Developer x
Developer 1
Developer 2
Front-end developmentA-stad
vagrant up
Minifying
JS hint Sass to css
Watch
Sprite generator
Concat
Strip & uglify
Bless
i18n
■API: styling API with variables, mixins, functions
■Base: styling for base HTML elements
■Grid: the Singularity grid■Helpers: definition of helper classes
Sass-kit
■Components:●Collections of HTML elements that form a new element together
●Directives
■Vendor: styling overrides for vendor components
Sass-kit
improvescode quality!
meldingen
A-kaart
notificationredactie
helpcenter
cart(betalen)
search
stadsplan
ui
user
contactboek
boodschap
vacature
meldingen
A-kaart
notificationredactie
helpcenter
cart(betalen)
search
stadsplan
ui
user
contactboek
boodschap
vacature
Single Point of Failure...
Contactboek app
Template
Service
Controller
$scope
Template
Controller
Service
Service
Service
Directives
<data-ng-if>
<data-ng-repeat>
<a>
Vragen?
Waarom en hoe automatiseren- Charlie Misonne
Automated RegressionTesting
Een verandering impacteert een voorheen werkend systeem op een negatieve manier
Wat is regressie
Testautomatisatie - algemeen
Agile? ⇒ Automatiseer!
Korte sprintsSnelle releasesContinuous integration
Waarom?
Verschillende niveaus
Begin onderaan!
5min
10min
90min
... uren, dagen??
UI test-automatisatie!
■Repetitieve testen?
■Regressie testen = repetitief⇒ Ideaal voor automatisatie!
Wanneer UI automatisatie?
Automation paradox
Veel veranderingen
Veel regressietesten nodig Automatisatie is moeilijk
Demo...
Protractor vs. Selenium...
SeleniumWebdriver
■Angular Locatorselement(by.binding('item.assignee.fullName'))element(by.repeater('answer in question.answers'))
■Wacht op page sync ($timeout, $http)
■A-stad technologieën
Waarom Protractor?
Demo...
Protractor
Top Related