Refactoring Workbook

import junit.framework.TestCase; import java.util.List; import java.util.Collection; public class TestReport extends TestCase { public TestReport(String name) { super(name); } public void testEmptyReport() throws Exception { Schedule.deleteAll(); Report report = new Report(); StringBuffer buffer = new StringBuffer(); report.write(buffer); assertEquals( "Number of scheduled offerings: 0\n", buffer.toString()); } public void testReport() throws Exception { Schedule.deleteAll(); Course cs101 = Course.create("CS101", 3); cs101.update(); Offering off1 = Offering.create(cs101, "M10"); off1.update(); Offering off2 = Offering.create(cs101, "T9"); off2.update(); Schedule s = Schedule.create("Bob"); s.add(off1); s.add(off2); s.update(); Schedule s2 = Schedule.create("Alice"); s2.add(off1); s2.update(); Report report = new Report(); StringBuffer buffer = new StringBuffer(); report.write(buffer); String result = buffer.toString(); String valid1 = "CS101 M10\n\tAlice\n\tBob\n" + "CS101 T9\n\tBob\n" + "Number of scheduled offerings: 2\n"; String valid2 = "CS101 T9\n\tBob\n" + "CS101 M10\n\tAlice\n\tBob\n" + "Number of scheduled offerings: 2\n"; assertTrue(result.equals(valid1) result.equals(valid2)); } }

Exercise 51 Duplication. (Challenging).
  1. Identify smells, especially the duplication (and the differences!) between these classes.

  2. What is the pattern of access for persistence? (That is, trace the life of an object from creation to destruction.)

See Appendix A for solutions.

Exercise 52 Application. (Challenging).
  1. The database- related routines are tantalizingly similar. Apply refactorings that will reduce this duplication.

  2. Create a class that provides the bulk of the database support. Should this be a parent of these objects or a separate class?

See Appendix A for solutions.

Exercise 53 Database Layer. (Challenging).

In the refactorings you just performed, one effect has been to move the code toward a database layer.

  1. What extra work would you have to do to create an in-memory version of the database classes?

  2. Why might you want to do this?

  3. How much of the JDBC would be exposed by your new layer?

See Appendix A for solutions.

For more information on creating a database layer, see J2EE (tool support for automatic mapping of Enterprise Java Beans [EJBs]), WebGain TopLink (see www.webgain.com/products/toplink/ ), or Scott Ambler's description ( www.ambysoft.com/mappingObjects.html ). One thing these references will show you is that you may not want to undertake lightly the development of a full-fledged layer.

Exercise 54 Find.

The find() routines create a new instance of an object even if it's already been found before.

  1. Make find() cache its objects, returning a previously found object if possible .

  2. Is this refactoring or development? Did you add tests to verify the new behavior? (You should.)

  3. The Report makes it a point to store keys of offerings. Use the improved nature of find() to simplify the report's code.

See Appendix A for solutions.

Exercise 55 Multiple Open Queries.

Some databases have a restriction that a connection can't have multiple queries open at the same time. (An example occurs in Schedule.find(): While building a Schedule, it queries Offerings.find(), which also queries the database.)

  1. How much code (and in how many places) would be affected by a change to enforce this discipline?

  2. The na ve approach used in this code instantiates all related objects for each row that is loaded. How else might you do it?

See Appendix A for solutions.

Exercise 56 Counter.

The counter in Offering is manipulated in a two-step process: Get the current max value of the counter in any row and create a new row with an ID one bigger. When will this strategy be inadequate? What could you do about it?

See Appendix A for solutions.

Exercise 57 Report.

The Report creates a list of offerings and the students in each.

  1. Write a structured query language ( SQL ) query (if you know SQL ) to produce the information in this report.

  2. What are the trade-offs between the two approaches?

Exercise 58 Database Refactorings. (Challenging).

Earlier, we described some possible database changes: introducing IDs (rather than using string keys), extracting a new table, and so on. We can't just make these changes in the database; our code depends on the database structure, so the changes must be coordinated.

  1. Describe Rename Column as a refactoring. Tell what to change in the database or the code, when to change it, when to run tests, and so on.

  2. Describe Split Table (turning one table into two related tables) as a refactoring. Make sure you account for any data migration.

  3. Are there intermediate steps that could temporarily leave the database in a slightly worse structure, but at the same time could make the overall refactoring safer? (Think of how Extract Method copies and adjusts the new method before deleting the old one, or how some refactorings change things one at a time, running tests after each change.)

See Appendix A for solutions.

Exercise 59 Domain Class Independence.

Suggest ways in which the domain classes could be made more independent of the database access part of these classes.

See Appendix A for solutions.

Категории