SlideShare une entreprise Scribd logo
1  sur  236
Télécharger pour lire hors ligne
Yann-Gaël Guéhéneuc
(/jan/, he/il)
Work licensed under Creative Commons
BY-NC-SA 4.0 International
Architecture, Design, and
Implementation in Action
yann-gael.gueheneuc@polytmtl.ca
Version 2.1
24/03/29
2/236
Patterns
 Patterns document reusable solutions to
recurring problems
– Architecture
• Architectural styles
– Design
• Design patterns
• Design anti-patterns
– Implementation
• Idioms
3/236
Example
 Do you know
– C++?
– Java?
– Lisp?
– Prolog?
– Smalltalk?
4/236
C++
class Dog {
string name;
Dog(const Dog* dog) : name(dog→
→
→
→name) {}}
class Kennel { Dog* dog; string name; }
if (&kennel != this) {
this→
→
→
→dog =
new Dog(kennel.dog);
this→
→
→
→name = kennel.name;
}
return *this;
Suite…
Bruce Eckel ; Thinking in C++ ; Volume 2, pages 551–553, Planet PDF, 2nd Edition, 2000.
5/236
C++
class Dog {
string name;
Dog(const Dog* dog) : name(dog→
→
→
→name) {}}
class Kennel { Dog* dog; string name; }
if (&kennel != this) {
this→
→
→
→dog =
new Dog(kennel.dog);
this→
→
→
→name = kennel.name;
}
return *this;
Suite…
Bruce Eckel ; Thinking in C++ ; Volume 2, pages 551–553, Planet PDF, 2nd Edition, 2000.
?
6/236
C++
class Dog {
string name;
Dog(const Dog* dog) : name(dog→
→
→
→name) {}}
class Kennel { Dog* dog; string name; }
if (&kennel != this) {
this→
→
→
→dog =
new Dog(kennel.dog);
this→
→
→
→name = kennel.name;
}
return *this;
Suite…
Bruce Eckel ; Thinking in C++ ; Volume 2, pages 551–553, Planet PDF, 2nd Edition, 2000.
?
Overriding of
operator =
7/236
Java
final Object oldListOfEntities =
this.listOfEntities();
this.fireVetoableChange(
"RemoveEntity",
oldListOfEntities,
anEntity);
this.removeEntity(anEntity);
this.firePropertyChange(
"RemoveEntity",
oldListOfEntities,
anEntity);
Suite…
8/236
Java
final Object oldListOfEntities =
this.listOfEntities();
this.fireVetoableChange(
"RemoveEntity",
oldListOfEntities,
anEntity);
this.removeEntity(anEntity);
this.firePropertyChange(
"RemoveEntity",
oldListOfEntities,
anEntity);
Suite…
?
9/236
Java
final Object oldListOfEntities =
this.listOfEntities();
this.fireVetoableChange(
"RemoveEntity",
oldListOfEntities,
anEntity);
this.removeEntity(anEntity);
this.firePropertyChange(
"RemoveEntity",
oldListOfEntities,
anEntity);
Suite…
?
Veto protocol
of JavaBeans
10/236
(define (square ls)
(if (null? ls)
'()
(cons (( lambda(x) (* x x))
(car ls))
(square (cdr ls)))))
Lisp
Suite…
11/236
(define (square ls)
(if (null? ls)
'()
(cons (( lambda(x) (* x x))
(car ls))
(square (cdr ls)))))
Lisp
Suite…
?
12/236
(define (square ls)
(if (null? ls)
'()
(cons (( lambda(x) (* x x))
(car ls))
(square (cdr ls)))))
Lisp
Suite…
?
Map
13/236
Prolog
checkLt0(LA, LT, LD, NNLA, NNLT, NNLD) :-
nextEvent(
[],
E),
interpretEvent(E, IE),
checkLt1(IE, LA, LT, LD, NLA, NLT, NLD),
!,
(
(IE = programEnd,
NNLA = NLA,
NNLT = NLT,
NNLD = NLD)
;
checkLt0(NLA, NLT, NLD, NNLA, NNLT, NNLD)
).
Suite…
14/236
Prolog
checkLt0(LA, LT, LD, NNLA, NNLT, NNLD) :-
nextEvent(
[],
E),
interpretEvent(E, IE),
checkLt1(IE, LA, LT, LD, NLA, NLT, NLD),
!,
(
(IE = programEnd,
NNLA = NLA,
NNLT = NLT,
NNLD = NLD)
;
checkLt0(NLA, NLT, NLD, NNLA, NNLT, NNLD)
).
?
Suite…
15/236
Prolog
checkLt0(LA, LT, LD, NNLA, NNLT, NNLD) :-
nextEvent(
[],
E),
interpretEvent(E, IE),
checkLt1(IE, LA, LT, LD, NLA, NLT, NLD),
!,
(
(IE = programEnd,
NNLA = NLA,
NNLT = NLT,
NNLD = NLD)
;
checkLt0(NLA, NLT, NLD, NNLA, NNLT, NNLD)
).
?
Condition
Suite…
16/236
Smalltalk
Integer>>+ aNumber
^aNumber addInteger: self
Float>>+ aNumber
^aNumber addFloat: self
Integer>>addInteger: anInteger
<primitive: 1>
Float>>addFloat: aFloat
<primitive: 2>
Integer>>addFloat: aFloat
^self asFloat addFloat: aFloat
Float>>addInteger: anInteger
^self addFloat: anInteger asFloat
Kent Beck ; Smalltalk – Best practice patterns ; Pages 55–57, Prentice Hall, 1997, ISBN 0-13-476904-X.
17/236
Smalltalk
Integer>>+ aNumber
^aNumber addInteger: self
Float>>+ aNumber
^aNumber addFloat: self
Integer>>addInteger: anInteger
<primitive: 1>
Float>>addFloat: aFloat
<primitive: 2>
Integer>>addFloat: aFloat
^self asFloat addFloat: aFloat
Float>>addInteger: anInteger
^self addFloat: anInteger asFloat
Kent Beck ; Smalltalk – Best practice patterns ; Pages 55–57, Prentice Hall, 1997, ISBN 0-13-476904-X.
?
18/236
Smalltalk
Integer>>+ aNumber
^aNumber addInteger: self
Float>>+ aNumber
^aNumber addFloat: self
Integer>>addInteger: anInteger
<primitive: 1>
Float>>addFloat: aFloat
<primitive: 2>
Integer>>addFloat: aFloat
^self asFloat addFloat: aFloat
Float>>addInteger: anInteger
^self addFloat: anInteger asFloat
Kent Beck ; Smalltalk – Best practice patterns ; Pages 55–57, Prentice Hall, 1997, ISBN 0-13-476904-X.
?
Double
dispatching
19/236
Conclusion on the Example
 You identified idioms in the given pieces of
source code
 These idioms are motifs in a program source
code
 These motifs connote a recognized style of
programming
20/236
Motivations
 To ease the understanding of a program
architecture to improve its quality
 To identify motifs in the program
architecture
21/236
Outline
 Introduction
– Patterns
– Case Study
 Patterns
– Process
– Architecture
– Design
– Implementation
 Conclusion
22/236
Outline
 Introduction
– Patterns
– Case Study
 Patterns
– Process
– Architecture
– Design
– Implementation
 Conclusion
23/236
Patterns
 Several books, articles
– “Theoretical”
– With examples
– Among others…
24/236
Patterns
 Several books, articles
– “Theoretical”
– With examples
– Among others…
25/236
Patterns
 Several books, articles
– “Theoretical”
– With examples
– Among others…
26/236
Patterns
 Several books, articles
– “Theoretical”
– With examples
– Among others…
27/236
Patterns
 Several books, articles
– “Theoretical”
– With examples
– Among others…
28/236
Patterns
 Several books, articles
– “Theoretical”
– With examples
– Among others…
29/236
Patterns
 Several books, articles
– Amazon.com
• Books › Computers & Technology › Programming ›
Software Design, Testing & Engineering › Object-
Oriented Design › "patterns"
• 224 results on May 31, 2013
30/236
Patterns
 Several books, articles
– Amazon.com
• Exclusion
– Unreleased books
– Specific to a technology or frameworks
» e.g., MVVM Unleashed by Michael Brown
– Process oriented, user-interface, programming languages
» e.g., Process Patterns: Building Large-Scale Systems
Using Object Technology by Scott W. Ambler and
Barbara Hanscome
– Proceedings of conferences
– Unrelated to software engineering
31/236
Patterns
1. Pattern-Oriented Software Architecture, Patterns for Concurrent and Networked Objects: Volume 2 (Wiley Software...
by Douglas C. Schmidt, Michael Stal, Hans Rohnert and Frank Buschmann
2. Pattern-Oriented Software Architecture, Patterns for Resource Management: Volume 3 (Wiley Software Patterns
Series... by Michael Kircher and Prashant Jain
3. Pattern-Oriented Software Architecture, A System of Patterns: Volume 1 (Wiley Software Patterns Series) by Frank
Buschmann, Regine Meunier, Hans Rohnert and Peter Sommerlad
4. Pattern-Oriented Software Architecture For Dummies (For Dummies (Computers)) by Robert Hanmer
5. Web Security Patterns by Ramesh Nagappan and Christopher Steel
6. Safe C++ by Vladimir Kushnir
7. Programming in the Large with Design Patterns by Eddie Burris
8. Elemental Design Patterns by Jason McC. Smith
9. Java Application Architecture: Modularity Patterns with Examples Using OSGi (Robert C. Martin Series) by Kirk
Knoernschild
10. Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions (Addison-Wesley
Signature... by Gregor Hohpe and Bobby Woolf
11. Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler)) by Martin Fowler
12. Cognitive Patterns: Problem-Solving Frameworks for Object Technology by Robert K Konitzer, Bobbin Teegarden,
Alexander Rush and Karen M Gardner
13. Service Design Patterns: Fundamental Design Solutions for SOAP/WSDL and RESTful Web Services by Robert
Daigneau
14. The ACE Programmer's Guide: Practical Design Patterns for Network and Systems Programming by Stephen D.
Huston, James CE Johnson and Umar Syyid
15. Patterns for Parallel Software Design (Wiley Software Patterns Series) by Jorge Luis Ortega-Arjona
16. Design Patterns in Object-oriented ABAP by Igor Barbaric
17. Object-Oriented Reengineering Patterns by Oscar Nierstrasz, Stéphane Ducasse and Serge Demeyer
18. Dependency Injection by Dhanji R. Prasanna
19. Object-Oriented Software Engineering Using UML, Patterns, and Java (3rd Edition) by Bernd Bruegge and Allen H.
Dutoit
20. J2EE Design Patterns by William Crawford and Jonathan Kaplan
21. Applying UML and Patterns: An Introduction to Object-oriented Analysis and Design and Iterative Development by
Craig Larman
22. Object-oriented Analysis and Design Using Umlan Introduction to Unified Process and Design Patterns by Mahesh P.
Matha
23. C++ Design Patterns and Derivatives Pricing (Mathematics, Finance and Risk) by M. S. Joshi
24. Effective Java (2nd Edition) by Joshua Bloch
25. Patterns for Fault Tolerant Software (Wiley Software Patterns Series) by Robert Hanmer
26. Implementation Patterns by Kent Beck
27. Patterns for Computer-Mediated Interaction (Wiley Software Patterns Series) by Till Schummer and Stephan Lukosch
28. Pattern Oriented Software Architecture Volume 5: On Patterns and Pattern Languages by Frank Buschmann, Kevlin
Henney and Douglas C. Schmidt
29. Object-Oriented Analysis and Design with Applications (3rd Edition) by Grady Booch, Robert A. Maksimchuk, Michael
W. Engle and Bobbi J. Young
30. Head First Object-Oriented Analysis and Design by Brett D. McLaughlin, Gary Pollice and Dave West
31. Agile Principles, Patterns, and Practices in C# by Robert C. Martin and Micah Martin
32. Design Patterns For Dummies by Steve Holzner
33. Pattern Languages of Program Design 5 by Dragos Manolescu, Markus Voelter and James Noble
34. Design Patterns in Java(TM) (Software Patterns Series) by Steven John Metsker and William C. Wake
35. Object-Oriented Design and Patterns by Cay S. Horstmann
37. Object-Oriented Modeling and Design with UML (2nd Edition) by Michael R. Blaha and James R Rumbaugh
38. Remoting Patterns: Foundations of Enterprise, Internet and Realtime Distributed Object Middleware (Wiley
Software... by Markus Völter, Michael Kircher and Uwe Zdun
39. Software Factories: Assembling Applications with Patterns, Models, Frameworks, and Tools (Wiley Application
Development... by Jack Greenfield, Keith Short, Steve Cook and Stuart Kent
40. Refactoring to Patterns by Joshua Kerievsky
41. Architecting Enterprise Solutions: Patterns for High-Capability Internet-based Systems (Wiley Software Patterns...
by Paul Dyson and Andrew Longshaw
42. Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML by Jim Arlow and Ila
Neustadt
43. Data Access Patterns: Database Interactions in Object-Oriented Applications by Clifton Nock
44. Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans
45. Pattern-Oriented Analysis and Design: Composing Patterns to Design Software Systems by Sherif M. Yacoub,
Hany H. Ammar, Sherif Yacoub and Hany Ammar
46. Java Extreme Programming Cookbook by Eric M. Burke and Brian M. Coyner
47. J2EE Best Practices: Java Design Patterns, Automation, and Performance (Wiley Application Development
Series) by Darren Broemmer
48. Real-Time Design Patterns: Robust Scalable Architecture for Real-Time Systems by Bruce Powel Douglass
49. Design Patterns Java¿ Workbook by Steven John Metsker
50. EJB Design Patterns: Advanced Patterns, Processes, and Idioms by Floyd Marinescu
51. Streamlined Object Modeling: Patterns, Rules, and Implementation by Jill Nicola, Mark Mayfield and Mike Abney
52. Design Patterns Explained: A New Perspective on Object-Oriented Design by Alan Shalloway and James Trott
53. Small Memory Software: Patterns for systems with limited memory (Software Patterns Series) by James Noble
and Charles Weir
54. AntiPatterns in Project Management by William J. Brown, Hays W. "Skip" McCormick III and Scott W. Thomas
55. Pattern Languages of Program Design 4 (Software Patterns Series) by Brian Foote, Neil Harrison and Hans
Rohnert
56. Testing Object-Oriented Systems: Models, Patterns, and Tools by Robert V. Binder
57. Design Patterns and Contracts by Jean-Marc Jezequel, Michel Train and Christine Mingins
58. Object-Oriented Software Development Using Java: Principles, Patterns, and Frameworks (1/e) by Xiaoping Jia
59. Refactoring: Improving the Design of Existing Code by Martin Fowler, Kent Beck, John Brant and William Opdyke
60. More Process Patterns: Delivering Large-Scale Systems Using Object Technology (SIGS: Managing Object
Technology... by Scott W. Ambler
61. Pattern Hatching: Design Patterns Applied by John Vlissides
62. AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis by William J. Brown, Raphael C. Malveau,
Hays W. "Skip" McCormick and Thomas J. Mowbray
63. A Little Java, A Few Patterns (Language, Speech, & Communication) by Matthias Felleisen, Daniel P. Friedman
and Ralph E. Johnson
64. Pattern Languages of Program Design 3 (v. 3) by Robert C. Martin, Dirk Riehle and Frank Buschmann
65. Object Models: Strategies, Patterns, and Applications (2nd Edition) by Peter Coad, David North and Mark Mayfield
66. Analysis Patterns: Reusable Object Models by Martin Fowler
67. Patterns of Software: Tales from the Software Community by Richard P. Gabriel
68. Pattern Languages of Program Design 2 (v. 2) by John Vlissides, James O. Coplien and Norman L. Kerth
69. Software Patterns by James Coplien
70. Software Architecture: Perspectives on an Emerging Discipline by Mary Shaw and David Garlan
71. Adaptive Object-Oriented Software: The Demeter Method with Propagation Patterns: The Demeter Method with
Propagation... by Karl Lieberherr
72. Pattern Languages of Program Design by James O. Coplien and Douglas C. Schmidt
32/236
Patterns
 The following is not a substitute to reading
previous books and practicing
 The following is complementary to reading
books and practicing
– These patterns that have been “found” the hard
way and that work (or do not work!)
33/236
Patterns
 The following is not a substitute to reading
these books and practicing
 The following is complementary to reading
books and practicing
– These patterns that have been “found” the hard
way and that work (or do not work!)
34/236
Patterns
 General form as for the GoF , also inspired
by Coplien’s form
– Name
– Problem(s)
– Solution
– Consequences
35/236
Patterns
 General form as for the GoF, also inspired
by Coplien’s form
– Name
– Problem(s)
– Example(s)
– Solution
– Example(s)
– Consequences
– (Follow-up)
36/236
Patterns
 General form as for the GoF, also inspired
by Coplien’s form
– Name
– Problem(s)
– Example(s)
– Solution
– Example(s)
– Consequences
– (Follow-up)
Problem:
Solution:
37/236
Patterns
 General form as for the GoF, also inspired
by Coplien’s form
– Not formal
– Room for interpretation
– But…
• UML-like class diagrams
• UML-like sequence diagrams
• Smalltalk / C++ example code
38/236
Problems
 What motifs and what model for these
motifs?
 What model for the program
architecture?
 How to perform the identification?
39/236
Our Solution
 What motifs and what model for these
motifs?
 What model for the program
architecture?
 How to perform the identification?
40/236
Our Solution
 What motifs and what model for these
motifs?
 What model for the program
architecture?
 How to perform the identification?
Design motifs and the
PADL meta-model
41/236
Our Solution
 What motifs and what model for these
motifs?
 What model for the program
architecture?
 How to perform the identification?
Design motifs and the
PADL meta-model
42/236
Our Solution
 What motifs and what model for these
motifs?
 What model for the program
architecture?
 How to perform the identification?
Design Meta-modelling
Design motifs and the
PADL meta-model
43/236
Our Solution
 What motifs and what model for these
motifs?
 What model for the program
architecture?
 How to perform the identification?
Design Meta-modelling
Design motifs and the
PADL meta-model
44/236
Our Solution
 What motifs and what model for these
motifs?
 What model for the program
architecture?
 How to perform the identification?
Design Meta-modelling
Design motifs and the
PADL meta-model
45/236
Our Solution
 What motifs and what model for these
motifs?
 What model for the program
architecture?
 How to perform the identification?
Design Meta-modelling
Design motifs and the
PADL meta-model
46/236
Outline
 Introduction
– Patterns
– Case Study
 Architecture
 Design
 Implementation
– Idioms
 Conclusion
47/236
Case Study
“[E]xisting books on design patterns take a
catalog approach, where they show the
individual design patterns in isolation. This
approach is […] flawed, because you can't see
how the design patterns actually function in the
real world. Most programmers learn by looking
at computer programs.”
—Allen Holub in Holub on Patterns: Learning
Design Patterns by Looking at Code
48/236
Ptidej Tool Suite
 Context
– Research work started since my Ph.D. thesis
(2000–2003)
– Pattern Trace Identification, Detection, and
Enhancement in Java
• Theories, methods, and tools, to evaluate and to
improve the quality of object-oriented programs by
promoting the use of idioms, design patterns, and
architectural patterns
49/236
Ptidej Tool Suite
 Requirements
– Software tools
• Support the analysis of the implementation, design,
and architecture of object-oriented programs
• Support the detection and introduction of patterns at
the code, design, and architectural levels
50/236
Ptidej Tool Suite
 Analysis
– Domain concepts
• “quality of object-oriented”
• “promoting the use of idioms, design patterns, and
architectural patterns”
• “analysis of the implementation, design, and
architecture of object-oriented programs”
• “detection and introduction of patterns at the code,
design, and architectural levels”
51/236
Ptidej Tool Suite
 Analysis
– Domain concepts
• “quality of object-oriented”
• “promoting the use of idioms, design patterns, and
architectural patterns”
• “analysis of the implementation, design, and
architecture of object-oriented programs”
• “detection and introduction of patterns at the code,
design, and architectural levels”
52/236
Ptidej Tool Suite
 Constraint
– Apply patterns/best practices (existing or new)
when developing the tools
• Architectural
• Design
• Implementation
– Self-imposed but sensible
• “Eating your own dog food”
(http://www.urbandictionary.com/define.php?
term=eating%20your%20own%20dog%20food)
53/236
Ptidej Tool Suite
 Related work
– Various parsers (target languages)
e.g., GCCXML
– Various meta-model (sometimes implicit)
• Similar to UML meta-model (1997)
• Before OMG KDM (2003)
• Before Eclipse EMF (2004)
• Before OMG MOF (2006)
– Various tools
e.g., Rigi (H. M. Kienle and H. A. Müller: Rigi – An environment
for software reverse engineering, exploration, visualization, and
redocumentation. Sci. Comput. Program. 75(4): 247-263, 2010)
54/236
Ptidej Tool Suite
 Related work
↑ Existing 
↓ Too low-level
e.g., GCCXML
↓ No “free” parsers
e.g., UML meta-model
↓ Difficult to access / to use / to adapt
e.g., Rigi
55/236
Ptidej Tool Suite
 Related work
– Pierre Cointe’s team in 2000 at
École des Mines de Nantes, France
– Fertile ground
• Hervé Albin-Amiot was already developing a meta-
model to describe design patterns
– “Idioms and patterns Java: application to code synthesis and
detection” (Ph.D. in 2003)
– PDL (Pattern Description Language)
56/236
Ptidej Tool Suite
What to detect?
How to
express it?
In what to
detect it?
57/236
Ptidej Tool Suite
“Great software is not built, it is grown”
—Bill de hÓra in 97 Things Every
Software Architect Should Know
58/236
Ptidej Tool Suite
Design Patterns
PDL meta-
model
Models of
OO programs
59/236
Ptidej Tool Suite


PDL meta-model
60/236
Ptidej Tool Suite
+ Models of OO programs

PDL meta-model
61/236
Ptidej Tool Suite
+ Models of OO programs
= PADL meta-model
PDL meta-model
62/236
Ptidej Tool Suite
PADL
Pattern and Abstract-level Description Language
63/236
Ptidej Tool Suite
PADL Creators
C++, C#, Java, JavaScript?
PADL
Pattern and Abstract-level Description Language
64/236
Ptidej Tool Suite
PADL Analyses
• Binary Class Relationships
• Systematic UML
PADL Creators
C++, C#, Java, JavaScript?
PADL
Pattern and Abstract-level Description Language
65/236
Ptidej Tool Suite
PADL Generators
XMI…
PADL Analyses
• Binary Class Relationships
• Systematic UML
PADL Creators
C++, C#, Java, JavaScript?
PADL
Pattern and Abstract-level Description Language
66/236
Ptidej Tool Suite
PADL Serialisers
DB4O, JOS…
PADL Generators
XMI…
PADL Analyses
• Binary Class Relationships
• Systematic UML
PADL Creators
C++, C#, Java, JavaScript?
PADL
Pattern and Abstract-level Description Language
67/236
Ptidej Tool Suite
PADL Serialisers
DB4O, JOS…
PADL Generators
XMI…
PADL Design Motifs
Anti-patterns, code smells, and µ-patterns
PADL Analyses
• Binary Class Relationships
• Systematic UML
PADL Creators
C++, C#, Java, JavaScript?
PADL
Pattern and Abstract-level Description Language
68/236
Ptidej Tool Suite
POM
Primitives, Operations, Metrics
PADL Serialisers
DB4O, JOS…
PADL Generators
XMI…
PADL Design Motifs
Anti-patterns, code smells, and µ-patterns
PADL Analyses
• Binary Class Relationships
• Systematic UML
PADL Creators
C++, C#, Java, JavaScript?
PADL
Pattern and Abstract-level Description Language
69/236
Ptidej Tool Suite
(Ptidej Solver)
Identification of design motifs
POM
Primitives, Operations, Metrics
PADL Serialisers
DB4O, JOS…
PADL Generators
XMI…
PADL Design Motifs
Anti-patterns, code smells, and µ-patterns
PADL Analyses
• Binary Class Relationships
• Systematic UML
PADL Creators
C++, C#, Java, JavaScript?
PADL
Pattern and Abstract-level Description Language
70/236
Ptidej Tool Suite
SAD
Identification of anti-patterns
(Ptidej Solver)
Identification of design motifs
POM
Primitives, Operations, Metrics
PADL Serialisers
DB4O, JOS…
PADL Generators
XMI…
PADL Design Motifs
Anti-patterns, code smells, and µ-patterns
PADL Analyses
• Binary Class Relationships
• Systematic UML
PADL Creators
C++, C#, Java, JavaScript?
PADL
Pattern and Abstract-level Description Language
71/236
Ptidej Tool Suite
SAD
Identification of anti-patterns
(Ptidej Solver)
Identification of design motifs
POM
Primitives, Operations, Metrics
PADL Serialisers
DB4O, JOS…
PADL Generators
XMI…
PADL Design Motifs
Anti-patterns, code smells, and µ-patterns
PADL Analyses
• Binary Class Relationships
• Systematic UML
PADL Creators
C++, C#, Java, JavaScript?
PADL
Pattern and Abstract-level Description Language
Ptidej UI
User interface (using reflection)
72/236
Ptidej UI Viewer Standalone Swing displaying PADL
(Another example of “Eating your own dog food” )
73/236
PADL Kernel, main interfaces provided to the users
(SVG and JPG from Ptidej UI Viewer Standalone Swing)
74/236
PADL Kernel, abstract-level models
Describe models of programs, including design motifs
75/236
PADL Kernel, elements
Describe methods, fields…
76/236
PADL Kernel, entities
Describe classes, interfaces…
77/236
PADL Kernel, relationships
Describe inheritances, associations…
78/236
Ptidej Tool Suite
 Advantages
– Creators
– BCRs
– Extensibility
– Reliability
(Has been used in many studies)
79/236
Ptidej Tool Suite
 Advantages
– Available! 
• https://web.soccerlab.polymtl.ca/rptidej/ptidejlab/
Software/Ptidej 5 Workspace
• Username: guestsvn
• Password: g1u2e3s4t5
– See also
• http://www.ptidej.net/material/inanutshell
• http://www.ptidej.net/material/development/
• http://wiki.ptidej.net/doku.php
80/236
Ptidej Tool Suite
 Advantages
– Extensible
e.g., C++ creator provide new/modified constituent
• Factory design pattern
• Builder design pattern
– Including for the user interface
81/236
Ptidej Tool Suite
 Limits
– Coarse representation
of method statements
– Unsatisfactory support of non-typed, non-object-
oriented programming languages
• (Very) partial support for Smalltalk
82/236
Ptidej Tool Suite
 Performance
– Eclipse v3.1
– Google Chrome v1.0.154.53
• Quality of the model under tests
83/236
Ptidej Tool Suite
 Academic Usage
– Dozen of empirical studies
e.g., S. Kpodjedo, F. Ricca, P. Galinier, G. Antoniol,
and Y.-G. Guéhéneuc. MADMatch: Many-to-many
Approximate Diagram Matching for Design
Comparison. IEEE TSE, Feburary 2013
– Please see
• http://www.ptidej.net/publications/
84/236
Ptidej Tool Suite
 Concrete Usage
– Build a model from some C++ code (1/2)
public static IIdiomLevelModel generateModelFromCppFilesUsingEclipse(
final String aName,
final String aSourceDirectory,
final IModelListener aModelListener) {
ICodeLevelModel codeLevelModel = null;
try {
final ICodeLevelModelCreator creator =
new padl.creator.cppfile.eclipse.CppCreator(aSourceDirectory);
codeLevelModel =
CPPFactoryEclipse.getInstance().createCodeLevelModel(aName);
if (aModelListener != null) {
codeLevelModel.addModelListener(aModelListener);
}
codeLevelModel.create(creator);
}
catch (final CreationException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
}
...
85/236
Ptidej Tool Suite
 Concrete Usage
– Build a model from some C++ code (1/2)
public static IIdiomLevelModel generateModelFromCppFilesUsingEclipse(
final String aName,
final String aSourceDirectory,
final IModelListener aModelListener) {
ICodeLevelModel codeLevelModel = null;
try {
final ICodeLevelModelCreator creator =
new padl.creator.cppfile.eclipse.CppCreator(aSourceDirectory);
codeLevelModel =
CPPFactoryEclipse.getInstance().createCodeLevelModel(aName);
if (aModelListener != null) {
codeLevelModel.addModelListener(aModelListener);
}
codeLevelModel.create(creator);
}
catch (final CreationException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
}
...
Specialised creator
86/236
Ptidej Tool Suite
 Concrete Usage
– Build a model from some C++ code (1/2)
public static IIdiomLevelModel generateModelFromCppFilesUsingEclipse(
final String aName,
final String aSourceDirectory,
final IModelListener aModelListener) {
ICodeLevelModel codeLevelModel = null;
try {
final ICodeLevelModelCreator creator =
new padl.creator.cppfile.eclipse.CppCreator(aSourceDirectory);
codeLevelModel =
CPPFactoryEclipse.getInstance().createCodeLevelModel(aName);
if (aModelListener != null) {
codeLevelModel.addModelListener(aModelListener);
}
codeLevelModel.create(creator);
}
catch (final CreationException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
}
...
Specialised creator
Specialised factory to
allow new constituents
87/236
Ptidej Tool Suite
 Concrete Usage
– Build a model from some C++ code (1/2)
public static IIdiomLevelModel generateModelFromCppFilesUsingEclipse(
final String aName,
final String aSourceDirectory,
final IModelListener aModelListener) {
ICodeLevelModel codeLevelModel = null;
try {
final ICodeLevelModelCreator creator =
new padl.creator.cppfile.eclipse.CppCreator(aSourceDirectory);
codeLevelModel =
CPPFactoryEclipse.getInstance().createCodeLevelModel(aName);
if (aModelListener != null) {
codeLevelModel.addModelListener(aModelListener);
}
codeLevelModel.create(creator);
}
catch (final CreationException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
}
...
Specialised creator
Specialised factory to
allow new constituents
Builder design pattern
88/236
Ptidej Tool Suite
 Concrete Usage
– Build a model from some C++ code (2/2)
public static IIdiomLevelModel generateModelFromCppFilesUsingEclipse(
final String aName,
final String aSourceDirectory,
final IModelListener aModelListener) {
...
IIdiomLevelModel idiomLevelModel = null;
try {
idiomLevelModel =
(IIdiomLevelModel) new AACRelationshipsAnalysis().invoke(aCodeLevelModel);
}
catch (final UnsupportedSourceModelException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
}
return idiomLevelModel;
}
89/236
Ptidej Tool Suite
 Concrete Usage
– Build a model from some C++ code (2/2)
public static IIdiomLevelModel generateModelFromCppFilesUsingEclipse(
final String aName,
final String aSourceDirectory,
final IModelListener aModelListener) {
...
IIdiomLevelModel idiomLevelModel = null;
try {
idiomLevelModel =
(IIdiomLevelModel) new AACRelationshipsAnalysis().invoke(aCodeLevelModel);
}
catch (final UnsupportedSourceModelException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
}
return idiomLevelModel;
}
Promotion of the model
90/236
Ptidej Tool Suite
 Concrete Usage
– Identify occurrence of the Composite DM
final Problem problem =
CompositeMotif.getProblem(Manager.build(idiomLevelModel));
final StringWriter writer = new StringWriter();
problem.setWriter(new PrintWriter(writer));
problem.automaticSolve(true);
final Properties properties = new Properties();
properties.load(new ReaderInputStream(new StringReader(writer.getBuffer().toString())));
final OccurrenceBuilder solutionBuilder = OccurrenceBuilder.getInstance();
final Occurrence[] solutions = solutionBuilder.getCanonicalOccurrences(properties);
91/236
Ptidej Tool Suite
 Concrete Usage
– Identify occurrence of the Composite DM
final Problem problem =
CompositeMotif.getProblem(Manager.build(idiomLevelModel));
final StringWriter writer = new StringWriter();
problem.setWriter(new PrintWriter(writer));
problem.automaticSolve(true);
final Properties properties = new Properties();
properties.load(new ReaderInputStream(new StringReader(writer.getBuffer().toString())));
final OccurrenceBuilder solutionBuilder = OccurrenceBuilder.getInstance();
final Occurrence[] solutions = solutionBuilder.getCanonicalOccurrences(properties);
From a library of
design motifs
92/236
Ptidej Tool Suite
 Concrete Usage
– Identify occurrence of the Blob anti-pattern
final IDesignSmellDetection detection = (IDesignSmellDetection) new BlobDetection();
detection.setMetricsFileRepository(ClassFileRepository.getInstance(Repository.class));
detection.setModel(idiomLevelModel);
detection.performDetection();
final String path = ...;
detection.output(new PrintWriter(ProxyDisk.getInstance().fileTempOutput(path)));
final Properties properties = new Properties();
properties.load(new ReaderInputStream(ProxyDisk.getInstance().fileTempInput(path)));
final OccurrenceBuilder solutionBuilder = OccurrenceBuilder.getInstance();
final Occurrence[] solutions = solutionBuilder.getCanonicalOccurrences(properties);
93/236
Ptidej Tool Suite
 Concrete Usage
– Identify occurrence of the Blob anti-pattern
final IDesignSmellDetection detection = (IDesignSmellDetection) new BlobDetection();
detection.setMetricsFileRepository(ClassFileRepository.getInstance(Repository.class));
detection.setModel(idiomLevelModel);
detection.performDetection();
final String path = ...;
detection.output(new PrintWriter(ProxyDisk.getInstance().fileTempOutput(path)));
final Properties properties = new Properties();
properties.load(new ReaderInputStream(ProxyDisk.getInstance().fileTempInput(path)));
final OccurrenceBuilder solutionBuilder = OccurrenceBuilder.getInstance();
final Occurrence[] solutions = solutionBuilder.getCanonicalOccurrences(properties);
From a library of
anti-patterns
94/236
Ptidej Tool Suite
 Limitations and future work
– Treatment and modelling of method bodies
• Coarse grain multi-language support for method
bodies currently available
• Fine grain through meta-model extension
– Treatment and modelling of non-typed, non-
object-oriented programming languages
• Unsatisfactory support for Smalltalk
• No support for PHP, JavaScript
95/236
Ptidej Tool Suite
 Limitations and future work
– Treatment and modelling of method bodies
• Coarse grain multi-language support for method
bodies currently available
• Fine grain through meta-model extension
– Treatment and modelling of non-typed, non-
object-oriented programming languages
• Unsatisfactory support for Smalltalk
• No support for PHP, JavaScript
96/236
Outline
 Introduction
– Patterns
– Case Study
 Patterns
– Process
– Architecture
– Design
– Implementation
 Conclusion
97/236
Patterns
 We (tried to) follow best practices when
developing the Ptidej Tool Suite
98/236
Outline
 Introduction
– Patterns
– Case Study
 Patterns
– Process
– Architecture
– Design
– Implementation
 Conclusion
99/236
Be a Profiler
 Name
– Be a profiler
 Problems
– Computation time
– Memory consumption
– Easy to “optimise” in the wrong places
• Make code needlessly complex
• Do not improve performances
100/236
Be a Profiler
“Premature optimization is the root of all evil”
—Donald Knuth in Structured Programming
with Go To Statements, December 1974
101/236
Be a Profiler
 Example
Thread [main] (Suspended (exception OutOfMemoryError))
GenericContainer...Constituents(Abstract...ContainerOfConstituents).broadcastAdditionOfConstituent(IConstituent) line: 267
GenericContainer...Constituents(Abstract...ContainerOfConstituents).directlyAddConstituent(IConstituent) line: 344
GenericContainer...Constituents(Abstract...ContainerOfConstituents).addConstituent(IConstituent) line: 214
Package.addConstituent(IConstituentOfModel) line: 76
…ClassFileCreator(AbstractClassFileCreator).createEntities(ICodeLevelModel, List, ConstituentRepository, ClassFile[]) line: 497
CompleteClassFileCreator(AbstractClassFileCreator).create(ICodeLevelModel) line: 220
CodeLevelModel.create(ICodeLevelModelCreator) line: 53
TestPathArgoUML.setUp() line: 57
TestPathArgoUML(TestCase).runBare() line: 140
TestResult$1.protect() line: 106
TestResult.runProtected(Test, Protectable) line: 124
TestResult.run(TestCase) line: 109
TestPathArgoUML(TestCase).run(TestResult) line: 133
TestSuite.runTest(Test, TestResult) line: 176
TestSuite.run(TestResult) line: 171
JUnit3TestReference.run(TestExecution) line: 130
TestExecution.run(ITestReference[]) line: 38
RemoteTestRunner.runTests(String[], String, TestExecution) line: 467
RemoteTestRunner.runTests(TestExecution) line: 683
RemoteTestRunner.run() line: 390
RemoteTestRunner.main(String[]) line: 197
102/236
Be a Profiler
 Example
– Using String
103/236
Be a Profiler
 Example
– Using char[]
104/236
Be a Profiler
 Solution
– Use a profiler to understand exactly what is
happening and where it is happening
– Profile regularly, as part of the testing phase
– Modify the code to remove only obvious and
dramatic bottlenecks, one at a time
• Time
• Memory
105/236
Be a Profiler
 Solution
– Follow the findings and recommendations of
studies on the performance of class-libraries
e.g., Nick Mitchell and Gary Sevitsky. The Causes of
Bloat, the Limits of Health, in the Proceedings of the
22nd ACM OOPSLA conference, October 2007
106/236
Be a Profiler
 Example
– Follow the findings and recommendations of
studies on the performance of class-libraries
e.g., Nick Mitchell and Gary Sevitsky. The Causes of
Bloat, the Limits of Health, in the Proceedings of the
22nd ACM OOPSLA conference, October 2007
– From
– To
107/236
Be a Profiler
 Consequences
↑ Improved performances
↑ Faster write-run-debug cycles
↔ Contradictory with “If it ain’t broke, don’t fix it”
↓ None, really!
108/236
Tests as Documentation
 Name
– Tests as documentation
 Problems
– When meeting a large program/framework for
the first time, where to start?
• main(…) methods may not exist or be helpful…
Ptidej include 423 such methods!
• Documentation is often inexistent
109/236
Tests as Documentation
 Example
110/236
Tests as Documentation
 Example
111/236
Tests as Documentation
 Example
Where to begin?
112/236
Tests as Documentation
“My advice here is to always provide a way to do
all [documentation] easily with a programmatic
interface, and then treat a [documentation] file as
an optional feature.”
—Martin Fowler in Inversion of Control Containers
and the Dependency Injection pattern
(http://www.martinfowler.com/articles/injection.html)
113/236
Tests as Documentation
“My advice here is to always provide a way to do
all [documentation] easily with a programmatic
interface, and then treat a [documentation] file as
an optional feature.”
—Martin Fowler in Inversion of Control Containers
and the Dependency Injection pattern
(http://www.martinfowler.com/articles/injection.html)
Fowler talked about
configuration originally
114/236
Tests as Documentation
 Solution
– Always pair a “development” project with a “test”
project, which contains unit/integration tests
– Use JUnit extensively to ease running
• Avoid main(…) methods
– Write the tests before writing the code
115/236
Tests as Documentation
 Example
public class TestPath extends TestCase {
...
public void setUp() {
try {
final char[] entityName = "A".toCharArray();
final IFirstClassEntity entity = Factory.getInstance().createClass(entityName);
final IMethod aGetter = Factory.getInstance().createMethod("get".toCharArray());
aGetter.setReturnType(entityName);
final IParameter aParameter2 = Factory.getInstance().createParameter(
entity, "a".toCharArray(), Constants.CARDINALITY_ONE);
...
entity.addConstituent(aGetter);
entity.addConstituent(aSetter);
entity.addConstituent(aField);
final IPackage aPackage = Factory.getInstance().createPackage("p".toCharArray());
aPackage.addConstituent(entity);
final ICodeLevelModel aCodeLevelModel = Factory.getInstance().createCodeLevelModel("Model");
aCodeLevelModel.addConstituent(aPackage);
116/236
Tests as Documentation
 Example
public class TestPath extends TestCase {
...
public void setUp() {
try {
final char[] entityName = "A".toCharArray();
final IFirstClassEntity entity = Factory.getInstance().createClass(entityName);
final IMethod aGetter = Factory.getInstance().createMethod("get".toCharArray());
aGetter.setReturnType(entityName);
final IParameter aParameter2 = Factory.getInstance().createParameter(
entity, "a".toCharArray(), Constants.CARDINALITY_ONE);
...
entity.addConstituent(aGetter);
entity.addConstituent(aSetter);
entity.addConstituent(aField);
final IPackage aPackage = Factory.getInstance().createPackage("p".toCharArray());
aPackage.addConstituent(entity);
final ICodeLevelModel aCodeLevelModel = Factory.getInstance().createCodeLevelModel("Model");
aCodeLevelModel.addConstituent(aPackage);
Factory and API
117/236
Tests as Documentation
 Consequences
↑ Even after years (or even when written by
students ), what the code does and how it
does is still evident
↑ Even after years, the code still runs
• Or the tests fail
↑ Novices can copy/paste/modify existing tests to
fit their needs and purposes
↓ None, really!
118/236
Outline
 Introduction
– Patterns
– Case Study
 Patterns
– Process
– Architecture
– Design
– Implementation
 Conclusion
119/236
Multi-layered Architecture
 Name
– Layered architecture
 Problems
– Organise your code into manageable chunks
that can be developed “independently”
– Organise your code into identifiable chunks
– Organise your code into controllable chunks
120/236
Multi-layered Architecture
 Name
– Layered architecture
 Problems
– Organise your code into manageable chunks
that can be developed “independently”
– Organise your code into identifiable chunks
– Organise your code into controllable chunks
121/236
Multi-layered Architecture
 Problems (cont’d)
– Manageable
• Developing
• Testing
• Versioning
122/236
Multi-layered Architecture
 Problems (cont’d)
– Identifiable
• Mental model
• Architectural style
123/236
Multi-layered Architecture
 Problems (cont’d)
– Controllable
• Visibility
• Dependencies
124/236
Multi-layered Architecture
 Solution
– Divide your code into “projects”
• Eclipse or NetBeans or… projects
– Give names that order the projects along the
lines of the chosen architecture
– Layered architecture
• Ease development
• Ease run-time… even on multiple computers
125/236
Multi-layered Architecture
 Example
126/236
Multi-layered Architecture
 Consequences
↑ Ease development
• Divide and conquer
• Restrain visibility
↓ May not be suitable for legacy systems
127/236
Outline
 Introduction
– Patterns
– Case Study
 Patterns
– Process
– Architecture
– Design
– Implementation
 Conclusion
128/236
Proxy Console
 Name
– Proxy console
 Problem
– Control output and prepare for production,
when output must be redirected to one or
more files/Console…
129/236
Proxy Console
 Solution
– Implement a class to act as a proxy between the
standard outputs and your code
– Implement a class to act as “demultiplexer” to
broadcast output to different channels
130/236
Proxy Console
 Examples
– Unified output
– Targets of the output
– Multiple outputs
ProxyConsole.getInstance().setDebugOutput(new PrintWriter(new NullWriter()));
ProxyConsole.getInstance().setErrorOutput(new PrintWriter(Console.getInstance().getErrorWriter()));
ProxyConsole.getInstance().setNormalOutput(new PrintWriter(Console.getInstance().getNormalWriter()));
...
}
catch (final Throwable t) {
t.printStackTrace(ProxyConsole.getInstance().errorOutput());
}
final FileOutputStream logStream = new FileOutputStream("Results.log");
final MultiChannelOutputStream outStream = new MultiChannelOutputStream(System.out, logStream);
System.setOut(new PrintStream(outStream));
131/236
public class ProxyConsole {
private static ProxyConsole UniqueInstance;
public static ProxyConsole getInstance() {
if (ProxyConsole.UniqueInstance == null) {
ProxyConsole.UniqueInstance = new ProxyConsole ();
}
return ProxyConsole.UniqueInstance;
}
private PrintWriter debugOutput = new PrintWriter(new NullWriter());
private PrintWriter errorOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.err));
private PrintWriter normalOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.out));
private ProxyConsole() {
}
public PrintWriter debugOutput() {
return this.debugOutput;
}
public PrintWriter errorOutput() {
return this.errorOutput;
}
public PrintWriter normalOutput() {
return this.normalOutput;
}
public void setDebugOutput(final PrintWriter messageWriter) {
this.debugOutput = messageWriter;
}
public void setErrorOutput(final PrintWriter messageWriter) {
this.errorOutput = messageWriter;
}
public void setNormalOutput(final PrintWriter messageWriter) {
this.normalOutput = messageWriter;
}
}
132/236
public class ProxyConsole {
private static ProxyConsole UniqueInstance;
public static ProxyConsole getInstance() {
if (ProxyConsole.UniqueInstance == null) {
ProxyConsole.UniqueInstance = new ProxyConsole ();
}
return ProxyConsole.UniqueInstance;
}
private PrintWriter debugOutput = new PrintWriter(new NullWriter());
private PrintWriter errorOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.err));
private PrintWriter normalOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.out));
private ProxyConsole() {
}
public PrintWriter debugOutput() {
return this.debugOutput;
}
public PrintWriter errorOutput() {
return this.errorOutput;
}
public PrintWriter normalOutput() {
return this.normalOutput;
}
public void setDebugOutput(final PrintWriter messageWriter) {
this.debugOutput = messageWriter;
}
public void setErrorOutput(final PrintWriter messageWriter) {
this.errorOutput = messageWriter;
}
public void setNormalOutput(final PrintWriter messageWriter) {
this.normalOutput = messageWriter;
}
}
Thread unsafe
133/236
public class ProxyConsole {
private static ProxyConsole UniqueInstance;
public static ProxyConsole getInstance() {
if (ProxyConsole.UniqueInstance == null) {
ProxyConsole.UniqueInstance = new ProxyConsole ();
}
return ProxyConsole.UniqueInstance;
}
private PrintWriter debugOutput = new PrintWriter(new NullWriter());
private PrintWriter errorOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.err));
private PrintWriter normalOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.out));
private ProxyConsole() {
}
public PrintWriter debugOutput() {
return this.debugOutput;
}
public PrintWriter errorOutput() {
return this.errorOutput;
}
public PrintWriter normalOutput() {
return this.normalOutput;
}
public void setDebugOutput(final PrintWriter messageWriter) {
this.debugOutput = messageWriter;
}
public void setErrorOutput(final PrintWriter messageWriter) {
this.errorOutput = messageWriter;
}
public void setNormalOutput(final PrintWriter messageWriter) {
this.normalOutput = messageWriter;
}
}
Thread unsafe
By default, no debug
134/236
public class ProxyConsole {
private static ProxyConsole UniqueInstance;
public static ProxyConsole getInstance() {
if (ProxyConsole.UniqueInstance == null) {
ProxyConsole.UniqueInstance = new ProxyConsole ();
}
return ProxyConsole.UniqueInstance;
}
private PrintWriter debugOutput = new PrintWriter(new NullWriter());
private PrintWriter errorOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.err));
private PrintWriter normalOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.out));
private ProxyConsole() {
}
public PrintWriter debugOutput() {
return this.debugOutput;
}
public PrintWriter errorOutput() {
return this.errorOutput;
}
public PrintWriter normalOutput() {
return this.normalOutput;
}
public void setDebugOutput(final PrintWriter messageWriter) {
this.debugOutput = messageWriter;
}
public void setErrorOutput(final PrintWriter messageWriter) {
this.errorOutput = messageWriter;
}
public void setNormalOutput(final PrintWriter messageWriter) {
this.normalOutput = messageWriter;
}
}
Thread unsafe
By default, no debug
Makes sure to flush
135/236
Proxy Console
 Solution
– Demultiplexer
public class MultiChannelOutputStream extends OutputStream {
private final OutputStream firstStream;
private final OutputStream secondStream;
public MultiChannelOutputStream(
final OutputStream theFirstOutputStream,
final OutputStream theSecondOutputStream) {
this.firstStream = theFirstOutputStream;
this.secondStream = theSecondOutputStream;
}
public void write(final int b) throws IOException {
this.firstStream.write(b);
this.secondStream.write(b);
}
}
136/236
Proxy Console
 Example
final FileOutputStream logStream = new FileOutputStream("ConstraintResults.log");
final MultiChannelOutputStream outStream =
new MultiChannelOutputStream(
ProxyConsole.getInstance().normalOutput(),
logStream);
System.setOut(new PrintStream(outStream));
final MultiChannelOutputStream errStream =
new MultiChannelOutputStream(
ProxyConsole.getInstance().normalOutput(),
logStream);
System.setErr(new PrintStream(errStream));
137/236
Proxy Console
 Example (cont’d)
138/236
Proxy Console
 Example (cont’d)
Any output redirected to
the Console and a log file
139/236
Proxy Console
 Consequences
↑ More professional code
• Output to Console during development
• Output to a file (and–or whatever) in production
– No output to the Console to “hide” any unexpected behavior,
forgotten debug messages…
• Introduce novel channels, i.e., warningOutput()
↓ Tiny impact on performance
↓ Coupling to ProxyConsole and its project
140/236
Proxy Disk
 Name
– Proxy disk
 Problems
– Need to write temporary files to disk
– Need to access data from disk
• Normal behaviour
• Tests
141/236
Proxy Disk
 Example
– Scattered in your code
final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar;
final File newOutputDirectiory = new File(newOutputDirectoryName);
if (!newOutputDirectiory.exists()) {
newOutputDirectiory.mkdirs();
}
this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName);
142/236
Proxy Disk
 Example
– Scattered in your code
– With many variants…
final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar;
final File newOutputDirectiory = new File(newOutputDirectoryName);
if (!newOutputDirectiory.exists()) {
newOutputDirectiory.mkdirs();
}
this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName);
143/236
Proxy Disk
 Example
– Scattered in your code
– With many variants…
• Which may or may not work depending on the order
of method executions
final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar;
final File newOutputDirectiory = new File(newOutputDirectoryName);
if (!newOutputDirectiory.exists()) {
newOutputDirectiory.mkdirs();
}
this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName);
144/236
Proxy Disk
 Example
– One possible variant
final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar;
final File newOutputDirectiory = new File(newOutputDirectoryName);
if (!newOutputDirectiory.exists()) {
newOutputDirectiory.mkdirs();
}
this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName);
145/236
Proxy Disk
 Example
– One possible variant
final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar;
final File newOutputDirectiory = new File(newOutputDirectoryName);
if (!newOutputDirectiory.exists()) {
newOutputDirectiory.mkdirs();
}
this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName);
What if aName does not
end with a file separator?
146/236
Proxy Disk
 Example
– Another possible variant
final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar;
final File newOutputDirectiory = new File(newOutputDirectoryName);
if (!newOutputDirectiory.exists()) {
newOutputDirectiory.mkdirs();
}
this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName);
147/236
Proxy Disk
 Example
– Another possible variant
final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar;
final File newOutputDirectiory = new File(newOutputDirectoryName);
if (!newOutputDirectiory.exists()) {
newOutputDirectiory.mkdirs();
}
this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName);
What if the directory
does not/already exist?
148/236
Proxy Disk
 Solution
– Have a single object to manage file access
– Centralise access
• Files
• Directories (always ending with a file separator)
– Manage the creation of directories (if needed)
– Handle
• FileReader
• FileWriter
• File/String
149/236
Proxy Disk
 Solution
– Have a single object to manage file access
– Centralise access
• Files
• Directories (always ending with a file separator)
– Manage the creation of directories (if needed)
– Handle
• FileReader
• FileWriter
• File/String
In Java, can describe
a file or a directory
150/236
Proxy Disk
 Example
– Single access point
final String path = anOutputDirectory + "DetectionResults in " + aName +
" for " + antipatternName + ".ini";
detection.output(new PrintWriter(ProxyDisk.getInstance().fileTempOutput(path)));
Takes care of
the “details”
151/236
Proxy Disk
 Solution
public class ProxyDisk {
private static final String TEMP_DIRECTORY = "../Temp/";
private static ProxyDisk UniqueInstance;
public static ProxyDisk getInstance() {
if (ProxyDisk.UniqueInstance == null) {
ProxyDisk.UniqueInstance = new ProxyDisk();
}
return ProxyDisk.UniqueInstance;
}
private File tempDirectory;
private ProxyDisk() {
try {
this.tempDirectory =
this.createDirectories(ProxyDisk.TEMP_DIRECTORY);
}
catch (final IOException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
}
}
...
By default, we create
a temporary directory
152/236
Proxy Disk
 Solution
private File createDirectories(final String aPathToADirectory)
throws IOException {
final File defaultDirectory = new File(aPathToADirectory);
if (!defaultDirectory.exists()) {
if (!defaultDirectory.mkdir()) {
throw new IOException(
"FileOutputProxy cannot create the necessary directory: "
+ aPathToADirectory);
}
}
else if (defaultDirectory.isFile()) {
throw new IOException(
"FileOutputProxy cannot use a file as a directory: "
+ aPathToADirectory);
}
return defaultDirectory;
}
Creates as many
directories as needed
153/236
Proxy Disk
private File createFile(final String aFileName, final boolean shouldAppend) {
File file;
int indexOfLastPathSeparator;
if ((indexOfLastPathSeparator =
Math.max(aFileName.lastIndexOf('/'), aFileName.lastIndexOf(''))) > -1) {
indexOfLastPathSeparator++;
final String somePaths = aFileName.substring(0, indexOfLastPathSeparator);
final String fileName = aFileName.substring(indexOfLastPathSeparator);
try {
file = new File(this.createDirectories(somePaths), fileName);
}
catch (final IOException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
ProxyConsole.getInstance().errorOutput().println(
"FileOutputProxy will use its default directory");
file = new File(ProxyDisk.TEMP_DIRECTORY, fileName);
}
}
else {
file = new File(aFileName);
}
if (file.exists() && !shouldAppend) {
ProxyConsole.getInstance().warningOutput().println(
"ProxyDisk reports that the file already exists: “ + aFileName);
}
return file;
}
154/236
Proxy Disk
private File createFile(final String aFileName, final boolean shouldAppend) {
File file;
int indexOfLastPathSeparator;
if ((indexOfLastPathSeparator =
Math.max(aFileName.lastIndexOf('/'), aFileName.lastIndexOf(''))) > -1) {
indexOfLastPathSeparator++;
final String somePaths = aFileName.substring(0, indexOfLastPathSeparator);
final String fileName = aFileName.substring(indexOfLastPathSeparator);
try {
file = new File(this.createDirectories(somePaths), fileName);
}
catch (final IOException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
ProxyConsole.getInstance().errorOutput().println(
"FileOutputProxy will use its default directory");
file = new File(ProxyDisk.TEMP_DIRECTORY, fileName);
}
}
else {
file = new File(aFileName);
}
if (file.exists() && !shouldAppend) {
ProxyConsole.getInstance().warningOutput().println(
"ProxyDisk reports that the file already exists: “ + aFileName);
}
return file;
}
Creates as many
directories as needed
155/236
Proxy Disk
private File createFile(final String aFileName, final boolean shouldAppend) {
File file;
int indexOfLastPathSeparator;
if ((indexOfLastPathSeparator =
Math.max(aFileName.lastIndexOf('/'), aFileName.lastIndexOf(''))) > -1) {
indexOfLastPathSeparator++;
final String somePaths = aFileName.substring(0, indexOfLastPathSeparator);
final String fileName = aFileName.substring(indexOfLastPathSeparator);
try {
file = new File(this.createDirectories(somePaths), fileName);
}
catch (final IOException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
ProxyConsole.getInstance().errorOutput().println(
"FileOutputProxy will use its default directory");
file = new File(ProxyDisk.TEMP_DIRECTORY, fileName);
}
}
else {
file = new File(aFileName);
}
if (file.exists() && !shouldAppend) {
ProxyConsole.getInstance().warningOutput().println(
"ProxyDisk reports that the file already exists: “ + aFileName);
}
return file;
}
Creates as many
directories as needed
Fails safe
156/236
Proxy Disk
private File createFile(final String aFileName, final boolean shouldAppend) {
File file;
int indexOfLastPathSeparator;
if ((indexOfLastPathSeparator =
Math.max(aFileName.lastIndexOf('/'), aFileName.lastIndexOf(''))) > -1) {
indexOfLastPathSeparator++;
final String somePaths = aFileName.substring(0, indexOfLastPathSeparator);
final String fileName = aFileName.substring(indexOfLastPathSeparator);
try {
file = new File(this.createDirectories(somePaths), fileName);
}
catch (final IOException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
ProxyConsole.getInstance().errorOutput().println(
"FileOutputProxy will use its default directory");
file = new File(ProxyDisk.TEMP_DIRECTORY, fileName);
}
}
else {
file = new File(aFileName);
}
if (file.exists() && !shouldAppend) {
ProxyConsole.getInstance().warningOutput().println(
"ProxyDisk reports that the file already exists: “ + aFileName);
}
return file;
}
Creates as many
directories as needed
Fails safe
Friendly warning
157/236
Proxy Disk
private FileReader fileInput(final String aFileName) {
try {
final File file = this.createFile(aFileName, false);
return new FileReader(file);
}
catch (final IOException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
// Fail fast!
return null;
}
}
private FileWriter fileOutput(
final String aFileName,
final boolean shouldAppend) {
try {
final File file = this.createFile(aFileName, shouldAppend);
return new FileWriter(file, shouldAppend);
}
catch (final IOException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
// Fail fast!
return null;
}
}
158/236
Proxy Disk
private FileReader fileInput(final String aFileName) {
try {
final File file = this.createFile(aFileName, false);
return new FileReader(file);
}
catch (final IOException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
// Fail fast!
return null;
}
}
private FileWriter fileOutput(
final String aFileName,
final boolean shouldAppend) {
try {
final File file = this.createFile(aFileName, shouldAppend);
return new FileWriter(file, shouldAppend);
}
catch (final IOException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
// Fail fast!
return null;
}
}
Fails fast by returning null
159/236
Proxy Disk
public File directoryTempOutput(final String someSubpaths) {
String newPath = ProxyDisk.TEMP_DIRECTORY + someSubpaths;
if (!(someSubpaths.endsWith("/") || someSubpaths.endsWith(""))) {
newPath += '/';
}
if (someSubpaths.indexOf("..") > -1) {
ProxyConsole.getInstance().warningOutput().println(
"ProxyDisk advises not to "escape" from its default directory: "
+ someSubpaths);
}
try {
final File directory = this.createDirectories(newPath);
return directory;
}
catch (final IOException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
ProxyConsole.getInstance().errorOutput().println(
"FileOutputProxy will use its default directory");
return this.tempDirectory;
}
}
160/236
Proxy Disk
public File directoryTempOutput(final String someSubpaths) {
String newPath = ProxyDisk.TEMP_DIRECTORY + someSubpaths;
if (!(someSubpaths.endsWith("/") || someSubpaths.endsWith(""))) {
newPath += '/';
}
if (someSubpaths.indexOf("..") > -1) {
ProxyConsole.getInstance().warningOutput().println(
"ProxyDisk advises not to "escape" from its default directory: "
+ someSubpaths);
}
try {
final File directory = this.createDirectories(newPath);
return directory;
}
catch (final IOException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
ProxyConsole.getInstance().errorOutput().println(
"FileOutputProxy will use its default directory");
return this.tempDirectory;
}
}
Takes care of the “details”
161/236
Proxy Disk
 Solution
– Rest of the API
util.io.ProxyDisk.directoryTempName() : String
util.io.ProxyDisk.directoryTempOutput() : File
util.io.ProxyDisk.directoryTempOutput(String) : File
util.io.ProxyDisk.fileAbsoluteInput(File) : FileReader
util.io.ProxyDisk.fileAbsoluteInput(String) : FileReader
util.io.ProxyDisk.fileTempInput(File) : FileReader
util.io.ProxyDisk.fileTempInput(String) : FileReader
util.io.ProxyDisk.fileAbsoluteOutput(String) : FileWriter
util.io.ProxyDisk.fileAbsoluteOutput(String, boolean) : FileWriter
...
util.io.ProxyDisk.fileTempOutput(String) : FileWriter
util.io.ProxyDisk.fileTempOutput(String, boolean) : FileWriter
162/236
Proxy Disk
 Examples
final XStream xstream = new XStream();
xstream.fromXML(
ProxyDisk.getInstance().fileAbsoluteInput(
Utils.TEMPORARY_OUTPUT_FILE),
aCodeLevelModel);
final PrintWriter writer =
new PrintWriter(ProxyDisk.getInstance().fileAbsoluteOutput(
Constants.PROGRAM_FILE_NAME + ".log",
true));
detection.output(new PrintWriter(ProxyDisk.getInstance().fileTempOutput(path)));
final String commandLine =
('"' + Files.getClassPath(OccurrenceGenerator.class)
+ PropertyManager.getSolverDirectory()
+ PropertyManager.getSolverCommand() + "" "
+ PropertyManager.getSolverArguments() + " -f ""
+ System.getProperty("user.dir") + '/'
+ ProxyDisk.getInstance().directoryTempName() + "Instructions.cl"")
163/236
Proxy Disk
 Consequences
↑ Systematic, tested, consistent access to files
↑ Ease debugging with a single access point
↔ Thread safety
• Fails-safe / fails-fast
↔ Default encoding
↓ Possible bottleneck
• But possibility of caching
164/236
Proxy Disk
 Follow-up
– Same pattern for database accesses
• Check for credentials, SQL injection
– Same pattern for URL accesses
• Could be combined with ProxyDisk
165/236
Hidden Language
 Name
– Hidden language
 Problems
– Manipulate, pass around, data coming from
third-party library and provided as Strings
166/236
Hidden Language
 Problems (cont’d)
– Also noted in Design Patterns for Teaching Type
Checking in a Compiler Construction Course by
Ortin, Zapico, and Cueva)
“The most serious disadvantage of [a string] is
the need to process the string as a program […].
[U]sing object-orientation, […] common and
specific [methods] can be properly set.”
167/236
Hidden Language
 Solution
– Use Strings
168/236
Hidden Language
 Solution
– Use Strings
– Of course…
169/236
Hidden Language
 Solution
– Use Strings
– Of course…
… Again, this obvious solution is not the better
170/236
Hidden Language
 Solution
– Use Strings
– Of course…
… Again, this obvious solution is not the better
• No semantics
171/236
Hidden Language
 Solution
– Use Strings
– Of course…
… Again, this obvious solution is not the better
• No semantics
• No compile-time checks
172/236
Hidden Language
 Example 1
– Class padl.creator.classfile.
relationship.DeepMethodInvocation
Analyzer
– Variable listOfCouples containing, e.g.,
[null,java.lang.Object<init>.void()]
173/236
Hidden Language
 Example 1
– Class padl.creator.classfile.
relationship.DeepMethodInvocation
Analyzer
– Variable listOfCouples containing, e.g.,
[null,java.lang.Object<init>.void()]
What do you
make of this?
174/236
Hidden Language
 Example 2
– Handling textual data
1.100.ClassGlobalVariable-0 = org.apache.html.dom.HTMLDocumentImpl
1.100.ClassGlobalVariable-0.FieldName-0 = class$0
1.100.ClassGlobalVariable-0.FieldName-1 = class$1
…
175/236
Hidden Language
 Solution
– Devise a meta-model
– Use instances of appropriate classes
176/236
Hidden Language
 As an aside…
– A meta-model defines a language to express
and reason about the existence,
• interface IMethodInvocation
properties,
• IMethodInvocation.getType()
and relations among domain concepts
• IMethodInvocation.getCalledMethod()
177/236
Hidden Language
 Example 1
– TODO 
“If it ain’t broke, don’t fix it”
—Bert Lance, May 1977
178/236
Hidden Language
 Example 2
179/236
Hidden Language
180/236
Hidden Language
 Consequences
↑ Use and debugging significantly easier
↑ Decoration, serialisation…
↑ Compile-time verification
↓ Memory overhead due to objects’ overhead
↓ Performance decrease due to indirections
181/236
Internal Observer
 Name
– “Internal” observer
 Problems
– Limit dependencies among classes and their
instances
– Yet, update some instances when other
instances are added/removed/changed
182/236
Internal Observer
 Solution
– Implement the Observer design pattern
– Use the Observer design pattern internally to
keep consistency in your model resorting to
difficult logic
183/236
Internal Observer
 Example
– Definition
– Use
public interface IObservable {
void addModelListener(final IModelListener aModelListener);
void addModelListeners(final List aListOfModelListeners);
void fireModelChange(final String anEventType, final IEvent anEvent);
Iterator getIteratorOnModelListeners();
void removeModelListener(final IModelListener aModelListener);
void removeModelListeners(final List modelListeners);
}
public interface IAbstractModel extends IContainer, INavigable, IObservable {
...
184/236
Internal Observer
 Example
private class TopLevelEntityManager implements IModelListener, Serializable {
...
public void entityRemoved(final EntityEvent entityEvent) {
final IConstituentOfModel constituent = entityEvent.getEntity();
if (constituent instanceof IFirstClassEntity) {
....this.removeTopLevelEntityFromID(constituent.getID());
}
}
public void entityAdded(final EntityEvent entityEvent) {
final IConstituentOfModel constituent = entityEvent.getEntity();
if (constituent instanceof IFirstClassEntity && !(constituent instanceof IMemberEntity)) {
....this.addTopLevelEntity(constituent);
}
}
….
}
185/236
Internal Observer
 Consequences
↑ All the benefits of the Observe design pattern
↑ Assurance to have a consistent model
↑ Remove need for complex updating logic
• Huge simplification
↓ Slight performance decrease
• Due to indirections
186/236
Run-time Deprecation
 Name
– Run-time deprecation
 Problem
– Let users know that they should not call certain
methods while internal code can call them
– Avoid deprecated annotation that generate
spurious warnings
187/236
Run-time Deprecation
 Solution
– Implement a guard class whose instances check
whether the caller of a method is “authorised”
at run-time
188/236
Run-time Deprecation
 Solution
public final class ConcreteReceiverGuard {
private static ConcreteReceiverGuard UniqueInstance;
public static ConcreteReceiverGuard getInstance() {
if (ConcreteReceiverGuard.UniqueInstance == null) {
ConcreteReceiverGuard.UniqueInstance = new ConcreteReceiverGuard();
}
return ConcreteReceiverGuard.UniqueInstance;
}
private ConcreteReceiverGuard() {
}
...
189/236
Run-time Deprecation
private void doCheck(
final String aConcreteReceiverClassToEnforce,
final String anErrorMessage) {
class ConcreteReceiverGuardThrownException extends RuntimeException {
private static final long serialVersionUID = -4100342857707204144L;
}
try {
throw new ConcreteReceiverGuardThrownException();
}
catch (final ConcreteReceiverGuardThrownException e) {
final StackTraceElement[] stackTrace = e.getStackTrace();
if (stackTrace.length < 4) {
// Error in the call of the guard
}
else {
final StringBuffer buffer = new StringBuffer();
buffer.append(stackTrace[2].getClassName());
buffer.append('.');
buffer.append(stackTrace[2].getMethodName());
final String nameOfGuardedMethod = buffer.toString();
final String nameOfClassCallingGuardedMethod =
stackTrace[3].getClassName();
if (!nameOfClassCallingGuardedMethod
.equals(aConcreteReceiverClassToEnforce)) {
// Runtime deprecation!
}
}
}
}
190/236
Run-time Deprecation
 Solution
public void check(
final String aConcreteReceiverClassToEnforce,
final String anErrorMessage) {
// Yann 2013/04/05: Stack!
// I added this spurious method to make sure that the
// doCheck() method is always called with the same stack
// depth from this class, i.e., 2 :-)
this.doCheck(aConcreteReceiverClassToEnforce, anErrorMessage);
}
public void check(
final Class aConcreteReceiverClassToEnforce,
final String anErrorMessage) {
this.doCheck(aConcreteReceiverClassToEnforce.getName(), anErrorMessage);
}
}
191/236
Run-time Deprecation
 Example
public void create(final ICodeLevelModelCreator aCodeLevelCreator) throws CreationException {
ConcreteReceiverGuard.getInstance().check(
"padl.generator.helper.ModelGenerator",
"Please use the methods in "padl.generator.helper.ModelGenerator“...");
aCodeLevelCreator.create(this);
}
192/236
Run-time Deprecation
 Consequences
↑ Identify “illegitimate” calls at run-time
↑ Avoid spurious “deprecation” warning at
compile-time
↓ Tiny performance reduction
193/236
Outline
 Introduction
– Patterns
– Case Study
 Patterns
– Process
– Architecture
– Design
– Implementation
 Conclusion
194/236
String Parsimony
 Name
– Data structure parsimony
 Problems
– Must give meaningful names/identifiers to some
instances in your system
195/236
String Parsimony
 Solution
– Use Strings
196/236
String Parsimony
 Solution
– Use Strings
– Of course…
197/236
String Parsimony
 Solution
– Use Strings
– Of course…
… But the most obvious solution is not the better
• To much overhead in memory
• See the article “The Causes of Bloat, the Limits of
Health” by Nick Mitchell and Gary Sevitsky
198/236
String Parsimony
 Example
– Overhead in a String[]
199/236
String Parsimony
 As an aside…
– Ockham's razor is “a principle of parsimony,
economy, or succinctness used in logic and
problem-solving” [Wikipedia]
– Why use more when you can use less?
c. 1287 – 1347
200/236
String Parsimony
 Solution
– Use char[]
– To manipulate char[]
• Arrays from Java class library
• ArrayUtils from Apache Commons Lang
• TCharArrayList from Trove4J
201/236
String Parsimony
 Example
public final class AnalysisEvent implements IEvent {
private final char[] name;
private final char[] elementType;
/**
* @deprecated by AnalysisEvent(final char[])
*/
public AnalysisEvent(final String aName) {
this.name = aName.toCharArray();
this.elementType = new char[0];
}
/**
* @deprecated by AnalysisEvent(final char[], final char[])
*/
public AnalysisEvent(final char[] aName) {
this.name = aName;
this.elementType = new char[0];
}
public AnalysisEvent(final char[] aName, final char[] anElementType) {
this.name = aName;
this.elementType = anElementType;
}
public char[] getConstituentName() {
return this.name;
}
...
}
202/236
String Parsimony
 Consequences
↑ Major gains in terms of space and time
↔ Code not significantly more complicate
• Eclipse warns of “unsafe” use of char[] with
“Must explicitly convert the char[] into a String”
↓ Costly to go from String/String[] to
char[]-related objects
• Use @deprecated
• Encapsulate accesses
203/236
Identity
 Name
– Identity
 Problems
– Distinguish instances whose values may be
identical
– Make similar instances that can be persisted in
database (serialised)
204/236
Identity
 Solution
– Distinguish between
• The value of the fields of an instance
• Its ID in the system at run-time
• Its unique ID automatically given by the VM
– Implement equals(Object)
– Implement hashCode()
205/236
Identity
 As an aside…
– An object has typically three identities
• Its System.identityHashCode(Object)
• Its hashCode() (see also equals())
• The hashCode() of its fields (recursively)
which may or may not be different
• See the article “Why Object Serialization is
Inappropriate for Providing Persistence in Java”
by Huw Evans
206/236
Identity
 Example
abstract class Constituent implements IConstituent {
private char[] id;
private char[] name;
...
public boolean equals(final Object obj) {
if (!(obj instanceof IConstituent)) {
return false;
}
return Arrays.equals(this.getID(), ((IConstituent) obj).getID());
}
...
public int hashCode() {
return this.getID().hashCode();
}
...
}
207/236
Identity
 Example
abstract class Constituent implements IConstituent {
private char[] id;
private char[] name;
...
public boolean equals(final Object obj) {
if (!(obj instanceof IConstituent)) {
return false;
}
return Arrays.equals(this.getID(), ((IConstituent) obj).getID());
}
...
public int hashCode() {
return this.getID().hashCode();
}
...
}
Takes care of null values
208/236
Identity
 Example
public class TestDB4OSerialiserSanity extends TestCase {
private IDesignMotifModel originalModel;
private IDesignMotifModel serialisedModel;
...
protected void setUp() throws ModelDeclarationException, CloneNotSupportedException {
this.originalModel = new Composite();
this.serialisedFileName =
DB4OSerialiser.getInstance().serialiseWithAutomaticNaming(this.originalModel);
this.serialisedModel = (IDesignMotifModel)
DB4OSerialiser.getInstance().deserialise(this.serialisedFileName);
}
public void testModels() {
Assert.assertEquals("Models", this.originalModel, this.serialisedModel);
Assert.assertEquals("Model names", this.originalModel.getDisplayName(),
this.serialisedModel.getDisplayName());
Assert.assertEquals("Model IDs", this.originalModel.getDisplayID(),
this.serialisedModel.getDisplayID());
Assert.assertTrue("Identity hashcodes of the models are different",
System.identityHashCode(this.originalModel) !=
System.identityHashCode(this.serialisedModel));
}
}
209/236
Identity
 Example
public class TestDB4OSerialiserSanity extends TestCase {
private IDesignMotifModel originalModel;
private IDesignMotifModel serialisedModel;
...
protected void setUp() throws ModelDeclarationException, CloneNotSupportedException {
this.originalModel = new Composite();
this.serialisedFileName =
DB4OSerialiser.getInstance().serialiseWithAutomaticNaming(this.originalModel);
this.serialisedModel = (IDesignMotifModel)
DB4OSerialiser.getInstance().deserialise(this.serialisedFileName);
}
public void testModels() {
Assert.assertEquals("Models", this.originalModel, this.serialisedModel);
Assert.assertEquals("Model names", this.originalModel.getDisplayName(),
this.serialisedModel.getDisplayName());
Assert.assertEquals("Model IDs", this.originalModel.getDisplayID(),
this.serialisedModel.getDisplayID());
Assert.assertTrue("Identity hashcodes of the models are different",
System.identityHashCode(this.originalModel) !=
System.identityHashCode(this.serialisedModel));
}
}
Different JVM identities
210/236
Identity
 Consequences
↑ Safe comparisons of instances, even after
serialisation/deserialisation
↓ Tiny memory impact
211/236
Identity
 Pragmatically
– Nowadays, better use builders
• EqualsBuilder and HashCodeBuilder in
Apache Commons Lang
• http://stackoverflow.com/questions/27581/
overriding-equals-and-hashcode-in-java
212/236
Address
 Name
– Address
 Problems
– When dealing with complex objects, such as
models of object-oriented programs, it is often
necessary to uniquely and directly reference one
particular constituent
213/236
Address
 Name
– Address
 Problems
– When dealing with complex objects, such as
models of object-oriented programs, it is often
necessary to uniquely and directly reference
one particular constituent
214/236
Address
 Example
public void removeTopLevelEntityFromID(final char[] anID) {
try {
final IConstituent constituent =
this.topLevelEntitiesContainer.getTopLevelEntityFromID(anID);
final IContainer container =
Finder.findContainer(constituent.getDisplayPath(), this);
container.removeConstituentFromID(anID);
}
catch (final FormatException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
}
}
215/236
Address
 Example
public void removeTopLevelEntityFromID(final char[] anID) {
try {
final IConstituent constituent =
this.topLevelEntitiesContainer.getTopLevelEntityFromID(anID);
final IContainer container =
Finder.findContainer(constituent.getDisplayPath(), this);
container.removeConstituentFromID(anID);
}
catch (final FormatException e) {
e.printStackTrace(ProxyConsole.getInstance().errorOutput());
}
}
Without back-pointers!
216/236
Address
 Solution
– Implement a unique “path” identifier that
describe uniquely and precisely the “address”
of a constituent
public interface INavigable {
String getDisplayPath();
char[] getPath();
}
217/236
Address
 Implementation
abstract class Abstract...ContainerOfConstituents extends GenericObservable
implements IContainer, Serializable {
...
private void updatePathUponAddition(final IConstituent aConstituent) {
final char[] containerPath = this.containerConsitituent.getPath();
final char[] constituentPath = aConstituent.getPath();
final char[] newPath = ...
((Constituent) aConstituent).setPath(newPath);
if (aConstituent instanceof IContainer) {
final Iterator iterator = ((IContainer) aConstituent).getIteratorOnConstituents();
while (iterator.hasNext()) {
final Constituent constituent = (Constituent) iterator.next();
this.updatePathUponAddition(constituent);
}
}
}
private void updatePathUponRemoval(final IConstituent aConstituent) {
...
218/236
Address
 Implementation
abstract class Abstract...ContainerOfConstituents extends GenericObservable
implements IContainer, Serializable {
...
private void updatePathUponAddition(final IConstituent aConstituent) {
final char[] containerPath = this.containerConsitituent.getPath();
final char[] constituentPath = aConstituent.getPath();
final char[] newPath = ...
((Constituent) aConstituent).setPath(newPath);
if (aConstituent instanceof IContainer) {
final Iterator iterator = ((IContainer) aConstituent).getIteratorOnConstituents();
while (iterator.hasNext()) {
final Constituent constituent = (Constituent) iterator.next();
this.updatePathUponAddition(constituent);
}
}
}
private void updatePathUponRemoval(final IConstituent aConstituent) {
...
This is not a back-pointer,
it is a surrogate for this
219/236
Address
 Consequences
↑ Unique, direct access to any constituent
↑ Path can be build/divided programmatically
↓ Slight impact on memory
 Related to
– Hidden language
220/236
Final Construction
 Name
– Final construction
 Problems
– Objects encapsulate state, which should always
be valid (class invariant)
– Providing setter methods raise questions about
which setters to use and when to use them
221/236
Final Construction
 Example
222/236
Final Construction
 Example
What do you make
of these setters?
223/236
Final Construction
“My long running default with objects is as much as
possible, to create valid objects at construction time.
This advice goes back to Kent Beck's Smalltalk Best
Practice Patterns […]. Constructors with parameters give
you a clear statement of what it means to create a valid
object in an obvious place. If there's more than one way
to do it, create multiple constructors that show the different
combinations.”
—Martin Fowler in Inversion of Control Containers
and the Dependency Injection pattern
(http://www.martinfowler.com/articles/injection.html)
224/236
Final Construction
 Solution
– Provide explicit constructors
– Limit the number of setters
– Limit the necessity to use setters after the
instantiation of an object to obtain a valid object
225/236
Final Construction
 Example
226/236
Final Construction
 Example
Only one setter,
not that important,
could be removed
(for convenience)
227/236
Final Construction
 Consequences
↑ When creating an object, no “bad” surprises
↑ Explicit (and compile-time checks) of the objects
necessary to instantiate a class
↔ The state of some objects must change at run-
time and setters cannot be avoided
228/236
StringBuffer As
Positioning Element
 Name
– StringBuffer as positioning element
 Problems
– Concatenating Strings creates lots of
intermediary objects at runtime
– Concatenated Strings do not look well in IDEs
229/236
StringBuffer As
Positioning Element
 Example
argument
.setValue("-Xmx2048M -classpath ""
+ equinoxLauncherPath
+ "" org.eclipse.equinox.launcher.Main -application PADL_Creator_Cpp_Eclipse.Launcher -data ""
+ this.pathToCurrentWorkspace
+ Common.EQUINOX_RUNTIME_WORKSPACE
+ "" -configuration "file:"
+ this.pathToCurrentWorkspace
+ ".metadata/.plugins/org.eclipse.pde.core/PADL Creator C++ (Eclipse)/" -dev "file:"
+ this.pathToCurrentWorkspace
+ ".metadata/.plugins/org.eclipse.pde.core/PADL Creator C++ (Eclipse)/dev.properties" "
+ architecture + " -consoleLog "
+ Common.ARGUMENT_DIRECTORY_TARGET_CPP_FILES
+ "="" + aRootDirectoryContainingCPPFiles + "" "
+ Common.ARGUMENT_DIRECTORY_PTIDEJ_WORKSPACE
+ "="" + this.pathToCurrentWorkspace + "" ");
230/236
StringBuffer As
Positioning Element
 Solution
– Use StringBuffers to append Strings and
chars without creating temporary Strings
– Use StringBuffers to obtain a more readable
layout of the code
231/236
StringBuffer As
Positioning Element
final StringBuilder arg = new StringBuilder();
arg.append("-Xmx2048M -classpath "");
arg.append(equinoxLauncherPath);
arg.append("" ");
arg.append("org.eclipse.equinox.launcher.Main");
arg.append(" -application PADL_Creator_Cpp_Eclipse.Launcher");
arg.append(" -data "");
arg.append(this.pathToCurrentWorkspace);
arg.append(Common.EQUINOX_RUNTIME_WORKSPACE);
arg.append(""");
arg.append(" -configuration "file:");
arg.append(this.pathToCurrentWorkspace);
arg.append(".metadata/.plugins/org.eclipse.pde.core/PADL Creator C++ (Eclipse)/"");
arg.append(" -dev "file:");
arg.append(this.pathToCurrentWorkspace);
arg.append(".metadata/.plugins/org.eclipse.pde.core/PADL Creator C++ (Eclipse)/dev.properties" ");
arg.append(architecture);
arg.append(" -consoleLog ");
arg.append(Common.ARGUMENT_DIRECTORY_TARGET_CPP_FILES);
arg.append("="");
arg.append(aRootDirectoryContainingCPPFiles);
arg.append("" ");
arg.append(Common.ARGUMENT_DIRECTORY_PTIDEJ_WORKSPACE);
arg.append("="");
arg.append(this.pathToCurrentWorkspace);
arg.append("" ");
argument.setValue(arg.toString());
232/236
StringBuffer As
Positioning Element
 Consequences
– Less temporary objects
– Clearer code
233/236
StringBuffer As
Positioning Element
 Follow-up
– StringBuffer is synchronised
– StringBuilder is similar to StringBuffer
but without synchronised methods
• Faster
234/236
StringBuffer As
Positioning Element
 Follow-up
– See http://stackoverflow.com/questions/47605/
java-string-concatenation-concat-vs-operator
– StringBuilder 0ms (longest 16ms)
– concat() 100,00ms (10s)
– a += b 400,00ms (40s)
String c = a;
for (long i = 0; i < 100000L; i++) {
c = c.concat(b);
}
235/236
Outline
 Introduction
– Patterns
– Case Study
 Patterns
– Process
– Architecture
– Design
– Implementation
 Conclusion
236/236
Conclusion
 Real case study
– Ptidej Tool Suite
 Different patterns
– Different benefits
– Some limitations

Contenu connexe

Similaire à Ptidej Architecture, Design, and Implementation in Action v2.1

Quantitative comparing design processes in digital and traditional sketching
Quantitative comparing design processes in digital and traditional sketchingQuantitative comparing design processes in digital and traditional sketching
Quantitative comparing design processes in digital and traditional sketchingMohd Syahmi
 
Design Patterns and Form Processing
Design Patterns and Form ProcessingDesign Patterns and Form Processing
Design Patterns and Form ProcessingJaime Metcher
 
Intro computational design_mega2016_1_with_recommendedplugins
Intro computational design_mega2016_1_with_recommendedpluginsIntro computational design_mega2016_1_with_recommendedplugins
Intro computational design_mega2016_1_with_recommendedpluginsPirouz Nourian
 
EDBT 2015: Summer School Overview
EDBT 2015: Summer School OverviewEDBT 2015: Summer School Overview
EDBT 2015: Summer School Overviewdgarijo
 
Software Design Patterns Lecutre (Intro)
Software Design Patterns Lecutre (Intro)Software Design Patterns Lecutre (Intro)
Software Design Patterns Lecutre (Intro)VikramJothyPrakash1
 
Design patterns
Design patternsDesign patterns
Design patternsnisheesh
 
Cloudera Data Science Challenge
Cloudera Data Science ChallengeCloudera Data Science Challenge
Cloudera Data Science ChallengeMark Nichols, P.E.
 
Data Science Challenge presentation given to the CinBITools Meetup Group
Data Science Challenge presentation given to the CinBITools Meetup GroupData Science Challenge presentation given to the CinBITools Meetup Group
Data Science Challenge presentation given to the CinBITools Meetup GroupDoug Needham
 
Design patters java_meetup_slideshare [compatibility mode]
Design patters java_meetup_slideshare [compatibility mode]Design patters java_meetup_slideshare [compatibility mode]
Design patters java_meetup_slideshare [compatibility mode]Dimitris Dranidis
 
Oose unit 4 ppt
Oose unit 4 pptOose unit 4 ppt
Oose unit 4 pptDr VISU P
 
Model-based Analysis of Large Scale Software Repositories
Model-based Analysis of Large Scale Software RepositoriesModel-based Analysis of Large Scale Software Repositories
Model-based Analysis of Large Scale Software RepositoriesMarkus Scheidgen
 
OOSE Unit 4 PPT.ppt
OOSE Unit 4 PPT.pptOOSE Unit 4 PPT.ppt
OOSE Unit 4 PPT.pptitadmin33
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringHironori Washizaki
 
Contemporary Software Engineering Practices Together With Enterprise
Contemporary Software Engineering Practices Together With EnterpriseContemporary Software Engineering Practices Together With Enterprise
Contemporary Software Engineering Practices Together With EnterpriseKenan Sevindik
 
Roadmap - SiriusCon2016
Roadmap - SiriusCon2016Roadmap - SiriusCon2016
Roadmap - SiriusCon2016Cédric Brun
 
An Elastic Middleware Platform for Concurrent and Distributed Cloud and MapRe...
An Elastic Middleware Platform for Concurrent and Distributed Cloud and MapRe...An Elastic Middleware Platform for Concurrent and Distributed Cloud and MapRe...
An Elastic Middleware Platform for Concurrent and Distributed Cloud and MapRe...Pradeeban Kathiravelu, Ph.D.
 
01. Birta L. G., Arbez G. - Modelling and Simulation_ (2007).pdf
01. Birta L. G., Arbez G. - Modelling and Simulation_  (2007).pdf01. Birta L. G., Arbez G. - Modelling and Simulation_  (2007).pdf
01. Birta L. G., Arbez G. - Modelling and Simulation_ (2007).pdfAftaZani1
 
Agile and Agile methods: what is the most important to understand to succeed
Agile and Agile methods: what is the most important to understand to succeedAgile and Agile methods: what is the most important to understand to succeed
Agile and Agile methods: what is the most important to understand to succeedVaidas Adomauskas
 
Research @ RELEASeD (presented at SATTOSE2013)
Research @ RELEASeD (presented at SATTOSE2013)Research @ RELEASeD (presented at SATTOSE2013)
Research @ RELEASeD (presented at SATTOSE2013)kim.mens
 

Similaire à Ptidej Architecture, Design, and Implementation in Action v2.1 (20)

Quantitative comparing design processes in digital and traditional sketching
Quantitative comparing design processes in digital and traditional sketchingQuantitative comparing design processes in digital and traditional sketching
Quantitative comparing design processes in digital and traditional sketching
 
Design Patterns and Form Processing
Design Patterns and Form ProcessingDesign Patterns and Form Processing
Design Patterns and Form Processing
 
Intro computational design_mega2016_1_with_recommendedplugins
Intro computational design_mega2016_1_with_recommendedpluginsIntro computational design_mega2016_1_with_recommendedplugins
Intro computational design_mega2016_1_with_recommendedplugins
 
EDBT 2015: Summer School Overview
EDBT 2015: Summer School OverviewEDBT 2015: Summer School Overview
EDBT 2015: Summer School Overview
 
Software Design Patterns Lecutre (Intro)
Software Design Patterns Lecutre (Intro)Software Design Patterns Lecutre (Intro)
Software Design Patterns Lecutre (Intro)
 
Design patterns
Design patternsDesign patterns
Design patterns
 
Cloudera Data Science Challenge
Cloudera Data Science ChallengeCloudera Data Science Challenge
Cloudera Data Science Challenge
 
Data Science Challenge presentation given to the CinBITools Meetup Group
Data Science Challenge presentation given to the CinBITools Meetup GroupData Science Challenge presentation given to the CinBITools Meetup Group
Data Science Challenge presentation given to the CinBITools Meetup Group
 
Design patters java_meetup_slideshare [compatibility mode]
Design patters java_meetup_slideshare [compatibility mode]Design patters java_meetup_slideshare [compatibility mode]
Design patters java_meetup_slideshare [compatibility mode]
 
Oose unit 4 ppt
Oose unit 4 pptOose unit 4 ppt
Oose unit 4 ppt
 
Model-based Analysis of Large Scale Software Repositories
Model-based Analysis of Large Scale Software RepositoriesModel-based Analysis of Large Scale Software Repositories
Model-based Analysis of Large Scale Software Repositories
 
OOSE Unit 4 PPT.ppt
OOSE Unit 4 PPT.pptOOSE Unit 4 PPT.ppt
OOSE Unit 4 PPT.ppt
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their Engineering
 
Contemporary Software Engineering Practices Together With Enterprise
Contemporary Software Engineering Practices Together With EnterpriseContemporary Software Engineering Practices Together With Enterprise
Contemporary Software Engineering Practices Together With Enterprise
 
Roadmap - SiriusCon2016
Roadmap - SiriusCon2016Roadmap - SiriusCon2016
Roadmap - SiriusCon2016
 
An Elastic Middleware Platform for Concurrent and Distributed Cloud and MapRe...
An Elastic Middleware Platform for Concurrent and Distributed Cloud and MapRe...An Elastic Middleware Platform for Concurrent and Distributed Cloud and MapRe...
An Elastic Middleware Platform for Concurrent and Distributed Cloud and MapRe...
 
01. Birta L. G., Arbez G. - Modelling and Simulation_ (2007).pdf
01. Birta L. G., Arbez G. - Modelling and Simulation_  (2007).pdf01. Birta L. G., Arbez G. - Modelling and Simulation_  (2007).pdf
01. Birta L. G., Arbez G. - Modelling and Simulation_ (2007).pdf
 
Agile and Agile methods: what is the most important to understand to succeed
Agile and Agile methods: what is the most important to understand to succeedAgile and Agile methods: what is the most important to understand to succeed
Agile and Agile methods: what is the most important to understand to succeed
 
Research @ RELEASeD (presented at SATTOSE2013)
Research @ RELEASeD (presented at SATTOSE2013)Research @ RELEASeD (presented at SATTOSE2013)
Research @ RELEASeD (presented at SATTOSE2013)
 
cs.pdf
cs.pdfcs.pdf
cs.pdf
 

Plus de Yann-Gaël Guéhéneuc

Advice for writing a NSERC Discovery grant application v0.5
Advice for writing a NSERC Discovery grant application v0.5Advice for writing a NSERC Discovery grant application v0.5
Advice for writing a NSERC Discovery grant application v0.5Yann-Gaël Guéhéneuc
 
Evolution and Examples of Java Features, from Java 1.7 to Java 22
Evolution and Examples of Java Features, from Java 1.7 to Java 22Evolution and Examples of Java Features, from Java 1.7 to Java 22
Evolution and Examples of Java Features, from Java 1.7 to Java 22Yann-Gaël Guéhéneuc
 
Consequences and Principles of Software Quality v0.3
Consequences and Principles of Software Quality v0.3Consequences and Principles of Software Quality v0.3
Consequences and Principles of Software Quality v0.3Yann-Gaël Guéhéneuc
 
Some Pitfalls with Python and Their Possible Solutions v0.9
Some Pitfalls with Python and Their Possible Solutions v0.9Some Pitfalls with Python and Their Possible Solutions v0.9
Some Pitfalls with Python and Their Possible Solutions v0.9Yann-Gaël Guéhéneuc
 
An Explanation of the Unicode, the Text Encoding Standard, Its Usages and Imp...
An Explanation of the Unicode, the Text Encoding Standard, Its Usages and Imp...An Explanation of the Unicode, the Text Encoding Standard, Its Usages and Imp...
An Explanation of the Unicode, the Text Encoding Standard, Its Usages and Imp...Yann-Gaël Guéhéneuc
 
An Explanation of the Halting Problem and Its Consequences
An Explanation of the Halting Problem and Its ConsequencesAn Explanation of the Halting Problem and Its Consequences
An Explanation of the Halting Problem and Its ConsequencesYann-Gaël Guéhéneuc
 
Informaticien(ne)s célèbres (v1.0.2, 19/02/20)
Informaticien(ne)s célèbres (v1.0.2, 19/02/20)Informaticien(ne)s célèbres (v1.0.2, 19/02/20)
Informaticien(ne)s célèbres (v1.0.2, 19/02/20)Yann-Gaël Guéhéneuc
 
On Java Generics, History, Use, Caveats v1.1
On Java Generics, History, Use, Caveats v1.1On Java Generics, History, Use, Caveats v1.1
On Java Generics, History, Use, Caveats v1.1Yann-Gaël Guéhéneuc
 
On Reflection in OO Programming Languages v1.6
On Reflection in OO Programming Languages v1.6On Reflection in OO Programming Languages v1.6
On Reflection in OO Programming Languages v1.6Yann-Gaël Guéhéneuc
 

Plus de Yann-Gaël Guéhéneuc (20)

Advice for writing a NSERC Discovery grant application v0.5
Advice for writing a NSERC Discovery grant application v0.5Advice for writing a NSERC Discovery grant application v0.5
Advice for writing a NSERC Discovery grant application v0.5
 
Evolution and Examples of Java Features, from Java 1.7 to Java 22
Evolution and Examples of Java Features, from Java 1.7 to Java 22Evolution and Examples of Java Features, from Java 1.7 to Java 22
Evolution and Examples of Java Features, from Java 1.7 to Java 22
 
Consequences and Principles of Software Quality v0.3
Consequences and Principles of Software Quality v0.3Consequences and Principles of Software Quality v0.3
Consequences and Principles of Software Quality v0.3
 
Some Pitfalls with Python and Their Possible Solutions v0.9
Some Pitfalls with Python and Their Possible Solutions v0.9Some Pitfalls with Python and Their Possible Solutions v0.9
Some Pitfalls with Python and Their Possible Solutions v0.9
 
An Explanation of the Unicode, the Text Encoding Standard, Its Usages and Imp...
An Explanation of the Unicode, the Text Encoding Standard, Its Usages and Imp...An Explanation of the Unicode, the Text Encoding Standard, Its Usages and Imp...
An Explanation of the Unicode, the Text Encoding Standard, Its Usages and Imp...
 
An Explanation of the Halting Problem and Its Consequences
An Explanation of the Halting Problem and Its ConsequencesAn Explanation of the Halting Problem and Its Consequences
An Explanation of the Halting Problem and Its Consequences
 
Are CPUs VMs Like Any Others? v1.0
Are CPUs VMs Like Any Others? v1.0Are CPUs VMs Like Any Others? v1.0
Are CPUs VMs Like Any Others? v1.0
 
Informaticien(ne)s célèbres (v1.0.2, 19/02/20)
Informaticien(ne)s célèbres (v1.0.2, 19/02/20)Informaticien(ne)s célèbres (v1.0.2, 19/02/20)
Informaticien(ne)s célèbres (v1.0.2, 19/02/20)
 
Well-known Computer Scientists v1.0.2
Well-known Computer Scientists v1.0.2Well-known Computer Scientists v1.0.2
Well-known Computer Scientists v1.0.2
 
On Java Generics, History, Use, Caveats v1.1
On Java Generics, History, Use, Caveats v1.1On Java Generics, History, Use, Caveats v1.1
On Java Generics, History, Use, Caveats v1.1
 
On Reflection in OO Programming Languages v1.6
On Reflection in OO Programming Languages v1.6On Reflection in OO Programming Languages v1.6
On Reflection in OO Programming Languages v1.6
 
ICSOC'21
ICSOC'21ICSOC'21
ICSOC'21
 
Vissoft21.ppt
Vissoft21.pptVissoft21.ppt
Vissoft21.ppt
 
Service computation20.ppt
Service computation20.pptService computation20.ppt
Service computation20.ppt
 
Serp4 iot20.ppt
Serp4 iot20.pptSerp4 iot20.ppt
Serp4 iot20.ppt
 
Msr20.ppt
Msr20.pptMsr20.ppt
Msr20.ppt
 
Iwesep19.ppt
Iwesep19.pptIwesep19.ppt
Iwesep19.ppt
 
Icsoc20.ppt
Icsoc20.pptIcsoc20.ppt
Icsoc20.ppt
 
Icsoc18.ppt
Icsoc18.pptIcsoc18.ppt
Icsoc18.ppt
 
Icsm20.ppt
Icsm20.pptIcsm20.ppt
Icsm20.ppt
 

Dernier

ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Intelisync
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 

Dernier (20)

ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 

Ptidej Architecture, Design, and Implementation in Action v2.1

  • 1. Yann-Gaël Guéhéneuc (/jan/, he/il) Work licensed under Creative Commons BY-NC-SA 4.0 International Architecture, Design, and Implementation in Action yann-gael.gueheneuc@polytmtl.ca Version 2.1 24/03/29
  • 2. 2/236 Patterns  Patterns document reusable solutions to recurring problems – Architecture • Architectural styles – Design • Design patterns • Design anti-patterns – Implementation • Idioms
  • 3. 3/236 Example  Do you know – C++? – Java? – Lisp? – Prolog? – Smalltalk?
  • 4. 4/236 C++ class Dog { string name; Dog(const Dog* dog) : name(dog→ → → →name) {}} class Kennel { Dog* dog; string name; } if (&kennel != this) { this→ → → →dog = new Dog(kennel.dog); this→ → → →name = kennel.name; } return *this; Suite… Bruce Eckel ; Thinking in C++ ; Volume 2, pages 551–553, Planet PDF, 2nd Edition, 2000.
  • 5. 5/236 C++ class Dog { string name; Dog(const Dog* dog) : name(dog→ → → →name) {}} class Kennel { Dog* dog; string name; } if (&kennel != this) { this→ → → →dog = new Dog(kennel.dog); this→ → → →name = kennel.name; } return *this; Suite… Bruce Eckel ; Thinking in C++ ; Volume 2, pages 551–553, Planet PDF, 2nd Edition, 2000. ?
  • 6. 6/236 C++ class Dog { string name; Dog(const Dog* dog) : name(dog→ → → →name) {}} class Kennel { Dog* dog; string name; } if (&kennel != this) { this→ → → →dog = new Dog(kennel.dog); this→ → → →name = kennel.name; } return *this; Suite… Bruce Eckel ; Thinking in C++ ; Volume 2, pages 551–553, Planet PDF, 2nd Edition, 2000. ? Overriding of operator =
  • 7. 7/236 Java final Object oldListOfEntities = this.listOfEntities(); this.fireVetoableChange( "RemoveEntity", oldListOfEntities, anEntity); this.removeEntity(anEntity); this.firePropertyChange( "RemoveEntity", oldListOfEntities, anEntity); Suite…
  • 8. 8/236 Java final Object oldListOfEntities = this.listOfEntities(); this.fireVetoableChange( "RemoveEntity", oldListOfEntities, anEntity); this.removeEntity(anEntity); this.firePropertyChange( "RemoveEntity", oldListOfEntities, anEntity); Suite… ?
  • 9. 9/236 Java final Object oldListOfEntities = this.listOfEntities(); this.fireVetoableChange( "RemoveEntity", oldListOfEntities, anEntity); this.removeEntity(anEntity); this.firePropertyChange( "RemoveEntity", oldListOfEntities, anEntity); Suite… ? Veto protocol of JavaBeans
  • 10. 10/236 (define (square ls) (if (null? ls) '() (cons (( lambda(x) (* x x)) (car ls)) (square (cdr ls))))) Lisp Suite…
  • 11. 11/236 (define (square ls) (if (null? ls) '() (cons (( lambda(x) (* x x)) (car ls)) (square (cdr ls))))) Lisp Suite… ?
  • 12. 12/236 (define (square ls) (if (null? ls) '() (cons (( lambda(x) (* x x)) (car ls)) (square (cdr ls))))) Lisp Suite… ? Map
  • 13. 13/236 Prolog checkLt0(LA, LT, LD, NNLA, NNLT, NNLD) :- nextEvent( [], E), interpretEvent(E, IE), checkLt1(IE, LA, LT, LD, NLA, NLT, NLD), !, ( (IE = programEnd, NNLA = NLA, NNLT = NLT, NNLD = NLD) ; checkLt0(NLA, NLT, NLD, NNLA, NNLT, NNLD) ). Suite…
  • 14. 14/236 Prolog checkLt0(LA, LT, LD, NNLA, NNLT, NNLD) :- nextEvent( [], E), interpretEvent(E, IE), checkLt1(IE, LA, LT, LD, NLA, NLT, NLD), !, ( (IE = programEnd, NNLA = NLA, NNLT = NLT, NNLD = NLD) ; checkLt0(NLA, NLT, NLD, NNLA, NNLT, NNLD) ). ? Suite…
  • 15. 15/236 Prolog checkLt0(LA, LT, LD, NNLA, NNLT, NNLD) :- nextEvent( [], E), interpretEvent(E, IE), checkLt1(IE, LA, LT, LD, NLA, NLT, NLD), !, ( (IE = programEnd, NNLA = NLA, NNLT = NLT, NNLD = NLD) ; checkLt0(NLA, NLT, NLD, NNLA, NNLT, NNLD) ). ? Condition Suite…
  • 16. 16/236 Smalltalk Integer>>+ aNumber ^aNumber addInteger: self Float>>+ aNumber ^aNumber addFloat: self Integer>>addInteger: anInteger <primitive: 1> Float>>addFloat: aFloat <primitive: 2> Integer>>addFloat: aFloat ^self asFloat addFloat: aFloat Float>>addInteger: anInteger ^self addFloat: anInteger asFloat Kent Beck ; Smalltalk – Best practice patterns ; Pages 55–57, Prentice Hall, 1997, ISBN 0-13-476904-X.
  • 17. 17/236 Smalltalk Integer>>+ aNumber ^aNumber addInteger: self Float>>+ aNumber ^aNumber addFloat: self Integer>>addInteger: anInteger <primitive: 1> Float>>addFloat: aFloat <primitive: 2> Integer>>addFloat: aFloat ^self asFloat addFloat: aFloat Float>>addInteger: anInteger ^self addFloat: anInteger asFloat Kent Beck ; Smalltalk – Best practice patterns ; Pages 55–57, Prentice Hall, 1997, ISBN 0-13-476904-X. ?
  • 18. 18/236 Smalltalk Integer>>+ aNumber ^aNumber addInteger: self Float>>+ aNumber ^aNumber addFloat: self Integer>>addInteger: anInteger <primitive: 1> Float>>addFloat: aFloat <primitive: 2> Integer>>addFloat: aFloat ^self asFloat addFloat: aFloat Float>>addInteger: anInteger ^self addFloat: anInteger asFloat Kent Beck ; Smalltalk – Best practice patterns ; Pages 55–57, Prentice Hall, 1997, ISBN 0-13-476904-X. ? Double dispatching
  • 19. 19/236 Conclusion on the Example  You identified idioms in the given pieces of source code  These idioms are motifs in a program source code  These motifs connote a recognized style of programming
  • 20. 20/236 Motivations  To ease the understanding of a program architecture to improve its quality  To identify motifs in the program architecture
  • 21. 21/236 Outline  Introduction – Patterns – Case Study  Patterns – Process – Architecture – Design – Implementation  Conclusion
  • 22. 22/236 Outline  Introduction – Patterns – Case Study  Patterns – Process – Architecture – Design – Implementation  Conclusion
  • 23. 23/236 Patterns  Several books, articles – “Theoretical” – With examples – Among others…
  • 24. 24/236 Patterns  Several books, articles – “Theoretical” – With examples – Among others…
  • 25. 25/236 Patterns  Several books, articles – “Theoretical” – With examples – Among others…
  • 26. 26/236 Patterns  Several books, articles – “Theoretical” – With examples – Among others…
  • 27. 27/236 Patterns  Several books, articles – “Theoretical” – With examples – Among others…
  • 28. 28/236 Patterns  Several books, articles – “Theoretical” – With examples – Among others…
  • 29. 29/236 Patterns  Several books, articles – Amazon.com • Books › Computers & Technology › Programming › Software Design, Testing & Engineering › Object- Oriented Design › "patterns" • 224 results on May 31, 2013
  • 30. 30/236 Patterns  Several books, articles – Amazon.com • Exclusion – Unreleased books – Specific to a technology or frameworks » e.g., MVVM Unleashed by Michael Brown – Process oriented, user-interface, programming languages » e.g., Process Patterns: Building Large-Scale Systems Using Object Technology by Scott W. Ambler and Barbara Hanscome – Proceedings of conferences – Unrelated to software engineering
  • 31. 31/236 Patterns 1. Pattern-Oriented Software Architecture, Patterns for Concurrent and Networked Objects: Volume 2 (Wiley Software... by Douglas C. Schmidt, Michael Stal, Hans Rohnert and Frank Buschmann 2. Pattern-Oriented Software Architecture, Patterns for Resource Management: Volume 3 (Wiley Software Patterns Series... by Michael Kircher and Prashant Jain 3. Pattern-Oriented Software Architecture, A System of Patterns: Volume 1 (Wiley Software Patterns Series) by Frank Buschmann, Regine Meunier, Hans Rohnert and Peter Sommerlad 4. Pattern-Oriented Software Architecture For Dummies (For Dummies (Computers)) by Robert Hanmer 5. Web Security Patterns by Ramesh Nagappan and Christopher Steel 6. Safe C++ by Vladimir Kushnir 7. Programming in the Large with Design Patterns by Eddie Burris 8. Elemental Design Patterns by Jason McC. Smith 9. Java Application Architecture: Modularity Patterns with Examples Using OSGi (Robert C. Martin Series) by Kirk Knoernschild 10. Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions (Addison-Wesley Signature... by Gregor Hohpe and Bobby Woolf 11. Patterns of Enterprise Application Architecture (Addison-Wesley Signature Series (Fowler)) by Martin Fowler 12. Cognitive Patterns: Problem-Solving Frameworks for Object Technology by Robert K Konitzer, Bobbin Teegarden, Alexander Rush and Karen M Gardner 13. Service Design Patterns: Fundamental Design Solutions for SOAP/WSDL and RESTful Web Services by Robert Daigneau 14. The ACE Programmer's Guide: Practical Design Patterns for Network and Systems Programming by Stephen D. Huston, James CE Johnson and Umar Syyid 15. Patterns for Parallel Software Design (Wiley Software Patterns Series) by Jorge Luis Ortega-Arjona 16. Design Patterns in Object-oriented ABAP by Igor Barbaric 17. Object-Oriented Reengineering Patterns by Oscar Nierstrasz, Stéphane Ducasse and Serge Demeyer 18. Dependency Injection by Dhanji R. Prasanna 19. Object-Oriented Software Engineering Using UML, Patterns, and Java (3rd Edition) by Bernd Bruegge and Allen H. Dutoit 20. J2EE Design Patterns by William Crawford and Jonathan Kaplan 21. Applying UML and Patterns: An Introduction to Object-oriented Analysis and Design and Iterative Development by Craig Larman 22. Object-oriented Analysis and Design Using Umlan Introduction to Unified Process and Design Patterns by Mahesh P. Matha 23. C++ Design Patterns and Derivatives Pricing (Mathematics, Finance and Risk) by M. S. Joshi 24. Effective Java (2nd Edition) by Joshua Bloch 25. Patterns for Fault Tolerant Software (Wiley Software Patterns Series) by Robert Hanmer 26. Implementation Patterns by Kent Beck 27. Patterns for Computer-Mediated Interaction (Wiley Software Patterns Series) by Till Schummer and Stephan Lukosch 28. Pattern Oriented Software Architecture Volume 5: On Patterns and Pattern Languages by Frank Buschmann, Kevlin Henney and Douglas C. Schmidt 29. Object-Oriented Analysis and Design with Applications (3rd Edition) by Grady Booch, Robert A. Maksimchuk, Michael W. Engle and Bobbi J. Young 30. Head First Object-Oriented Analysis and Design by Brett D. McLaughlin, Gary Pollice and Dave West 31. Agile Principles, Patterns, and Practices in C# by Robert C. Martin and Micah Martin 32. Design Patterns For Dummies by Steve Holzner 33. Pattern Languages of Program Design 5 by Dragos Manolescu, Markus Voelter and James Noble 34. Design Patterns in Java(TM) (Software Patterns Series) by Steven John Metsker and William C. Wake 35. Object-Oriented Design and Patterns by Cay S. Horstmann 37. Object-Oriented Modeling and Design with UML (2nd Edition) by Michael R. Blaha and James R Rumbaugh 38. Remoting Patterns: Foundations of Enterprise, Internet and Realtime Distributed Object Middleware (Wiley Software... by Markus Völter, Michael Kircher and Uwe Zdun 39. Software Factories: Assembling Applications with Patterns, Models, Frameworks, and Tools (Wiley Application Development... by Jack Greenfield, Keith Short, Steve Cook and Stuart Kent 40. Refactoring to Patterns by Joshua Kerievsky 41. Architecting Enterprise Solutions: Patterns for High-Capability Internet-based Systems (Wiley Software Patterns... by Paul Dyson and Andrew Longshaw 42. Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML by Jim Arlow and Ila Neustadt 43. Data Access Patterns: Database Interactions in Object-Oriented Applications by Clifton Nock 44. Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans 45. Pattern-Oriented Analysis and Design: Composing Patterns to Design Software Systems by Sherif M. Yacoub, Hany H. Ammar, Sherif Yacoub and Hany Ammar 46. Java Extreme Programming Cookbook by Eric M. Burke and Brian M. Coyner 47. J2EE Best Practices: Java Design Patterns, Automation, and Performance (Wiley Application Development Series) by Darren Broemmer 48. Real-Time Design Patterns: Robust Scalable Architecture for Real-Time Systems by Bruce Powel Douglass 49. Design Patterns Java¿ Workbook by Steven John Metsker 50. EJB Design Patterns: Advanced Patterns, Processes, and Idioms by Floyd Marinescu 51. Streamlined Object Modeling: Patterns, Rules, and Implementation by Jill Nicola, Mark Mayfield and Mike Abney 52. Design Patterns Explained: A New Perspective on Object-Oriented Design by Alan Shalloway and James Trott 53. Small Memory Software: Patterns for systems with limited memory (Software Patterns Series) by James Noble and Charles Weir 54. AntiPatterns in Project Management by William J. Brown, Hays W. "Skip" McCormick III and Scott W. Thomas 55. Pattern Languages of Program Design 4 (Software Patterns Series) by Brian Foote, Neil Harrison and Hans Rohnert 56. Testing Object-Oriented Systems: Models, Patterns, and Tools by Robert V. Binder 57. Design Patterns and Contracts by Jean-Marc Jezequel, Michel Train and Christine Mingins 58. Object-Oriented Software Development Using Java: Principles, Patterns, and Frameworks (1/e) by Xiaoping Jia 59. Refactoring: Improving the Design of Existing Code by Martin Fowler, Kent Beck, John Brant and William Opdyke 60. More Process Patterns: Delivering Large-Scale Systems Using Object Technology (SIGS: Managing Object Technology... by Scott W. Ambler 61. Pattern Hatching: Design Patterns Applied by John Vlissides 62. AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis by William J. Brown, Raphael C. Malveau, Hays W. "Skip" McCormick and Thomas J. Mowbray 63. A Little Java, A Few Patterns (Language, Speech, & Communication) by Matthias Felleisen, Daniel P. Friedman and Ralph E. Johnson 64. Pattern Languages of Program Design 3 (v. 3) by Robert C. Martin, Dirk Riehle and Frank Buschmann 65. Object Models: Strategies, Patterns, and Applications (2nd Edition) by Peter Coad, David North and Mark Mayfield 66. Analysis Patterns: Reusable Object Models by Martin Fowler 67. Patterns of Software: Tales from the Software Community by Richard P. Gabriel 68. Pattern Languages of Program Design 2 (v. 2) by John Vlissides, James O. Coplien and Norman L. Kerth 69. Software Patterns by James Coplien 70. Software Architecture: Perspectives on an Emerging Discipline by Mary Shaw and David Garlan 71. Adaptive Object-Oriented Software: The Demeter Method with Propagation Patterns: The Demeter Method with Propagation... by Karl Lieberherr 72. Pattern Languages of Program Design by James O. Coplien and Douglas C. Schmidt
  • 32. 32/236 Patterns  The following is not a substitute to reading previous books and practicing  The following is complementary to reading books and practicing – These patterns that have been “found” the hard way and that work (or do not work!)
  • 33. 33/236 Patterns  The following is not a substitute to reading these books and practicing  The following is complementary to reading books and practicing – These patterns that have been “found” the hard way and that work (or do not work!)
  • 34. 34/236 Patterns  General form as for the GoF , also inspired by Coplien’s form – Name – Problem(s) – Solution – Consequences
  • 35. 35/236 Patterns  General form as for the GoF, also inspired by Coplien’s form – Name – Problem(s) – Example(s) – Solution – Example(s) – Consequences – (Follow-up)
  • 36. 36/236 Patterns  General form as for the GoF, also inspired by Coplien’s form – Name – Problem(s) – Example(s) – Solution – Example(s) – Consequences – (Follow-up) Problem: Solution:
  • 37. 37/236 Patterns  General form as for the GoF, also inspired by Coplien’s form – Not formal – Room for interpretation – But… • UML-like class diagrams • UML-like sequence diagrams • Smalltalk / C++ example code
  • 38. 38/236 Problems  What motifs and what model for these motifs?  What model for the program architecture?  How to perform the identification?
  • 39. 39/236 Our Solution  What motifs and what model for these motifs?  What model for the program architecture?  How to perform the identification?
  • 40. 40/236 Our Solution  What motifs and what model for these motifs?  What model for the program architecture?  How to perform the identification? Design motifs and the PADL meta-model
  • 41. 41/236 Our Solution  What motifs and what model for these motifs?  What model for the program architecture?  How to perform the identification? Design motifs and the PADL meta-model
  • 42. 42/236 Our Solution  What motifs and what model for these motifs?  What model for the program architecture?  How to perform the identification? Design Meta-modelling Design motifs and the PADL meta-model
  • 43. 43/236 Our Solution  What motifs and what model for these motifs?  What model for the program architecture?  How to perform the identification? Design Meta-modelling Design motifs and the PADL meta-model
  • 44. 44/236 Our Solution  What motifs and what model for these motifs?  What model for the program architecture?  How to perform the identification? Design Meta-modelling Design motifs and the PADL meta-model
  • 45. 45/236 Our Solution  What motifs and what model for these motifs?  What model for the program architecture?  How to perform the identification? Design Meta-modelling Design motifs and the PADL meta-model
  • 46. 46/236 Outline  Introduction – Patterns – Case Study  Architecture  Design  Implementation – Idioms  Conclusion
  • 47. 47/236 Case Study “[E]xisting books on design patterns take a catalog approach, where they show the individual design patterns in isolation. This approach is […] flawed, because you can't see how the design patterns actually function in the real world. Most programmers learn by looking at computer programs.” —Allen Holub in Holub on Patterns: Learning Design Patterns by Looking at Code
  • 48. 48/236 Ptidej Tool Suite  Context – Research work started since my Ph.D. thesis (2000–2003) – Pattern Trace Identification, Detection, and Enhancement in Java • Theories, methods, and tools, to evaluate and to improve the quality of object-oriented programs by promoting the use of idioms, design patterns, and architectural patterns
  • 49. 49/236 Ptidej Tool Suite  Requirements – Software tools • Support the analysis of the implementation, design, and architecture of object-oriented programs • Support the detection and introduction of patterns at the code, design, and architectural levels
  • 50. 50/236 Ptidej Tool Suite  Analysis – Domain concepts • “quality of object-oriented” • “promoting the use of idioms, design patterns, and architectural patterns” • “analysis of the implementation, design, and architecture of object-oriented programs” • “detection and introduction of patterns at the code, design, and architectural levels”
  • 51. 51/236 Ptidej Tool Suite  Analysis – Domain concepts • “quality of object-oriented” • “promoting the use of idioms, design patterns, and architectural patterns” • “analysis of the implementation, design, and architecture of object-oriented programs” • “detection and introduction of patterns at the code, design, and architectural levels”
  • 52. 52/236 Ptidej Tool Suite  Constraint – Apply patterns/best practices (existing or new) when developing the tools • Architectural • Design • Implementation – Self-imposed but sensible • “Eating your own dog food” (http://www.urbandictionary.com/define.php? term=eating%20your%20own%20dog%20food)
  • 53. 53/236 Ptidej Tool Suite  Related work – Various parsers (target languages) e.g., GCCXML – Various meta-model (sometimes implicit) • Similar to UML meta-model (1997) • Before OMG KDM (2003) • Before Eclipse EMF (2004) • Before OMG MOF (2006) – Various tools e.g., Rigi (H. M. Kienle and H. A. Müller: Rigi – An environment for software reverse engineering, exploration, visualization, and redocumentation. Sci. Comput. Program. 75(4): 247-263, 2010)
  • 54. 54/236 Ptidej Tool Suite  Related work ↑ Existing  ↓ Too low-level e.g., GCCXML ↓ No “free” parsers e.g., UML meta-model ↓ Difficult to access / to use / to adapt e.g., Rigi
  • 55. 55/236 Ptidej Tool Suite  Related work – Pierre Cointe’s team in 2000 at École des Mines de Nantes, France – Fertile ground • Hervé Albin-Amiot was already developing a meta- model to describe design patterns – “Idioms and patterns Java: application to code synthesis and detection” (Ph.D. in 2003) – PDL (Pattern Description Language)
  • 56. 56/236 Ptidej Tool Suite What to detect? How to express it? In what to detect it?
  • 57. 57/236 Ptidej Tool Suite “Great software is not built, it is grown” —Bill de hÓra in 97 Things Every Software Architect Should Know
  • 58. 58/236 Ptidej Tool Suite Design Patterns PDL meta- model Models of OO programs
  • 60. 60/236 Ptidej Tool Suite + Models of OO programs  PDL meta-model
  • 61. 61/236 Ptidej Tool Suite + Models of OO programs = PADL meta-model PDL meta-model
  • 62. 62/236 Ptidej Tool Suite PADL Pattern and Abstract-level Description Language
  • 63. 63/236 Ptidej Tool Suite PADL Creators C++, C#, Java, JavaScript? PADL Pattern and Abstract-level Description Language
  • 64. 64/236 Ptidej Tool Suite PADL Analyses • Binary Class Relationships • Systematic UML PADL Creators C++, C#, Java, JavaScript? PADL Pattern and Abstract-level Description Language
  • 65. 65/236 Ptidej Tool Suite PADL Generators XMI… PADL Analyses • Binary Class Relationships • Systematic UML PADL Creators C++, C#, Java, JavaScript? PADL Pattern and Abstract-level Description Language
  • 66. 66/236 Ptidej Tool Suite PADL Serialisers DB4O, JOS… PADL Generators XMI… PADL Analyses • Binary Class Relationships • Systematic UML PADL Creators C++, C#, Java, JavaScript? PADL Pattern and Abstract-level Description Language
  • 67. 67/236 Ptidej Tool Suite PADL Serialisers DB4O, JOS… PADL Generators XMI… PADL Design Motifs Anti-patterns, code smells, and µ-patterns PADL Analyses • Binary Class Relationships • Systematic UML PADL Creators C++, C#, Java, JavaScript? PADL Pattern and Abstract-level Description Language
  • 68. 68/236 Ptidej Tool Suite POM Primitives, Operations, Metrics PADL Serialisers DB4O, JOS… PADL Generators XMI… PADL Design Motifs Anti-patterns, code smells, and µ-patterns PADL Analyses • Binary Class Relationships • Systematic UML PADL Creators C++, C#, Java, JavaScript? PADL Pattern and Abstract-level Description Language
  • 69. 69/236 Ptidej Tool Suite (Ptidej Solver) Identification of design motifs POM Primitives, Operations, Metrics PADL Serialisers DB4O, JOS… PADL Generators XMI… PADL Design Motifs Anti-patterns, code smells, and µ-patterns PADL Analyses • Binary Class Relationships • Systematic UML PADL Creators C++, C#, Java, JavaScript? PADL Pattern and Abstract-level Description Language
  • 70. 70/236 Ptidej Tool Suite SAD Identification of anti-patterns (Ptidej Solver) Identification of design motifs POM Primitives, Operations, Metrics PADL Serialisers DB4O, JOS… PADL Generators XMI… PADL Design Motifs Anti-patterns, code smells, and µ-patterns PADL Analyses • Binary Class Relationships • Systematic UML PADL Creators C++, C#, Java, JavaScript? PADL Pattern and Abstract-level Description Language
  • 71. 71/236 Ptidej Tool Suite SAD Identification of anti-patterns (Ptidej Solver) Identification of design motifs POM Primitives, Operations, Metrics PADL Serialisers DB4O, JOS… PADL Generators XMI… PADL Design Motifs Anti-patterns, code smells, and µ-patterns PADL Analyses • Binary Class Relationships • Systematic UML PADL Creators C++, C#, Java, JavaScript? PADL Pattern and Abstract-level Description Language Ptidej UI User interface (using reflection)
  • 72. 72/236 Ptidej UI Viewer Standalone Swing displaying PADL (Another example of “Eating your own dog food” )
  • 73. 73/236 PADL Kernel, main interfaces provided to the users (SVG and JPG from Ptidej UI Viewer Standalone Swing)
  • 74. 74/236 PADL Kernel, abstract-level models Describe models of programs, including design motifs
  • 76. 76/236 PADL Kernel, entities Describe classes, interfaces…
  • 77. 77/236 PADL Kernel, relationships Describe inheritances, associations…
  • 78. 78/236 Ptidej Tool Suite  Advantages – Creators – BCRs – Extensibility – Reliability (Has been used in many studies)
  • 79. 79/236 Ptidej Tool Suite  Advantages – Available!  • https://web.soccerlab.polymtl.ca/rptidej/ptidejlab/ Software/Ptidej 5 Workspace • Username: guestsvn • Password: g1u2e3s4t5 – See also • http://www.ptidej.net/material/inanutshell • http://www.ptidej.net/material/development/ • http://wiki.ptidej.net/doku.php
  • 80. 80/236 Ptidej Tool Suite  Advantages – Extensible e.g., C++ creator provide new/modified constituent • Factory design pattern • Builder design pattern – Including for the user interface
  • 81. 81/236 Ptidej Tool Suite  Limits – Coarse representation of method statements – Unsatisfactory support of non-typed, non-object- oriented programming languages • (Very) partial support for Smalltalk
  • 82. 82/236 Ptidej Tool Suite  Performance – Eclipse v3.1 – Google Chrome v1.0.154.53 • Quality of the model under tests
  • 83. 83/236 Ptidej Tool Suite  Academic Usage – Dozen of empirical studies e.g., S. Kpodjedo, F. Ricca, P. Galinier, G. Antoniol, and Y.-G. Guéhéneuc. MADMatch: Many-to-many Approximate Diagram Matching for Design Comparison. IEEE TSE, Feburary 2013 – Please see • http://www.ptidej.net/publications/
  • 84. 84/236 Ptidej Tool Suite  Concrete Usage – Build a model from some C++ code (1/2) public static IIdiomLevelModel generateModelFromCppFilesUsingEclipse( final String aName, final String aSourceDirectory, final IModelListener aModelListener) { ICodeLevelModel codeLevelModel = null; try { final ICodeLevelModelCreator creator = new padl.creator.cppfile.eclipse.CppCreator(aSourceDirectory); codeLevelModel = CPPFactoryEclipse.getInstance().createCodeLevelModel(aName); if (aModelListener != null) { codeLevelModel.addModelListener(aModelListener); } codeLevelModel.create(creator); } catch (final CreationException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); } ...
  • 85. 85/236 Ptidej Tool Suite  Concrete Usage – Build a model from some C++ code (1/2) public static IIdiomLevelModel generateModelFromCppFilesUsingEclipse( final String aName, final String aSourceDirectory, final IModelListener aModelListener) { ICodeLevelModel codeLevelModel = null; try { final ICodeLevelModelCreator creator = new padl.creator.cppfile.eclipse.CppCreator(aSourceDirectory); codeLevelModel = CPPFactoryEclipse.getInstance().createCodeLevelModel(aName); if (aModelListener != null) { codeLevelModel.addModelListener(aModelListener); } codeLevelModel.create(creator); } catch (final CreationException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); } ... Specialised creator
  • 86. 86/236 Ptidej Tool Suite  Concrete Usage – Build a model from some C++ code (1/2) public static IIdiomLevelModel generateModelFromCppFilesUsingEclipse( final String aName, final String aSourceDirectory, final IModelListener aModelListener) { ICodeLevelModel codeLevelModel = null; try { final ICodeLevelModelCreator creator = new padl.creator.cppfile.eclipse.CppCreator(aSourceDirectory); codeLevelModel = CPPFactoryEclipse.getInstance().createCodeLevelModel(aName); if (aModelListener != null) { codeLevelModel.addModelListener(aModelListener); } codeLevelModel.create(creator); } catch (final CreationException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); } ... Specialised creator Specialised factory to allow new constituents
  • 87. 87/236 Ptidej Tool Suite  Concrete Usage – Build a model from some C++ code (1/2) public static IIdiomLevelModel generateModelFromCppFilesUsingEclipse( final String aName, final String aSourceDirectory, final IModelListener aModelListener) { ICodeLevelModel codeLevelModel = null; try { final ICodeLevelModelCreator creator = new padl.creator.cppfile.eclipse.CppCreator(aSourceDirectory); codeLevelModel = CPPFactoryEclipse.getInstance().createCodeLevelModel(aName); if (aModelListener != null) { codeLevelModel.addModelListener(aModelListener); } codeLevelModel.create(creator); } catch (final CreationException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); } ... Specialised creator Specialised factory to allow new constituents Builder design pattern
  • 88. 88/236 Ptidej Tool Suite  Concrete Usage – Build a model from some C++ code (2/2) public static IIdiomLevelModel generateModelFromCppFilesUsingEclipse( final String aName, final String aSourceDirectory, final IModelListener aModelListener) { ... IIdiomLevelModel idiomLevelModel = null; try { idiomLevelModel = (IIdiomLevelModel) new AACRelationshipsAnalysis().invoke(aCodeLevelModel); } catch (final UnsupportedSourceModelException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); } return idiomLevelModel; }
  • 89. 89/236 Ptidej Tool Suite  Concrete Usage – Build a model from some C++ code (2/2) public static IIdiomLevelModel generateModelFromCppFilesUsingEclipse( final String aName, final String aSourceDirectory, final IModelListener aModelListener) { ... IIdiomLevelModel idiomLevelModel = null; try { idiomLevelModel = (IIdiomLevelModel) new AACRelationshipsAnalysis().invoke(aCodeLevelModel); } catch (final UnsupportedSourceModelException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); } return idiomLevelModel; } Promotion of the model
  • 90. 90/236 Ptidej Tool Suite  Concrete Usage – Identify occurrence of the Composite DM final Problem problem = CompositeMotif.getProblem(Manager.build(idiomLevelModel)); final StringWriter writer = new StringWriter(); problem.setWriter(new PrintWriter(writer)); problem.automaticSolve(true); final Properties properties = new Properties(); properties.load(new ReaderInputStream(new StringReader(writer.getBuffer().toString()))); final OccurrenceBuilder solutionBuilder = OccurrenceBuilder.getInstance(); final Occurrence[] solutions = solutionBuilder.getCanonicalOccurrences(properties);
  • 91. 91/236 Ptidej Tool Suite  Concrete Usage – Identify occurrence of the Composite DM final Problem problem = CompositeMotif.getProblem(Manager.build(idiomLevelModel)); final StringWriter writer = new StringWriter(); problem.setWriter(new PrintWriter(writer)); problem.automaticSolve(true); final Properties properties = new Properties(); properties.load(new ReaderInputStream(new StringReader(writer.getBuffer().toString()))); final OccurrenceBuilder solutionBuilder = OccurrenceBuilder.getInstance(); final Occurrence[] solutions = solutionBuilder.getCanonicalOccurrences(properties); From a library of design motifs
  • 92. 92/236 Ptidej Tool Suite  Concrete Usage – Identify occurrence of the Blob anti-pattern final IDesignSmellDetection detection = (IDesignSmellDetection) new BlobDetection(); detection.setMetricsFileRepository(ClassFileRepository.getInstance(Repository.class)); detection.setModel(idiomLevelModel); detection.performDetection(); final String path = ...; detection.output(new PrintWriter(ProxyDisk.getInstance().fileTempOutput(path))); final Properties properties = new Properties(); properties.load(new ReaderInputStream(ProxyDisk.getInstance().fileTempInput(path))); final OccurrenceBuilder solutionBuilder = OccurrenceBuilder.getInstance(); final Occurrence[] solutions = solutionBuilder.getCanonicalOccurrences(properties);
  • 93. 93/236 Ptidej Tool Suite  Concrete Usage – Identify occurrence of the Blob anti-pattern final IDesignSmellDetection detection = (IDesignSmellDetection) new BlobDetection(); detection.setMetricsFileRepository(ClassFileRepository.getInstance(Repository.class)); detection.setModel(idiomLevelModel); detection.performDetection(); final String path = ...; detection.output(new PrintWriter(ProxyDisk.getInstance().fileTempOutput(path))); final Properties properties = new Properties(); properties.load(new ReaderInputStream(ProxyDisk.getInstance().fileTempInput(path))); final OccurrenceBuilder solutionBuilder = OccurrenceBuilder.getInstance(); final Occurrence[] solutions = solutionBuilder.getCanonicalOccurrences(properties); From a library of anti-patterns
  • 94. 94/236 Ptidej Tool Suite  Limitations and future work – Treatment and modelling of method bodies • Coarse grain multi-language support for method bodies currently available • Fine grain through meta-model extension – Treatment and modelling of non-typed, non- object-oriented programming languages • Unsatisfactory support for Smalltalk • No support for PHP, JavaScript
  • 95. 95/236 Ptidej Tool Suite  Limitations and future work – Treatment and modelling of method bodies • Coarse grain multi-language support for method bodies currently available • Fine grain through meta-model extension – Treatment and modelling of non-typed, non- object-oriented programming languages • Unsatisfactory support for Smalltalk • No support for PHP, JavaScript
  • 96. 96/236 Outline  Introduction – Patterns – Case Study  Patterns – Process – Architecture – Design – Implementation  Conclusion
  • 97. 97/236 Patterns  We (tried to) follow best practices when developing the Ptidej Tool Suite
  • 98. 98/236 Outline  Introduction – Patterns – Case Study  Patterns – Process – Architecture – Design – Implementation  Conclusion
  • 99. 99/236 Be a Profiler  Name – Be a profiler  Problems – Computation time – Memory consumption – Easy to “optimise” in the wrong places • Make code needlessly complex • Do not improve performances
  • 100. 100/236 Be a Profiler “Premature optimization is the root of all evil” —Donald Knuth in Structured Programming with Go To Statements, December 1974
  • 101. 101/236 Be a Profiler  Example Thread [main] (Suspended (exception OutOfMemoryError)) GenericContainer...Constituents(Abstract...ContainerOfConstituents).broadcastAdditionOfConstituent(IConstituent) line: 267 GenericContainer...Constituents(Abstract...ContainerOfConstituents).directlyAddConstituent(IConstituent) line: 344 GenericContainer...Constituents(Abstract...ContainerOfConstituents).addConstituent(IConstituent) line: 214 Package.addConstituent(IConstituentOfModel) line: 76 …ClassFileCreator(AbstractClassFileCreator).createEntities(ICodeLevelModel, List, ConstituentRepository, ClassFile[]) line: 497 CompleteClassFileCreator(AbstractClassFileCreator).create(ICodeLevelModel) line: 220 CodeLevelModel.create(ICodeLevelModelCreator) line: 53 TestPathArgoUML.setUp() line: 57 TestPathArgoUML(TestCase).runBare() line: 140 TestResult$1.protect() line: 106 TestResult.runProtected(Test, Protectable) line: 124 TestResult.run(TestCase) line: 109 TestPathArgoUML(TestCase).run(TestResult) line: 133 TestSuite.runTest(Test, TestResult) line: 176 TestSuite.run(TestResult) line: 171 JUnit3TestReference.run(TestExecution) line: 130 TestExecution.run(ITestReference[]) line: 38 RemoteTestRunner.runTests(String[], String, TestExecution) line: 467 RemoteTestRunner.runTests(TestExecution) line: 683 RemoteTestRunner.run() line: 390 RemoteTestRunner.main(String[]) line: 197
  • 102. 102/236 Be a Profiler  Example – Using String
  • 103. 103/236 Be a Profiler  Example – Using char[]
  • 104. 104/236 Be a Profiler  Solution – Use a profiler to understand exactly what is happening and where it is happening – Profile regularly, as part of the testing phase – Modify the code to remove only obvious and dramatic bottlenecks, one at a time • Time • Memory
  • 105. 105/236 Be a Profiler  Solution – Follow the findings and recommendations of studies on the performance of class-libraries e.g., Nick Mitchell and Gary Sevitsky. The Causes of Bloat, the Limits of Health, in the Proceedings of the 22nd ACM OOPSLA conference, October 2007
  • 106. 106/236 Be a Profiler  Example – Follow the findings and recommendations of studies on the performance of class-libraries e.g., Nick Mitchell and Gary Sevitsky. The Causes of Bloat, the Limits of Health, in the Proceedings of the 22nd ACM OOPSLA conference, October 2007 – From – To
  • 107. 107/236 Be a Profiler  Consequences ↑ Improved performances ↑ Faster write-run-debug cycles ↔ Contradictory with “If it ain’t broke, don’t fix it” ↓ None, really!
  • 108. 108/236 Tests as Documentation  Name – Tests as documentation  Problems – When meeting a large program/framework for the first time, where to start? • main(…) methods may not exist or be helpful… Ptidej include 423 such methods! • Documentation is often inexistent
  • 111. 111/236 Tests as Documentation  Example Where to begin?
  • 112. 112/236 Tests as Documentation “My advice here is to always provide a way to do all [documentation] easily with a programmatic interface, and then treat a [documentation] file as an optional feature.” —Martin Fowler in Inversion of Control Containers and the Dependency Injection pattern (http://www.martinfowler.com/articles/injection.html)
  • 113. 113/236 Tests as Documentation “My advice here is to always provide a way to do all [documentation] easily with a programmatic interface, and then treat a [documentation] file as an optional feature.” —Martin Fowler in Inversion of Control Containers and the Dependency Injection pattern (http://www.martinfowler.com/articles/injection.html) Fowler talked about configuration originally
  • 114. 114/236 Tests as Documentation  Solution – Always pair a “development” project with a “test” project, which contains unit/integration tests – Use JUnit extensively to ease running • Avoid main(…) methods – Write the tests before writing the code
  • 115. 115/236 Tests as Documentation  Example public class TestPath extends TestCase { ... public void setUp() { try { final char[] entityName = "A".toCharArray(); final IFirstClassEntity entity = Factory.getInstance().createClass(entityName); final IMethod aGetter = Factory.getInstance().createMethod("get".toCharArray()); aGetter.setReturnType(entityName); final IParameter aParameter2 = Factory.getInstance().createParameter( entity, "a".toCharArray(), Constants.CARDINALITY_ONE); ... entity.addConstituent(aGetter); entity.addConstituent(aSetter); entity.addConstituent(aField); final IPackage aPackage = Factory.getInstance().createPackage("p".toCharArray()); aPackage.addConstituent(entity); final ICodeLevelModel aCodeLevelModel = Factory.getInstance().createCodeLevelModel("Model"); aCodeLevelModel.addConstituent(aPackage);
  • 116. 116/236 Tests as Documentation  Example public class TestPath extends TestCase { ... public void setUp() { try { final char[] entityName = "A".toCharArray(); final IFirstClassEntity entity = Factory.getInstance().createClass(entityName); final IMethod aGetter = Factory.getInstance().createMethod("get".toCharArray()); aGetter.setReturnType(entityName); final IParameter aParameter2 = Factory.getInstance().createParameter( entity, "a".toCharArray(), Constants.CARDINALITY_ONE); ... entity.addConstituent(aGetter); entity.addConstituent(aSetter); entity.addConstituent(aField); final IPackage aPackage = Factory.getInstance().createPackage("p".toCharArray()); aPackage.addConstituent(entity); final ICodeLevelModel aCodeLevelModel = Factory.getInstance().createCodeLevelModel("Model"); aCodeLevelModel.addConstituent(aPackage); Factory and API
  • 117. 117/236 Tests as Documentation  Consequences ↑ Even after years (or even when written by students ), what the code does and how it does is still evident ↑ Even after years, the code still runs • Or the tests fail ↑ Novices can copy/paste/modify existing tests to fit their needs and purposes ↓ None, really!
  • 118. 118/236 Outline  Introduction – Patterns – Case Study  Patterns – Process – Architecture – Design – Implementation  Conclusion
  • 119. 119/236 Multi-layered Architecture  Name – Layered architecture  Problems – Organise your code into manageable chunks that can be developed “independently” – Organise your code into identifiable chunks – Organise your code into controllable chunks
  • 120. 120/236 Multi-layered Architecture  Name – Layered architecture  Problems – Organise your code into manageable chunks that can be developed “independently” – Organise your code into identifiable chunks – Organise your code into controllable chunks
  • 121. 121/236 Multi-layered Architecture  Problems (cont’d) – Manageable • Developing • Testing • Versioning
  • 122. 122/236 Multi-layered Architecture  Problems (cont’d) – Identifiable • Mental model • Architectural style
  • 123. 123/236 Multi-layered Architecture  Problems (cont’d) – Controllable • Visibility • Dependencies
  • 124. 124/236 Multi-layered Architecture  Solution – Divide your code into “projects” • Eclipse or NetBeans or… projects – Give names that order the projects along the lines of the chosen architecture – Layered architecture • Ease development • Ease run-time… even on multiple computers
  • 126. 126/236 Multi-layered Architecture  Consequences ↑ Ease development • Divide and conquer • Restrain visibility ↓ May not be suitable for legacy systems
  • 127. 127/236 Outline  Introduction – Patterns – Case Study  Patterns – Process – Architecture – Design – Implementation  Conclusion
  • 128. 128/236 Proxy Console  Name – Proxy console  Problem – Control output and prepare for production, when output must be redirected to one or more files/Console…
  • 129. 129/236 Proxy Console  Solution – Implement a class to act as a proxy between the standard outputs and your code – Implement a class to act as “demultiplexer” to broadcast output to different channels
  • 130. 130/236 Proxy Console  Examples – Unified output – Targets of the output – Multiple outputs ProxyConsole.getInstance().setDebugOutput(new PrintWriter(new NullWriter())); ProxyConsole.getInstance().setErrorOutput(new PrintWriter(Console.getInstance().getErrorWriter())); ProxyConsole.getInstance().setNormalOutput(new PrintWriter(Console.getInstance().getNormalWriter())); ... } catch (final Throwable t) { t.printStackTrace(ProxyConsole.getInstance().errorOutput()); } final FileOutputStream logStream = new FileOutputStream("Results.log"); final MultiChannelOutputStream outStream = new MultiChannelOutputStream(System.out, logStream); System.setOut(new PrintStream(outStream));
  • 131. 131/236 public class ProxyConsole { private static ProxyConsole UniqueInstance; public static ProxyConsole getInstance() { if (ProxyConsole.UniqueInstance == null) { ProxyConsole.UniqueInstance = new ProxyConsole (); } return ProxyConsole.UniqueInstance; } private PrintWriter debugOutput = new PrintWriter(new NullWriter()); private PrintWriter errorOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.err)); private PrintWriter normalOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.out)); private ProxyConsole() { } public PrintWriter debugOutput() { return this.debugOutput; } public PrintWriter errorOutput() { return this.errorOutput; } public PrintWriter normalOutput() { return this.normalOutput; } public void setDebugOutput(final PrintWriter messageWriter) { this.debugOutput = messageWriter; } public void setErrorOutput(final PrintWriter messageWriter) { this.errorOutput = messageWriter; } public void setNormalOutput(final PrintWriter messageWriter) { this.normalOutput = messageWriter; } }
  • 132. 132/236 public class ProxyConsole { private static ProxyConsole UniqueInstance; public static ProxyConsole getInstance() { if (ProxyConsole.UniqueInstance == null) { ProxyConsole.UniqueInstance = new ProxyConsole (); } return ProxyConsole.UniqueInstance; } private PrintWriter debugOutput = new PrintWriter(new NullWriter()); private PrintWriter errorOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.err)); private PrintWriter normalOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.out)); private ProxyConsole() { } public PrintWriter debugOutput() { return this.debugOutput; } public PrintWriter errorOutput() { return this.errorOutput; } public PrintWriter normalOutput() { return this.normalOutput; } public void setDebugOutput(final PrintWriter messageWriter) { this.debugOutput = messageWriter; } public void setErrorOutput(final PrintWriter messageWriter) { this.errorOutput = messageWriter; } public void setNormalOutput(final PrintWriter messageWriter) { this.normalOutput = messageWriter; } } Thread unsafe
  • 133. 133/236 public class ProxyConsole { private static ProxyConsole UniqueInstance; public static ProxyConsole getInstance() { if (ProxyConsole.UniqueInstance == null) { ProxyConsole.UniqueInstance = new ProxyConsole (); } return ProxyConsole.UniqueInstance; } private PrintWriter debugOutput = new PrintWriter(new NullWriter()); private PrintWriter errorOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.err)); private PrintWriter normalOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.out)); private ProxyConsole() { } public PrintWriter debugOutput() { return this.debugOutput; } public PrintWriter errorOutput() { return this.errorOutput; } public PrintWriter normalOutput() { return this.normalOutput; } public void setDebugOutput(final PrintWriter messageWriter) { this.debugOutput = messageWriter; } public void setErrorOutput(final PrintWriter messageWriter) { this.errorOutput = messageWriter; } public void setNormalOutput(final PrintWriter messageWriter) { this.normalOutput = messageWriter; } } Thread unsafe By default, no debug
  • 134. 134/236 public class ProxyConsole { private static ProxyConsole UniqueInstance; public static ProxyConsole getInstance() { if (ProxyConsole.UniqueInstance == null) { ProxyConsole.UniqueInstance = new ProxyConsole (); } return ProxyConsole.UniqueInstance; } private PrintWriter debugOutput = new PrintWriter(new NullWriter()); private PrintWriter errorOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.err)); private PrintWriter normalOutput = new AutoFlushPrintWriter(new OutputStreamWriter(System.out)); private ProxyConsole() { } public PrintWriter debugOutput() { return this.debugOutput; } public PrintWriter errorOutput() { return this.errorOutput; } public PrintWriter normalOutput() { return this.normalOutput; } public void setDebugOutput(final PrintWriter messageWriter) { this.debugOutput = messageWriter; } public void setErrorOutput(final PrintWriter messageWriter) { this.errorOutput = messageWriter; } public void setNormalOutput(final PrintWriter messageWriter) { this.normalOutput = messageWriter; } } Thread unsafe By default, no debug Makes sure to flush
  • 135. 135/236 Proxy Console  Solution – Demultiplexer public class MultiChannelOutputStream extends OutputStream { private final OutputStream firstStream; private final OutputStream secondStream; public MultiChannelOutputStream( final OutputStream theFirstOutputStream, final OutputStream theSecondOutputStream) { this.firstStream = theFirstOutputStream; this.secondStream = theSecondOutputStream; } public void write(final int b) throws IOException { this.firstStream.write(b); this.secondStream.write(b); } }
  • 136. 136/236 Proxy Console  Example final FileOutputStream logStream = new FileOutputStream("ConstraintResults.log"); final MultiChannelOutputStream outStream = new MultiChannelOutputStream( ProxyConsole.getInstance().normalOutput(), logStream); System.setOut(new PrintStream(outStream)); final MultiChannelOutputStream errStream = new MultiChannelOutputStream( ProxyConsole.getInstance().normalOutput(), logStream); System.setErr(new PrintStream(errStream));
  • 138. 138/236 Proxy Console  Example (cont’d) Any output redirected to the Console and a log file
  • 139. 139/236 Proxy Console  Consequences ↑ More professional code • Output to Console during development • Output to a file (and–or whatever) in production – No output to the Console to “hide” any unexpected behavior, forgotten debug messages… • Introduce novel channels, i.e., warningOutput() ↓ Tiny impact on performance ↓ Coupling to ProxyConsole and its project
  • 140. 140/236 Proxy Disk  Name – Proxy disk  Problems – Need to write temporary files to disk – Need to access data from disk • Normal behaviour • Tests
  • 141. 141/236 Proxy Disk  Example – Scattered in your code final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar; final File newOutputDirectiory = new File(newOutputDirectoryName); if (!newOutputDirectiory.exists()) { newOutputDirectiory.mkdirs(); } this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName);
  • 142. 142/236 Proxy Disk  Example – Scattered in your code – With many variants… final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar; final File newOutputDirectiory = new File(newOutputDirectoryName); if (!newOutputDirectiory.exists()) { newOutputDirectiory.mkdirs(); } this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName);
  • 143. 143/236 Proxy Disk  Example – Scattered in your code – With many variants… • Which may or may not work depending on the order of method executions final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar; final File newOutputDirectiory = new File(newOutputDirectoryName); if (!newOutputDirectiory.exists()) { newOutputDirectiory.mkdirs(); } this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName);
  • 144. 144/236 Proxy Disk  Example – One possible variant final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar; final File newOutputDirectiory = new File(newOutputDirectoryName); if (!newOutputDirectiory.exists()) { newOutputDirectiory.mkdirs(); } this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName);
  • 145. 145/236 Proxy Disk  Example – One possible variant final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar; final File newOutputDirectiory = new File(newOutputDirectoryName); if (!newOutputDirectiory.exists()) { newOutputDirectiory.mkdirs(); } this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName); What if aName does not end with a file separator?
  • 146. 146/236 Proxy Disk  Example – Another possible variant final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar; final File newOutputDirectiory = new File(newOutputDirectoryName); if (!newOutputDirectiory.exists()) { newOutputDirectiory.mkdirs(); } this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName);
  • 147. 147/236 Proxy Disk  Example – Another possible variant final String newOutputDirectoryName = anOutputDirectoryName + aName + File.separatorChar; final File newOutputDirectiory = new File(newOutputDirectoryName); if (!newOutputDirectiory.exists()) { newOutputDirectiory.mkdirs(); } this.analyseCodeLevelModel(someSmells, aName, annotatedCodeLevelModel2, newOutputDirectoryName); What if the directory does not/already exist?
  • 148. 148/236 Proxy Disk  Solution – Have a single object to manage file access – Centralise access • Files • Directories (always ending with a file separator) – Manage the creation of directories (if needed) – Handle • FileReader • FileWriter • File/String
  • 149. 149/236 Proxy Disk  Solution – Have a single object to manage file access – Centralise access • Files • Directories (always ending with a file separator) – Manage the creation of directories (if needed) – Handle • FileReader • FileWriter • File/String In Java, can describe a file or a directory
  • 150. 150/236 Proxy Disk  Example – Single access point final String path = anOutputDirectory + "DetectionResults in " + aName + " for " + antipatternName + ".ini"; detection.output(new PrintWriter(ProxyDisk.getInstance().fileTempOutput(path))); Takes care of the “details”
  • 151. 151/236 Proxy Disk  Solution public class ProxyDisk { private static final String TEMP_DIRECTORY = "../Temp/"; private static ProxyDisk UniqueInstance; public static ProxyDisk getInstance() { if (ProxyDisk.UniqueInstance == null) { ProxyDisk.UniqueInstance = new ProxyDisk(); } return ProxyDisk.UniqueInstance; } private File tempDirectory; private ProxyDisk() { try { this.tempDirectory = this.createDirectories(ProxyDisk.TEMP_DIRECTORY); } catch (final IOException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); } } ... By default, we create a temporary directory
  • 152. 152/236 Proxy Disk  Solution private File createDirectories(final String aPathToADirectory) throws IOException { final File defaultDirectory = new File(aPathToADirectory); if (!defaultDirectory.exists()) { if (!defaultDirectory.mkdir()) { throw new IOException( "FileOutputProxy cannot create the necessary directory: " + aPathToADirectory); } } else if (defaultDirectory.isFile()) { throw new IOException( "FileOutputProxy cannot use a file as a directory: " + aPathToADirectory); } return defaultDirectory; } Creates as many directories as needed
  • 153. 153/236 Proxy Disk private File createFile(final String aFileName, final boolean shouldAppend) { File file; int indexOfLastPathSeparator; if ((indexOfLastPathSeparator = Math.max(aFileName.lastIndexOf('/'), aFileName.lastIndexOf(''))) > -1) { indexOfLastPathSeparator++; final String somePaths = aFileName.substring(0, indexOfLastPathSeparator); final String fileName = aFileName.substring(indexOfLastPathSeparator); try { file = new File(this.createDirectories(somePaths), fileName); } catch (final IOException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); ProxyConsole.getInstance().errorOutput().println( "FileOutputProxy will use its default directory"); file = new File(ProxyDisk.TEMP_DIRECTORY, fileName); } } else { file = new File(aFileName); } if (file.exists() && !shouldAppend) { ProxyConsole.getInstance().warningOutput().println( "ProxyDisk reports that the file already exists: “ + aFileName); } return file; }
  • 154. 154/236 Proxy Disk private File createFile(final String aFileName, final boolean shouldAppend) { File file; int indexOfLastPathSeparator; if ((indexOfLastPathSeparator = Math.max(aFileName.lastIndexOf('/'), aFileName.lastIndexOf(''))) > -1) { indexOfLastPathSeparator++; final String somePaths = aFileName.substring(0, indexOfLastPathSeparator); final String fileName = aFileName.substring(indexOfLastPathSeparator); try { file = new File(this.createDirectories(somePaths), fileName); } catch (final IOException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); ProxyConsole.getInstance().errorOutput().println( "FileOutputProxy will use its default directory"); file = new File(ProxyDisk.TEMP_DIRECTORY, fileName); } } else { file = new File(aFileName); } if (file.exists() && !shouldAppend) { ProxyConsole.getInstance().warningOutput().println( "ProxyDisk reports that the file already exists: “ + aFileName); } return file; } Creates as many directories as needed
  • 155. 155/236 Proxy Disk private File createFile(final String aFileName, final boolean shouldAppend) { File file; int indexOfLastPathSeparator; if ((indexOfLastPathSeparator = Math.max(aFileName.lastIndexOf('/'), aFileName.lastIndexOf(''))) > -1) { indexOfLastPathSeparator++; final String somePaths = aFileName.substring(0, indexOfLastPathSeparator); final String fileName = aFileName.substring(indexOfLastPathSeparator); try { file = new File(this.createDirectories(somePaths), fileName); } catch (final IOException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); ProxyConsole.getInstance().errorOutput().println( "FileOutputProxy will use its default directory"); file = new File(ProxyDisk.TEMP_DIRECTORY, fileName); } } else { file = new File(aFileName); } if (file.exists() && !shouldAppend) { ProxyConsole.getInstance().warningOutput().println( "ProxyDisk reports that the file already exists: “ + aFileName); } return file; } Creates as many directories as needed Fails safe
  • 156. 156/236 Proxy Disk private File createFile(final String aFileName, final boolean shouldAppend) { File file; int indexOfLastPathSeparator; if ((indexOfLastPathSeparator = Math.max(aFileName.lastIndexOf('/'), aFileName.lastIndexOf(''))) > -1) { indexOfLastPathSeparator++; final String somePaths = aFileName.substring(0, indexOfLastPathSeparator); final String fileName = aFileName.substring(indexOfLastPathSeparator); try { file = new File(this.createDirectories(somePaths), fileName); } catch (final IOException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); ProxyConsole.getInstance().errorOutput().println( "FileOutputProxy will use its default directory"); file = new File(ProxyDisk.TEMP_DIRECTORY, fileName); } } else { file = new File(aFileName); } if (file.exists() && !shouldAppend) { ProxyConsole.getInstance().warningOutput().println( "ProxyDisk reports that the file already exists: “ + aFileName); } return file; } Creates as many directories as needed Fails safe Friendly warning
  • 157. 157/236 Proxy Disk private FileReader fileInput(final String aFileName) { try { final File file = this.createFile(aFileName, false); return new FileReader(file); } catch (final IOException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); // Fail fast! return null; } } private FileWriter fileOutput( final String aFileName, final boolean shouldAppend) { try { final File file = this.createFile(aFileName, shouldAppend); return new FileWriter(file, shouldAppend); } catch (final IOException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); // Fail fast! return null; } }
  • 158. 158/236 Proxy Disk private FileReader fileInput(final String aFileName) { try { final File file = this.createFile(aFileName, false); return new FileReader(file); } catch (final IOException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); // Fail fast! return null; } } private FileWriter fileOutput( final String aFileName, final boolean shouldAppend) { try { final File file = this.createFile(aFileName, shouldAppend); return new FileWriter(file, shouldAppend); } catch (final IOException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); // Fail fast! return null; } } Fails fast by returning null
  • 159. 159/236 Proxy Disk public File directoryTempOutput(final String someSubpaths) { String newPath = ProxyDisk.TEMP_DIRECTORY + someSubpaths; if (!(someSubpaths.endsWith("/") || someSubpaths.endsWith(""))) { newPath += '/'; } if (someSubpaths.indexOf("..") > -1) { ProxyConsole.getInstance().warningOutput().println( "ProxyDisk advises not to "escape" from its default directory: " + someSubpaths); } try { final File directory = this.createDirectories(newPath); return directory; } catch (final IOException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); ProxyConsole.getInstance().errorOutput().println( "FileOutputProxy will use its default directory"); return this.tempDirectory; } }
  • 160. 160/236 Proxy Disk public File directoryTempOutput(final String someSubpaths) { String newPath = ProxyDisk.TEMP_DIRECTORY + someSubpaths; if (!(someSubpaths.endsWith("/") || someSubpaths.endsWith(""))) { newPath += '/'; } if (someSubpaths.indexOf("..") > -1) { ProxyConsole.getInstance().warningOutput().println( "ProxyDisk advises not to "escape" from its default directory: " + someSubpaths); } try { final File directory = this.createDirectories(newPath); return directory; } catch (final IOException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); ProxyConsole.getInstance().errorOutput().println( "FileOutputProxy will use its default directory"); return this.tempDirectory; } } Takes care of the “details”
  • 161. 161/236 Proxy Disk  Solution – Rest of the API util.io.ProxyDisk.directoryTempName() : String util.io.ProxyDisk.directoryTempOutput() : File util.io.ProxyDisk.directoryTempOutput(String) : File util.io.ProxyDisk.fileAbsoluteInput(File) : FileReader util.io.ProxyDisk.fileAbsoluteInput(String) : FileReader util.io.ProxyDisk.fileTempInput(File) : FileReader util.io.ProxyDisk.fileTempInput(String) : FileReader util.io.ProxyDisk.fileAbsoluteOutput(String) : FileWriter util.io.ProxyDisk.fileAbsoluteOutput(String, boolean) : FileWriter ... util.io.ProxyDisk.fileTempOutput(String) : FileWriter util.io.ProxyDisk.fileTempOutput(String, boolean) : FileWriter
  • 162. 162/236 Proxy Disk  Examples final XStream xstream = new XStream(); xstream.fromXML( ProxyDisk.getInstance().fileAbsoluteInput( Utils.TEMPORARY_OUTPUT_FILE), aCodeLevelModel); final PrintWriter writer = new PrintWriter(ProxyDisk.getInstance().fileAbsoluteOutput( Constants.PROGRAM_FILE_NAME + ".log", true)); detection.output(new PrintWriter(ProxyDisk.getInstance().fileTempOutput(path))); final String commandLine = ('"' + Files.getClassPath(OccurrenceGenerator.class) + PropertyManager.getSolverDirectory() + PropertyManager.getSolverCommand() + "" " + PropertyManager.getSolverArguments() + " -f "" + System.getProperty("user.dir") + '/' + ProxyDisk.getInstance().directoryTempName() + "Instructions.cl"")
  • 163. 163/236 Proxy Disk  Consequences ↑ Systematic, tested, consistent access to files ↑ Ease debugging with a single access point ↔ Thread safety • Fails-safe / fails-fast ↔ Default encoding ↓ Possible bottleneck • But possibility of caching
  • 164. 164/236 Proxy Disk  Follow-up – Same pattern for database accesses • Check for credentials, SQL injection – Same pattern for URL accesses • Could be combined with ProxyDisk
  • 165. 165/236 Hidden Language  Name – Hidden language  Problems – Manipulate, pass around, data coming from third-party library and provided as Strings
  • 166. 166/236 Hidden Language  Problems (cont’d) – Also noted in Design Patterns for Teaching Type Checking in a Compiler Construction Course by Ortin, Zapico, and Cueva) “The most serious disadvantage of [a string] is the need to process the string as a program […]. [U]sing object-orientation, […] common and specific [methods] can be properly set.”
  • 168. 168/236 Hidden Language  Solution – Use Strings – Of course…
  • 169. 169/236 Hidden Language  Solution – Use Strings – Of course… … Again, this obvious solution is not the better
  • 170. 170/236 Hidden Language  Solution – Use Strings – Of course… … Again, this obvious solution is not the better • No semantics
  • 171. 171/236 Hidden Language  Solution – Use Strings – Of course… … Again, this obvious solution is not the better • No semantics • No compile-time checks
  • 172. 172/236 Hidden Language  Example 1 – Class padl.creator.classfile. relationship.DeepMethodInvocation Analyzer – Variable listOfCouples containing, e.g., [null,java.lang.Object<init>.void()]
  • 173. 173/236 Hidden Language  Example 1 – Class padl.creator.classfile. relationship.DeepMethodInvocation Analyzer – Variable listOfCouples containing, e.g., [null,java.lang.Object<init>.void()] What do you make of this?
  • 174. 174/236 Hidden Language  Example 2 – Handling textual data 1.100.ClassGlobalVariable-0 = org.apache.html.dom.HTMLDocumentImpl 1.100.ClassGlobalVariable-0.FieldName-0 = class$0 1.100.ClassGlobalVariable-0.FieldName-1 = class$1 …
  • 175. 175/236 Hidden Language  Solution – Devise a meta-model – Use instances of appropriate classes
  • 176. 176/236 Hidden Language  As an aside… – A meta-model defines a language to express and reason about the existence, • interface IMethodInvocation properties, • IMethodInvocation.getType() and relations among domain concepts • IMethodInvocation.getCalledMethod()
  • 177. 177/236 Hidden Language  Example 1 – TODO  “If it ain’t broke, don’t fix it” —Bert Lance, May 1977
  • 180. 180/236 Hidden Language  Consequences ↑ Use and debugging significantly easier ↑ Decoration, serialisation… ↑ Compile-time verification ↓ Memory overhead due to objects’ overhead ↓ Performance decrease due to indirections
  • 181. 181/236 Internal Observer  Name – “Internal” observer  Problems – Limit dependencies among classes and their instances – Yet, update some instances when other instances are added/removed/changed
  • 182. 182/236 Internal Observer  Solution – Implement the Observer design pattern – Use the Observer design pattern internally to keep consistency in your model resorting to difficult logic
  • 183. 183/236 Internal Observer  Example – Definition – Use public interface IObservable { void addModelListener(final IModelListener aModelListener); void addModelListeners(final List aListOfModelListeners); void fireModelChange(final String anEventType, final IEvent anEvent); Iterator getIteratorOnModelListeners(); void removeModelListener(final IModelListener aModelListener); void removeModelListeners(final List modelListeners); } public interface IAbstractModel extends IContainer, INavigable, IObservable { ...
  • 184. 184/236 Internal Observer  Example private class TopLevelEntityManager implements IModelListener, Serializable { ... public void entityRemoved(final EntityEvent entityEvent) { final IConstituentOfModel constituent = entityEvent.getEntity(); if (constituent instanceof IFirstClassEntity) { ....this.removeTopLevelEntityFromID(constituent.getID()); } } public void entityAdded(final EntityEvent entityEvent) { final IConstituentOfModel constituent = entityEvent.getEntity(); if (constituent instanceof IFirstClassEntity && !(constituent instanceof IMemberEntity)) { ....this.addTopLevelEntity(constituent); } } …. }
  • 185. 185/236 Internal Observer  Consequences ↑ All the benefits of the Observe design pattern ↑ Assurance to have a consistent model ↑ Remove need for complex updating logic • Huge simplification ↓ Slight performance decrease • Due to indirections
  • 186. 186/236 Run-time Deprecation  Name – Run-time deprecation  Problem – Let users know that they should not call certain methods while internal code can call them – Avoid deprecated annotation that generate spurious warnings
  • 187. 187/236 Run-time Deprecation  Solution – Implement a guard class whose instances check whether the caller of a method is “authorised” at run-time
  • 188. 188/236 Run-time Deprecation  Solution public final class ConcreteReceiverGuard { private static ConcreteReceiverGuard UniqueInstance; public static ConcreteReceiverGuard getInstance() { if (ConcreteReceiverGuard.UniqueInstance == null) { ConcreteReceiverGuard.UniqueInstance = new ConcreteReceiverGuard(); } return ConcreteReceiverGuard.UniqueInstance; } private ConcreteReceiverGuard() { } ...
  • 189. 189/236 Run-time Deprecation private void doCheck( final String aConcreteReceiverClassToEnforce, final String anErrorMessage) { class ConcreteReceiverGuardThrownException extends RuntimeException { private static final long serialVersionUID = -4100342857707204144L; } try { throw new ConcreteReceiverGuardThrownException(); } catch (final ConcreteReceiverGuardThrownException e) { final StackTraceElement[] stackTrace = e.getStackTrace(); if (stackTrace.length < 4) { // Error in the call of the guard } else { final StringBuffer buffer = new StringBuffer(); buffer.append(stackTrace[2].getClassName()); buffer.append('.'); buffer.append(stackTrace[2].getMethodName()); final String nameOfGuardedMethod = buffer.toString(); final String nameOfClassCallingGuardedMethod = stackTrace[3].getClassName(); if (!nameOfClassCallingGuardedMethod .equals(aConcreteReceiverClassToEnforce)) { // Runtime deprecation! } } } }
  • 190. 190/236 Run-time Deprecation  Solution public void check( final String aConcreteReceiverClassToEnforce, final String anErrorMessage) { // Yann 2013/04/05: Stack! // I added this spurious method to make sure that the // doCheck() method is always called with the same stack // depth from this class, i.e., 2 :-) this.doCheck(aConcreteReceiverClassToEnforce, anErrorMessage); } public void check( final Class aConcreteReceiverClassToEnforce, final String anErrorMessage) { this.doCheck(aConcreteReceiverClassToEnforce.getName(), anErrorMessage); } }
  • 191. 191/236 Run-time Deprecation  Example public void create(final ICodeLevelModelCreator aCodeLevelCreator) throws CreationException { ConcreteReceiverGuard.getInstance().check( "padl.generator.helper.ModelGenerator", "Please use the methods in "padl.generator.helper.ModelGenerator“..."); aCodeLevelCreator.create(this); }
  • 192. 192/236 Run-time Deprecation  Consequences ↑ Identify “illegitimate” calls at run-time ↑ Avoid spurious “deprecation” warning at compile-time ↓ Tiny performance reduction
  • 193. 193/236 Outline  Introduction – Patterns – Case Study  Patterns – Process – Architecture – Design – Implementation  Conclusion
  • 194. 194/236 String Parsimony  Name – Data structure parsimony  Problems – Must give meaningful names/identifiers to some instances in your system
  • 196. 196/236 String Parsimony  Solution – Use Strings – Of course…
  • 197. 197/236 String Parsimony  Solution – Use Strings – Of course… … But the most obvious solution is not the better • To much overhead in memory • See the article “The Causes of Bloat, the Limits of Health” by Nick Mitchell and Gary Sevitsky
  • 198. 198/236 String Parsimony  Example – Overhead in a String[]
  • 199. 199/236 String Parsimony  As an aside… – Ockham's razor is “a principle of parsimony, economy, or succinctness used in logic and problem-solving” [Wikipedia] – Why use more when you can use less? c. 1287 – 1347
  • 200. 200/236 String Parsimony  Solution – Use char[] – To manipulate char[] • Arrays from Java class library • ArrayUtils from Apache Commons Lang • TCharArrayList from Trove4J
  • 201. 201/236 String Parsimony  Example public final class AnalysisEvent implements IEvent { private final char[] name; private final char[] elementType; /** * @deprecated by AnalysisEvent(final char[]) */ public AnalysisEvent(final String aName) { this.name = aName.toCharArray(); this.elementType = new char[0]; } /** * @deprecated by AnalysisEvent(final char[], final char[]) */ public AnalysisEvent(final char[] aName) { this.name = aName; this.elementType = new char[0]; } public AnalysisEvent(final char[] aName, final char[] anElementType) { this.name = aName; this.elementType = anElementType; } public char[] getConstituentName() { return this.name; } ... }
  • 202. 202/236 String Parsimony  Consequences ↑ Major gains in terms of space and time ↔ Code not significantly more complicate • Eclipse warns of “unsafe” use of char[] with “Must explicitly convert the char[] into a String” ↓ Costly to go from String/String[] to char[]-related objects • Use @deprecated • Encapsulate accesses
  • 203. 203/236 Identity  Name – Identity  Problems – Distinguish instances whose values may be identical – Make similar instances that can be persisted in database (serialised)
  • 204. 204/236 Identity  Solution – Distinguish between • The value of the fields of an instance • Its ID in the system at run-time • Its unique ID automatically given by the VM – Implement equals(Object) – Implement hashCode()
  • 205. 205/236 Identity  As an aside… – An object has typically three identities • Its System.identityHashCode(Object) • Its hashCode() (see also equals()) • The hashCode() of its fields (recursively) which may or may not be different • See the article “Why Object Serialization is Inappropriate for Providing Persistence in Java” by Huw Evans
  • 206. 206/236 Identity  Example abstract class Constituent implements IConstituent { private char[] id; private char[] name; ... public boolean equals(final Object obj) { if (!(obj instanceof IConstituent)) { return false; } return Arrays.equals(this.getID(), ((IConstituent) obj).getID()); } ... public int hashCode() { return this.getID().hashCode(); } ... }
  • 207. 207/236 Identity  Example abstract class Constituent implements IConstituent { private char[] id; private char[] name; ... public boolean equals(final Object obj) { if (!(obj instanceof IConstituent)) { return false; } return Arrays.equals(this.getID(), ((IConstituent) obj).getID()); } ... public int hashCode() { return this.getID().hashCode(); } ... } Takes care of null values
  • 208. 208/236 Identity  Example public class TestDB4OSerialiserSanity extends TestCase { private IDesignMotifModel originalModel; private IDesignMotifModel serialisedModel; ... protected void setUp() throws ModelDeclarationException, CloneNotSupportedException { this.originalModel = new Composite(); this.serialisedFileName = DB4OSerialiser.getInstance().serialiseWithAutomaticNaming(this.originalModel); this.serialisedModel = (IDesignMotifModel) DB4OSerialiser.getInstance().deserialise(this.serialisedFileName); } public void testModels() { Assert.assertEquals("Models", this.originalModel, this.serialisedModel); Assert.assertEquals("Model names", this.originalModel.getDisplayName(), this.serialisedModel.getDisplayName()); Assert.assertEquals("Model IDs", this.originalModel.getDisplayID(), this.serialisedModel.getDisplayID()); Assert.assertTrue("Identity hashcodes of the models are different", System.identityHashCode(this.originalModel) != System.identityHashCode(this.serialisedModel)); } }
  • 209. 209/236 Identity  Example public class TestDB4OSerialiserSanity extends TestCase { private IDesignMotifModel originalModel; private IDesignMotifModel serialisedModel; ... protected void setUp() throws ModelDeclarationException, CloneNotSupportedException { this.originalModel = new Composite(); this.serialisedFileName = DB4OSerialiser.getInstance().serialiseWithAutomaticNaming(this.originalModel); this.serialisedModel = (IDesignMotifModel) DB4OSerialiser.getInstance().deserialise(this.serialisedFileName); } public void testModels() { Assert.assertEquals("Models", this.originalModel, this.serialisedModel); Assert.assertEquals("Model names", this.originalModel.getDisplayName(), this.serialisedModel.getDisplayName()); Assert.assertEquals("Model IDs", this.originalModel.getDisplayID(), this.serialisedModel.getDisplayID()); Assert.assertTrue("Identity hashcodes of the models are different", System.identityHashCode(this.originalModel) != System.identityHashCode(this.serialisedModel)); } } Different JVM identities
  • 210. 210/236 Identity  Consequences ↑ Safe comparisons of instances, even after serialisation/deserialisation ↓ Tiny memory impact
  • 211. 211/236 Identity  Pragmatically – Nowadays, better use builders • EqualsBuilder and HashCodeBuilder in Apache Commons Lang • http://stackoverflow.com/questions/27581/ overriding-equals-and-hashcode-in-java
  • 212. 212/236 Address  Name – Address  Problems – When dealing with complex objects, such as models of object-oriented programs, it is often necessary to uniquely and directly reference one particular constituent
  • 213. 213/236 Address  Name – Address  Problems – When dealing with complex objects, such as models of object-oriented programs, it is often necessary to uniquely and directly reference one particular constituent
  • 214. 214/236 Address  Example public void removeTopLevelEntityFromID(final char[] anID) { try { final IConstituent constituent = this.topLevelEntitiesContainer.getTopLevelEntityFromID(anID); final IContainer container = Finder.findContainer(constituent.getDisplayPath(), this); container.removeConstituentFromID(anID); } catch (final FormatException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); } }
  • 215. 215/236 Address  Example public void removeTopLevelEntityFromID(final char[] anID) { try { final IConstituent constituent = this.topLevelEntitiesContainer.getTopLevelEntityFromID(anID); final IContainer container = Finder.findContainer(constituent.getDisplayPath(), this); container.removeConstituentFromID(anID); } catch (final FormatException e) { e.printStackTrace(ProxyConsole.getInstance().errorOutput()); } } Without back-pointers!
  • 216. 216/236 Address  Solution – Implement a unique “path” identifier that describe uniquely and precisely the “address” of a constituent public interface INavigable { String getDisplayPath(); char[] getPath(); }
  • 217. 217/236 Address  Implementation abstract class Abstract...ContainerOfConstituents extends GenericObservable implements IContainer, Serializable { ... private void updatePathUponAddition(final IConstituent aConstituent) { final char[] containerPath = this.containerConsitituent.getPath(); final char[] constituentPath = aConstituent.getPath(); final char[] newPath = ... ((Constituent) aConstituent).setPath(newPath); if (aConstituent instanceof IContainer) { final Iterator iterator = ((IContainer) aConstituent).getIteratorOnConstituents(); while (iterator.hasNext()) { final Constituent constituent = (Constituent) iterator.next(); this.updatePathUponAddition(constituent); } } } private void updatePathUponRemoval(final IConstituent aConstituent) { ...
  • 218. 218/236 Address  Implementation abstract class Abstract...ContainerOfConstituents extends GenericObservable implements IContainer, Serializable { ... private void updatePathUponAddition(final IConstituent aConstituent) { final char[] containerPath = this.containerConsitituent.getPath(); final char[] constituentPath = aConstituent.getPath(); final char[] newPath = ... ((Constituent) aConstituent).setPath(newPath); if (aConstituent instanceof IContainer) { final Iterator iterator = ((IContainer) aConstituent).getIteratorOnConstituents(); while (iterator.hasNext()) { final Constituent constituent = (Constituent) iterator.next(); this.updatePathUponAddition(constituent); } } } private void updatePathUponRemoval(final IConstituent aConstituent) { ... This is not a back-pointer, it is a surrogate for this
  • 219. 219/236 Address  Consequences ↑ Unique, direct access to any constituent ↑ Path can be build/divided programmatically ↓ Slight impact on memory  Related to – Hidden language
  • 220. 220/236 Final Construction  Name – Final construction  Problems – Objects encapsulate state, which should always be valid (class invariant) – Providing setter methods raise questions about which setters to use and when to use them
  • 222. 222/236 Final Construction  Example What do you make of these setters?
  • 223. 223/236 Final Construction “My long running default with objects is as much as possible, to create valid objects at construction time. This advice goes back to Kent Beck's Smalltalk Best Practice Patterns […]. Constructors with parameters give you a clear statement of what it means to create a valid object in an obvious place. If there's more than one way to do it, create multiple constructors that show the different combinations.” —Martin Fowler in Inversion of Control Containers and the Dependency Injection pattern (http://www.martinfowler.com/articles/injection.html)
  • 224. 224/236 Final Construction  Solution – Provide explicit constructors – Limit the number of setters – Limit the necessity to use setters after the instantiation of an object to obtain a valid object
  • 226. 226/236 Final Construction  Example Only one setter, not that important, could be removed (for convenience)
  • 227. 227/236 Final Construction  Consequences ↑ When creating an object, no “bad” surprises ↑ Explicit (and compile-time checks) of the objects necessary to instantiate a class ↔ The state of some objects must change at run- time and setters cannot be avoided
  • 228. 228/236 StringBuffer As Positioning Element  Name – StringBuffer as positioning element  Problems – Concatenating Strings creates lots of intermediary objects at runtime – Concatenated Strings do not look well in IDEs
  • 229. 229/236 StringBuffer As Positioning Element  Example argument .setValue("-Xmx2048M -classpath "" + equinoxLauncherPath + "" org.eclipse.equinox.launcher.Main -application PADL_Creator_Cpp_Eclipse.Launcher -data "" + this.pathToCurrentWorkspace + Common.EQUINOX_RUNTIME_WORKSPACE + "" -configuration "file:" + this.pathToCurrentWorkspace + ".metadata/.plugins/org.eclipse.pde.core/PADL Creator C++ (Eclipse)/" -dev "file:" + this.pathToCurrentWorkspace + ".metadata/.plugins/org.eclipse.pde.core/PADL Creator C++ (Eclipse)/dev.properties" " + architecture + " -consoleLog " + Common.ARGUMENT_DIRECTORY_TARGET_CPP_FILES + "="" + aRootDirectoryContainingCPPFiles + "" " + Common.ARGUMENT_DIRECTORY_PTIDEJ_WORKSPACE + "="" + this.pathToCurrentWorkspace + "" ");
  • 230. 230/236 StringBuffer As Positioning Element  Solution – Use StringBuffers to append Strings and chars without creating temporary Strings – Use StringBuffers to obtain a more readable layout of the code
  • 231. 231/236 StringBuffer As Positioning Element final StringBuilder arg = new StringBuilder(); arg.append("-Xmx2048M -classpath ""); arg.append(equinoxLauncherPath); arg.append("" "); arg.append("org.eclipse.equinox.launcher.Main"); arg.append(" -application PADL_Creator_Cpp_Eclipse.Launcher"); arg.append(" -data ""); arg.append(this.pathToCurrentWorkspace); arg.append(Common.EQUINOX_RUNTIME_WORKSPACE); arg.append("""); arg.append(" -configuration "file:"); arg.append(this.pathToCurrentWorkspace); arg.append(".metadata/.plugins/org.eclipse.pde.core/PADL Creator C++ (Eclipse)/""); arg.append(" -dev "file:"); arg.append(this.pathToCurrentWorkspace); arg.append(".metadata/.plugins/org.eclipse.pde.core/PADL Creator C++ (Eclipse)/dev.properties" "); arg.append(architecture); arg.append(" -consoleLog "); arg.append(Common.ARGUMENT_DIRECTORY_TARGET_CPP_FILES); arg.append("=""); arg.append(aRootDirectoryContainingCPPFiles); arg.append("" "); arg.append(Common.ARGUMENT_DIRECTORY_PTIDEJ_WORKSPACE); arg.append("=""); arg.append(this.pathToCurrentWorkspace); arg.append("" "); argument.setValue(arg.toString());
  • 232. 232/236 StringBuffer As Positioning Element  Consequences – Less temporary objects – Clearer code
  • 233. 233/236 StringBuffer As Positioning Element  Follow-up – StringBuffer is synchronised – StringBuilder is similar to StringBuffer but without synchronised methods • Faster
  • 234. 234/236 StringBuffer As Positioning Element  Follow-up – See http://stackoverflow.com/questions/47605/ java-string-concatenation-concat-vs-operator – StringBuilder 0ms (longest 16ms) – concat() 100,00ms (10s) – a += b 400,00ms (40s) String c = a; for (long i = 0; i < 100000L; i++) { c = c.concat(b); }
  • 235. 235/236 Outline  Introduction – Patterns – Case Study  Patterns – Process – Architecture – Design – Implementation  Conclusion
  • 236. 236/236 Conclusion  Real case study – Ptidej Tool Suite  Different patterns – Different benefits – Some limitations