SlideShare ist ein Scribd-Unternehmen logo
1 von 44
Downloaden Sie, um offline zu lesen
APACHE SLING & FRIENDS TECH MEETUP
BERLIN, 25-27 SEPTEMBER 2017
How to write clean & testable code without
losing your mind - Andreas Czakaj
How did you learn what you know today?
2
“There are three kinds of men:
1. The one that learns by reading.
2. The few who learn by observation.
3. The rest of them have to p**
on the electric fence for themselves.”
-- Will Rogers
Source: brainyquote.com
this is us
learning AEM…
Our early experience with AEM
3
 Painful upgrades
 Slow progress
 Hard to change code
 Hard to fix bugs
 Regression bugs
Image: „03-15: At the Dentist“, jlk.1, CC BY-SA 2.0
Our early AEM code
4
 Low coverage
 Expensive tests
 Slow & fragile tests
 Extensive logging
 High coupling
 Low cohesion
Edvard Munch, “The Scream”, https://en.wikipedia.org/wiki/The_Scream
What we actually wanted
5
 If you need to maintain, extend and adapt
over several years you’ll want…
 reliable software
 confidence in code
 understanding
 control
 adaptability, extensibility
How we actually wanted to work
6
 If you need to maintain, extend and adapt
over several years you’ll need…
 regression tests
 high coverage
 knowledge management
 control over dependencies
 high cohesion + low coupling
7
Refuse, Resist
Test Driven/First Development
8
 In 2005 I was a freelancer working on a
project using Servlets & JSPs, Hibernate &
JPA, SOAP etc.
 They forced me to do TDD
 After some weeks of futile protest…
 … I realized how TDD works & why it’s great
What IS great about TDD?
9
 Fewer bugs (duh!)
 Permanently up-to-date documentation
 You work faster (fast response, no maven)
 You have a tool to check your
design decisions
 … in a straightforward way
Test Driven Development
10
 If it’s hard to test it’s likely poorly designed
 Focus on creating testable code
 For your design decisions you should ask:
 what makes the code more testable?
 which of my options yields more testable code?
Test First Development
11
 Write the test first
 Write prod. code
 Run test
 Refactoring
 ~ Double-Entry
Accounting
Account
Furniture
Cash
Test
assertEquals(
6, fac(3)
);
Prod. Code
int fac(int n) {
return n > 1
? n * fac(n-1)
: 1;
}
Debit
€ 1,500
Credit
€ 1,500
Refactor production code, keep existing tests
12
Test
assertEquals(
6, fac(3)
);
Prod. Code
int fac(final int n) {
int out = 1;
for (int i = n; i > 1; i--) {
out *= i;
}
return out;
}
As a result…
13
 fewer bugs -> reliable software
 high coverage -> control, confidence in code
 tests as documentation -> understanding
 refactoring -> adaptability, extensibility
 -> That’s what we were looking for, right?
 -> I’ll tell my AEM developers about it!
However, the team was not impressed
14
Your boss telling you to
“get 100% coverage”
does not work…
… especially, when you
have to deal with code
like this:…
Image: Wikipedia, License: Public Domain
How do you test THIS?
15
public void onEvent(final EventIterator events) {
while (events.hasNext()) {
final Event event = events.nextEvent();
Session session = null; Node node = null;
try {
String path = event.getPath();
if (path.endsWith(JcrConstants.JCR_CONTENT)) {
session = repository.login(new Credentials(){/*…*/}));
node = session.getNode(path);
if (node.hasProperty("cq:template") &&
“…".equals(node.getProperty("cq:template").getString())){
processExport(node);
}}
} catch (RepositoryException e) {/*…*/} finally{/*logout*/}}}
Team: “Isn’t it obvious?”
16
 “We already tried everything™”…
 mocks
 end-to-end tests
 in-container tests
 “We can reach some coverage…”
 “…but, obviously, it will be
a lot of tedious work and pretty expensive”
Team decision
17
 “You can’t test
everything in AEM
without losing your
mind”
Source: pixabay, License: CC0 Creative Commons
No need to lose your mind
18
 TDD is NOT about
testing cleverly
 TDD is about
writing code in a
different way:
clever == testable
Sigmund Freud, https://de.wikipedia.org/wiki/Datei:Sigmund_Freud_LIFE.jpg
Digging into the problem - together
19
 We spent some time
figuring out new
design approaches
 Here’s what we
found out
really works…
Image: “Digging the Drain” by International Disaster Volunteers, License: CC BY 2.0
20
Some AEM Examples
Busy, busy method
21
public void onEvent(final EventIterator events) {
while (events.hasNext()) {
final Event event = events.nextEvent();
Session session = null; Node node = null;
try {
String path = event.getPath();
if (path.endsWith(JcrConstants.JCR_CONTENT)) {
session = repository.login(new Credentials(){/*…*/}));
node = session.getNode(path);
if (node.hasProperty("cq:template") &&
“…".equals(node.getProperty("cq:template").getString())){
processExport(node);
}}
} catch (RepositoryException e) {/*…*/} finally{/*logout*/}}}
… in a busy, busy class
22
private void processExport(final Node node) {// original method: ~100 loc
try {
String group;
if (node.hasProperty(PROPERTY_GROUP)) {
group = node.getProperty(PROPERTY_GROUP).getString();
} else {
LOG.warn("There is no group. Stop export.");
return;
}
/*…*/
File csvFile = File.createTempFile(“…”, "csv");
exportToFile(group, /*…*/, csvFile);
/*…*/
} catch(/*…*/) {/*…*/} finally {cleanupTempFiles();/*…*/}
Single Responsibility Principle & Clean Code
23
 “A class should have only 1 reason to change”
 Clean Code: find the “reason(s)”:
 Event loop
 Data retrieval
 Data processing
 Export to FileSystem
 … in specialized format
this part might
lead to
philosophical
debates…
Single Responsibility Principle & TDD
24
 … or you can look at
it from a TDD
point of view
 TDD: imagine
writing tests for it…
 -> meh
Image “meh” by GalacticWanderlust, License CC BY-ND 2.0
The TDD way
25
 Don’t be clever at testing…
 … instead, aim at fixing the code
 Write the tests first…
 … then find the code that works best for the
tests
 Start simple – but be thorough & complete
Specify your rules with plain unit tests
26
@Test
public void test_toList_allEmpty() throws Exception {
List<String> row = exporter.toList(new MyExportData());
assertEquals("It should export nulls as empty strings",
Arrays.asList("", ""), row);
}
/** production code*/
/* … */
items.stream()
.filter(item -> item != null)
.map(this::toList)
.forEach(rowConsumer::accept); // List::add in tests,
/* … */ // OutputStream.write in prod code
Don’t be clever at testing, fix the code instead
27
class ExportEventListener {
public void onEvent(final EventIterator events) {
final Dao dao = new DaoJcrImpl(repository);
final MyService service = new MyService(dao);
while (events.hasNext()) {
final Event event = events.nextEvent();
final ProcessingContext ctx = toProcessingContext(event);
service.process(ctx);}}}
public class MyService {
private final Dao dao;
private final Exporter exporter;
public void process(final ProcessingContext ctx) {
final Data data = dao.getData(ctx);
exporter.export(data);}}
SRP & TDD
28
 TDD:
 Event loop: simple setup
 DAO: AemMock / MockJcrSlingRepository
 Data processing: POJOs -> unit testable
 Export to FileSystem: using POJOs
 Specialized format: plain Java -> unit testable
 Service: each “piece” can be replaced by stub
SRP & Clean Code
29
 Clean Code: 1 class per “reason” / ”concern”
 Event loop (Entry point)
 Data retrieval (DAO + Adapter)
 Data processing (Domain logic)
 Export to FileSystem (Gateway)
 Specialized export format (Strategy)
 Service: integrate pieces (Dependency Injection)
TDD & Clean Code
30
 Bottom line:
 To make TDD work you need to decouple code
 … using SRP, DI, “Ports” etc.
 … i.e. Clean Code principles
 -> TDD will lead you to Clean Code
 (… if you stick to the rules…)
 But how does it work on application-scale?
31
Application-scale Dependency Management
The Dependency Rule – for AEM
32Inspired by “The Clean Architecture” by Uncle Bob Martin, https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html
Enterprise
Domain
specific
Use Cases
“source code
dependencies
can only point
inwards”
Actros, MPC,
Enterp. Rules
Trucker Profile,
EQP Code,
Rules
ControllersOSGi
SysDate
DAOs
FS
DB
JCR
SOAP/REST
ResourceResolver
Simple Example
33
 Approach 1
package com.mercedes-benz.trucks.domain;
public class Actros {
static Actros fromRequest(HttpServletRequest req) {/* … */};
}
 Approach 2
package com.mercedes-benz.trucks.integration.web;
public class ActrosAdapter {
Actros toActros(HttpServletRequest req) {/* … */};
}
 => which one works according to the Dependency Rule?
Simple Example
34
 Approach 1
package com.mercedes-benz.trucks.domain;
public class Actros {
static Actros fromRequest(HttpServletRequest req) {/* … */};
}
 Approach 2
package com.mercedes-benz.trucks.integration.web;
public class ActrosAdapter {
Actros toActros(HttpServletRequest req) {/* … */};
}
 => Keep outer layer dependencies out of inner layers
Ports & Adapters / Dependency Inversion
35
 “But the Use Cases and Domain objects need
data from the outer layers!”
 “How can I read from and write to the outer
layer without depending on it?”
 -> Dependency INVERSION
 -> “Ports”
(simplified: outer layers behind interfaces)
36
TDD + Dependency Rule = key to success
Identify the Domain
37
 … yes, it exists
 Start at the core: start at the Domain
 … it’s the code that’s the easiest to test
 -> you’ll start at 100% coverage
 … then stay at 100%
 -> E.g. keep the ResourceResolver / JCR
out of your Domain, Rules and APIs
This approach scales & works also for…
38
 Services
 Models
 Components
 Workflows
 Listeners
 …
How does it pay off for us in the real world?
39
 We reach 100% coverage (in new code)
 Sometimes, we still have bugs…
 … but mostly in the front end / JavaScript
 … or because of production data mismatch
 We’re faster
 Developers no longer lose their minds ;-)
Useful links
40
 Ports & Adapters
 DAO / Repository Pattern
 Clean Architecture / Dependency Rule
 3 Rules of TDD / Bowling Game Kata
 Single Responsibility Principle
 “The more testing you do…”
Code examples
41
https://github.com/mensemedia/adaptTo2017
 Exporter:
Refactored version of a real life project
(w/ 100% coverage)
42
#thx
Image: pixabay, License: CC0 Creative Commons
43
Questions?
#HappyHacking
44
Andreas Czakaj (CTO)
mensemedia Gesellschaft für Neue Medien mbH
Neumannstr. 10
40235 Düsseldorf
Germany
Email: andreas.czakaj@mensemedia.net
Twitter: @AndreasCzakaj
Blog: https://blog.acnebs.com/

Weitere ähnliche Inhalte

Was ist angesagt?

10 Typical Enterprise Java Problems
10 Typical Enterprise Java Problems10 Typical Enterprise Java Problems
10 Typical Enterprise Java Problems
Eberhard Wolff
 
Verilator: Fast, Free, But for Me?
Verilator: Fast, Free, But for Me? Verilator: Fast, Free, But for Me?
Verilator: Fast, Free, But for Me?
DVClub
 
Anti-Debugging - A Developers View
Anti-Debugging - A Developers ViewAnti-Debugging - A Developers View
Anti-Debugging - A Developers View
Tyler Shields
 
Processor Verification Using Open Source Tools and the GCC Regression Test Suite
Processor Verification Using Open Source Tools and the GCC Regression Test SuiteProcessor Verification Using Open Source Tools and the GCC Regression Test Suite
Processor Verification Using Open Source Tools and the GCC Regression Test Suite
DVClub
 

Was ist angesagt? (20)

Static Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal EngineStatic Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal Engine
 
10 Typical Enterprise Java Problems
10 Typical Enterprise Java Problems10 Typical Enterprise Java Problems
10 Typical Enterprise Java Problems
 
Verilator: Fast, Free, But for Me?
Verilator: Fast, Free, But for Me? Verilator: Fast, Free, But for Me?
Verilator: Fast, Free, But for Me?
 
SAST and Application Security: how to fight vulnerabilities in the code
SAST and Application Security: how to fight vulnerabilities in the codeSAST and Application Security: how to fight vulnerabilities in the code
SAST and Application Security: how to fight vulnerabilities in the code
 
關於測試,我說的其實是......
關於測試,我說的其實是......關於測試,我說的其實是......
關於測試,我說的其實是......
 
PVS-Studio is ready to improve the code of Tizen operating system
PVS-Studio is ready to improve the code of Tizen operating systemPVS-Studio is ready to improve the code of Tizen operating system
PVS-Studio is ready to improve the code of Tizen operating system
 
PVS-Studio 5.00, a solution for developers of modern resource-intensive appl...
PVS-Studio 5.00, a solution for developers of modern resource-intensive appl...PVS-Studio 5.00, a solution for developers of modern resource-intensive appl...
PVS-Studio 5.00, a solution for developers of modern resource-intensive appl...
 
Zero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for youZero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for you
 
Anti-Debugging - A Developers View
Anti-Debugging - A Developers ViewAnti-Debugging - A Developers View
Anti-Debugging - A Developers View
 
Processor Verification Using Open Source Tools and the GCC Regression Test Suite
Processor Verification Using Open Source Tools and the GCC Regression Test SuiteProcessor Verification Using Open Source Tools and the GCC Regression Test Suite
Processor Verification Using Open Source Tools and the GCC Regression Test Suite
 
Checking VirtualDub
Checking VirtualDubChecking VirtualDub
Checking VirtualDub
 
PVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's codePVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's code
 
Exploring lambdas and invokedynamic for embedded systems
Exploring lambdas and invokedynamic for embedded systemsExploring lambdas and invokedynamic for embedded systems
Exploring lambdas and invokedynamic for embedded systems
 
Clean code & design patterns
Clean code & design patternsClean code & design patterns
Clean code & design patterns
 
Non-blocking synchronization — what is it and why we (don't?) need it
Non-blocking synchronization — what is it and why we (don't?) need itNon-blocking synchronization — what is it and why we (don't?) need it
Non-blocking synchronization — what is it and why we (don't?) need it
 
OWASP Poland Day 2018 - Pedro Fortuna - Are your Java Script based protection...
OWASP Poland Day 2018 - Pedro Fortuna - Are your Java Script based protection...OWASP Poland Day 2018 - Pedro Fortuna - Are your Java Script based protection...
OWASP Poland Day 2018 - Pedro Fortuna - Are your Java Script based protection...
 
The Little Unicorn That Could
The Little Unicorn That CouldThe Little Unicorn That Could
The Little Unicorn That Could
 
PVS-Studio advertisement - static analysis of C/C++ code
PVS-Studio advertisement - static analysis of C/C++ codePVS-Studio advertisement - static analysis of C/C++ code
PVS-Studio advertisement - static analysis of C/C++ code
 
Documenting Bugs in Doxygen
Documenting Bugs in DoxygenDocumenting Bugs in Doxygen
Documenting Bugs in Doxygen
 
Joel Falcou, Boost.SIMD
Joel Falcou, Boost.SIMDJoel Falcou, Boost.SIMD
Joel Falcou, Boost.SIMD
 

Ähnlich wie How to write clean & testable code without losing your mind

Ähnlich wie How to write clean & testable code without losing your mind (20)

Skiron - Experiments in CPU Design in D
Skiron - Experiments in CPU Design in DSkiron - Experiments in CPU Design in D
Skiron - Experiments in CPU Design in D
 
Discussing Errors in Unity3D's Open-Source Components
Discussing Errors in Unity3D's Open-Source ComponentsDiscussing Errors in Unity3D's Open-Source Components
Discussing Errors in Unity3D's Open-Source Components
 
Analysis of bugs in Orchard CMS
Analysis of bugs in Orchard CMSAnalysis of bugs in Orchard CMS
Analysis of bugs in Orchard CMS
 
100 bugs in Open Source C/C++ projects
100 bugs in Open Source C/C++ projects 100 bugs in Open Source C/C++ projects
100 bugs in Open Source C/C++ projects
 
Book
BookBook
Book
 
PVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's codePVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's code
 
Production Debugging at Code Camp Philly
Production Debugging at Code Camp PhillyProduction Debugging at Code Camp Philly
Production Debugging at Code Camp Philly
 
CodeChecker summary 21062021
CodeChecker summary 21062021CodeChecker summary 21062021
CodeChecker summary 21062021
 
How to be a smart contract engineer
How to be a smart contract engineerHow to be a smart contract engineer
How to be a smart contract engineer
 
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
 
PVS-Studio vs Chromium. 3-rd Check
PVS-Studio vs Chromium. 3-rd CheckPVS-Studio vs Chromium. 3-rd Check
PVS-Studio vs Chromium. 3-rd Check
 
Re-checking the ReactOS project - a large report
Re-checking the ReactOS project - a large reportRe-checking the ReactOS project - a large report
Re-checking the ReactOS project - a large report
 
Consequences of using the Copy-Paste method in C++ programming and how to dea...
Consequences of using the Copy-Paste method in C++ programming and how to dea...Consequences of using the Copy-Paste method in C++ programming and how to dea...
Consequences of using the Copy-Paste method in C++ programming and how to dea...
 
Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016
 
Checking 7-Zip with PVS-Studio analyzer
Checking 7-Zip with PVS-Studio analyzerChecking 7-Zip with PVS-Studio analyzer
Checking 7-Zip with PVS-Studio analyzer
 
A Check of the Open-Source Project WinSCP Developed in Embarcadero C++ Builder
A Check of the Open-Source Project WinSCP Developed in Embarcadero C++ BuilderA Check of the Open-Source Project WinSCP Developed in Embarcadero C++ Builder
A Check of the Open-Source Project WinSCP Developed in Embarcadero C++ Builder
 
powershell-is-dead-epic-learnings-london
powershell-is-dead-epic-learnings-londonpowershell-is-dead-epic-learnings-london
powershell-is-dead-epic-learnings-london
 
Csharp dot net
Csharp dot netCsharp dot net
Csharp dot net
 
PVS-Studio vs Chromium
PVS-Studio vs ChromiumPVS-Studio vs Chromium
PVS-Studio vs Chromium
 
PVS-Studio vs Chromium
PVS-Studio vs ChromiumPVS-Studio vs Chromium
PVS-Studio vs Chromium
 

Kürzlich hochgeladen

%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
masabamasaba
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 

Kürzlich hochgeladen (20)

WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 

How to write clean & testable code without losing your mind

  • 1. APACHE SLING & FRIENDS TECH MEETUP BERLIN, 25-27 SEPTEMBER 2017 How to write clean & testable code without losing your mind - Andreas Czakaj
  • 2. How did you learn what you know today? 2 “There are three kinds of men: 1. The one that learns by reading. 2. The few who learn by observation. 3. The rest of them have to p** on the electric fence for themselves.” -- Will Rogers Source: brainyquote.com this is us learning AEM…
  • 3. Our early experience with AEM 3  Painful upgrades  Slow progress  Hard to change code  Hard to fix bugs  Regression bugs Image: „03-15: At the Dentist“, jlk.1, CC BY-SA 2.0
  • 4. Our early AEM code 4  Low coverage  Expensive tests  Slow & fragile tests  Extensive logging  High coupling  Low cohesion Edvard Munch, “The Scream”, https://en.wikipedia.org/wiki/The_Scream
  • 5. What we actually wanted 5  If you need to maintain, extend and adapt over several years you’ll want…  reliable software  confidence in code  understanding  control  adaptability, extensibility
  • 6. How we actually wanted to work 6  If you need to maintain, extend and adapt over several years you’ll need…  regression tests  high coverage  knowledge management  control over dependencies  high cohesion + low coupling
  • 8. Test Driven/First Development 8  In 2005 I was a freelancer working on a project using Servlets & JSPs, Hibernate & JPA, SOAP etc.  They forced me to do TDD  After some weeks of futile protest…  … I realized how TDD works & why it’s great
  • 9. What IS great about TDD? 9  Fewer bugs (duh!)  Permanently up-to-date documentation  You work faster (fast response, no maven)  You have a tool to check your design decisions  … in a straightforward way
  • 10. Test Driven Development 10  If it’s hard to test it’s likely poorly designed  Focus on creating testable code  For your design decisions you should ask:  what makes the code more testable?  which of my options yields more testable code?
  • 11. Test First Development 11  Write the test first  Write prod. code  Run test  Refactoring  ~ Double-Entry Accounting Account Furniture Cash Test assertEquals( 6, fac(3) ); Prod. Code int fac(int n) { return n > 1 ? n * fac(n-1) : 1; } Debit € 1,500 Credit € 1,500
  • 12. Refactor production code, keep existing tests 12 Test assertEquals( 6, fac(3) ); Prod. Code int fac(final int n) { int out = 1; for (int i = n; i > 1; i--) { out *= i; } return out; }
  • 13. As a result… 13  fewer bugs -> reliable software  high coverage -> control, confidence in code  tests as documentation -> understanding  refactoring -> adaptability, extensibility  -> That’s what we were looking for, right?  -> I’ll tell my AEM developers about it!
  • 14. However, the team was not impressed 14 Your boss telling you to “get 100% coverage” does not work… … especially, when you have to deal with code like this:… Image: Wikipedia, License: Public Domain
  • 15. How do you test THIS? 15 public void onEvent(final EventIterator events) { while (events.hasNext()) { final Event event = events.nextEvent(); Session session = null; Node node = null; try { String path = event.getPath(); if (path.endsWith(JcrConstants.JCR_CONTENT)) { session = repository.login(new Credentials(){/*…*/})); node = session.getNode(path); if (node.hasProperty("cq:template") && “…".equals(node.getProperty("cq:template").getString())){ processExport(node); }} } catch (RepositoryException e) {/*…*/} finally{/*logout*/}}}
  • 16. Team: “Isn’t it obvious?” 16  “We already tried everything™”…  mocks  end-to-end tests  in-container tests  “We can reach some coverage…”  “…but, obviously, it will be a lot of tedious work and pretty expensive”
  • 17. Team decision 17  “You can’t test everything in AEM without losing your mind” Source: pixabay, License: CC0 Creative Commons
  • 18. No need to lose your mind 18  TDD is NOT about testing cleverly  TDD is about writing code in a different way: clever == testable Sigmund Freud, https://de.wikipedia.org/wiki/Datei:Sigmund_Freud_LIFE.jpg
  • 19. Digging into the problem - together 19  We spent some time figuring out new design approaches  Here’s what we found out really works… Image: “Digging the Drain” by International Disaster Volunteers, License: CC BY 2.0
  • 21. Busy, busy method 21 public void onEvent(final EventIterator events) { while (events.hasNext()) { final Event event = events.nextEvent(); Session session = null; Node node = null; try { String path = event.getPath(); if (path.endsWith(JcrConstants.JCR_CONTENT)) { session = repository.login(new Credentials(){/*…*/})); node = session.getNode(path); if (node.hasProperty("cq:template") && “…".equals(node.getProperty("cq:template").getString())){ processExport(node); }} } catch (RepositoryException e) {/*…*/} finally{/*logout*/}}}
  • 22. … in a busy, busy class 22 private void processExport(final Node node) {// original method: ~100 loc try { String group; if (node.hasProperty(PROPERTY_GROUP)) { group = node.getProperty(PROPERTY_GROUP).getString(); } else { LOG.warn("There is no group. Stop export."); return; } /*…*/ File csvFile = File.createTempFile(“…”, "csv"); exportToFile(group, /*…*/, csvFile); /*…*/ } catch(/*…*/) {/*…*/} finally {cleanupTempFiles();/*…*/}
  • 23. Single Responsibility Principle & Clean Code 23  “A class should have only 1 reason to change”  Clean Code: find the “reason(s)”:  Event loop  Data retrieval  Data processing  Export to FileSystem  … in specialized format this part might lead to philosophical debates…
  • 24. Single Responsibility Principle & TDD 24  … or you can look at it from a TDD point of view  TDD: imagine writing tests for it…  -> meh Image “meh” by GalacticWanderlust, License CC BY-ND 2.0
  • 25. The TDD way 25  Don’t be clever at testing…  … instead, aim at fixing the code  Write the tests first…  … then find the code that works best for the tests  Start simple – but be thorough & complete
  • 26. Specify your rules with plain unit tests 26 @Test public void test_toList_allEmpty() throws Exception { List<String> row = exporter.toList(new MyExportData()); assertEquals("It should export nulls as empty strings", Arrays.asList("", ""), row); } /** production code*/ /* … */ items.stream() .filter(item -> item != null) .map(this::toList) .forEach(rowConsumer::accept); // List::add in tests, /* … */ // OutputStream.write in prod code
  • 27. Don’t be clever at testing, fix the code instead 27 class ExportEventListener { public void onEvent(final EventIterator events) { final Dao dao = new DaoJcrImpl(repository); final MyService service = new MyService(dao); while (events.hasNext()) { final Event event = events.nextEvent(); final ProcessingContext ctx = toProcessingContext(event); service.process(ctx);}}} public class MyService { private final Dao dao; private final Exporter exporter; public void process(final ProcessingContext ctx) { final Data data = dao.getData(ctx); exporter.export(data);}}
  • 28. SRP & TDD 28  TDD:  Event loop: simple setup  DAO: AemMock / MockJcrSlingRepository  Data processing: POJOs -> unit testable  Export to FileSystem: using POJOs  Specialized format: plain Java -> unit testable  Service: each “piece” can be replaced by stub
  • 29. SRP & Clean Code 29  Clean Code: 1 class per “reason” / ”concern”  Event loop (Entry point)  Data retrieval (DAO + Adapter)  Data processing (Domain logic)  Export to FileSystem (Gateway)  Specialized export format (Strategy)  Service: integrate pieces (Dependency Injection)
  • 30. TDD & Clean Code 30  Bottom line:  To make TDD work you need to decouple code  … using SRP, DI, “Ports” etc.  … i.e. Clean Code principles  -> TDD will lead you to Clean Code  (… if you stick to the rules…)  But how does it work on application-scale?
  • 32. The Dependency Rule – for AEM 32Inspired by “The Clean Architecture” by Uncle Bob Martin, https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html Enterprise Domain specific Use Cases “source code dependencies can only point inwards” Actros, MPC, Enterp. Rules Trucker Profile, EQP Code, Rules ControllersOSGi SysDate DAOs FS DB JCR SOAP/REST ResourceResolver
  • 33. Simple Example 33  Approach 1 package com.mercedes-benz.trucks.domain; public class Actros { static Actros fromRequest(HttpServletRequest req) {/* … */}; }  Approach 2 package com.mercedes-benz.trucks.integration.web; public class ActrosAdapter { Actros toActros(HttpServletRequest req) {/* … */}; }  => which one works according to the Dependency Rule?
  • 34. Simple Example 34  Approach 1 package com.mercedes-benz.trucks.domain; public class Actros { static Actros fromRequest(HttpServletRequest req) {/* … */}; }  Approach 2 package com.mercedes-benz.trucks.integration.web; public class ActrosAdapter { Actros toActros(HttpServletRequest req) {/* … */}; }  => Keep outer layer dependencies out of inner layers
  • 35. Ports & Adapters / Dependency Inversion 35  “But the Use Cases and Domain objects need data from the outer layers!”  “How can I read from and write to the outer layer without depending on it?”  -> Dependency INVERSION  -> “Ports” (simplified: outer layers behind interfaces)
  • 36. 36 TDD + Dependency Rule = key to success
  • 37. Identify the Domain 37  … yes, it exists  Start at the core: start at the Domain  … it’s the code that’s the easiest to test  -> you’ll start at 100% coverage  … then stay at 100%  -> E.g. keep the ResourceResolver / JCR out of your Domain, Rules and APIs
  • 38. This approach scales & works also for… 38  Services  Models  Components  Workflows  Listeners  …
  • 39. How does it pay off for us in the real world? 39  We reach 100% coverage (in new code)  Sometimes, we still have bugs…  … but mostly in the front end / JavaScript  … or because of production data mismatch  We’re faster  Developers no longer lose their minds ;-)
  • 40. Useful links 40  Ports & Adapters  DAO / Repository Pattern  Clean Architecture / Dependency Rule  3 Rules of TDD / Bowling Game Kata  Single Responsibility Principle  “The more testing you do…”
  • 42. 42 #thx Image: pixabay, License: CC0 Creative Commons
  • 44. #HappyHacking 44 Andreas Czakaj (CTO) mensemedia Gesellschaft für Neue Medien mbH Neumannstr. 10 40235 Düsseldorf Germany Email: andreas.czakaj@mensemedia.net Twitter: @AndreasCzakaj Blog: https://blog.acnebs.com/