SlideShare a Scribd company logo
The Magic of Spring
The Proxy Fairy
Victor Rentea - Independent Trainer VictorRentea.ro @victorrentea
When something is painful
but you can't avoid doing it…
postpone it
When something is painful
but you can't avoid doing it…
delegate it
When something is painful
but you can't avoid doing it…
Do It More Often!
"Bring The Pain Forward!"
Continuous Integration
Pair Programming
Continuous Refactoring
TDD
XP
"Bring The Pain Forward!"
Victor Rentea
14 years of Java
Clean Code Evangelist
VictorRentea.ro
30+ talks, 12 meetups
.NET
Lead Architect
Tech Team Lead and Consultant
Software Craftsman
XP: Pair Programming, Refactoring, TDD
VictorRentea.ro @victorrentea victor.rentea@gmail.com
Independent
Technical Trainer & Coach
HibernateSpring Java 8
Architecture, DDDDesign Patterns
Clean Code Unit Testing, TDD
Java Performance and much more…Scala
180+ days1300 devs6 years
VictorRentea.rovictor.rentea@gmail.com
30 companies
Posting daily on
▪Log the arguments passed to m1()
▪The same for m2(), please
▪And for m3,m4,...m30
▪I love it! I want the same
for all methods in this package
copy-paste
A Success Story
?!!...Argh!!... copy-paste ...
You add a log.debug(...) in m1
You copy-paste in m2 and adjust it
Whaat?!!! ... copy-paste in 110 methods.
You feel bad. For 5 minutes.
Next task...
copy-paste
copy-paste
Time passes by
▪BUG: a method
is not logged !!!%@^!
Time passes by
(2 weeks later)
I’ll put this method here...
▪Please change the log format Oh boy! 1, 2, 3, .. 109, Done!
I  my job!▪BUG: you missed a spot !!!%@^!
A Success Story
▪Log the arguments passed to m1()
▪The same for m2(), please
▪And for m3,m4,...m30
▪I love it! I want the same
for all methods in this package
copy-paste
A Success Story
?!!...Argh!!... copy-paste ...
You add a log.debug(...) in m1
You copy-paste in m2 and adjust it
Whaat?!!! ... copy-paste in 110 methods.
You feel bad. For 5 minutes.
Next task...
copy-paste
copy-paste
Time passes by
copy-pasteNever logic
R
decompose it in smaller methods
and call them as you need
Don’t Repeat Yourself
The Capital Sin in Programming
copy-pastecopy-paste
D Y
What if I could magicaly
intercept method calls
and do stuff for each call ?
Aspect-Oriented Programming
Logging
Transactions
Access Control
Audit
...
“Cross-cutting concerns”:
“But I will still need to add one line in each method!
placeholder intermediating interactions with an object
•The client wants to work with the Real Subject
•But we trick him to intercept his calls, to do
(1) AOP
(2) Remote calls (RMI, Web Services)
Proxy
«interface»
Subject
someMethod()
RealSubject
someMethod()
Proxy
someMethod()
represents
calls
actually uses
generated
do more things in an object’s methods, by composition
• Implement the Subject interface,
execute code before/after/instead calling the real method
➢Can be nested: new Decor1(new Decor2(original));
➢Usually written by hand
Decorator
Proxy«interface»
Subject
someMethod()
RealSubject
someMethod()
Proxy
someMethod()
represents
calls
actually uses
Decorator
delegate
someMethod()
•Decorator + Proxy Patterns
•Interface Proxies
•Class Proxies
•In-depth Spring AOP
•Custom Aspects - Best Practices
Contents
Every time you don’t understand how Spring does something…
it's a Proxy
@Cacheable
@Transactional
@Aspect
@Async
@Secured
@Validated
Request/Thread scope
…
The Magic of Spring
class A {
private B b;
...
}
class BImpl
implements B {
...
}
interface B {
...
}
Interface Proxy
has a
:A
B
:BImpl
implem
call
Static
Runtime
implem
proxy
Created at run-time with
java.lang.reflect.Proxy
class A {
private B b;
...
}
interface B {
...
}
Class Proxy
has a
:A
B
:B
call
Static
Runtime
proxy
Concrete classes are proxyied
via bytecode generation
class B {
extends
*
*
•A method of a non-Spring bean?
•A final method/class?
• For a class-proxy:
•Field access?
•A private method call?
Can AOP Intercept…
NO!
NO!
NO!
Well…
Actually…
You know…
You can do any of that via:
Bytecode Enhancement
(compile-time hacking)
Or Instrumentation
(classload-time hacking)
NO!
•Autowiring yourself ?
•@Autowired ApplicationContext + getBean(T)
•@Autowired ObjectFactory<> + getObject()
•@Lookup method
•AopContext.currentProxy()
Call Yourself via a Proxy
To intercept a local call,
AopContext.currentProxy()
proxy
methodWithTx();
CurrentClass myselfProxied =
(CurrentClass)AopContext.currentProxy();
myselfProxied.methodWithTx();
AopContext.currentProxy()
@Transactional(propagation = REQUIRES_NEW)
public void methodWithTx() {
No More Magic
- an AOP Alternative -
Functional Programming
"Execute Around" Pattern
transactionTemplate.execute(this::methodInNewTx);
I found my code!
The Hamburger Problem
Proxies
What the heck is the rest?!
in front of any class with 1+ methods to intercept
Are you sure you want to know?
stacktrace
How can Aspects
(invisible logic)
communicate?
What is shared?
(within an invocation)
ThreadLocal
(invisible data)
ThreadLocal Data -- what about @Async calls?
Propagate Thread Data
to worker threads
Hunt me
afterwards
•Decorator + Proxy Patterns
•Interface Proxies
•Class Proxies
•In-depth Spring AOP
•Custom Aspects - Best Practices
Contents
@annotation(my.proj.Logged)
annotation-based weaving
Designing Custom Aspects - Best Practices
@Around("execution(* *(..)) && @within(my.proj.Facade))")
public Object logAround(ProceedingJoinPoint point) { … }
make them visible
@Facade
public class ExpensiveOps {
@Logged
public Boolean isPrime(int n) {…}
}
Designing Custom Aspects - Best Practices
"execution(* com.mycomp.proj.facade.*.*(..))"
instead of
package name
or
class name
"execution(* com.mycomp..*DAO.*(..))"
annotation-based weaving
keep them light
Designing Custom Aspects - Best Practices
synchronized
files
database
http
don't intercept insane-rate calls
Designing Custom Aspects - Best Practices
I did that!
don't intercept insane-rate calls
alternatives:
Execute-AroundFP
BeanPostProcessor
CPP
BPP
after init
@PostConstruct
BPP
before init
@Autowired
Designing Custom Aspects - Best Practices
BeanPostProcessor
new
*Technically, each step above hides a bit more work, and more ways to configure
Can return a different instanceproxy
WHY?
Average Error (99.9%) Unit
Cache Method 357.7 ± 11.7
us/op
Decorator 355.1 ± 6.0
Interface Proxy 398.7 ± 28.0
Class Proxy 386.9 ± 17.5
Class Proxy / BPP 373.9 ± 36.0
@Cacheable 8109.8 ± 1097.5
Performance
Details? Run it yourself: https://github.com/victorrentea/proxy-fairy-performance
Leftover Tricks
Designing Custom Aspects - Best Practices
- Double proxying
- @Aspect @Order
- Sharing the PersistenceContext
- Proxies in ORMs
Hunt me
afterwards
Every time you don’t understand how Spring does something…
it's a Proxy
The Magic of Spring
mixins
Spring Data
mixins
CustomerRepository
Customer findByName(String name);
@Query("SELECT c FROM Cust... ")
List<Customer> getActiveCustomers();
JpaRepository<E,ID>
List<E> findAll();
E findOne(ID);
void save(E);
void delete(E); ...
CustomerRepositoryCustom
List<Customer> search(CustomerSearch);
CustomerRepositoryImpl
List<Customer> search(CustomerSearch) {
...<implem>...
}
YourBaseRepository<E,ID>
abc customMethod(xyz);
YourBase
RepositoryImpl
<implem>
naming
rules
✓Proxy + Decorator Patterns; wiring
✓Interface & Class Proxy - under the hood
✓Spring AOP - tricks & limitations
✓Custom Aspects - Best Practices
Key Points
And have a nice Spring!
Thank You!
I'm available
a proof of seniority
I use both hemispheres
Tough meetings?
Abused estimates?
Purpose of code:--Uncle Bob
1. Maintainable
2. Does its job!
Functional Party
Activist
Stay into
The Light
Trainings, Talks, Goodies Daily Posts
Clean Code
needs strength
and determination
Let's chat!
Thanks for review,
Vladimir Sitnikov
Hunt me
down

More Related Content

What's hot

Spring @Transactional Explained
Spring @Transactional ExplainedSpring @Transactional Explained
Spring @Transactional Explained
Victor Rentea
 
Extreme Professionalism - Software Craftsmanship
Extreme Professionalism - Software CraftsmanshipExtreme Professionalism - Software Craftsmanship
Extreme Professionalism - Software Craftsmanship
Victor Rentea
 
The tests are trying to tell you something@VoxxedBucharest.pptx
The tests are trying to tell you something@VoxxedBucharest.pptxThe tests are trying to tell you something@VoxxedBucharest.pptx
The tests are trying to tell you something@VoxxedBucharest.pptx
Victor Rentea
 
The Art of Clean code
The Art of Clean codeThe Art of Clean code
The Art of Clean code
Victor Rentea
 
Clean Code III - Software Craftsmanship
Clean Code III - Software CraftsmanshipClean Code III - Software Craftsmanship
Clean Code III - Software Craftsmanship
Theo Jungeblut
 
Clean pragmatic architecture @ devflix
Clean pragmatic architecture @ devflixClean pragmatic architecture @ devflix
Clean pragmatic architecture @ devflix
Victor Rentea
 
Functional Patterns with Java8 @Bucharest Java User Group
Functional Patterns with Java8 @Bucharest Java User GroupFunctional Patterns with Java8 @Bucharest Java User Group
Functional Patterns with Java8 @Bucharest Java User Group
Victor Rentea
 
Clean Code
Clean CodeClean Code
Clean Code
Victor Rentea
 
Clean Code - The Next Chapter
Clean Code - The Next ChapterClean Code - The Next Chapter
Clean Code - The Next Chapter
Victor Rentea
 
You code sucks, let's fix it
You code sucks, let's fix itYou code sucks, let's fix it
You code sucks, let's fix it
Rafael Dohms
 
Clean Code I - Best Practices
Clean Code I - Best PracticesClean Code I - Best Practices
Clean Code I - Best Practices
Theo Jungeblut
 
Clean Code II - Dependency Injection
Clean Code II - Dependency InjectionClean Code II - Dependency Injection
Clean Code II - Dependency Injection
Theo Jungeblut
 
Clean code: understanding Boundaries and Unit Tests
Clean code: understanding Boundaries and Unit TestsClean code: understanding Boundaries and Unit Tests
Clean code: understanding Boundaries and Unit Tests
radin reth
 
Clean backends with NestJs
Clean backends with NestJsClean backends with NestJs
Clean backends with NestJs
Aymene Bennour
 
Hexagonal architecture in PHP
Hexagonal architecture in PHPHexagonal architecture in PHP
Hexagonal architecture in PHP
Paulo Victor Gomes
 
Clean code
Clean codeClean code
Clean code
ifnu bima
 
Clean architecture - Protecting the Domain
Clean architecture - Protecting the DomainClean architecture - Protecting the Domain
Clean architecture - Protecting the Domain
Victor Rentea
 
OWASP SD: Deserialize My Shorts: Or How I Learned To Start Worrying and Hate ...
OWASP SD: Deserialize My Shorts: Or How I Learned To Start Worrying and Hate ...OWASP SD: Deserialize My Shorts: Or How I Learned To Start Worrying and Hate ...
OWASP SD: Deserialize My Shorts: Or How I Learned To Start Worrying and Hate ...
Christopher Frohoff
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass Slides
Nir Kaufman
 
Clean Code at Silicon Valley Code Camp 2011 (02/17/2012)
Clean Code at Silicon Valley Code Camp 2011 (02/17/2012)Clean Code at Silicon Valley Code Camp 2011 (02/17/2012)
Clean Code at Silicon Valley Code Camp 2011 (02/17/2012)
Theo Jungeblut
 

What's hot (20)

Spring @Transactional Explained
Spring @Transactional ExplainedSpring @Transactional Explained
Spring @Transactional Explained
 
Extreme Professionalism - Software Craftsmanship
Extreme Professionalism - Software CraftsmanshipExtreme Professionalism - Software Craftsmanship
Extreme Professionalism - Software Craftsmanship
 
The tests are trying to tell you something@VoxxedBucharest.pptx
The tests are trying to tell you something@VoxxedBucharest.pptxThe tests are trying to tell you something@VoxxedBucharest.pptx
The tests are trying to tell you something@VoxxedBucharest.pptx
 
The Art of Clean code
The Art of Clean codeThe Art of Clean code
The Art of Clean code
 
Clean Code III - Software Craftsmanship
Clean Code III - Software CraftsmanshipClean Code III - Software Craftsmanship
Clean Code III - Software Craftsmanship
 
Clean pragmatic architecture @ devflix
Clean pragmatic architecture @ devflixClean pragmatic architecture @ devflix
Clean pragmatic architecture @ devflix
 
Functional Patterns with Java8 @Bucharest Java User Group
Functional Patterns with Java8 @Bucharest Java User GroupFunctional Patterns with Java8 @Bucharest Java User Group
Functional Patterns with Java8 @Bucharest Java User Group
 
Clean Code
Clean CodeClean Code
Clean Code
 
Clean Code - The Next Chapter
Clean Code - The Next ChapterClean Code - The Next Chapter
Clean Code - The Next Chapter
 
You code sucks, let's fix it
You code sucks, let's fix itYou code sucks, let's fix it
You code sucks, let's fix it
 
Clean Code I - Best Practices
Clean Code I - Best PracticesClean Code I - Best Practices
Clean Code I - Best Practices
 
Clean Code II - Dependency Injection
Clean Code II - Dependency InjectionClean Code II - Dependency Injection
Clean Code II - Dependency Injection
 
Clean code: understanding Boundaries and Unit Tests
Clean code: understanding Boundaries and Unit TestsClean code: understanding Boundaries and Unit Tests
Clean code: understanding Boundaries and Unit Tests
 
Clean backends with NestJs
Clean backends with NestJsClean backends with NestJs
Clean backends with NestJs
 
Hexagonal architecture in PHP
Hexagonal architecture in PHPHexagonal architecture in PHP
Hexagonal architecture in PHP
 
Clean code
Clean codeClean code
Clean code
 
Clean architecture - Protecting the Domain
Clean architecture - Protecting the DomainClean architecture - Protecting the Domain
Clean architecture - Protecting the Domain
 
OWASP SD: Deserialize My Shorts: Or How I Learned To Start Worrying and Hate ...
OWASP SD: Deserialize My Shorts: Or How I Learned To Start Worrying and Hate ...OWASP SD: Deserialize My Shorts: Or How I Learned To Start Worrying and Hate ...
OWASP SD: Deserialize My Shorts: Or How I Learned To Start Worrying and Hate ...
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass Slides
 
Clean Code at Silicon Valley Code Camp 2011 (02/17/2012)
Clean Code at Silicon Valley Code Camp 2011 (02/17/2012)Clean Code at Silicon Valley Code Camp 2011 (02/17/2012)
Clean Code at Silicon Valley Code Camp 2011 (02/17/2012)
 

Similar to The Proxy Fairy, and The Magic of Spring Framework

Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...
Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...
Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...
Spark Summit
 
Neal Ford Emergent Design And Evolutionary Architecture
Neal Ford Emergent Design And Evolutionary ArchitectureNeal Ford Emergent Design And Evolutionary Architecture
Neal Ford Emergent Design And Evolutionary Architecture
Thoughtworks
 
Node azure
Node azureNode azure
Node azure
Emanuele DelBono
 
Robotlegs on Top of Gaia
Robotlegs on Top of GaiaRobotlegs on Top of Gaia
Robotlegs on Top of Gaia
Jesse Warden
 
What's new in CQ 5.3? Top 10 features.
What's new in CQ 5.3? Top 10 features.What's new in CQ 5.3? Top 10 features.
What's new in CQ 5.3? Top 10 features.
David Nuescheler
 
The "Holy Grail" of Dev/Ops
The "Holy Grail" of Dev/OpsThe "Holy Grail" of Dev/Ops
The "Holy Grail" of Dev/Ops
Erik Osterman
 
Deploying 3 times a day without a downtime @ Rocket Tech Summit in Berlin
Deploying 3 times a day without a downtime @ Rocket Tech Summit in BerlinDeploying 3 times a day without a downtime @ Rocket Tech Summit in Berlin
Deploying 3 times a day without a downtime @ Rocket Tech Summit in Berlin
Alessandro Nadalin
 
Functional solid
Functional solidFunctional solid
Functional solid
Matt Stine
 
Modular Web Applications With Netzke
Modular Web Applications With NetzkeModular Web Applications With Netzke
Modular Web Applications With Netzke
netzke
 
What’s new in Google Dart - Seth Ladd
What’s new in Google Dart - Seth LaddWhat’s new in Google Dart - Seth Ladd
What’s new in Google Dart - Seth Ladd
jaxconf
 
From Elixir to Akka (and back) - ElixirConf Mx 2017
From Elixir to Akka (and back) - ElixirConf Mx 2017From Elixir to Akka (and back) - ElixirConf Mx 2017
From Elixir to Akka (and back) - ElixirConf Mx 2017
Agustin Ramos
 
System insight without Interference
System insight without InterferenceSystem insight without Interference
System insight without Interference
Tony Tam
 
Protect Your Payloads: Modern Keying Techniques
Protect Your Payloads: Modern Keying TechniquesProtect Your Payloads: Modern Keying Techniques
Protect Your Payloads: Modern Keying Techniques
Leo Loobeek
 
the productive programer: mechanics
the productive programer: mechanicsthe productive programer: mechanics
the productive programer: mechanicselliando dias
 
Introduction to TypeScript
Introduction to TypeScriptIntroduction to TypeScript
Introduction to TypeScript
Jeremy Likness
 
Evolving a Clean, Pragmatic Architecture at JBCNConf 2019
Evolving a Clean, Pragmatic Architecture at JBCNConf 2019Evolving a Clean, Pragmatic Architecture at JBCNConf 2019
Evolving a Clean, Pragmatic Architecture at JBCNConf 2019
Victor Rentea
 

Similar to The Proxy Fairy, and The Magic of Spring Framework (20)

All of javascript
All of javascriptAll of javascript
All of javascript
 
Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...
Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...
Bulletproof Jobs: Patterns for Large-Scale Spark Processing: Spark Summit Eas...
 
All of Javascript
All of JavascriptAll of Javascript
All of Javascript
 
Neal Ford Emergent Design And Evolutionary Architecture
Neal Ford Emergent Design And Evolutionary ArchitectureNeal Ford Emergent Design And Evolutionary Architecture
Neal Ford Emergent Design And Evolutionary Architecture
 
Node azure
Node azureNode azure
Node azure
 
Java scriptforjavadev part2a
Java scriptforjavadev part2aJava scriptforjavadev part2a
Java scriptforjavadev part2a
 
Robotlegs on Top of Gaia
Robotlegs on Top of GaiaRobotlegs on Top of Gaia
Robotlegs on Top of Gaia
 
What's new in CQ 5.3? Top 10 features.
What's new in CQ 5.3? Top 10 features.What's new in CQ 5.3? Top 10 features.
What's new in CQ 5.3? Top 10 features.
 
The "Holy Grail" of Dev/Ops
The "Holy Grail" of Dev/OpsThe "Holy Grail" of Dev/Ops
The "Holy Grail" of Dev/Ops
 
Deploying 3 times a day without a downtime @ Rocket Tech Summit in Berlin
Deploying 3 times a day without a downtime @ Rocket Tech Summit in BerlinDeploying 3 times a day without a downtime @ Rocket Tech Summit in Berlin
Deploying 3 times a day without a downtime @ Rocket Tech Summit in Berlin
 
Functional solid
Functional solidFunctional solid
Functional solid
 
Modular Web Applications With Netzke
Modular Web Applications With NetzkeModular Web Applications With Netzke
Modular Web Applications With Netzke
 
What’s new in Google Dart - Seth Ladd
What’s new in Google Dart - Seth LaddWhat’s new in Google Dart - Seth Ladd
What’s new in Google Dart - Seth Ladd
 
From Elixir to Akka (and back) - ElixirConf Mx 2017
From Elixir to Akka (and back) - ElixirConf Mx 2017From Elixir to Akka (and back) - ElixirConf Mx 2017
From Elixir to Akka (and back) - ElixirConf Mx 2017
 
System insight without Interference
System insight without InterferenceSystem insight without Interference
System insight without Interference
 
Protect Your Payloads: Modern Keying Techniques
Protect Your Payloads: Modern Keying TechniquesProtect Your Payloads: Modern Keying Techniques
Protect Your Payloads: Modern Keying Techniques
 
the productive programer: mechanics
the productive programer: mechanicsthe productive programer: mechanics
the productive programer: mechanics
 
Introduction to TypeScript
Introduction to TypeScriptIntroduction to TypeScript
Introduction to TypeScript
 
The Joy Of Ruby
The Joy Of RubyThe Joy Of Ruby
The Joy Of Ruby
 
Evolving a Clean, Pragmatic Architecture at JBCNConf 2019
Evolving a Clean, Pragmatic Architecture at JBCNConf 2019Evolving a Clean, Pragmatic Architecture at JBCNConf 2019
Evolving a Clean, Pragmatic Architecture at JBCNConf 2019
 

More from Victor Rentea

Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
Microservice Resilience Patterns @VoxxedCern'24
Microservice Resilience Patterns @VoxxedCern'24Microservice Resilience Patterns @VoxxedCern'24
Microservice Resilience Patterns @VoxxedCern'24
Victor Rentea
 
Distributed Consistency.pdf
Distributed Consistency.pdfDistributed Consistency.pdf
Distributed Consistency.pdf
Victor Rentea
 
Testing Microservices @DevoxxBE 23.pdf
Testing Microservices @DevoxxBE 23.pdfTesting Microservices @DevoxxBE 23.pdf
Testing Microservices @DevoxxBE 23.pdf
Victor Rentea
 
From Web to Flux @DevoxxBE 2023.pptx
From Web to Flux @DevoxxBE 2023.pptxFrom Web to Flux @DevoxxBE 2023.pptx
From Web to Flux @DevoxxBE 2023.pptx
Victor Rentea
 
Test-Driven Design Insights@DevoxxBE 2023.pptx
Test-Driven Design Insights@DevoxxBE 2023.pptxTest-Driven Design Insights@DevoxxBE 2023.pptx
Test-Driven Design Insights@DevoxxBE 2023.pptx
Victor Rentea
 
Profiling your Java Application
Profiling your Java ApplicationProfiling your Java Application
Profiling your Java Application
Victor Rentea
 
OAuth in the Wild
OAuth in the WildOAuth in the Wild
OAuth in the Wild
Victor Rentea
 
Vertical Slicing Architectures
Vertical Slicing ArchitecturesVertical Slicing Architectures
Vertical Slicing Architectures
Victor Rentea
 
Software Craftsmanship @Code Camp Festival 2022.pdf
Software Craftsmanship @Code Camp Festival 2022.pdfSoftware Craftsmanship @Code Camp Festival 2022.pdf
Software Craftsmanship @Code Camp Festival 2022.pdf
Victor Rentea
 
Unit testing - 9 design hints
Unit testing - 9 design hintsUnit testing - 9 design hints
Unit testing - 9 design hints
Victor Rentea
 
Refactoring blockers and code smells @jNation 2021
Refactoring   blockers and code smells @jNation 2021Refactoring   blockers and code smells @jNation 2021
Refactoring blockers and code smells @jNation 2021
Victor Rentea
 
Hibernate and Spring - Unleash the Magic
Hibernate and Spring - Unleash the MagicHibernate and Spring - Unleash the Magic
Hibernate and Spring - Unleash the Magic
Victor Rentea
 
Integration testing with spring @JAX Mainz
Integration testing with spring @JAX MainzIntegration testing with spring @JAX Mainz
Integration testing with spring @JAX Mainz
Victor Rentea
 
The Proxy Fairy and the Magic of Spring @JAX Mainz 2021
The Proxy Fairy and the Magic of Spring @JAX Mainz 2021The Proxy Fairy and the Magic of Spring @JAX Mainz 2021
The Proxy Fairy and the Magic of Spring @JAX Mainz 2021
Victor Rentea
 
Pure functions and immutable objects @dev nexus 2021
Pure functions and immutable objects @dev nexus 2021Pure functions and immutable objects @dev nexus 2021
Pure functions and immutable objects @dev nexus 2021
Victor Rentea
 
TDD Mantra
TDD MantraTDD Mantra
TDD Mantra
Victor Rentea
 
Definitive Guide to Working With Exceptions in Java - takj at Java Champions ...
Definitive Guide to Working With Exceptions in Java - takj at Java Champions ...Definitive Guide to Working With Exceptions in Java - takj at Java Champions ...
Definitive Guide to Working With Exceptions in Java - takj at Java Champions ...
Victor Rentea
 
Pure Functions and Immutable Objects
Pure Functions and Immutable ObjectsPure Functions and Immutable Objects
Pure Functions and Immutable Objects
Victor Rentea
 

More from Victor Rentea (20)

Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Microservice Resilience Patterns @VoxxedCern'24
Microservice Resilience Patterns @VoxxedCern'24Microservice Resilience Patterns @VoxxedCern'24
Microservice Resilience Patterns @VoxxedCern'24
 
Distributed Consistency.pdf
Distributed Consistency.pdfDistributed Consistency.pdf
Distributed Consistency.pdf
 
Testing Microservices @DevoxxBE 23.pdf
Testing Microservices @DevoxxBE 23.pdfTesting Microservices @DevoxxBE 23.pdf
Testing Microservices @DevoxxBE 23.pdf
 
From Web to Flux @DevoxxBE 2023.pptx
From Web to Flux @DevoxxBE 2023.pptxFrom Web to Flux @DevoxxBE 2023.pptx
From Web to Flux @DevoxxBE 2023.pptx
 
Test-Driven Design Insights@DevoxxBE 2023.pptx
Test-Driven Design Insights@DevoxxBE 2023.pptxTest-Driven Design Insights@DevoxxBE 2023.pptx
Test-Driven Design Insights@DevoxxBE 2023.pptx
 
Profiling your Java Application
Profiling your Java ApplicationProfiling your Java Application
Profiling your Java Application
 
OAuth in the Wild
OAuth in the WildOAuth in the Wild
OAuth in the Wild
 
Vertical Slicing Architectures
Vertical Slicing ArchitecturesVertical Slicing Architectures
Vertical Slicing Architectures
 
Software Craftsmanship @Code Camp Festival 2022.pdf
Software Craftsmanship @Code Camp Festival 2022.pdfSoftware Craftsmanship @Code Camp Festival 2022.pdf
Software Craftsmanship @Code Camp Festival 2022.pdf
 
Unit testing - 9 design hints
Unit testing - 9 design hintsUnit testing - 9 design hints
Unit testing - 9 design hints
 
Refactoring blockers and code smells @jNation 2021
Refactoring   blockers and code smells @jNation 2021Refactoring   blockers and code smells @jNation 2021
Refactoring blockers and code smells @jNation 2021
 
Hibernate and Spring - Unleash the Magic
Hibernate and Spring - Unleash the MagicHibernate and Spring - Unleash the Magic
Hibernate and Spring - Unleash the Magic
 
Integration testing with spring @JAX Mainz
Integration testing with spring @JAX MainzIntegration testing with spring @JAX Mainz
Integration testing with spring @JAX Mainz
 
The Proxy Fairy and the Magic of Spring @JAX Mainz 2021
The Proxy Fairy and the Magic of Spring @JAX Mainz 2021The Proxy Fairy and the Magic of Spring @JAX Mainz 2021
The Proxy Fairy and the Magic of Spring @JAX Mainz 2021
 
Pure functions and immutable objects @dev nexus 2021
Pure functions and immutable objects @dev nexus 2021Pure functions and immutable objects @dev nexus 2021
Pure functions and immutable objects @dev nexus 2021
 
TDD Mantra
TDD MantraTDD Mantra
TDD Mantra
 
Definitive Guide to Working With Exceptions in Java - takj at Java Champions ...
Definitive Guide to Working With Exceptions in Java - takj at Java Champions ...Definitive Guide to Working With Exceptions in Java - takj at Java Champions ...
Definitive Guide to Working With Exceptions in Java - takj at Java Champions ...
 
Pure Functions and Immutable Objects
Pure Functions and Immutable ObjectsPure Functions and Immutable Objects
Pure Functions and Immutable Objects
 

Recently uploaded

First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
Globus
 
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Shahin Sheidaei
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
XfilesPro
 
Software Testing Exam imp Ques Notes.pdf
Software Testing Exam imp Ques Notes.pdfSoftware Testing Exam imp Ques Notes.pdf
Software Testing Exam imp Ques Notes.pdf
MayankTawar1
 
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoamOpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
takuyayamamoto1800
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Globus
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
Tier1 app
 
A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdf
kalichargn70th171
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
Ortus Solutions, Corp
 
Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024
Sharepoint Designs
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
Paco van Beckhoven
 
Using IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New ZealandUsing IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New Zealand
IES VE
 
Strategies for Successful Data Migration Tools.pptx
Strategies for Successful Data Migration Tools.pptxStrategies for Successful Data Migration Tools.pptx
Strategies for Successful Data Migration Tools.pptx
varshanayak241
 
How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
Globus
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2
 
Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
Tendenci - The Open Source AMS (Association Management Software)
 
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
XfilesPro
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
abdulrafaychaudhry
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
Globus
 

Recently uploaded (20)

First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
 
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
 
Software Testing Exam imp Ques Notes.pdf
Software Testing Exam imp Ques Notes.pdfSoftware Testing Exam imp Ques Notes.pdf
Software Testing Exam imp Ques Notes.pdf
 
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoamOpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
 
A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdf
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
 
Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
 
Using IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New ZealandUsing IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New Zealand
 
Strategies for Successful Data Migration Tools.pptx
Strategies for Successful Data Migration Tools.pptxStrategies for Successful Data Migration Tools.pptx
Strategies for Successful Data Migration Tools.pptx
 
How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
 
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
 

The Proxy Fairy, and The Magic of Spring Framework

  • 1. The Magic of Spring The Proxy Fairy Victor Rentea - Independent Trainer VictorRentea.ro @victorrentea
  • 2. When something is painful but you can't avoid doing it… postpone it
  • 3. When something is painful but you can't avoid doing it… delegate it
  • 4. When something is painful but you can't avoid doing it… Do It More Often! "Bring The Pain Forward!"
  • 5. Continuous Integration Pair Programming Continuous Refactoring TDD XP "Bring The Pain Forward!"
  • 6. Victor Rentea 14 years of Java Clean Code Evangelist VictorRentea.ro 30+ talks, 12 meetups .NET Lead Architect Tech Team Lead and Consultant Software Craftsman XP: Pair Programming, Refactoring, TDD
  • 7. VictorRentea.ro @victorrentea victor.rentea@gmail.com Independent Technical Trainer & Coach HibernateSpring Java 8 Architecture, DDDDesign Patterns Clean Code Unit Testing, TDD Java Performance and much more…Scala 180+ days1300 devs6 years VictorRentea.rovictor.rentea@gmail.com 30 companies Posting daily on
  • 8.
  • 9.
  • 10.
  • 11.
  • 12. ▪Log the arguments passed to m1() ▪The same for m2(), please ▪And for m3,m4,...m30 ▪I love it! I want the same for all methods in this package copy-paste A Success Story ?!!...Argh!!... copy-paste ... You add a log.debug(...) in m1 You copy-paste in m2 and adjust it Whaat?!!! ... copy-paste in 110 methods. You feel bad. For 5 minutes. Next task... copy-paste copy-paste Time passes by
  • 13. ▪BUG: a method is not logged !!!%@^! Time passes by (2 weeks later) I’ll put this method here... ▪Please change the log format Oh boy! 1, 2, 3, .. 109, Done! I  my job!▪BUG: you missed a spot !!!%@^! A Success Story
  • 14.
  • 15. ▪Log the arguments passed to m1() ▪The same for m2(), please ▪And for m3,m4,...m30 ▪I love it! I want the same for all methods in this package copy-paste A Success Story ?!!...Argh!!... copy-paste ... You add a log.debug(...) in m1 You copy-paste in m2 and adjust it Whaat?!!! ... copy-paste in 110 methods. You feel bad. For 5 minutes. Next task... copy-paste copy-paste Time passes by
  • 16. copy-pasteNever logic R decompose it in smaller methods and call them as you need Don’t Repeat Yourself The Capital Sin in Programming copy-pastecopy-paste D Y
  • 17. What if I could magicaly intercept method calls and do stuff for each call ? Aspect-Oriented Programming Logging Transactions Access Control Audit ... “Cross-cutting concerns”: “But I will still need to add one line in each method!
  • 18. placeholder intermediating interactions with an object •The client wants to work with the Real Subject •But we trick him to intercept his calls, to do (1) AOP (2) Remote calls (RMI, Web Services) Proxy «interface» Subject someMethod() RealSubject someMethod() Proxy someMethod() represents calls actually uses generated
  • 19. do more things in an object’s methods, by composition • Implement the Subject interface, execute code before/after/instead calling the real method ➢Can be nested: new Decor1(new Decor2(original)); ➢Usually written by hand Decorator Proxy«interface» Subject someMethod() RealSubject someMethod() Proxy someMethod() represents calls actually uses Decorator delegate someMethod()
  • 20. •Decorator + Proxy Patterns •Interface Proxies •Class Proxies •In-depth Spring AOP •Custom Aspects - Best Practices Contents
  • 21.
  • 22. Every time you don’t understand how Spring does something… it's a Proxy @Cacheable @Transactional @Aspect @Async @Secured @Validated Request/Thread scope … The Magic of Spring
  • 23. class A { private B b; ... } class BImpl implements B { ... } interface B { ... } Interface Proxy has a :A B :BImpl implem call Static Runtime implem proxy Created at run-time with java.lang.reflect.Proxy
  • 24. class A { private B b; ... } interface B { ... } Class Proxy has a :A B :B call Static Runtime proxy Concrete classes are proxyied via bytecode generation class B { extends * *
  • 25. •A method of a non-Spring bean? •A final method/class? • For a class-proxy: •Field access? •A private method call? Can AOP Intercept… NO! NO! NO! Well… Actually… You know… You can do any of that via: Bytecode Enhancement (compile-time hacking) Or Instrumentation (classload-time hacking) NO!
  • 26. •Autowiring yourself ? •@Autowired ApplicationContext + getBean(T) •@Autowired ObjectFactory<> + getObject() •@Lookup method •AopContext.currentProxy() Call Yourself via a Proxy To intercept a local call, AopContext.currentProxy()
  • 29. - an AOP Alternative - Functional Programming "Execute Around" Pattern transactionTemplate.execute(this::methodInNewTx);
  • 30. I found my code! The Hamburger Problem Proxies What the heck is the rest?! in front of any class with 1+ methods to intercept Are you sure you want to know? stacktrace
  • 31. How can Aspects (invisible logic) communicate? What is shared? (within an invocation) ThreadLocal (invisible data)
  • 32.
  • 33. ThreadLocal Data -- what about @Async calls? Propagate Thread Data to worker threads Hunt me afterwards
  • 34. •Decorator + Proxy Patterns •Interface Proxies •Class Proxies •In-depth Spring AOP •Custom Aspects - Best Practices Contents
  • 35. @annotation(my.proj.Logged) annotation-based weaving Designing Custom Aspects - Best Practices @Around("execution(* *(..)) && @within(my.proj.Facade))") public Object logAround(ProceedingJoinPoint point) { … } make them visible @Facade public class ExpensiveOps { @Logged public Boolean isPrime(int n) {…} }
  • 36. Designing Custom Aspects - Best Practices "execution(* com.mycomp.proj.facade.*.*(..))" instead of package name or class name "execution(* com.mycomp..*DAO.*(..))" annotation-based weaving
  • 37. keep them light Designing Custom Aspects - Best Practices synchronized files database http don't intercept insane-rate calls
  • 38. Designing Custom Aspects - Best Practices I did that! don't intercept insane-rate calls alternatives: Execute-AroundFP BeanPostProcessor CPP
  • 39. BPP after init @PostConstruct BPP before init @Autowired Designing Custom Aspects - Best Practices BeanPostProcessor new *Technically, each step above hides a bit more work, and more ways to configure Can return a different instanceproxy WHY?
  • 40. Average Error (99.9%) Unit Cache Method 357.7 ± 11.7 us/op Decorator 355.1 ± 6.0 Interface Proxy 398.7 ± 28.0 Class Proxy 386.9 ± 17.5 Class Proxy / BPP 373.9 ± 36.0 @Cacheable 8109.8 ± 1097.5 Performance Details? Run it yourself: https://github.com/victorrentea/proxy-fairy-performance
  • 41. Leftover Tricks Designing Custom Aspects - Best Practices - Double proxying - @Aspect @Order - Sharing the PersistenceContext - Proxies in ORMs Hunt me afterwards
  • 42. Every time you don’t understand how Spring does something… it's a Proxy The Magic of Spring mixins
  • 43. Spring Data mixins CustomerRepository Customer findByName(String name); @Query("SELECT c FROM Cust... ") List<Customer> getActiveCustomers(); JpaRepository<E,ID> List<E> findAll(); E findOne(ID); void save(E); void delete(E); ... CustomerRepositoryCustom List<Customer> search(CustomerSearch); CustomerRepositoryImpl List<Customer> search(CustomerSearch) { ...<implem>... } YourBaseRepository<E,ID> abc customMethod(xyz); YourBase RepositoryImpl <implem> naming rules
  • 44. ✓Proxy + Decorator Patterns; wiring ✓Interface & Class Proxy - under the hood ✓Spring AOP - tricks & limitations ✓Custom Aspects - Best Practices Key Points
  • 45.
  • 46. And have a nice Spring! Thank You! I'm available a proof of seniority I use both hemispheres Tough meetings? Abused estimates? Purpose of code:--Uncle Bob 1. Maintainable 2. Does its job! Functional Party Activist Stay into The Light Trainings, Talks, Goodies Daily Posts Clean Code needs strength and determination Let's chat! Thanks for review, Vladimir Sitnikov Hunt me down