Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.
FAKE IT OUTSIDE-IN TDD
WORKSHOP
David Völkel
20th June 2017 @ Clean Code Days
https://github.com/davidvoelkel/fake-it-outs...
@DAVIDVOELKEL
@codecentric
@softwerkskammer
#TDD
YOU?
Language/IDE?
TDD background?
Expectations for today?
INFLUENCES
2003 Kent Beck’s "Fake It" Pattern
2009 #GOOS’s "Outside-In" Design
2013 Emily Bache 

"Outside-In development ...
INFLUENCES
2003 Kent Beck’s "Fake It" Pattern
2009 #GOOS’s "Outside-In" Design
2013 Emily Bache 

"Outside-In development ...
INFLUENCES
2003 Kent Beck’s "Fake It" Pattern
2009 #GOOS’s "Outside-In" Design
COMBINATION
FAKE IT OUTSIDE-IN TDD
INFLUENCES
2003 Kent Beck’s "Fake It" Pattern
2009 #GOOS’s "Outside-In" Design
2013 Emily Bache 

"Outside-In development ...
INFLUENCES
2003 Kent Beck’s "Fake It" Pattern
2009 #GOOS’s "Outside-In" Design
2013 Emily Bache 

"Outside-In development ...
INFLUENCES
2003 Kent Beck’s "Fake It" Pattern
2009 #GOOS’s "Outside-In" Design
2013 Emily Bache 

"Outside-In development ...
INFLUENCES
2003 Kent Beck’s "Fake It" Pattern
2009 #GOOS’s "Outside-In" Design
2013 Emily Bache 

"Outside-In development ...
INFLUENCES
2003 Kent Beck’s "Fake It" Pattern
2009 #GOOS’s "Outside-In" Design
2013 Emily Bache 

"Outside-In development ...
TODAY’S GOALS
Unterstand TDD patterns & trade-offs
Fake It vs. Triangulation
Fake It vs. Outside-In Mocking
Get to a seque...
AGENDA
Building Blocks
Theory/Slides
Screencasts
Small Exercises (Mob)
Fake It Outside-In
Big Kata (Pairs)
Reflect
Retro
As...
BUILDING BLOCKS
INTEGRATION OPERATION
SEGREGATION PRINCIPLE
*"Integration Operation Segregation Principle", Ralf Westphal
"Die kniffligen ...
INTEGRATION OPERATION
SEGREGATION PRINCIPLE
public void sendDiscountMailingTo(String email) {
Customer customer = customer...
OPERATION
public void sendDiscountMailingTo(String email) {
Customer customer = customerDB.findCustomerBy(email);
Account ...
INTEGRATION
INTEGRATION
OPERATION
public void sendDiscountMailingTo(String email) {
Customer customer = customerDB.findCus...
INTEGRATION
INTEGRATION
OPERATION
public void sendDiscountMailingTo(String email) {
Customer customer = customerDB.findCus...
OPERATION
INTEGRATION
public void sendDiscountMailingTo(String email) {
Customer customer = customerDB.findCustomerBy(emai...
public void sendDiscountMailingTo(String email) {
Customer customer = customerDB.findCustomerBy(email);
String content = r...
OPERATION
public void sendDiscountMailingTo(String email) {
Customer customer = customerDB.findCustomerBy(email);
String c...
INTEGRATION
OPERATION
public void sendDiscountMailingTo(String email) {
Customer customer = customerDB.findCustomerBy(emai...
CODING SESSION
KATA
Refactoring of
credit-application/…/
CreditApplicationController.performScoring()
Tasks / Constraints
...
Benefits?
Limits?
REFLECT IOSP
GREEN BAR PATTERNS*
Obvious Implementation
Fake it (until you make it)
Triangulation
* Kent Beck in "TDD by Example"
GREEN BAR PATTERNS
Obvious Implementation
Fake it
Triangulation
Trade-Off
Complexity
GREEN BAR PATTERNS
DEMO
GREEN BAR PATTERNS
Obvious Implementation
Fake it
Triangulation Fake Result
Refactor
Big Step
Fake Result
2nd Test
SWEET SPOT
Logic
GREEN BAR PATTERNS
Obvious Implementation
Fake it
Triangulation
SWEET SPOT
Structure
Logic
GREEN BAR PATTERNS
Obvious Implementation
Fake it
Triangulation
SWEET SPOT
Trivial
Structure
Logic
GREEN BAR PATTERNS
Obvious Implementation
Fake it
Triangulation
INTEGRATION
OPERATION
Fake it
Triangulation
GREEN BAR PATTERNS
Structure
Logic
IOSP
DECOMPOSE FAKE DATA
TO BUILD STRUCTURE
CODING SESSION
KATA
assertThat(format(LocalDate.of(2017, 6, 21)))
.isEqualTo("2017-06-21");
Tasks / Constraints
Obvious Im...
Obvious Impl.
Fake It
Triangulation
Properties?
Strengths?
Weaknesses?
GREEN BAR PATTERNS
DATA GUIDES STRUCTURE
Triangulation Fake It
Structure Cumbersome Data guides well
# BRANCHES
Triangulation Fake It
# N 1
More confidence
More effort
# BRANCHES
Triangulation Fake It
# N 1
Fake data easy to forget
Omitting cases is
tempting
PREPARATORY REFACTORINGS*
*"An example of preparatory refactoring", Martin Fowler
"GREEN" PHASE TRIANGULATION
Implementation Run Test
"Green Phase"
LIMIT YOUR TIME IN RED
"Green Phase"
Implementation Run Test
Implementation Run TestPreparatory Refactoring
PREPARATORY REFACTORINGS
DEMO
FAKE-IT VARIANT
CALCULATE BACKWARDS
DEMO
CODING SESSION
KATAS
assertThat(sum(„1,2,3")).isEqualTo(6);
assertThat(toCharacters(asList(0, 1, 2)))
.isEqualTo("a,b,c");...
Working Backwards
Preparatory Refactorings
Observations?
Why / Benefits?
REFLECT
TIME IN GREEN
Triangulation
Prep Refactoring
Triangulation
Fake It
Acceptance Test
UI
Persistence
OUTSIDE-IN
Unit test
Mock
OUTSIDE-IN & MOCKS
Unit Test
OUTSIDE-IN & MOCKS
Acceptance Test
UI
Persistence
OUTSIDE-IN & MOCKS
Comprehensive
Acceptance Test
OUTSIDE-IN & FAKE IT
Comprehensive
Acceptance Test
Faked Result
OUTSIDE-IN & FAKE IT
Acceptance Test
Fake
Fake
OUTSIDE-IN & FAKE IT
Acceptance Test Drive Structure
through Refactoring
OUTSIDE-IN & FAKE IT
OUTSIDE-IN & FAKE IT
Acceptance Test
Unit Test
Fill logic with
triangulation
OUTSIDE-IN & FAKE IT
Acceptance Test Unit Test
OUTSIDE-IN & FAKE IT
Fake It
Triangulation
Start with
• comprehensive 

Acceptance Test
• faked result
Drive structure by ...
OUTSIDE-IN & FAKE IT
Fake It
Triangulation
Start with
• comprehensive 

Acceptance Test
• faked result
Drive structure by ...
OUTSIDE-IN & FAKE IT
INTEGRATION
Fake It
Triangulation
OPERATION
Start with
• comprehensive 

Acceptance Test
• faked resu...
DIAMOND KATA
FAKE IT OUTSIDE-IN
DEMO
PAIRING SESSION
KATA
Continue Diamond Kata
https://github.com/davidvoelkel/diamond-kata
CONSTRAINTS
Drive structure by ref...
What did you observe?
What worked?
What was hard?
REFLECT KATA
Fake It
vs Outside-in & Mocks
vs Triangulation
REFLECT TRADE-OFFS
TRADE-OFFS
FAKE IT VS
OUTSIDE-IN & MOCKS
TRIANGULATION
CONDITIONAL INTERACTIONS
Mocking when IOSP not possible
public String signup(String username) throws Exception {
if(userDB...
COUPLING OUTSIDE-IN
Mocking Fake It
Decoupling Refactorability
DATA GUIDES STRUCTURE
Triangulation Fake It
Structure Cumbersome Data guides well
# BRANCHES
Triangulation Fake It
# N 1
More confidence
More effort
# BRANCHES
Triangulation Fake It
# N 1
Fake data easy to forget
Omitting cases is
tempting
What surprised you?
What did you learn?
What will you take into your project?
CONTENT REFLECTION
What did you (not) like?
What could be improved?
SESSION REFLECTION
THANK YOU!
REFERENCES
2003 Kent Beck’s "TDD by Example“: “Fake It" Pattern
2009 Steve Freeman, Nat Pryce:
„Growing Object Oriented So...
EXERCISE CODE SAMPLES
https://github.com/davidvoelkel/fake-it-outside-in-tdd-workshop-clean-code-days
SCREENCASTS
Playlist...
LICENSE
Creative Commons Attribution-ShareAlike 3.0
IMAGES
Most are Public Domain except theses
Creative Commons with attributions:
"Unstruttalbrücke" by Störfix
From State Li...
Nächste SlideShare
Wird geladen in …5
×

Fake It Outside-In TDD Workshop @ Clean Code Days

287 Aufrufe

Veröffentlicht am

The slides of my Fake It Outside-In TDD Workshop at the Clean Code Days 2017. Do not miss to check out the referenced screencasts that illustrate the approach very well: (https://www.youtube.com/playlist?list=PL_ueet93U84VIy8O7U4dUV0GyGvuzFAt8).

Veröffentlicht in: Software
  • Als Erste(r) kommentieren

Fake It Outside-In TDD Workshop @ Clean Code Days

  1. 1. FAKE IT OUTSIDE-IN TDD WORKSHOP David Völkel 20th June 2017 @ Clean Code Days https://github.com/davidvoelkel/fake-it-outside-in-tdd-workshop-clean-code-days
  2. 2. @DAVIDVOELKEL @codecentric @softwerkskammer #TDD
  3. 3. YOU? Language/IDE? TDD background? Expectations for today?
  4. 4. INFLUENCES 2003 Kent Beck’s "Fake It" Pattern 2009 #GOOS’s "Outside-In" Design 2013 Emily Bache 
 "Outside-In development with Double Loop TDD" 2014 Justin Searls "The Failures of 'Intro to TDD'" COMBINATION 2015 Dimitry Polivaev Outside-In with faked Data 2016 SoCraTes DE Outside-In Fake It Session 2017 Refinement
  5. 5. INFLUENCES 2003 Kent Beck’s "Fake It" Pattern 2009 #GOOS’s "Outside-In" Design 2013 Emily Bache 
 "Outside-In development with Double Loop TDD" 2014 Justin Searls "The Failures of 'Intro to TDD'" COMBINATION 2015 Dimitry Polivaev Outside-In with faked Data 2016 SoCraTes DE Outside-In Fake It Session 2017 Refinement
  6. 6. INFLUENCES 2003 Kent Beck’s "Fake It" Pattern 2009 #GOOS’s "Outside-In" Design COMBINATION FAKE IT OUTSIDE-IN TDD
  7. 7. INFLUENCES 2003 Kent Beck’s "Fake It" Pattern 2009 #GOOS’s "Outside-In" Design 2013 Emily Bache 
 "Outside-In development with Double Loop TDD" 2014 Justin Searls "The Failures of 'Intro to TDD'" COMBINATION 2016 SoCraTes DE Outside-In Fake It Session
  8. 8. INFLUENCES 2003 Kent Beck’s "Fake It" Pattern 2009 #GOOS’s "Outside-In" Design 2013 Emily Bache 
 "Outside-In development with Double Loop TDD" 2014 Justin Searls "The Failures of 'Intro to TDD'" COMBINATION 2016 SoCraTes DE Outside-In Fake It Session 2017 Refinement / Work in Progress
  9. 9. INFLUENCES 2003 Kent Beck’s "Fake It" Pattern 2009 #GOOS’s "Outside-In" Design 2013 Emily Bache 
 "Outside-In development with Double Loop TDD" COMBINATION 2016 SoCraTes DE Outside-In Fake It Session 2017 Refinement / Work in Progress
  10. 10. INFLUENCES 2003 Kent Beck’s "Fake It" Pattern 2009 #GOOS’s "Outside-In" Design 2013 Emily Bache 
 "Outside-In development with Double Loop TDD" 2014 Justin Searls "The Failures of 'Intro to TDD'" COMBINATION 2016 SoCraTes DE Outside-In Fake It Session 2017 Refinement / Work in Progress
  11. 11. INFLUENCES 2003 Kent Beck’s "Fake It" Pattern 2009 #GOOS’s "Outside-In" Design 2013 Emily Bache 
 "Outside-In development with Double Loop TDD" 2014 Justin Searls "The Failures of 'Intro to TDD'" 2017 Llewelyn Falco "Extreme: Fake it Till you Make It" COMBINATION 2016 SoCraTes DE Outside-In Fake It Session 2017 Refinement / Work in Progress
  12. 12. TODAY’S GOALS Unterstand TDD patterns & trade-offs Fake It vs. Triangulation Fake It vs. Outside-In Mocking Get to a sequence of very small steps
  13. 13. AGENDA Building Blocks Theory/Slides Screencasts Small Exercises (Mob) Fake It Outside-In Big Kata (Pairs) Reflect Retro Assessment Focus Big Picture
  14. 14. BUILDING BLOCKS
  15. 15. INTEGRATION OPERATION SEGREGATION PRINCIPLE *"Integration Operation Segregation Principle", Ralf Westphal "Die kniffligen Fälle beim Testen - Sichtbarkeit", Stefan Lieser *
  16. 16. INTEGRATION OPERATION SEGREGATION PRINCIPLE public void sendDiscountMailingTo(String email) { Customer customer = customerDB.findCustomerBy(email); Account account = customer.account(); String discount = account == FREE ? "no" : account == BASE ? "a 10%" : account == PREMIUM ? "a 25%" : "-ERROR-"; String content = "Hello " + customer.getName() + ",nn" + "This week you get " + discount + " discount " + "on all our products.nn" + "Best Regards,n" + "ACME Customer Service"; mailService.sendMail(email, content); }
  17. 17. OPERATION public void sendDiscountMailingTo(String email) { Customer customer = customerDB.findCustomerBy(email); Account account = customer.account(); String discount = account == FREE ? "no" : account == BASE ? "a 10%" : account == PREMIUM ? "a 25%" : "-ERROR-"; String content = "Hello " + customer.getName() + ",nn" + "This week you get " + discount + " discount " + "on all our products.nn" + "Best Regards,n" + "ACME Customer Service"; mailService.sendMail(email, content); } INTEGRATION OPERATION SEGREGATION PRINCIPLE
  18. 18. INTEGRATION INTEGRATION OPERATION public void sendDiscountMailingTo(String email) { Customer customer = customerDB.findCustomerBy(email); Account account = customer.account(); String discount = account == FREE ? "no" : account == BASE ? "a 10%" : account == PREMIUM ? "a 25%" : "-ERROR-"; String content = "Hello " + customer.getName() + ",nn" + "This week you get " + discount + " discount " + "on all our products.nn" + "Best Regards,n" + "ACME Customer Service"; mailService.sendMail(email, content); } INTEGRATION OPERATION SEGREGATION PRINCIPLE
  19. 19. INTEGRATION INTEGRATION OPERATION public void sendDiscountMailingTo(String email) { Customer customer = customerDB.findCustomerBy(email); Account account = customer.account(); String discount = account == FREE ? "no" : account == BASE ? "a 10%" : account == PREMIUM ? "a 25%" : "-ERROR-"; String content = "Hello " + customer.getName() + ",nn" + "This week you get " + discount + " discount " + "on all our products.nn" + "Best Regards,n" + "ACME Customer Service"; mailService.sendMail(email, content); } INTEGRATION OPERATION SEGREGATION PRINCIPLE
  20. 20. OPERATION INTEGRATION public void sendDiscountMailingTo(String email) { Customer customer = customerDB.findCustomerBy(email); String content = renderMessage(customer, customer.account()); mailService.sendMail(email, content); } private String renderMessage(Customer customer, Account account) { String discount = account == FREE ? "no" : account == BASE ? "a 10%" : account == PREMIUM ? "a 25%" : "-ERROR-"; return "Hello " + customer.getName() + ",nn" + "This week you get " + discount + " discount " + "on all our products.nn" + "Best Regards,n" + "ACME Customer Service"; } INTEGRATION OPERATION SEGREGATION PRINCIPLE
  21. 21. public void sendDiscountMailingTo(String email) { Customer customer = customerDB.findCustomerBy(email); String content = renderMessage(customer, customer.account()); mailService.sendMail(email, content); } private String renderMessage(Customer customer, Account account) { String discount = account == FREE ? "no" : account == BASE ? "a 10%" : account == PREMIUM ? "a 25%" : "-ERROR-"; return "Hello " + customer.getName() + ",nn" + "This week you get " + discount + " discount " + "on all our products.nn" + "Best Regards,n" + "ACME Customer Service"; } TESTS?
  22. 22. OPERATION public void sendDiscountMailingTo(String email) { Customer customer = customerDB.findCustomerBy(email); String content = renderMessage(customer, customer.account()); mailService.sendMail(email, content); } private String renderMessage(Customer customer, Account account) { String discount = account == FREE ? "no" : account == BASE ? "a 10%" : account == PREMIUM ? "a 25%" : "-ERROR-"; return "Hello " + customer.getName() + ",nn" + "This week you get " + discount + " discount " + "on all our products.nn" + "Best Regards,n" + "ACME Customer Service"; } TESTS? N UNITTESTS
  23. 23. INTEGRATION OPERATION public void sendDiscountMailingTo(String email) { Customer customer = customerDB.findCustomerBy(email); String content = renderMessage(customer, customer.account()); mailService.sendMail(email, content); } private String renderMessage(Customer customer, Account account) { String discount = account == FREE ? "no" : account == BASE ? "a 10%" : account == PREMIUM ? "a 25%" : "-ERROR-"; return "Hello " + customer.getName() + ",nn" + "This week you get " + discount + " discount " + "on all our products.nn" + "Best Regards,n" + "ACME Customer Service"; } TESTS?1 INTEGRATION TEST N UNITTESTS
  24. 24. CODING SESSION KATA Refactoring of credit-application/…/ CreditApplicationController.performScoring() Tasks / Constraints Enforce IOSP: Segregate Operation from Integration Check (unit) testability
  25. 25. Benefits? Limits? REFLECT IOSP
  26. 26. GREEN BAR PATTERNS* Obvious Implementation Fake it (until you make it) Triangulation * Kent Beck in "TDD by Example"
  27. 27. GREEN BAR PATTERNS Obvious Implementation Fake it Triangulation Trade-Off Complexity
  28. 28. GREEN BAR PATTERNS DEMO
  29. 29. GREEN BAR PATTERNS Obvious Implementation Fake it Triangulation Fake Result Refactor Big Step Fake Result 2nd Test
  30. 30. SWEET SPOT Logic GREEN BAR PATTERNS Obvious Implementation Fake it Triangulation
  31. 31. SWEET SPOT Structure Logic GREEN BAR PATTERNS Obvious Implementation Fake it Triangulation
  32. 32. SWEET SPOT Trivial Structure Logic GREEN BAR PATTERNS Obvious Implementation Fake it Triangulation
  33. 33. INTEGRATION OPERATION Fake it Triangulation GREEN BAR PATTERNS Structure Logic IOSP
  34. 34. DECOMPOSE FAKE DATA TO BUILD STRUCTURE
  35. 35. CODING SESSION KATA assertThat(format(LocalDate.of(2017, 6, 21))) .isEqualTo("2017-06-21"); Tasks / Constraints Obvious Implementation Fake it / Decompose as long as possible Then triangulate the remaining logic Triangulate with fake data
  36. 36. Obvious Impl. Fake It Triangulation Properties? Strengths? Weaknesses? GREEN BAR PATTERNS
  37. 37. DATA GUIDES STRUCTURE Triangulation Fake It Structure Cumbersome Data guides well
  38. 38. # BRANCHES Triangulation Fake It # N 1 More confidence More effort
  39. 39. # BRANCHES Triangulation Fake It # N 1 Fake data easy to forget Omitting cases is tempting
  40. 40. PREPARATORY REFACTORINGS* *"An example of preparatory refactoring", Martin Fowler
  41. 41. "GREEN" PHASE TRIANGULATION Implementation Run Test "Green Phase"
  42. 42. LIMIT YOUR TIME IN RED "Green Phase" Implementation Run Test Implementation Run TestPreparatory Refactoring
  43. 43. PREPARATORY REFACTORINGS DEMO
  44. 44. FAKE-IT VARIANT CALCULATE BACKWARDS DEMO
  45. 45. CODING SESSION KATAS assertThat(sum(„1,2,3")).isEqualTo(6); assertThat(toCharacters(asList(0, 1, 2))) .isEqualTo("a,b,c"); Tasks / Constraints Working Backwards Decompose Preparatory Refactoring
  46. 46. Working Backwards Preparatory Refactorings Observations? Why / Benefits? REFLECT
  47. 47. TIME IN GREEN Triangulation Prep Refactoring Triangulation Fake It
  48. 48. Acceptance Test UI Persistence OUTSIDE-IN
  49. 49. Unit test Mock OUTSIDE-IN & MOCKS
  50. 50. Unit Test OUTSIDE-IN & MOCKS
  51. 51. Acceptance Test UI Persistence OUTSIDE-IN & MOCKS
  52. 52. Comprehensive Acceptance Test OUTSIDE-IN & FAKE IT
  53. 53. Comprehensive Acceptance Test Faked Result OUTSIDE-IN & FAKE IT
  54. 54. Acceptance Test Fake Fake OUTSIDE-IN & FAKE IT
  55. 55. Acceptance Test Drive Structure through Refactoring OUTSIDE-IN & FAKE IT
  56. 56. OUTSIDE-IN & FAKE IT Acceptance Test Unit Test Fill logic with triangulation
  57. 57. OUTSIDE-IN & FAKE IT Acceptance Test Unit Test
  58. 58. OUTSIDE-IN & FAKE IT Fake It Triangulation Start with • comprehensive 
 Acceptance Test • faked result Drive structure by refactoring Drive logic by unit tests
  59. 59. OUTSIDE-IN & FAKE IT Fake It Triangulation Start with • comprehensive 
 Acceptance Test • faked result Drive structure by refactoring Drive logic by unit tests
  60. 60. OUTSIDE-IN & FAKE IT INTEGRATION Fake It Triangulation OPERATION Start with • comprehensive 
 Acceptance Test • faked result Drive structure by refactoring Drive logic by unit tests
  61. 61. DIAMOND KATA
  62. 62. FAKE IT OUTSIDE-IN DEMO
  63. 63. PAIRING SESSION KATA Continue Diamond Kata https://github.com/davidvoelkel/diamond-kata CONSTRAINTS Drive structure by refactoring Drive conditionals by triangulation
  64. 64. What did you observe? What worked? What was hard? REFLECT KATA
  65. 65. Fake It vs Outside-in & Mocks vs Triangulation REFLECT TRADE-OFFS
  66. 66. TRADE-OFFS FAKE IT VS OUTSIDE-IN & MOCKS TRIANGULATION
  67. 67. CONDITIONAL INTERACTIONS Mocking when IOSP not possible public String signup(String username) throws Exception { if(userDB.findUserBy(username) == null) { userDB.createUser(new User(username)); return "Welcome " + username; } else { return "Username ' " + username + "' " + "already taken, please choose another"; } }
  68. 68. COUPLING OUTSIDE-IN Mocking Fake It Decoupling Refactorability
  69. 69. DATA GUIDES STRUCTURE Triangulation Fake It Structure Cumbersome Data guides well
  70. 70. # BRANCHES Triangulation Fake It # N 1 More confidence More effort
  71. 71. # BRANCHES Triangulation Fake It # N 1 Fake data easy to forget Omitting cases is tempting
  72. 72. What surprised you? What did you learn? What will you take into your project? CONTENT REFLECTION
  73. 73. What did you (not) like? What could be improved? SESSION REFLECTION
  74. 74. THANK YOU!
  75. 75. REFERENCES 2003 Kent Beck’s "TDD by Example“: “Fake It" Pattern 2009 Steve Freeman, Nat Pryce: „Growing Object Oriented Software Guide by Tests“: "Outside-In" Design 2013 Emily Bache 
 "Outside-In development with Double Loop TDD" 2014 Justin Searls "The Failures of 'Intro to TDD'" 2017 Llewelyn Falco "Extreme: Fake it Till you Make It"
  76. 76. EXERCISE CODE SAMPLES https://github.com/davidvoelkel/fake-it-outside-in-tdd-workshop-clean-code-days SCREENCASTS Playlist on Youtube
  77. 77. LICENSE Creative Commons Attribution-ShareAlike 3.0
  78. 78. IMAGES Most are Public Domain except theses Creative Commons with attributions: "Unstruttalbrücke" by Störfix From State Library of Queensland

×