Software development
phmb@cin.ufpe.br ◈ twitter.com/pauloborba
Paulo Borba
Informatics Center
Federal University of Pernambuco
Implementation and
maintenance
• Values
• Principles
• Patterns
• architectural, design, implementation
Should be guided by...
Coding values, Beck
• Communication: focus on the reader
• Simplicity: eliminate excess complexity
• Flexibility: easy to change, in expected ways
• Precision: names aligned to behavior
Coding principles, Beck
• Local consequences (compositionality)
• Minimize repetition
• Logic and data together
• Symmetry
• Declarative expression
• Rate of change
SOLID design principles
• A class should have a single responsibility (single responsibility)
• A module should be open for extension but closed for modification (open closed)
• Subclasses should be substitutable for their base classes (Liskov Substitution)
• Dependencies should be injected into a dependent object (dependency injection)
• A method of class C should only call methods of
C or of the classes of C attributes (Demeter)
More design principles
• Depend upon Abstractions, do not depend upon concretions (dependency inversion)
• Reusable code calls custom code,
abstractions call concretions (inversion of control)
• Many client specific interfaces are better than one general purpose interface
(interface segregation)
Package cohesion principles
• The granule of reuse is the granule of release (release reuse equivalency)
• Classes that change together, belong together (common closure)
• Classes that aren’t reused together should
not be grouped together (common reuse
principle)
Package coupling principles
• The dependencies betwen packages must not form cycles (acyclic dependencies)
• Depend in the direction of stability (stable dependencies)
• Stable packages should be abstract
packages (stable abstractions)
Other rules
Rule of Modularity: Write simple parts connected by clean interfaces.
Rule of Clarity: Clarity is better than cleverness.
Rule of Composition: Design programs to be connected to other programs.
Rule of Separation: Separate policy from mechanism; separate interfaces from engines.
Rule of Simplicity: Design for simplicity; add complexity only where you must.
Rule of Parsimony: Write a big program only when it is clear by demonstration that nothing else will do.
Rule of Transparency: Design for visibility to make inspection and debugging easier.
Rule of Robustness: Robustness is the child of transparency and simplicity.
Rule of Representation: Fold knowledge into data so program logic can be stupid and robust.
The Art of Unix Programming, Eric Raymond
Other rules
Rule of Least Surprise: In interface design, always do the least surprising thing.
Rule of Silence: When a program has nothing surprising to say, it should say nothing.
Rule of Repair: When you must fail, fail noisily and as soon as possible.
Rule of Economy: Programmer time is expensive; conserve it in preference to machine time.
Rule of Generation: Avoid hand-hacking; write programs to write programs when you can.
Rule of Optimization: Prototype before polishing. Get it working before you optimize it.
Rule of Diversity: Distrust all claims for “one true way”.
Rule of Extensibility: Design for the future, because it will be here sooner than you think.
The Art of Unix Programming, Eric Raymond
Patterns
• Context
• Problem
• Forces
• Solution
• Consequences
• Known uses
Professors and courses
Java POI
• Java APIs Java for manipulating “OLE 2
Compound Document” files, such as xls e doc:
• HSSF (Horrible Spreadsheet Format)
• HDF (Horrible Document Format)
• HPSF (Horrible Property Set Format)
Class diagrams…
Engineering Software as a Service, an Agile Approach Using Cloud Computing, de Armando Fox e David Patterson
use with care
Architecture as a class diagram...
• is often not abstract enough for
• understanding and communication
• task division
• focus on static structure
• shows only how the code is organized
• not much support for evaluation before
construction
Better to have abstract class
diagrams...
or component diagrams
http://www.visual-paradigm.com/VPGallery/img/diagrams/Component/Component-Diagram-Sample.png
http://docs.google.com/Doc?docid=0Aeq-cxjLYT32ZGRicGpuYl8zM3d0cDI0NmRr&hl=en
Factory pattern for
using POI
No interface?
direct
dependence
Abstract factory
http://www.tml.tkk.fi/~pnr/Tik-76.278/gof/html/Abstract-factory.html
Separating concerns
Decorator
http://www.tml.tkk.fi/~pnr/Tik-76.278/gof/html/Decorator.html
Pattern catalogues
http://hillside.net/patterns/patterns-catalog
Strategy
• Analyze change request
• Any pattern for the given context?
• New solution based on values and principles?
• Apply appropriate pattern or principles
• Check whether new functionality breaks
existing tests
Focus on bad design smells, related to classes and their
relationships
Not on bad code smells, related to method
implementations
Implementation techniques
• Patterns
• Parametrization (methods, classes, property files, etc.)
• Components
• AOMs
• Conditional compilation (preprocessing)
• Code generation
• Metaprogramming, program transformation
• Aspects, mixins (traits)
Conditional execution
canvas_midp2 = Boolean.valueOf(args[1]);
canvas_siemens = Boolean.valueOf(args[2]);
if (canvas_midp2 || canvas_siemens) { this.mainCanvas.paint();
this.mainCanvas.flushGraphics();
}
else {
this.mainCanvas.repaint();
this.mainCanvas.serviceRepaints();
}
Technique analysis
• Increased bytecode size, more RAM
• Slower
• Not many supported variation points
• Flexible, dynamic choices
• Variations are all checked
Conditional compilation
//#if canvas_midp2 || canvas_siemens this.mainCanvas.paint();
this.mainCanvas.flushGraphics();
//#else
//# this.mainCanvas.repaint();
//# this.mainCanvas.serviceRepaints();
//#endif
From Meantime Mobile CreationsPre-processing followed by compilation
canvas_midp2,
device_screen_128x128, ...
Tags file
Antenna file
product
Inside commands...
if (display.getCurrent()==this.mainCanvas) { //#if canvas_midp2 || canvas_siemens
//# this.mainCanvas.paint();
//# this.mainCanvas.flushGraphics();
//#else
//# this.mainCanvas.repaint();
//# this.mainCanvas.serviceRepaints();
//#endif }
From Meantime Mobile Creations
and everywhere
//#if canvas_nokiaui
//# public class MainCanvas extends FullCanvas { //#elif canvas_midp2 || canvas_siemens
//# public class MainCanvas extends GameCanvas { //#else
//# public class MainCanvas extends Canvas { //#endif
private static int keyStatesNotRepeatable;
//#if device_screen_128x128
//# public static final int SCREEN_WIDTH = 128;
//# public static final int SCREEN_HEIGHT = 128;
//#elif device_screen_128x117
//# public static final int SCREEN_WIDTH = 128;
...
From Meantime Mobile Creations
From Meantime Mobile Creations
Aspects and mixins:
separating feature code
W eaving é usado para…
Sistema original
chamadas locais entre A e B
Sistema distribuído
chamadas remotas entre A e B
Processo de composição
Composição nos join points
Pointcuts especificam join points
•
Identificam joint points de um sistema
• chamadas e execuções de métodos (e construtores)
• acessos a atributos
• tratamento de exceções
• inicialização estática e dinâmica
•
Composição de joint points
• && , || e !
Identificando chamadas de métodos
pointcut printCall():
call(public void *.println(String));
com
argumento string
método println de qualquer classe
identifica
chamadas de …
nome do
pointcut
Advice especifica
comportamento nos join points
•
Define código que deve ser executado…
•before
•after
•after returning
•after throwing
• ou around
join points
Alterando o comportamento de chamadas de métodos
after(): printCall() && within(HelloWorld) { System.out.println(“ AOP World");
}
após...
qualquer chamada a Write dentro de HelloWorld
a ação especificada será
executada
Aspectos agrupam pointcuts, advices, etc.
aspect HelloAOPWorld {
pointcut printCall():
call(public void *.print(String));
after():
printCall() && within(HelloWorld) { System.out.println(“ AOP World!");
}
...
}
Hello AOP World!
public class HelloWorld {
public static void Main(string[] args) { System.out.println(“Hello");
} }
Chamada afetada pelo advice, caso
HelloAOPWorld tenha sido composto
com HelloWorld
Changing class hierarchy
declare parents: HealthWatcherFacade implements IFacade;
declare parents: Complaint || Person implements java.io.Serializable;
public static void
HealthWatcherFacade.main(String[] args){
try {...
java.rmi.Naming.rebind("/HW");
} catch ...
} Adicionando o
método main na
classe fachada
Alterando a hierarquia de tipos
Groovy AOP
class MyAspect {
static aspect = {
def pc = pcall("T.*")
before(pc) { println "before testing" } }
}
https://github.com/chanwit/groovy-aop
Annotations in Grails, tagging joinpoints...
http://manbuildswebsite.com/2010/03/15/simple-aspects-using-annotations-in-grails/
public class UserService { @UpdatesUser
User updateUser(user) {...}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface UpdatesUser {}
pointcuts and advice
http://manbuildswebsite.com/2010/03/15/simple-aspects-using-annotations-in-grails/
@Aspect
@Component("refreshUserAspect") public class RefreshUserAspect {
@Pointcut("@annotation(UpdatesUser)") public void userUpdatingOperation() {}
@AfterReturning(pointcut="...
userUpdatingOperation()", returning="user")
public void refreshAuthenticatedUser(
User user){...}
Metaclasses in Groovy
class Aspect {
def mc = Account.metaClass def init() {
mc.record = []
mc.addRecord = {op, value ->
delegate.record <<
new Entry(op,value,delegate)}
mc.credit = {value ->
balance = balance + value addRecord "C",value}
} }
Metaclasses in Groovy
class Account {
def balance = 0
def credit(value) {
balance = balance + value } }
def a = new Aspect()
a.init()
Mixins
class MMixin {
def record = []
def addRecord(op, value) {
record << new Entry(op,value) } def credit(value) {
setBalance(balance + value) addRecord("C",value)
} }
Account.mixin MMixin
Applies for testing code
too!
Take notes,
now!
Software development
phmb@cin.ufpe.br ◈ twitter.com/pauloborba