SlideShare una empresa de Scribd logo
1 de 84
Descargar para leer sin conexión
Test, beauty, cleanness
        Alexandre Bergel
      abergel@dcc.uchile.cl
           16/06/2011
Problem description



  We would like to build a two-dimensional graphics
framework for structured drawing editors
 Widgets such as circle and rectanglehave to be
supported
 Operations like translating, scaling have to be offered
What are the responsibilities?



Containing the widgets
Modeling the widgets
Applying the operations
Version 1




Creating a canvas to contains the widgets
Testing the canvas




public class HotDrawTest {
	 @Test public void testEmptyCanvas() {
	 	 Canvas canvas = new Canvas ();
	 	 assertEquals(canvas.getNumberOfElements(), 0);
	 }
}



        The class Canvas is not created yet!
Creating the class Canvas




public class Canvas {
	 public Object getNumberOfElements() {
	 	 return 0;
	 }
}
Introducing the containment


	   @Test public void testCanvas() {
	   	 Canvas canvas = new Canvas ();
	   	
	   	 canvas.add(new Object());
	   	 assertEquals(1, canvas.getNumberOfElements());
	   	
	   	 canvas.add(new Object());
	   	 canvas.add(new Object());
	   	 assertEquals(3, canvas.getNumberOfElements());
	   }



    We need to be able to add objects in a canvas!
Revising the definition of Canvas

public class Canvas {
	 private ArrayList<Object> elements =
	 	 	 	 new ArrayList<Object>();

	   public int getNumberOfElements() {
	   	 return elements.size();
	   }

	   public void add(Object object) {
	   	 elements.add(object);
	   }
}
Revising the definition of Canvas

public class Canvas {
	 private ArrayList<Object> elements =
	 	 	 	 new ArrayList<Object>();

	   public int getNumberOfElements() {
	   	 return elements.size();
	   }
                                         Tests are green!
	   public void add(Object object) {
	   	 elements.add(object);
	   }
}
Version 2




Introducing some widgets
We revise our testCanvas


	   @Test public void testCanvas() {
	   	 Canvas canvas = new Canvas ();
	   	
	   	 canvas.add(new Circle());
	   	 assertEquals(1, canvas.getNumberOfElements());
	   	
	   	 canvas.add(new Circle());
	   	 canvas.add(new Rectangle());
	   	 assertEquals(3, canvas.getNumberOfElements());
	   }
Circle and Rectangle



public class Circle {
}

public class Rectangle {
}
Adding position to circle and
               rectangle
	   @Test public void testCanvas() {
	   	 Canvas canvas = new Canvas ();
	   	
	   	 //(10, 20), radius 5
	   	 canvas.add(new Circle(10,20, 5));
	   	 assertEquals(1, canvas.getNumberOfElements());
	   	
	   	 canvas.add(new Circle());
	   	
	   	 //(5,6) -> (10,8)
	   	 canvas.add(new Rectangle(5, 6, 10, 8));
	   	 assertEquals(3, canvas.getNumberOfElements());
	   }
Generated template



public class Circle {

	   public Circle(int i, int j, int k) {
	   	 // TODO Auto-generated constructor stub
	   }
}
Filling the template template

public class Circle {
	 private int x, y, radius;
	
	 public Circle() {
	 	 this(5, 5, 10);
	 }
	
	 public Circle(int x, int y, int radius) {
	 	 this.x = x;
	 	 this.y = y;
	 	 this.radius = radius;
	 }
}
Generated template



public class Rectangle {

	   public Rectangle(int i, int j, int k, int l) {
	   	 // TODO Auto-generated constructor stub
	   }
}
Filling the template template

public class Rectangle {
	 private int x1, y1, x2, y2;

	   public Rectangle() {
	   	 this(2, 3, 5, 6);
	   }
	
	   public Rectangle(int x1, int y1, int x2, int y2) {
	   	 this.x1 = x1;
	   	 this.y1 = y1;
	   	 this.x2 = x2;
	   	 this.y2 = y2;
	   }
}
Version 3




 Before moving on, lets step back on what we wrote
to see whether there are opportunities for cleaning a
bit the code
HotDrawTest


public class HotDrawTest {

	   @Test public void testEmptyCanvas() {
	   	 Canvas canvas = new Canvas ();
        ...
     }

	   @Test public void testCanvas() {
	   	 Canvas canvas = new Canvas ();
        ...
    }
}
HotDrawTest


public class HotDrawTest {

	   @Test public void testEmptyCanvas() {
	   	 Canvas canvas = new Canvas ();
        ...
     }                                      Duplication!
	   @Test public void testCanvas() {
	   	 Canvas canvas = new Canvas ();
        ...
    }
}
Refactoring our test

public class HotDrawTest {
	 private Canvas canvas;
	
	 @Before public void initializingFixture() {
	 	 canvas = new Canvas ();
	 }
	
	 @Test public void testEmptyCanvas() {	
	 	 assertEquals(canvas.getNumberOfElements(), 0);
	 }
	
	 @Test public void testCanvas() {	 	
	 	 //(10, 20), radius 5
	 	 canvas.add(new Circle(10,20, 5));
       ...
   }
}
Giving a better name to the variable
canvas -> emptyCanvas

public class HotDrawTest {
	 private Canvas emptyCanvas;
	
	 @Before public void initializingFixture() {
	 	 emptyCanvas = new Canvas ();
	 }
	
	 @Test public void testEmptyCanvas() {	
	 	 assertEquals(emptyCanvas.getNumberOfElements(), 0);
	 }
	
	 @Test public void testCanvas() {	 	
	 	 //(10, 20), radius 5
	 	 emptyCanvas.add(new Circle(10,20, 5));
       ...
   }
}
canvas -> emptyCanvas

public class HotDrawTest {
	 private Canvas emptyCanvas;
	
	 @Before public void initializingFixture() {
	 	 emptyCanvas = new Canvas ();
	 }
	
	 @Test public void testEmptyCanvas() {	
	 	 assertEquals(emptyCanvas.getNumberOfElements(), 0);
	 }
	
	 @Test public void testCanvas() {	 	
	 	 //(10, 20), radius 5
	 	 emptyCanvas.add(new Circle(10,20, 5));
       ...
   }
}
Version 4

 Applying the operations on the widget


 Note that at that point, we have not seen the need to
have a common superclass for Circle and Rectangle
 As well we have not seen the need to have a
common interface
 We should be test driven, else it is too easy to go
wrong
 The class canvas also contains a list of objects
Adding an operation



 Let’s translate our objects
  Each widget should now understand the message
translate(deltaX, deltaY)
 Let’s write some test first
Testing circle first


	   @Test public void translatingCircle() {
	   	 Circle circle = new Circle();
	   	 int oldX = circle.getX();
	   	 int oldY = circle.getY();
	   	
	   	 circle.translate(2, 3);
	   	 assertEquals(circle.getX(), oldX + 2);
	   	 assertEquals(circle.getY(), oldY + 3);
	   }
Modifying Circle

public class Circle {
	 private int x, y, radius;
	
	 public int getX() {
	 	 return x;
	 }
	
	 public int getY() {
	 	 return y;
	 }
   ...
}
// Note that there is no accessor for radius, we have not
seen the need of it!
Translating Circle



public class Circle {
   ...
	 public void translate(int dx, int dy) {
	 	 x = x + dx;
	 	 y = y + dy;
	 }
   ...
}
Translating Circle



public class Circle {
   ...
	 public void translate(int dx, int dy) {
	 	 x = x + dx;
	 	 y = y + dy;
	 }
   ...
}
Translating the rectangle

	   @Test public void translatingRectangle() {
	   	 Rectangle rectangle = new Rectangle();
	   	 int oldX1 = rectangle.getX1();
	   	 int oldY1 = rectangle.getY1();
	   	 int oldX2 = rectangle.getX2();
	   	 int oldY2 = rectangle.getY2();
	   	
	   	 rectangle.translate(2, 3);
	   	 assertEquals(rectangle.getX1(), oldX1 +    2);
	   	 assertEquals(rectangle.getX2(), oldX2 +    2);
	   	 assertEquals(rectangle.getY1(), oldY1 +    3);
	   	 assertEquals(rectangle.getY2(), oldY2 +    3);
	   }
Updating Rectangle

public class Rectangle {
   ...
	 public int getX1() {...	
                         }
	 public int getY1() {...}
	 public int getX2() {...}
	 public int getY2() {
	 	 return y2;
	 }

	   public void translate(int dx, int dy) {
	   	 x1 = x1 + dx;
	   	 x2 = x2 + dx;
	   	 y1 = y1 + dy;
	   	 y2 = y2 + dy;
	   }
}
Important



 Note that we have not still see the need to have a
common interface and a common superclass
 If you doing it upfront, when your design will look like
what you want it to be, and not what it has to be
Version 5



 It is a bit cumbersome to have to translate each
element one by one
 Let’s ask the canvas to translate all the nodes
Translating the canvas

	 @Test public void translatingTheCanvas() {

	   	   Rectangle rectangle = new Rectangle();
	   	   int rectangleOldX1 = rectangle.getX1();
	   	   int rectangleOldY1 = rectangle.getY1();
	   	   int rectangleOldX2 = rectangle.getX2();
	   	   int rectangleOldY2 = rectangle.getY2();
	
	   	   Circle circle = new Circle();
	   	   int circleOldX = circle.getX();
	   	   int circleOldY = circle.getY();

	   	   emptyCanvas.add(rectangle);
	   	   emptyCanvas.add(circle);
	   	   emptyCanvas.translate(2, 3);
        ...
Translating the canvas


        ...
	   	
	   	   assertEquals(rectangle.getX1(), rectangleOldX1   +   2);
	   	   assertEquals(rectangle.getX2(), rectangleOldX2   +   2);
	   	   assertEquals(rectangle.getY1(), rectangleOldY1   +   3);
	   	   assertEquals(rectangle.getY2(), rectangleOldY2   +   3);
	   	   assertEquals(circle.getX(), circleOldX + 2);
	   	   assertEquals(circle.getY(), circleOldY + 3);
	   }
Updating Canvas - what we would
               like to do
public class Canvas {

	   private ArrayList<Object> elements =
	   	 	 	 new ArrayList<Object>();

	   public void add(Object object) {
	   	 elements.add(object);
	   }

	   public void translate(int dx, int dy) {
	   	 for(Object o : elements)
	   	 	 o.translate(dx, dy);
	   }
    ...
}
Updating Canvas - what we would
               like to do
public class Canvas {

	   private ArrayList<Object> elements =
	   	 	 	 new ArrayList<Object>();

	   public void add(Object object) {
	   	 elements.add(object);
	   }

	   public void translate(int dx, int dy) {
	   	 for(Object o : elements)
	   	 	 o.translate(dx, dy);
	   }
    ...
}                                The compiler will not be
                                      happy with this
What is happening?



  Only now we see the need to introduce a common
interface that the object have to fulfill
 This interface will only be aware of the translate(dx,dy)
method
Let’s introduce the Widget interface


public interface Widget {
	 public void translate(int dx, int dy);
}

public class Rectangle implements Widget {
   ...
}

public class Circle implements Widget {
   ...
}
Updating Canvas

public class Canvas {
	 private ArrayList<Widget> elements =
	 	 	 	 new ArrayList<Widget>();

	   public void add(Widget widget) {
	   	 elements.add(widget);
	   }

	   public void translate(int dx, int dy) {
	   	 for(Widget o : elements)
	   	 	 o.translate(dx, dy);
	   }
    ...
}
Updating Canvas

public class Canvas {
	 private ArrayList<Widget> elements =
	 	 	 	 new ArrayList<Widget>();

	   public void add(Widget widget) {
	   	 elements.add(widget);
	   }

	   public void translate(int dx, int dy) {
	   	 for(Widget o : elements)
	   	 	 o.translate(dx, dy);
	   }
    ...
}
Version 6



 We are doing a pretty good job so far
 Let’s add a group of widgets that can be commonly
manipulated
Testing Group



	   @Test public void groupingWidgets() {
	   	 Group group = new Group();
	   	 assertEquals(group.getNumberOfElements(), 0);
	   	
	   	 group.add(new Circle());
	   	 group.add(new Rectangle());
	   	 assertEquals(group.getNumberOfElements(), 2);
	   }
Defining Group

public class Group {
	 private ArrayList<Object> elements =
              new ArrayList<Object>();
	
	 public void add(Object w) {
	 	 elements.add(w);
	 }

	   public int getNumberOfElements() {
	   	 return elements.size();
	   }
}
Defining Group

public class Group {
	 private ArrayList<Object> elements =
              new ArrayList<Object>();
	
	 public void add(Object w) {
	 	 elements.add(w);
	 }
                        Yes! We haven’t seen the
	   public int getNumberOfElements() {
	   	 return elements.size(); to have Widget here
                        need
	   }
}
Defining Group

  public class Group {
  	 private ArrayList<Object> elements =
                new ArrayList<Object>();
  	
  	 public void add(Object w) {
  	 	 elements.add(w);
  	 }
                          Yes! We haven’t seen the
  	   public int getNumberOfElements() {
  	   	 return elements.size(); to have Widget here
                          need
  	   }
  }

This is the proof that we
     do not need it!
Translating a group - what we could write,
    but it contains a lot of duplication



  	   @Test public void translatingGroup() {
  	   	 Group group = new Group();
  	   	 group.add(new Circle());
  	   	 group.add(new Rectangle());
  	   	 group.translate(...)
  	   }
But let’s refactor first

public class HotDrawTest {
	 private Canvas emptyCanvas;
	 private Group emptyGroup, group;
	 private Circle circle;
	 private Rectangle rectangle;
	
	 @Before public void initializingFixture() {
	 	 emptyCanvas = new Canvas ();
	 	 emptyGroup = new Group();
	 	 group = new Group();
	 	 group.add(circle = new Circle());
	 	 group.add(rectangle = new Rectangle());
	 }
But let’s refactor first



	   @Test public void groupingWidgets() {
	   	 assertEquals(emptyGroup.getNumberOfElements(), 0);
	   	 assertEquals(group.getNumberOfElements(), 2);
	   }
Translating a group

	   @Test public void translatingGroup() {
	   	 int circleOldX = circle.getX();
	   	 int circleOldY = circle.getY();
	   	 int rOldX1 = rectangle.getX1();
	   	 int rOldY1 = rectangle.getY1();

	   	   group.translate(2, 3);
	   	
	   	   assertEquals(rectangle.getX1(), rOldX1   +   2);
	   	   assertEquals(rectangle.getY1(), rOldY1   +   3);
	   	   assertEquals(circle.getX(), circleOldX   +   2);
	   	   assertEquals(circle.getY(), circleOldY   +   3);
	   	
	   }
Translating a group

public class Group {
	 private ArrayList<Widget> elements =
	 	 	 	 new ArrayList<Widget>();
	
	 public void add(Widget w) {
	 	 elements.add(w);
	 }

	   public int getNumberOfElements() {
	   	 return elements.size();
	   }

	   public void translate(int i, int j) {
	   	 for(Widget w : elements)
	   	 	 w.translate(i, j);
	   }
}
Translating a group

public class Group {
	 private ArrayList<Widget> elements =
	 	 	 	 new ArrayList<Widget>();
	
	 public void add(Widget w) {
	 	 elements.add(w);
	 }                           Yes, we need an array
                                   of Widgets
	   public int getNumberOfElements() {
	   	 return elements.size();
	   }

	   public void translate(int i, int j) {
	   	 for(Widget w : elements)
	   	 	 w.translate(i, j);
	   }
}
Translating a group

public class Group {
	 private ArrayList<Widget> elements =
	 	 	 	 new ArrayList<Widget>();
	
	 public void add(Widget w) {
	 	 elements.add(w);
	 }

	   public int getNumberOfElements() {
	   	 return elements.size();
	   }

	   public void translate(int i, int j) {
	   	 for(Widget w : elements)
	   	 	 w.translate(i, j);
	   }
}
Version 7



Let’s refactor Canvas
  instead of containing a list of elements, it will solely contains a
 group
Canvas is getting simpler
public class Canvas {
	 private Group group = new Group();

	   public void add(Widget widget) {
	   	 group.add(widget);
	   }

	   public void translate(int dx, int dy) {
	   	 group.translate(dx, dy);
	   }
	
	   public int getNumberOfElements() {
	   	 return group.getNumberOfElements();
	   }
}
Canvas is getting simpler
public class Canvas {
	 private Group group = new Group();

	   public void add(Widget widget) {
	   	 group.add(widget);
	   }

	   public void translate(int dx, int dy) {
	   	 group.translate(dx, dy);
	   }
	
	   public int getNumberOfElements() {
	   	 return group.getNumberOfElements();
	   }
}
Version 8

Adding a new operation
We will now scale objects


                         scale x2
Adding a test for scalability


	   @Test public void scalingGroup() {
	   	 int oldRadius = circle.radius();
	   	 int rectangleWidth = rectangle.width();
	   	 int rectangleHeight = rectangle.height();
	   	
	   	 group.scale(2);
	   	
	   	 assertEquals(circle.radius(), 2 * oldRadius);
	   	 assertEquals(rectangle.width(), 2 * rectangleWidth);
	   	 assertEquals(rectangle.height(), 2 * rectangleHeight);
	   }
Adding a test for scalability
                                            Accessing
                                              radius
	   @Test public void scalingGroup() {
	   	 int oldRadius = circle.radius();
	   	 int rectangleWidth = rectangle.width();
	   	 int rectangleHeight = rectangle.height();
	   	
	   	 group.scale(2);
                                                Accessing
	   	                                        width and height
	   	 assertEquals(circle.radius(), 2 * oldRadius);
	   	 assertEquals(rectangle.width(), 2 * rectangleWidth);
	   	 assertEquals(rectangle.height(), 2 * rectangleHeight);
	   }
Updating Circle



public class Circle implements Widget {
	 private int x, y, radius;

     public int radius() {
	   	 return radius;
	   }
    ...
}
Updating Rectangle


public class Rectangle implements Widget {
	 public int width() {
	 	 return Math.abs(x2 - x1);
	 }
	
	 public int height() {
	 	 return Math.abs(y2 - y1);
	 }
   ...
}
Scalability
public class Group {
	   public void scale(double s) {
	   	   for(Widget w : elements)
	   	   	   w.scale(s);
	   }
   ... }

public interface Widget {
   ...
	   public void scale(double s); }

public class Circle implements Widget {
	   public void scale(double s) {
	   	   radius *= s;
	   }
}

public class Rectangle implements Widget {
	   public void scale(double s) {
	   	   x1 *= s; y1 *= s; x2 *= s; y2 *= s;
	   }
}
Scalability
public class Group {
	   public void scale(double s) {
	   	   for(Widget w : elements)
	   	   	   w.scale(s);
	   }
   ... }

public interface Widget {
   ...
	   public void scale(double s); }

public class Circle implements Widget {
	   public void scale(double s) {
	   	   radius *= s;
	   }
}

public class Rectangle implements Widget {
	   public void scale(double s) {
	   	   x1 *= s; y1 *= s; x2 *= s; y2 *= s;
	   }
}
Cost of adding a Scalability
                operation


 As you can see, there is a high cost of adding an
operation
 Adding the scalability implies touching 4 types
   Circle, Rectangle, Widget, Group
Cost of adding a Scalability
                  operation

 In addition, there is some code duplication between
scale() and (translate). In the class Group
	 public void translate(int i, int j) {

	   	   for(Widget w : elements)
	   	   	 w.translate(i, j);
	   }
	
	   public void scale(double s) {
	   	 for(Widget w : elements)
	   	 	 w.scale(s);
	   }
Cost of adding a Scalability
                operation
 Ok, you may argue that’s not so bad. Tests are green!
 In fact, yes, it is bad: our code is getting bad
 People who authored Swing did not expect to end up
with a JComponent long of 5471 lines of code
  Swing is becoming so complex, that no much is
happening on it now. It is slowly missing the
put-smoothly-your-GUI-on-the-web trend that
framework like GWT is offering
 So yes, this is bad what we have to touch 4 classes
and introduce duplication
Why a Visitor pattern


 Let’s refactor all that by introducing a visitor
  Remember two of the three responsibilities we
identified:
   Modeling the widgets

   Applying the operations

 The problem we are facing is that widgets and the
operations you can do on them are mixed
 We are mixing responsibilities!
Why a Visitor pattern
 A well modularized software should let you add new
operations without touching your widgets
 Ok, there is a cheat here
 A visitor makes introduction of new operation very
cheap, but the cost of extending the domain is high
 What we are implicitly implying here, it is more likely
we will have new operations to add than extending the
domain
 Is that reasonable? Difficult to answer. But try this:
How many times do you add a new field in a
database? How many times you perform a different
query on them?
Updating with a visitor

public interface Widget {
	 public void translate(int dx, int dy);
	 public void scale(double s);
	 public void accept(Visitor visitor);
}
public class Circle implements Widget {
	 public void accept(Visitor visitor) {
	 	 visitor.visitCircle(this);
	 }
   ...
}
public class Rectangle implements Widget {
	 public void accept(Visitor visitor) {
	 	 visitor.visitRectangle(this);
	 }
   ...
}
Updating with a visitor
public class Group {
   ...
	 public void accept(Visitor visitor) {
	 	 visitor.visitGroup(this);
	 	 for(Widget w : elements)
	 	 	 w.accept(visitor);
	 }
}

// Yes, Group does not implement Widget, we have
felt the need so far.
// Currently, a group cannot contains another
group
// Note that Group does the recursion. It could
well be in the visitor itself, in that case, the
elements have to be accessible from outside.
Which may not be what we want
Creating the visitor




public class Visitor {
	 public void visitCircle(Circle circle) { }
	 public void visitGroup(Group group) { }
	 public void visitRectangle(Rectangle rectangle) { }
}
Trying out our visitor - let’s introduce
      a visitor to count objects

	   @Test public void countingObject() {
	   	 CountingVisitor visitor = new CountingVisitor();
	   	 assertEquals(0, visitor.result());
	   	
	   	 visitor = new CountingVisitor();
	   	 emptyGroup.accept(visitor);
	   	 assertEquals(0, visitor.result());
	   	
	   	 visitor = new CountingVisitor();
	   	 group.accept(visitor);
	   	 assertEquals(2, visitor.result());
	   }
Counting


public class CountingVisitor extends Visitor {
	 private int result = 0;
	
	 public void visitCircle(Circle circle) { result++; }
	 public void visitGroup(Group group) { result++; }
	 public void visitRectangle(Rectangle rectangle) { result++; }
	
	 public int result() {
	 	 return result;
	 }
}
Trying out our visitor - let’s introduce
      a visitor to count objects

	   @Test public void countingObject() {
	   	 CountingVisitor visitor = new CountingVisitor();
	   	 assertEquals(0, visitor.result());
	   	
	   	 visitor = new CountingVisitor();
	   	 emptyGroup.accept(visitor);
	   	 assertEquals(0, visitor.result());
	   	
	   	 visitor = new CountingVisitor();
	   	 group.accept(visitor);
	   	 assertEquals(2, visitor.result());
	   }
Version 9




Let’s refactoring and clean!
Using the visitor to count


public class Canvas {
	 private Group group = new Group();

	   public int getNumberOfElements() {
	   	 CountingVisitor visitor = new CountingVisitor();
	   	 group.accept(visitor);

	   	 return visitor.result() - 1;
	   }
    ...
}
Using Group


public class Group {
   ...
	 public void translate(int dx, int dy) {
	 	 this.accept(new TranslatingVisitor(dx,dy));
	 }
	
	 public void scale(double s) {
	 	 this.accept(new ScalingVisitor(s));
	 }
}
Scaling
public class ScalingVisitor extends Visitor {
	 private double scale;
	
	 public ScalingVisitor(double scale) {
	 	 this.scale = scale;
	 }

	   @Override
	   public void visitCircle(Circle circle) {
	   	 circle.scale(scale);
	   }
	
	   @Override
	   public void visitRectangle(Rectangle rectangle) {
	   	 rectangle.scale(scale);
	   }
}
Scaling
public class ScalingVisitor extends Visitor {
	 private double scale;
	
	 public ScalingVisitor(double scale) {
	 	 this.scale = scale;
	 }

	   @Override
	   public void visitCircle(Circle circle) {
	   	 circle.scale(scale);
	   }
	
	   @Override
	   public void visitRectangle(Rectangle rectangle) {
	   	 rectangle.scale(scale);
	   }
}
Version 10




Making group recursive
A group can now contains a group
Recursive group




	   @Test public void recursiveGroup() {
	   	 Group group = new Group();
	   	 emptyGroup.add(group);
	   	 assertEquals(group.getNumberOfElements(), 1);
	   }
Group implement Widget



public class Group implements Widget {
   ...
}
Test beautycleanness

Más contenido relacionado

La actualidad más candente

The Ring programming language version 1.5.4 book - Part 36 of 185
The Ring programming language version 1.5.4 book - Part 36 of 185The Ring programming language version 1.5.4 book - Part 36 of 185
The Ring programming language version 1.5.4 book - Part 36 of 185Mahmoud Samir Fayed
 
Paradigmas de programação funcional + objetos no liquidificador com scala
Paradigmas de programação funcional + objetos no liquidificador com scalaParadigmas de programação funcional + objetos no liquidificador com scala
Paradigmas de programação funcional + objetos no liquidificador com scalaBruno Oliveira
 
Java Puzzle
Java PuzzleJava Puzzle
Java PuzzleSFilipp
 
Algebra 2 Section 3-1
Algebra 2 Section 3-1Algebra 2 Section 3-1
Algebra 2 Section 3-1Jimbo Lamb
 
12X1 T07 01 v and a In terms of x (2010)
12X1 T07 01 v and a In terms of x (2010)12X1 T07 01 v and a In terms of x (2010)
12X1 T07 01 v and a In terms of x (2010)Nigel Simmons
 
On the Impossibility of Batch Update for Cryptographic Accumulators
On the Impossibility of Batch Update for Cryptographic AccumulatorsOn the Impossibility of Batch Update for Cryptographic Accumulators
On the Impossibility of Batch Update for Cryptographic AccumulatorsPhilippe Camacho, Ph.D.
 
Lesson 27: Integration by Substitution (Section 4 version)
Lesson 27: Integration by Substitution (Section 4 version)Lesson 27: Integration by Substitution (Section 4 version)
Lesson 27: Integration by Substitution (Section 4 version)Matthew Leingang
 
87fg8df7g8df7g87sd7f8s7df8sdf7
87fg8df7g8df7g87sd7f8s7df8sdf787fg8df7g8df7g87sd7f8s7df8sdf7
87fg8df7g8df7g87sd7f8s7df8sdf78as787f8s
 
The Ring programming language version 1.8 book - Part 36 of 202
The Ring programming language version 1.8 book - Part 36 of 202The Ring programming language version 1.8 book - Part 36 of 202
The Ring programming language version 1.8 book - Part 36 of 202Mahmoud Samir Fayed
 
Techniques of differentiation further
Techniques of differentiation furtherTechniques of differentiation further
Techniques of differentiation furthermanrak
 
Functional programming in Java 8 - workshop at flatMap Oslo 2014
Functional programming in Java 8 - workshop at flatMap Oslo 2014Functional programming in Java 8 - workshop at flatMap Oslo 2014
Functional programming in Java 8 - workshop at flatMap Oslo 2014Fredrik Vraalsen
 
The Ring programming language version 1.5.3 book - Part 83 of 184
The Ring programming language version 1.5.3 book - Part 83 of 184The Ring programming language version 1.5.3 book - Part 83 of 184
The Ring programming language version 1.5.3 book - Part 83 of 184Mahmoud Samir Fayed
 

La actualidad más candente (16)

The Ring programming language version 1.5.4 book - Part 36 of 185
The Ring programming language version 1.5.4 book - Part 36 of 185The Ring programming language version 1.5.4 book - Part 36 of 185
The Ring programming language version 1.5.4 book - Part 36 of 185
 
Paradigmas de programação funcional + objetos no liquidificador com scala
Paradigmas de programação funcional + objetos no liquidificador com scalaParadigmas de programação funcional + objetos no liquidificador com scala
Paradigmas de programação funcional + objetos no liquidificador com scala
 
662305 LAB13
662305 LAB13662305 LAB13
662305 LAB13
 
ScalaMeter 2014
ScalaMeter 2014ScalaMeter 2014
ScalaMeter 2014
 
Java Puzzle
Java PuzzleJava Puzzle
Java Puzzle
 
Algebra 2 Section 3-1
Algebra 2 Section 3-1Algebra 2 Section 3-1
Algebra 2 Section 3-1
 
12X1 T07 01 v and a In terms of x (2010)
12X1 T07 01 v and a In terms of x (2010)12X1 T07 01 v and a In terms of x (2010)
12X1 T07 01 v and a In terms of x (2010)
 
On the Impossibility of Batch Update for Cryptographic Accumulators
On the Impossibility of Batch Update for Cryptographic AccumulatorsOn the Impossibility of Batch Update for Cryptographic Accumulators
On the Impossibility of Batch Update for Cryptographic Accumulators
 
Lesson 27: Integration by Substitution (Section 4 version)
Lesson 27: Integration by Substitution (Section 4 version)Lesson 27: Integration by Substitution (Section 4 version)
Lesson 27: Integration by Substitution (Section 4 version)
 
87fg8df7g8df7g87sd7f8s7df8sdf7
87fg8df7g8df7g87sd7f8s7df8sdf787fg8df7g8df7g87sd7f8s7df8sdf7
87fg8df7g8df7g87sd7f8s7df8sdf7
 
Metric Embeddings and Expanders
Metric Embeddings and ExpandersMetric Embeddings and Expanders
Metric Embeddings and Expanders
 
The Ring programming language version 1.8 book - Part 36 of 202
The Ring programming language version 1.8 book - Part 36 of 202The Ring programming language version 1.8 book - Part 36 of 202
The Ring programming language version 1.8 book - Part 36 of 202
 
Techniques of differentiation further
Techniques of differentiation furtherTechniques of differentiation further
Techniques of differentiation further
 
Functional programming in Java 8 - workshop at flatMap Oslo 2014
Functional programming in Java 8 - workshop at flatMap Oslo 2014Functional programming in Java 8 - workshop at flatMap Oslo 2014
Functional programming in Java 8 - workshop at flatMap Oslo 2014
 
The Ring programming language version 1.5.3 book - Part 83 of 184
The Ring programming language version 1.5.3 book - Part 83 of 184The Ring programming language version 1.5.3 book - Part 83 of 184
The Ring programming language version 1.5.3 book - Part 83 of 184
 
Lesson 15: The Chain Rule
Lesson 15: The Chain RuleLesson 15: The Chain Rule
Lesson 15: The Chain Rule
 

Destacado

2005 Oopsla Classboxj
2005 Oopsla Classboxj2005 Oopsla Classboxj
2005 Oopsla Classboxjbergel
 
2006 Esug Omnibrowser
2006 Esug Omnibrowser2006 Esug Omnibrowser
2006 Esug Omnibrowserbergel
 
Multi dimensional profiling
Multi dimensional profilingMulti dimensional profiling
Multi dimensional profilingbergel
 
2006 Small Scheme
2006 Small Scheme2006 Small Scheme
2006 Small Schemebergel
 
tres fotos
tres fotostres fotos
tres fotossara356
 
2008 Sccc Inheritance
2008 Sccc Inheritance2008 Sccc Inheritance
2008 Sccc Inheritancebergel
 
2008 Sccc Smalltalk
2008 Sccc Smalltalk2008 Sccc Smalltalk
2008 Sccc Smalltalkbergel
 

Destacado (7)

2005 Oopsla Classboxj
2005 Oopsla Classboxj2005 Oopsla Classboxj
2005 Oopsla Classboxj
 
2006 Esug Omnibrowser
2006 Esug Omnibrowser2006 Esug Omnibrowser
2006 Esug Omnibrowser
 
Multi dimensional profiling
Multi dimensional profilingMulti dimensional profiling
Multi dimensional profiling
 
2006 Small Scheme
2006 Small Scheme2006 Small Scheme
2006 Small Scheme
 
tres fotos
tres fotostres fotos
tres fotos
 
2008 Sccc Inheritance
2008 Sccc Inheritance2008 Sccc Inheritance
2008 Sccc Inheritance
 
2008 Sccc Smalltalk
2008 Sccc Smalltalk2008 Sccc Smalltalk
2008 Sccc Smalltalk
 

Similar a Test beautycleanness

Lec 9 05_sept [compatibility mode]
Lec 9 05_sept [compatibility mode]Lec 9 05_sept [compatibility mode]
Lec 9 05_sept [compatibility mode]Palak Sanghani
 
Object Oriented Solved Practice Programs C++ Exams
Object Oriented Solved Practice Programs C++ ExamsObject Oriented Solved Practice Programs C++ Exams
Object Oriented Solved Practice Programs C++ ExamsMuhammadTalha436
 
openFrameworks 007 - 3D
openFrameworks 007 - 3DopenFrameworks 007 - 3D
openFrameworks 007 - 3Droxlu
 
Lecture 5: Functional Programming
Lecture 5: Functional ProgrammingLecture 5: Functional Programming
Lecture 5: Functional ProgrammingEelco Visser
 
麻省理工C++公开教学课程(二)
麻省理工C++公开教学课程(二)麻省理工C++公开教学课程(二)
麻省理工C++公开教学课程(二)ProCharm
 
[Codemotion 2015] patrones de diseño con java8
[Codemotion 2015] patrones de diseño con java8[Codemotion 2015] patrones de diseño con java8
[Codemotion 2015] patrones de diseño con java8Alonso Torres
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghStuart Roebuck
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript IntroductionDmitry Sheiko
 
Hidden Gems in Swift
Hidden Gems in SwiftHidden Gems in Swift
Hidden Gems in SwiftNetguru
 
Java Generics
Java GenericsJava Generics
Java Genericsjeslie
 
Monadologie
MonadologieMonadologie
Monadologieleague
 
Martian Cubics and Unit TestingYou must implement all of the data .pdf
Martian Cubics and Unit TestingYou must implement all of the data .pdfMartian Cubics and Unit TestingYou must implement all of the data .pdf
Martian Cubics and Unit TestingYou must implement all of the data .pdfellanorfelicityri239
 
Set up a JavaFX GUI-based program that shows a 10 times 10 grid of la.pdf
Set up a JavaFX GUI-based program that shows a 10 times 10 grid of la.pdfSet up a JavaFX GUI-based program that shows a 10 times 10 grid of la.pdf
Set up a JavaFX GUI-based program that shows a 10 times 10 grid of la.pdfxlynettalampleyxc
 
Structures
StructuresStructures
StructuresSV.CO
 
Hi,I have modified the Point.java file as per your requirement.P.pdf
Hi,I have modified the Point.java file as per your requirement.P.pdfHi,I have modified the Point.java file as per your requirement.P.pdf
Hi,I have modified the Point.java file as per your requirement.P.pdfanokhijew
 

Similar a Test beautycleanness (20)

Lec 9 05_sept [compatibility mode]
Lec 9 05_sept [compatibility mode]Lec 9 05_sept [compatibility mode]
Lec 9 05_sept [compatibility mode]
 
Object Oriented Solved Practice Programs C++ Exams
Object Oriented Solved Practice Programs C++ ExamsObject Oriented Solved Practice Programs C++ Exams
Object Oriented Solved Practice Programs C++ Exams
 
openFrameworks 007 - 3D
openFrameworks 007 - 3DopenFrameworks 007 - 3D
openFrameworks 007 - 3D
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
Lecture 5: Functional Programming
Lecture 5: Functional ProgrammingLecture 5: Functional Programming
Lecture 5: Functional Programming
 
麻省理工C++公开教学课程(二)
麻省理工C++公开教学课程(二)麻省理工C++公开教学课程(二)
麻省理工C++公开教学课程(二)
 
[Codemotion 2015] patrones de diseño con java8
[Codemotion 2015] patrones de diseño con java8[Codemotion 2015] patrones de diseño con java8
[Codemotion 2015] patrones de diseño con java8
 
Oop objects_classes
Oop objects_classesOop objects_classes
Oop objects_classes
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup Edinburgh
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
Hidden Gems in Swift
Hidden Gems in SwiftHidden Gems in Swift
Hidden Gems in Swift
 
Java Generics
Java GenericsJava Generics
Java Generics
 
Monadologie
MonadologieMonadologie
Monadologie
 
Martian Cubics and Unit TestingYou must implement all of the data .pdf
Martian Cubics and Unit TestingYou must implement all of the data .pdfMartian Cubics and Unit TestingYou must implement all of the data .pdf
Martian Cubics and Unit TestingYou must implement all of the data .pdf
 
An introduction to scala
An introduction to scalaAn introduction to scala
An introduction to scala
 
Set up a JavaFX GUI-based program that shows a 10 times 10 grid of la.pdf
Set up a JavaFX GUI-based program that shows a 10 times 10 grid of la.pdfSet up a JavaFX GUI-based program that shows a 10 times 10 grid of la.pdf
Set up a JavaFX GUI-based program that shows a 10 times 10 grid of la.pdf
 
Structures
StructuresStructures
Structures
 
Object and class
Object and classObject and class
Object and class
 
Lec2
Lec2Lec2
Lec2
 
Hi,I have modified the Point.java file as per your requirement.P.pdf
Hi,I have modified the Point.java file as per your requirement.P.pdfHi,I have modified the Point.java file as per your requirement.P.pdf
Hi,I have modified the Point.java file as per your requirement.P.pdf
 

Más de bergel

Building Neural Network Through Neuroevolution
Building Neural Network Through NeuroevolutionBuilding Neural Network Through Neuroevolution
Building Neural Network Through Neuroevolutionbergel
 
Roassal presentation
Roassal presentationRoassal presentation
Roassal presentationbergel
 
2011 famoosr
2011 famoosr2011 famoosr
2011 famoosrbergel
 
2011 ecoop
2011 ecoop2011 ecoop
2011 ecoopbergel
 
Profiling blueprints
Profiling blueprintsProfiling blueprints
Profiling blueprintsbergel
 
The Pharo Programming Language
The Pharo Programming LanguageThe Pharo Programming Language
The Pharo Programming Languagebergel
 
Presentation of Traits
Presentation of TraitsPresentation of Traits
Presentation of Traitsbergel
 
2006 Seaside
2006 Seaside2006 Seaside
2006 Seasidebergel
 
2004 Esug Prototalk
2004 Esug Prototalk2004 Esug Prototalk
2004 Esug Prototalkbergel
 

Más de bergel (9)

Building Neural Network Through Neuroevolution
Building Neural Network Through NeuroevolutionBuilding Neural Network Through Neuroevolution
Building Neural Network Through Neuroevolution
 
Roassal presentation
Roassal presentationRoassal presentation
Roassal presentation
 
2011 famoosr
2011 famoosr2011 famoosr
2011 famoosr
 
2011 ecoop
2011 ecoop2011 ecoop
2011 ecoop
 
Profiling blueprints
Profiling blueprintsProfiling blueprints
Profiling blueprints
 
The Pharo Programming Language
The Pharo Programming LanguageThe Pharo Programming Language
The Pharo Programming Language
 
Presentation of Traits
Presentation of TraitsPresentation of Traits
Presentation of Traits
 
2006 Seaside
2006 Seaside2006 Seaside
2006 Seaside
 
2004 Esug Prototalk
2004 Esug Prototalk2004 Esug Prototalk
2004 Esug Prototalk
 

Último

The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 

Último (20)

The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 

Test beautycleanness

  • 1. Test, beauty, cleanness Alexandre Bergel abergel@dcc.uchile.cl 16/06/2011
  • 2. Problem description We would like to build a two-dimensional graphics framework for structured drawing editors Widgets such as circle and rectanglehave to be supported Operations like translating, scaling have to be offered
  • 3. What are the responsibilities? Containing the widgets Modeling the widgets Applying the operations
  • 4. Version 1 Creating a canvas to contains the widgets
  • 5. Testing the canvas public class HotDrawTest { @Test public void testEmptyCanvas() { Canvas canvas = new Canvas (); assertEquals(canvas.getNumberOfElements(), 0); } } The class Canvas is not created yet!
  • 6. Creating the class Canvas public class Canvas { public Object getNumberOfElements() { return 0; } }
  • 7. Introducing the containment @Test public void testCanvas() { Canvas canvas = new Canvas (); canvas.add(new Object()); assertEquals(1, canvas.getNumberOfElements()); canvas.add(new Object()); canvas.add(new Object()); assertEquals(3, canvas.getNumberOfElements()); } We need to be able to add objects in a canvas!
  • 8. Revising the definition of Canvas public class Canvas { private ArrayList<Object> elements = new ArrayList<Object>(); public int getNumberOfElements() { return elements.size(); } public void add(Object object) { elements.add(object); } }
  • 9. Revising the definition of Canvas public class Canvas { private ArrayList<Object> elements = new ArrayList<Object>(); public int getNumberOfElements() { return elements.size(); } Tests are green! public void add(Object object) { elements.add(object); } }
  • 11. We revise our testCanvas @Test public void testCanvas() { Canvas canvas = new Canvas (); canvas.add(new Circle()); assertEquals(1, canvas.getNumberOfElements()); canvas.add(new Circle()); canvas.add(new Rectangle()); assertEquals(3, canvas.getNumberOfElements()); }
  • 12. Circle and Rectangle public class Circle { } public class Rectangle { }
  • 13. Adding position to circle and rectangle @Test public void testCanvas() { Canvas canvas = new Canvas (); //(10, 20), radius 5 canvas.add(new Circle(10,20, 5)); assertEquals(1, canvas.getNumberOfElements()); canvas.add(new Circle()); //(5,6) -> (10,8) canvas.add(new Rectangle(5, 6, 10, 8)); assertEquals(3, canvas.getNumberOfElements()); }
  • 14. Generated template public class Circle { public Circle(int i, int j, int k) { // TODO Auto-generated constructor stub } }
  • 15. Filling the template template public class Circle { private int x, y, radius; public Circle() { this(5, 5, 10); } public Circle(int x, int y, int radius) { this.x = x; this.y = y; this.radius = radius; } }
  • 16. Generated template public class Rectangle { public Rectangle(int i, int j, int k, int l) { // TODO Auto-generated constructor stub } }
  • 17. Filling the template template public class Rectangle { private int x1, y1, x2, y2; public Rectangle() { this(2, 3, 5, 6); } public Rectangle(int x1, int y1, int x2, int y2) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; } }
  • 18. Version 3 Before moving on, lets step back on what we wrote to see whether there are opportunities for cleaning a bit the code
  • 19. HotDrawTest public class HotDrawTest { @Test public void testEmptyCanvas() { Canvas canvas = new Canvas (); ... } @Test public void testCanvas() { Canvas canvas = new Canvas (); ... } }
  • 20. HotDrawTest public class HotDrawTest { @Test public void testEmptyCanvas() { Canvas canvas = new Canvas (); ... } Duplication! @Test public void testCanvas() { Canvas canvas = new Canvas (); ... } }
  • 21. Refactoring our test public class HotDrawTest { private Canvas canvas; @Before public void initializingFixture() { canvas = new Canvas (); } @Test public void testEmptyCanvas() { assertEquals(canvas.getNumberOfElements(), 0); } @Test public void testCanvas() { //(10, 20), radius 5 canvas.add(new Circle(10,20, 5)); ... } }
  • 22. Giving a better name to the variable
  • 23. canvas -> emptyCanvas public class HotDrawTest { private Canvas emptyCanvas; @Before public void initializingFixture() { emptyCanvas = new Canvas (); } @Test public void testEmptyCanvas() { assertEquals(emptyCanvas.getNumberOfElements(), 0); } @Test public void testCanvas() { //(10, 20), radius 5 emptyCanvas.add(new Circle(10,20, 5)); ... } }
  • 24. canvas -> emptyCanvas public class HotDrawTest { private Canvas emptyCanvas; @Before public void initializingFixture() { emptyCanvas = new Canvas (); } @Test public void testEmptyCanvas() { assertEquals(emptyCanvas.getNumberOfElements(), 0); } @Test public void testCanvas() { //(10, 20), radius 5 emptyCanvas.add(new Circle(10,20, 5)); ... } }
  • 25. Version 4 Applying the operations on the widget Note that at that point, we have not seen the need to have a common superclass for Circle and Rectangle As well we have not seen the need to have a common interface We should be test driven, else it is too easy to go wrong The class canvas also contains a list of objects
  • 26. Adding an operation Let’s translate our objects Each widget should now understand the message translate(deltaX, deltaY) Let’s write some test first
  • 27. Testing circle first @Test public void translatingCircle() { Circle circle = new Circle(); int oldX = circle.getX(); int oldY = circle.getY(); circle.translate(2, 3); assertEquals(circle.getX(), oldX + 2); assertEquals(circle.getY(), oldY + 3); }
  • 28. Modifying Circle public class Circle { private int x, y, radius; public int getX() { return x; } public int getY() { return y; } ... } // Note that there is no accessor for radius, we have not seen the need of it!
  • 29. Translating Circle public class Circle { ... public void translate(int dx, int dy) { x = x + dx; y = y + dy; } ... }
  • 30. Translating Circle public class Circle { ... public void translate(int dx, int dy) { x = x + dx; y = y + dy; } ... }
  • 31. Translating the rectangle @Test public void translatingRectangle() { Rectangle rectangle = new Rectangle(); int oldX1 = rectangle.getX1(); int oldY1 = rectangle.getY1(); int oldX2 = rectangle.getX2(); int oldY2 = rectangle.getY2(); rectangle.translate(2, 3); assertEquals(rectangle.getX1(), oldX1 + 2); assertEquals(rectangle.getX2(), oldX2 + 2); assertEquals(rectangle.getY1(), oldY1 + 3); assertEquals(rectangle.getY2(), oldY2 + 3); }
  • 32. Updating Rectangle public class Rectangle { ... public int getX1() {... } public int getY1() {...} public int getX2() {...} public int getY2() { return y2; } public void translate(int dx, int dy) { x1 = x1 + dx; x2 = x2 + dx; y1 = y1 + dy; y2 = y2 + dy; } }
  • 33. Important Note that we have not still see the need to have a common interface and a common superclass If you doing it upfront, when your design will look like what you want it to be, and not what it has to be
  • 34. Version 5 It is a bit cumbersome to have to translate each element one by one Let’s ask the canvas to translate all the nodes
  • 35. Translating the canvas @Test public void translatingTheCanvas() { Rectangle rectangle = new Rectangle(); int rectangleOldX1 = rectangle.getX1(); int rectangleOldY1 = rectangle.getY1(); int rectangleOldX2 = rectangle.getX2(); int rectangleOldY2 = rectangle.getY2(); Circle circle = new Circle(); int circleOldX = circle.getX(); int circleOldY = circle.getY(); emptyCanvas.add(rectangle); emptyCanvas.add(circle); emptyCanvas.translate(2, 3); ...
  • 36. Translating the canvas ... assertEquals(rectangle.getX1(), rectangleOldX1 + 2); assertEquals(rectangle.getX2(), rectangleOldX2 + 2); assertEquals(rectangle.getY1(), rectangleOldY1 + 3); assertEquals(rectangle.getY2(), rectangleOldY2 + 3); assertEquals(circle.getX(), circleOldX + 2); assertEquals(circle.getY(), circleOldY + 3); }
  • 37. Updating Canvas - what we would like to do public class Canvas { private ArrayList<Object> elements = new ArrayList<Object>(); public void add(Object object) { elements.add(object); } public void translate(int dx, int dy) { for(Object o : elements) o.translate(dx, dy); } ... }
  • 38. Updating Canvas - what we would like to do public class Canvas { private ArrayList<Object> elements = new ArrayList<Object>(); public void add(Object object) { elements.add(object); } public void translate(int dx, int dy) { for(Object o : elements) o.translate(dx, dy); } ... } The compiler will not be happy with this
  • 39. What is happening? Only now we see the need to introduce a common interface that the object have to fulfill This interface will only be aware of the translate(dx,dy) method
  • 40. Let’s introduce the Widget interface public interface Widget { public void translate(int dx, int dy); } public class Rectangle implements Widget { ... } public class Circle implements Widget { ... }
  • 41. Updating Canvas public class Canvas { private ArrayList<Widget> elements = new ArrayList<Widget>(); public void add(Widget widget) { elements.add(widget); } public void translate(int dx, int dy) { for(Widget o : elements) o.translate(dx, dy); } ... }
  • 42. Updating Canvas public class Canvas { private ArrayList<Widget> elements = new ArrayList<Widget>(); public void add(Widget widget) { elements.add(widget); } public void translate(int dx, int dy) { for(Widget o : elements) o.translate(dx, dy); } ... }
  • 43. Version 6 We are doing a pretty good job so far Let’s add a group of widgets that can be commonly manipulated
  • 44. Testing Group @Test public void groupingWidgets() { Group group = new Group(); assertEquals(group.getNumberOfElements(), 0); group.add(new Circle()); group.add(new Rectangle()); assertEquals(group.getNumberOfElements(), 2); }
  • 45. Defining Group public class Group { private ArrayList<Object> elements = new ArrayList<Object>(); public void add(Object w) { elements.add(w); } public int getNumberOfElements() { return elements.size(); } }
  • 46. Defining Group public class Group { private ArrayList<Object> elements = new ArrayList<Object>(); public void add(Object w) { elements.add(w); } Yes! We haven’t seen the public int getNumberOfElements() { return elements.size(); to have Widget here need } }
  • 47. Defining Group public class Group { private ArrayList<Object> elements = new ArrayList<Object>(); public void add(Object w) { elements.add(w); } Yes! We haven’t seen the public int getNumberOfElements() { return elements.size(); to have Widget here need } } This is the proof that we do not need it!
  • 48. Translating a group - what we could write, but it contains a lot of duplication @Test public void translatingGroup() { Group group = new Group(); group.add(new Circle()); group.add(new Rectangle()); group.translate(...) }
  • 49. But let’s refactor first public class HotDrawTest { private Canvas emptyCanvas; private Group emptyGroup, group; private Circle circle; private Rectangle rectangle; @Before public void initializingFixture() { emptyCanvas = new Canvas (); emptyGroup = new Group(); group = new Group(); group.add(circle = new Circle()); group.add(rectangle = new Rectangle()); }
  • 50. But let’s refactor first @Test public void groupingWidgets() { assertEquals(emptyGroup.getNumberOfElements(), 0); assertEquals(group.getNumberOfElements(), 2); }
  • 51. Translating a group @Test public void translatingGroup() { int circleOldX = circle.getX(); int circleOldY = circle.getY(); int rOldX1 = rectangle.getX1(); int rOldY1 = rectangle.getY1(); group.translate(2, 3); assertEquals(rectangle.getX1(), rOldX1 + 2); assertEquals(rectangle.getY1(), rOldY1 + 3); assertEquals(circle.getX(), circleOldX + 2); assertEquals(circle.getY(), circleOldY + 3); }
  • 52. Translating a group public class Group { private ArrayList<Widget> elements = new ArrayList<Widget>(); public void add(Widget w) { elements.add(w); } public int getNumberOfElements() { return elements.size(); } public void translate(int i, int j) { for(Widget w : elements) w.translate(i, j); } }
  • 53. Translating a group public class Group { private ArrayList<Widget> elements = new ArrayList<Widget>(); public void add(Widget w) { elements.add(w); } Yes, we need an array of Widgets public int getNumberOfElements() { return elements.size(); } public void translate(int i, int j) { for(Widget w : elements) w.translate(i, j); } }
  • 54. Translating a group public class Group { private ArrayList<Widget> elements = new ArrayList<Widget>(); public void add(Widget w) { elements.add(w); } public int getNumberOfElements() { return elements.size(); } public void translate(int i, int j) { for(Widget w : elements) w.translate(i, j); } }
  • 55. Version 7 Let’s refactor Canvas instead of containing a list of elements, it will solely contains a group
  • 56. Canvas is getting simpler public class Canvas { private Group group = new Group(); public void add(Widget widget) { group.add(widget); } public void translate(int dx, int dy) { group.translate(dx, dy); } public int getNumberOfElements() { return group.getNumberOfElements(); } }
  • 57. Canvas is getting simpler public class Canvas { private Group group = new Group(); public void add(Widget widget) { group.add(widget); } public void translate(int dx, int dy) { group.translate(dx, dy); } public int getNumberOfElements() { return group.getNumberOfElements(); } }
  • 58. Version 8 Adding a new operation We will now scale objects scale x2
  • 59. Adding a test for scalability @Test public void scalingGroup() { int oldRadius = circle.radius(); int rectangleWidth = rectangle.width(); int rectangleHeight = rectangle.height(); group.scale(2); assertEquals(circle.radius(), 2 * oldRadius); assertEquals(rectangle.width(), 2 * rectangleWidth); assertEquals(rectangle.height(), 2 * rectangleHeight); }
  • 60. Adding a test for scalability Accessing radius @Test public void scalingGroup() { int oldRadius = circle.radius(); int rectangleWidth = rectangle.width(); int rectangleHeight = rectangle.height(); group.scale(2); Accessing width and height assertEquals(circle.radius(), 2 * oldRadius); assertEquals(rectangle.width(), 2 * rectangleWidth); assertEquals(rectangle.height(), 2 * rectangleHeight); }
  • 61. Updating Circle public class Circle implements Widget { private int x, y, radius; public int radius() { return radius; } ... }
  • 62. Updating Rectangle public class Rectangle implements Widget { public int width() { return Math.abs(x2 - x1); } public int height() { return Math.abs(y2 - y1); } ... }
  • 63. Scalability public class Group { public void scale(double s) { for(Widget w : elements) w.scale(s); } ... } public interface Widget { ... public void scale(double s); } public class Circle implements Widget { public void scale(double s) { radius *= s; } } public class Rectangle implements Widget { public void scale(double s) { x1 *= s; y1 *= s; x2 *= s; y2 *= s; } }
  • 64. Scalability public class Group { public void scale(double s) { for(Widget w : elements) w.scale(s); } ... } public interface Widget { ... public void scale(double s); } public class Circle implements Widget { public void scale(double s) { radius *= s; } } public class Rectangle implements Widget { public void scale(double s) { x1 *= s; y1 *= s; x2 *= s; y2 *= s; } }
  • 65. Cost of adding a Scalability operation As you can see, there is a high cost of adding an operation Adding the scalability implies touching 4 types Circle, Rectangle, Widget, Group
  • 66. Cost of adding a Scalability operation In addition, there is some code duplication between scale() and (translate). In the class Group public void translate(int i, int j) { for(Widget w : elements) w.translate(i, j); } public void scale(double s) { for(Widget w : elements) w.scale(s); }
  • 67. Cost of adding a Scalability operation Ok, you may argue that’s not so bad. Tests are green! In fact, yes, it is bad: our code is getting bad People who authored Swing did not expect to end up with a JComponent long of 5471 lines of code Swing is becoming so complex, that no much is happening on it now. It is slowly missing the put-smoothly-your-GUI-on-the-web trend that framework like GWT is offering So yes, this is bad what we have to touch 4 classes and introduce duplication
  • 68. Why a Visitor pattern Let’s refactor all that by introducing a visitor Remember two of the three responsibilities we identified: Modeling the widgets Applying the operations The problem we are facing is that widgets and the operations you can do on them are mixed We are mixing responsibilities!
  • 69. Why a Visitor pattern A well modularized software should let you add new operations without touching your widgets Ok, there is a cheat here A visitor makes introduction of new operation very cheap, but the cost of extending the domain is high What we are implicitly implying here, it is more likely we will have new operations to add than extending the domain Is that reasonable? Difficult to answer. But try this: How many times do you add a new field in a database? How many times you perform a different query on them?
  • 70. Updating with a visitor public interface Widget { public void translate(int dx, int dy); public void scale(double s); public void accept(Visitor visitor); } public class Circle implements Widget { public void accept(Visitor visitor) { visitor.visitCircle(this); } ... } public class Rectangle implements Widget { public void accept(Visitor visitor) { visitor.visitRectangle(this); } ... }
  • 71. Updating with a visitor public class Group { ... public void accept(Visitor visitor) { visitor.visitGroup(this); for(Widget w : elements) w.accept(visitor); } } // Yes, Group does not implement Widget, we have felt the need so far. // Currently, a group cannot contains another group // Note that Group does the recursion. It could well be in the visitor itself, in that case, the elements have to be accessible from outside. Which may not be what we want
  • 72. Creating the visitor public class Visitor { public void visitCircle(Circle circle) { } public void visitGroup(Group group) { } public void visitRectangle(Rectangle rectangle) { } }
  • 73. Trying out our visitor - let’s introduce a visitor to count objects @Test public void countingObject() { CountingVisitor visitor = new CountingVisitor(); assertEquals(0, visitor.result()); visitor = new CountingVisitor(); emptyGroup.accept(visitor); assertEquals(0, visitor.result()); visitor = new CountingVisitor(); group.accept(visitor); assertEquals(2, visitor.result()); }
  • 74. Counting public class CountingVisitor extends Visitor { private int result = 0; public void visitCircle(Circle circle) { result++; } public void visitGroup(Group group) { result++; } public void visitRectangle(Rectangle rectangle) { result++; } public int result() { return result; } }
  • 75. Trying out our visitor - let’s introduce a visitor to count objects @Test public void countingObject() { CountingVisitor visitor = new CountingVisitor(); assertEquals(0, visitor.result()); visitor = new CountingVisitor(); emptyGroup.accept(visitor); assertEquals(0, visitor.result()); visitor = new CountingVisitor(); group.accept(visitor); assertEquals(2, visitor.result()); }
  • 77. Using the visitor to count public class Canvas { private Group group = new Group(); public int getNumberOfElements() { CountingVisitor visitor = new CountingVisitor(); group.accept(visitor); return visitor.result() - 1; } ... }
  • 78. Using Group public class Group { ... public void translate(int dx, int dy) { this.accept(new TranslatingVisitor(dx,dy)); } public void scale(double s) { this.accept(new ScalingVisitor(s)); } }
  • 79. Scaling public class ScalingVisitor extends Visitor { private double scale; public ScalingVisitor(double scale) { this.scale = scale; } @Override public void visitCircle(Circle circle) { circle.scale(scale); } @Override public void visitRectangle(Rectangle rectangle) { rectangle.scale(scale); } }
  • 80. Scaling public class ScalingVisitor extends Visitor { private double scale; public ScalingVisitor(double scale) { this.scale = scale; } @Override public void visitCircle(Circle circle) { circle.scale(scale); } @Override public void visitRectangle(Rectangle rectangle) { rectangle.scale(scale); } }
  • 81. Version 10 Making group recursive A group can now contains a group
  • 82. Recursive group @Test public void recursiveGroup() { Group group = new Group(); emptyGroup.add(group); assertEquals(group.getNumberOfElements(), 1); }
  • 83. Group implement Widget public class Group implements Widget { ... }