List of Figures

Chapter 1. Understanding brownfield applications

Figure 1.1. Brownfield applications have three components that distinguish them from greenfield and legacy applications.

Figure 1.2. The Iron Triangle. Changes in any of the three vertices will affect the project’s overall quality.

Figure 1.3. Generally speaking, your job will be to balance time and resources against code quality and features.

Figure 1.4. There are many challenges to a brownfield application. As developers, we often focus only on the technical ones.

Figure 1.5. Before starting any change, be sure you can measure how successful it will be when you’re done.

Figure 1.6. Proofs of concept and mockups can help convince your boss of the value of a concept and can help you work out kinks before implementing it large-scale.

Chapter 2. Version control in brownfield applications

Figure 2.1. Many brownfield applications will give reference errors when first downloading them from version control.

Figure 2.2. Often, reference errors are due to missing assemblies. The developer must hunt down all the dependencies for the project.

Figure 2.3. Editing a file with a VCS that uses file locking. Note that while Dean has the file checked out, no other developer can edit the file.

Figure 2.4. Editing a file with a VCS that uses version merging. Both Dean and Martin are able to make changes to version 1 of the file. But because Dean checks in his changes first, Martin must merge those changes into his version before checking in.

Figure 2.5. The branching process. Each node represents a check-in.

Figure 2.6. New developers should be able to follow these simple steps to start being productive on a brownfield application. Anything else will result in friction and lost productivity.

Figure 2.7. A sample folder structure to facilitate getting developers up and running quickly

Figure 2.8. Example of maintaining the same physical file structure in the VCS as you have on a local working folder

Figure 2.9. TortoiseSVN, like many VCS tools, allows for ignoring patterns and files.

Figure 2.10. The steps of the check-in dance for a file-locking VCS

Figure 2.11. The steps of the check-in dance for a version-merging VCS

Chapter 3. Continuous integration

Figure 3.1. Adding a component to version control that requires developers to install something first is a source of friction.

Figure 3.2. As a problem or bug makes its way through each stage in a project’s life cycle, the effort and cost required to resolve the bug increase by an order of magnitude.

Figure 3.3. After adding continuous integration, you need to add a step to the end of the check-in dance to allow the CI server to do its work.

Figure 3.4. During the time between when you get the latest version and check in, someone else may have checked in code.

Figure 3.5. The three basic steps of an automated build. Each of the incremental steps builds and relies on the previous.

Figure 3.6. Keep the build components separate from your code and third-party libraries.

Figure 3.7. Build components can be stored in Visual Studio in solution folders or even separate projects for ease of use. Note that solution folders don’t map to physical folders.

Figure 3.8. Example of creating a release archive in your folder structure

Chapter 4. Automated testing

Figure 4.1. An example of branching logic within your code. Each path through the code represents a potential point of failure and should be tested.

Figure 4.2. State-based testing doesn’t require any knowledge of the code under test.

Figure 4.3. Steps to integrate an existing test project back into your process

Figure 4.4. There are many reasons a test may be invalid.

Figure 4.5. Physically separating unit and integration tests in the folder structure allows for build scripts to easily create separate testing assemblies.

Figure 4.6. Many considerations are involved when you’re testing a web interface, not least of which is the fact that you must test on all major web browsers.

Figure 4.7. The process for running integrations tests against a known set of data

Chapter 5. Software metrics and code analysis

Figure 5.1. Code coverage utilities are useful when attached to your automated test process. Here, the code coverage tool monitors the test utility to see how much of your application code is exercised by the tests.

Figure 5.2. Efferent coupling (left) tells you how many classes your class depends on. Afferent coupling (right) shows how many classes depend on your class.

Figure 5.3. A dependency matrix (shown here from NDepend) can help assess cohesion. Squares around the diagonal suggest higher cohesion.

Figure 5.4. A graph of the distance from the main sequence taken from NDepend. Notice the Common assembly nestled in the Zone of Pain indicating that it contains a high number of concrete assemblies and that many assemblies depend on it.

Chapter 6. Defect management

Figure 6.1. Your policy toward defects will affect both your project team’s confidence and the overall quality.

Figure 6.2. Defects come in many flavors: languishing, incomplete, spurious, and feature requests.

Figure 6.3. In the initial defect review, the goal is either to close the defect or assign it to the development or test team.

Figure 6.4. New feature development and defect resolution will almost always occur in parallel.

Figure 6.5. Swapping team members regularly from defect resolution to new features helps keep morale from flagging.

Figure 6.6. The question about whether something is a defect or a feature is moot. The work still ends up in the backlog either way.

Figure 6.7. Concise, clear, complete, constructive, and, ultimately, closed are the traits of a good defect entry.

Figure 6.8. Remember that the development team is only one part of the overall project team.

Figure 6.9. A sample graph showing number of defects per module over time. Note that the increasing defect count in the A/P module indicates it could use some attention.

Chapter 7. Bringing better OO practices to the project

Figure 7.1. Five “-abilities” that help lead to a maintainable application

Figure 7.2. Extreme inheritance isn’t always a good thing. A change in the Item class will have far-reaching ripple effects.

Chapter 8. Relayering your application

Figure 8.1. Traditional three-tier architecture. The user accesses the presentation tier, which talks to the business logic tier, which talks to the data access tier.

Figure 8.2. Very often, a physical tier will contain several logical layers.

Figure 8.3. A seam is the interface that one logical layer uses to communicate with another.

Figure 8.4. A vertical layer (along the left) will span several, sometimes all, horizontal layers. In this example, the physical tiers are grouped by color.

Figure 8.5. Traditional n-tier representation of a data request. Although we show it here, the domain often doesn’t exist as a separate layer.

Figure 8.6. With a domain-centric approach, the domain encapsulates both the business logic and the domain objects.

Figure 8.7. The domain-centric architecture we’re working toward. It highlights the importance of the domain as the center of the application.

Figure 8.8. An overview of the steps involved when you refactor your application to use layers

Figure 8.9. When refactoring to layers, the key is incremental changes—refactoring only a small portion of each screen at a time.

Figure 8.10. Further refining the layers

Figure 8.11. The final refactorings

Chapter 9. Loosen up: Taming your dependencies

Figure 9.1. Dependencies for our sample classes. Each gray arrow represents a dependency on another class. The dashed arrows indicate that the dependency is based on inheritance.

Figure 9.2. After introducing an interface, we’ve reduced the number of dependencies and changed the direction of one. More importantly, SpellChecker now relies on only one interface.

Chapter 10. Cleaning up the user interface

Figure 10.1. The Passive View. The presenter mediates between the model and the view, which have no knowledge of each other.

Figure 10.2. The Supervising Controller. Unlike the Passive View, the view has direct access to the model.

Figure 10.3. In the Presentation Model, the view keeps itself synchronized with a screen-specific Presentation Model object.

Figure 10.4. The high-level steps to refactoring to an implementation of MVP. The first step, writing a test, may not be possible depending on your current architecture.

Figure 10.5. A Passive View is more testable than the Supervising Controller but at the risk of being more chatty.

Figure 10.6. Model-View-Controller. Like the Supervising Controller, the view has access to the model.

Figure 10.7. Some differences between MVP and MVC. MVP is usually better suited to brownfield applications.

Chapter 11. Refactoring data access

Figure 11.1. Initial approach to layering your data access code. As in chapter 8, we refactor in increments.

Figure 11.2. Interfaces and implementations for a generic data access scheme. The IRepository interface and BaseRepository implementation provide most of the basic operations.

Figure 11.3. Features of an effective data access layer. Some are easier to implement than others.

Figure 11.4. Database calls are queued in the Unit of Work and executed in a single transaction.

Figure 11.5. Hand-rolled DALs can be application specific or corporate wide. Each has advantages and disadvantages.

Figure 11.6. ORMs can provide a lot of benefit, but be prepared for possible resistance and a learning curve.

Chapter 12. Managing external system dependencies

Figure 12.1. Example of four screens calling the same third-party component. What happens when something changes in the third-party component?

Figure 12.2. The same drawing with an anticorruption layer added. Now the screens call out to your own service, which passes the calls on to the third-party component. If the component changes, only the anticorruption layer needs to be changed.

Figure 12.3. Ticket Chooser, a sample application that reads a web service

Figure 12.4. A class diagram of a possible structure you’d like to use instead of DataSets

Figure 12.5. This sample application provides a simple search function against a music library. It uses two different third-party libraries to extract the metadata from each file.

Figure 12.6. Useful patterns for dealing with external dependencies. All deal with the same theme of hiding parts or all of the access to the dependency.

Figure 12.7. When connecting to a web service, Visual Studio generates a proxy class to control access to it.

Chapter 13. Keeping the momentum

Figure 13.1. Without a consistent and conscientious effort to improve, a brownfield application reverts back to its old self very quickly.

Figure 13.2. Once a large project has built up momentum, it’s hard to make drastic changes. The beast will crash right through most roadblocks you put up.

Figure 13.3. Nudging a project to change its course slowly and steadily over time provides a smoother transition than an all-at-once, or “big bang,” approach.

Figure 13.4. Each topic lays a foundation for the one above it. Make sure you have a good grasp of each one before moving on.

Figure 13.5. No one likes spring cleaning. So don’t do it.

Figure 13.6. Pair programming is an excellent way to introduce new concepts to a team.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset