@IanAtha· #PastitsioTechtalk	

2013-12-17· Unify· Kifisia, Greece
29 πολιτικοί αρχηγοί συνιστούν

να βάλετε τα κινητά στη διαπασών

οπότε… τα κινητά στη σίγαση…6
but not your questions!

(...
#PastitsioTechtalk
•
•

macaroni	


•

kimas	


•

layer everything	


•

bake it	


•

quality control	


•

#PastitsioTechtalk

béchamel	

...
•
•

design	


•

implementation	


•

testing	


•

debugging	


•

integrating	


•

#PastitsioTechtalk

decision-making...
SOFTWARE IS LIKE A FACTORY	



(UNUSED INVENTORY IS WASTE)

#PastitsioTechtalk
•

code is inventory	


•

code accumulates between stages	


•

it costs money	


•

it costs well-being

#PastitsioTecht...
MISTAKES BECOME MORE
EXPENSIVE AS TIME PASSES

#PastitsioTechtalk
ALL THE TIME
•

Commit	


•

Test (in isolation)	


•

Test (in coordination)	

Deploy	


Measure
#PastitsioTechtalk
•

Mi...
WHO DOES THAT?
Wealthfront	

6

Box	

6

Autma
TESTING AIN’T FROSTING	

(ΔΕΝ ΕΙΝ’ ΓΑΡΝΙΤΟΥΡΑ)

#PastitsioTechtalk
•
•
•

continuous integration	

immune system (metrics)	


•

#PastitsioTechtalk

test-driven development	


•

Ω

culture...
•
•
•

continuous integration	

immune system (metrics)	


•

#PastitsioTechtalk

test-driven development	


•

culture
Ω
...
λίγη σιγουριά ακόµα
•

every failure, only once	


•

root-cause analysis	


•

stop the line

if anything fails	


•
•

s...
#PastitsioTechtalk
•
•
•

continuous integration	

immune system (metrics)	


•

#PastitsioTechtalk

test-driven developmen

•

test-driven	
...
HOW DO YOU WRITE	

HARD-TO-TEST CODE?
TO WRITE HARD-TO-TEST CODE
•

Global State (singleton)	


•

Principle of Least Knowledge	


•

Global Reference to Time	
...
public class InboxSyncer {

private static final InboxSyncer instance = new InboxSyncer(Config.get());

public static getI...
public class ♥ {

private static final ♥ instance = new ♥(Config.get());

public static getInstance() { return instance; }...
public class ♥ {

private static final ♥ instance = new ♥(Config.get());

public static getInstance() { return instance; }...
public class ♥ {

private static final ♥ instance = new ♥(Config.get());

public static getInstance() { return instance; }...
public class ♥ {

private static final ♥ instance = new ♥(Config.get());

public static getInstance() { return instance; }...
public class ♥ {

private static final ♥ instance = new ♥(Config.get());

public static getInstance() { return instance; }...
public class ♥ {

private static final ♥ instance = new ♥(Config.get());

public static getInstance() { return instance; }...
SPEC FIRST

HELPS YOU THINK RIGHT
•

Assume code hasn’t been written yet	


•

Write the spec first	


•

The spec tells a ...
Class InboxSyncerSpec {

@Test itShouldSyncMessagesFromPopSinceLastSync() {}

@Test itShouldCloseConnectionEvenWhenExcepti...
public @Test itShouldSyncMessagesFromPopSinceLastSync() {
// Premises
Date longAgo = new Date(1);

Date past = new Date(2)...
FINALLY THE CODE
!
!
public class InboxSyncer {
…
private InboxSyncer(
POPConnector pop,
Inbox inbox,
Filter filter,
Date ...
UNIT-TESTING
•

new operators are dangerous	


•

ask for what you need	


•

If you need it, then you must interact with ...
•
•
•

continuous integration	

immune system

•

#PastitsioTechtalk

test-driven development	


•

immune system

culture...
CANARIES
deployments as statistical experiments

#PastitsioTechtalk
•
•
•

continuous integration	

immune system	


•

#PastitsioTechtalk

test-driven development	


•

continuous deploymen...
ONE-CLICK DEPLOYMENT
(ΚΕΝΤΡΟ ΕΞΥΠΗΡΕΤΗΣΗΣ ΠΟΛΙΤΩΝ)
ONE-CLICK DEPLOYMENT
(ΚΕΝΤΡΟ ΕΞΥΠΗΡΕΤΗΣΗΣ ΠΡΟΓΡΑΜΜΑΤΙΣΤΩΝ)
THANK YOU
ian@autma.com	

@IanAtha

#PastitsioTechtalk
BIBLIOGRAPHY
•

http://www.slideshare.net/pascallouis/developingan-immune-system-the-hard-and-soft-skillsrequired-to-avoid...
Unify - Pastitsio Techtalk - Ian Atha
Unify - Pastitsio Techtalk - Ian Atha
Upcoming SlideShare
Loading in …5
×

Unify - Pastitsio Techtalk - Ian Atha

597 views

Published on

Just like you test each component of your pastitsio separately, to ensure it's good, you should test each component of your code.

Published in: Technology, News & Politics
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
597
On SlideShare
0
From Embeds
0
Number of Embeds
20
Actions
Shares
0
Downloads
7
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Unify - Pastitsio Techtalk - Ian Atha

  1. 1. @IanAtha· #PastitsioTechtalk 2013-12-17· Unify· Kifisia, Greece
  2. 2. 29 πολιτικοί αρχηγοί συνιστούν
 να βάλετε τα κινητά στη διαπασών οπότε… τα κινητά στη σίγαση…6 but not your questions!
 (ask anything anytime)
  3. 3. #PastitsioTechtalk
  4. 4. • • macaroni • kimas • layer everything • bake it • quality control • #PastitsioTechtalk béchamel cut it in pieces
  5. 5. • • design • implementation • testing • debugging • integrating • #PastitsioTechtalk decision-making deploying
  6. 6. SOFTWARE IS LIKE A FACTORY 
 (UNUSED INVENTORY IS WASTE) #PastitsioTechtalk
  7. 7. • code is inventory • code accumulates between stages • it costs money • it costs well-being #PastitsioTechtalk
  8. 8. MISTAKES BECOME MORE EXPENSIVE AS TIME PASSES #PastitsioTechtalk
  9. 9. ALL THE TIME • Commit • Test (in isolation) • Test (in coordination) Deploy Measure #PastitsioTechtalk • Minimize the cost of mistakes • • • If it’s painful,
 do it more.
  10. 10. WHO DOES THAT? Wealthfront 6 Box 6 Autma
  11. 11. TESTING AIN’T FROSTING (ΔΕΝ ΕΙΝ’ ΓΑΡΝΙΤΟΥΡΑ) #PastitsioTechtalk
  12. 12. • • • continuous integration immune system (metrics) • #PastitsioTechtalk test-driven development • Ω culture continuous deployment
  13. 13. • • • continuous integration immune system (metrics) • #PastitsioTechtalk test-driven development • culture Ω culture continuous deployment
  14. 14. λίγη σιγουριά ακόµα • every failure, only once • root-cause analysis • stop the line
 if anything fails • • stable trunk automated tests #PastitsioTechtalk • small commits • trivial deployments & rollbacks • canaries • feature flips • fast response
 instead of prevention
  15. 15. #PastitsioTechtalk
  16. 16. • • • continuous integration immune system (metrics) • #PastitsioTechtalk test-driven developmen • test-driven Ω development culture continuous deployment
  17. 17. HOW DO YOU WRITE HARD-TO-TEST CODE?
  18. 18. TO WRITE HARD-TO-TEST CODE • Global State (singleton) • Principle of Least Knowledge • Global Reference to Time • Hard-coded object construction (new)
  19. 19. public class InboxSyncer {
 private static final InboxSyncer instance = new InboxSyncer(Config.get());
 public static getInstance() { return instance; }
 private final Certificate cert;
 private final String username;
 private final String password;
 private long lastSync = -1;
 
 
 private InboxSyncer(Config config) {
 this.cert = DESReader.read(config.get(“cert.path”));
 User user = config.getUser();
 this.username = user.getUsername();
 this.password = user.getPassword();
 }
 public sync() {
 long syncFrom = lastSync;
 if (syncFrom == -1)
 syncFrom = new Date().getTime() - Defaults.INBOX_SYNC_AMOUNT;
 Inbox inbox = Inbox.get(username);
 POPConnector pop = new POPConnector(cert, username, password);
 pop.connect();
 try {
 Iterator<Messages> messages = pop.messagesIterator();
 Message message;
 while ( messages.hasNext() &&
 (message = messages.next()).getTime() > syncFrom ) {
 if (Defaults.FILTER_SPAM
 ? MessageFilter.spam(message)
 : MessageFilter.addressedToMe(message, username)) {
 this.lastSync = Math.max(this.lastSync, message.getTime());
 if (!inbox.contains(message.getId())
 inbox.add(message);
 }
 }
 } finally {
 pop.disconnect();
 }
 }

  20. 20. public class ♥ {
 private static final ♥ instance = new ♥(Config.get());
 public static getInstance() { return instance; }
 private final Certificate cert;
 private final String username;
 private final String password;
 private long lastSync = -1;
 
 
 private ♥(Config config) {
 this.cert = DESReader.read(config.get(“cert.path”));
 User user = config.getUser();
 this.username = user.getUsername();
 this.password = user.getPassword();
 }
 public sync() {
 long syncFrom = lastSync;
 if (syncFrom == -1)
 syncFrom = new Date().getTime() - Defaults.INBOX_SYNC_AMOUNT;
 Inbox inbox = Inbox.get(username);
 ♦ pop = new ♦(cert, username, password);
 pop.connect();
 try {
 Iterator<Messages> messages = pop.messagesIterator();
 Message message;
 while ( messages.hasNext() &&
 (message = messages.next()).getTime() > syncFrom ) {
 if (Defaults.FILTER_SPAM
 ? MessageFilter.spam(message)
 : MessageFilter.addressedToMe(message, username)) {
 this.lastSync = Math.max(this.lastSync, message.getTime());
 if (!inbox.contains(message.getId())
 inbox.add(message);
 }
 }
 } finally {
 pop.disconnect();
 }
 }

  21. 21. public class ♥ {
 private static final ♥ instance = new ♥(Config.get());
 public static getInstance() { return instance; }
 private final Certificate cert;
 private final String username;
 private final String password;
 private long lastSync = -1;
 • Global State (singleton) • Principle of Least Knowledge • Global Reference to Time 
 • Hard-coded object construction (new) 
 private ♥(Config config) {
 this.cert = DESReader.read(config.get(“cert.path”));
 User user = config.getUser();
 this.username = user.getUsername();
 this.password = user.getPassword();
 }
 public sync() {
 long syncFrom = lastSync;
 if (syncFrom == -1)
 syncFrom = new Date().getTime() - Defaults.INBOX_SYNC_AMOUNT;
 Inbox inbox = Inbox.get(username);
 ♦ pop = new ♦(cert, username, password);
 pop.connect();
 try {
 Iterator<Messages> messages = pop.messagesIterator();
 Message message;
 while ( messages.hasNext() &&
 (message = messages.next()).getTime() > syncFrom ) {
 if (Defaults.FILTER_SPAM
 ? MessageFilter.spam(message)
 : MessageFilter.addressedToMe(message, username)) {
 this.lastSync = Math.max(this.lastSync, message.getTime());
 if (!inbox.contains(message.getId())
 inbox.add(message);
 }
 }
 } finally {
 pop.disconnect();
 }
 }

  22. 22. public class ♥ {
 private static final ♥ instance = new ♥(Config.get());
 public static getInstance() { return instance; }
 private final Certificate cert;
 private final String username;
 private final String password;
 private long lastSync = -1;
 • Global State (singleton) • Principle of Least Knowledge • Global Reference to Time 
 
 private ♥(Config config) {
 this.cert = DESReader.read(config.get(“cert.path”));
 User user = config.getUser();
 this.username = user.getUsername();
 this.password = user.getPassword();
 }
 public sync() {
 long syncFrom = lastSync;
 if (syncFrom == -1)
 syncFrom = new Date().getTime() - Defaults.INBOX_SYNC_AMOUNT;
 Inbox inbox = Inbox.get(username);
 ♦ pop = new ♦(cert, username, password);
 pop.connect();
 try {
 Iterator<Messages> messages = pop.messagesIterator();
 Message message;
 while ( messages.hasNext() &&
 (message = messages.next()).getTime() > syncFrom ) {
 if (Defaults.FILTER_SPAM
 ? MessageFilter.spam(message)
 : MessageFilter.addressedToMe(message, username)) {
 this.lastSync = Math.max(this.lastSync, message.getTime());
 if (!inbox.contains(message.getId())
 inbox.add(message);
 }
 }
 } finally {
 pop.disconnect();
 }
 }
 • Hard-coded object construction (new)
  23. 23. public class ♥ {
 private static final ♥ instance = new ♥(Config.get());
 public static getInstance() { return instance; }
 private final Certificate cert;
 private final String username;
 private final String password;
 private long lastSync = -1;
 • Global State (singleton) • Principle of Least Knowledge • Global Reference to Time 
 
 private ♥(Config config) {
 this.cert = DESReader.read(config.get(“cert.path”));
 User user = config.getUser();
 this.username = user.getUsername();
 this.password = user.getPassword();
 }
 public sync() {
 long syncFrom = lastSync;
 if (syncFrom == -1)
 syncFrom = new Date().getTime() - Defaults.INBOX_SYNC_AMOUNT;
 Inbox inbox = Inbox.get(username);
 ♦ pop = new ♦(cert, username, password);
 pop.connect();
 try {
 Iterator<Messages> messages = pop.messagesIterator();
 Message message;
 while ( messages.hasNext() &&
 (message = messages.next()).getTime() > syncFrom ) {
 if (Defaults.FILTER_SPAM
 ? MessageFilter.spam(message)
 : MessageFilter.addressedToMe(message, username)) {
 this.lastSync = Math.max(this.lastSync, message.getTime());
 if (!inbox.contains(message.getId())
 inbox.add(message);
 }
 }
 } finally {
 pop.disconnect();
 }
 }
 • Hard-coded object construction (new)
  24. 24. public class ♥ {
 private static final ♥ instance = new ♥(Config.get());
 public static getInstance() { return instance; }
 private final Certificate cert;
 private final String username;
 private final String password;
 private long lastSync = -1;
 • Global State (singleton) • Principle of Least Knowledge • Global Reference to Time 
 
 private ♥(Config config) {
 this.cert = DESReader.read(config.get(“cert.path”));
 User user = config.getUser();
 this.username = user.getUsername();
 this.password = user.getPassword();
 }
 public sync() {
 long syncFrom = lastSync;
 if (syncFrom == -1)
 syncFrom = new Date().getTime() - Defaults.INBOX_SYNC_AMOUNT;
 Inbox inbox = Inbox.get(username);
 ♦ pop = new ♦(cert, username, password);
 pop.connect();
 try {
 Iterator<Messages> messages = pop.messagesIterator();
 Message message;
 while ( messages.hasNext() &&
 (message = messages.next()).getTime() > syncFrom ) {
 if (Defaults.FILTER_SPAM
 ? MessageFilter.spam(message)
 : MessageFilter.addressedToMe(message, username)) {
 this.lastSync = Math.max(this.lastSync, message.getTime());
 if (!inbox.contains(message.getId())
 inbox.add(message);
 }
 }
 } finally {
 pop.disconnect();
 }
 }
 • Hard-coded object construction (new)
  25. 25. public class ♥ {
 private static final ♥ instance = new ♥(Config.get());
 public static getInstance() { return instance; }
 private final Certificate cert;
 private final String username;
 private final String password;
 private long lastSync = -1;
 • Global State (singleton) • Principle of Least Knowledge • Global Reference to Time 
 
 private ♥(Config config) {
 this.cert = DESReader.read(config.get(“cert.path”));
 User user = config.getUser();
 this.username = user.getUsername();
 this.password = user.getPassword();
 }
 public sync() {
 long syncFrom = lastSync;
 if (syncFrom == -1)
 syncFrom = new Date().getTime() - Defaults.INBOX_SYNC_AMOUNT;
 Inbox inbox = Inbox.get(username);
 ♦ pop = new ♦(cert, username, password);
 pop.connect();
 try {
 Iterator<Messages> messages = pop.messagesIterator();
 Message message;
 while ( messages.hasNext() &&
 (message = messages.next()).getTime() > syncFrom ) {
 if (Defaults.FILTER_SPAM
 ? MessageFilter.spam(message)
 : MessageFilter.addressedToMe(message, username)) {
 this.lastSync = Math.max(this.lastSync, message.getTime());
 if (!inbox.contains(message.getId())
 inbox.add(message);
 }
 }
 } finally {
 pop.disconnect();
 }
 }
 • Hard-coded object construction (new)
  26. 26. SPEC FIRST
 HELPS YOU THINK RIGHT • Assume code hasn’t been written yet • Write the spec first • The spec tells a story • Each spec describes a single behavior
  27. 27. Class InboxSyncerSpec {
 @Test itShouldSyncMessagesFromPopSinceLastSync() {}
 @Test itShouldCloseConnectionEvenWhenExceptionThrown() {}
 @Test itShouldSyncMessagesOnlyWhenNotAlreadyInInbox() {}
 @Test itShouldIgnoreMessagesOlderThenLastSync() {}
 @Test itShouldIgnoreMessagesFailingFilter() {}
 @Test itShouldDefaultToDefaultTimeWhenNeverSynced() {}
 }
  28. 28. public @Test itShouldSyncMessagesFromPopSinceLastSync() { // Premises Date longAgo = new Date(1);
 Date past = new Date(2); Date now = new Date(3); POPConnector pop = new MockPOPConnector(); Inbox inbox = new Inbox(); Filter filter = new NoopFilter(); Message longAgoMsg = new Message(“from”, “to”, “sbj”, “msg”, longAgo); Message pastMsg = new Message(“me”, “you”, “hello”, “world”, past); long noDefaultSync = -1; pop.addMessage(longAgoMsg); pop.addMessage(pastMsg); ! // Operation new InboxSyncer(pop, inbox, filter, longAgo, noDefaultSync).sync(now);
 // Assurances assertThat(inbox.getMessages(), is(equalTo(pastMsg))); assertThat(pop.isClosed(), is(true)); }
  29. 29. FINALLY THE CODE ! ! public class InboxSyncer { … private InboxSyncer( POPConnector pop, Inbox inbox, Filter filter, Date lastSync, long defaultPastSync) { this.pop = pop; this.inbox = inbox; this.filter = filter; this.lastSync = lastSync; this.defaultPastSync = defaultPastSync; } … }
  30. 30. UNIT-TESTING • new operators are dangerous • ask for what you need • If you need it, then you must interact with it • Global State is testability nightmare • Doing work in constructor is dangerous
  31. 31. • • • continuous integration immune system • #PastitsioTechtalk test-driven development • immune system culture continuous deployment
  32. 32. CANARIES deployments as statistical experiments #PastitsioTechtalk
  33. 33. • • • continuous integration immune system • #PastitsioTechtalk test-driven development • continuous deployment culture continuous deployment
  34. 34. ONE-CLICK DEPLOYMENT (ΚΕΝΤΡΟ ΕΞΥΠΗΡΕΤΗΣΗΣ ΠΟΛΙΤΩΝ)
  35. 35. ONE-CLICK DEPLOYMENT (ΚΕΝΤΡΟ ΕΞΥΠΗΡΕΤΗΣΗΣ ΠΡΟΓΡΑΜΜΑΤΙΣΤΩΝ)
  36. 36. THANK YOU ian@autma.com @IanAtha #PastitsioTechtalk
  37. 37. BIBLIOGRAPHY • http://www.slideshare.net/pascallouis/developingan-immune-system-the-hard-and-soft-skillsrequired-to-avoid-outages (P. Perez) • http://www.slideshare.net/pascallouis/iterate-like-awhirling-dervish (P. Perez) • http://goo.gl/vBOZH (M. Hevery)

×