In-Depth
Visualize Code With the VSTS Class Designer
Visual Studio Team System's Class Designer allows you to reverse-engineer and visualize existing code in order to better understand it. It ensures that your object model and documentation remain accurate and helpful throughout your app's cycle.
Technology Toolbox: Visual Basic, C#
Editor's Note: This article is excerpted from Chapter 12, "Class Designer," of Jeff Levinson and David Nelson's book, Pro Visual Studio 2005 Team System, with permission from Apress [2005, ISBN: 1590594606]. It has been edited for length and format to fit the magazine.
Visual Studio Team System's (VSTS') Class Designer is a tool intended for both architects and developers. It lets architects communicate ideas about an application's structure to the development team, while also providing a way for developers to build a skeleton of the classes before they dive into coding them.
Developers at Microsoft had four discrete goals when they created the Class Designer. First, they wanted to help developers understand existing code. Second, they wanted to let developers review and refactor an application's structure and code easily. The third goal was to provide diagrams and documentation for an application that were relevant throughout the life of the application, including the maintenance cycle. Finally, the developers at Microsoft wanted to give you the ability to get a jump start on creating the initial application by using class designs. To this extent, the code generation and synchronization is first-class and seamless in the IDE.
Let's look at how these goals apply to real-world situations. Developers, architects, and even testers are often called upon to review the code of applications they haven't worked on directly. This is the case when one part of a team has worked on code that needs to be reviewed by another part of the team who might have never seen the code before. Typically, performing a code review of another app involves reviewing the UML diagrams, user requirements, and functional specifications, and then diving into the code. But often the UML diagram is out of date, requirements change, and you don't have the traceability you need from your code. VSTS' ability to generate an entire class diagram that is accurate and up to date directly from the code aids you tremendously in understanding the code. You'll save many hours of headaches. On top of this, VSTS gives you the ability to reverse-engineer any class from any assembly, including framework classes.
Designing classes and their relationships is the first thing that architects or development leads do once they understand the overall requirements and have a conceptual view of the architecture. Many times during this process the views on how objects relate to each other, what objects should be created, and what properties and methods they should have change. The Class Designer succeeds as a simple tool to generate and change class and application structure quickly and easily. Creating classes is as simple as drag and drop, and relating classes is as simple as three clicks of a mouse button. The Class Designer will most likely become one of your primary class design tools because of its simplicity and power.
When you create an object model and examine it, you're likely to discover changes that need to be implemented. In some cases, you discover these changes after the code is implemented. Typically, this is a problem because you must rework the diagram and then rework the code that it is based on. Many diagramming tools don't give you the ability to refactor code from the model, but the Class Designer lets you review and change your application structure directly from the design surface. In C#, steps can range from creating interfaces based on already existing methods to encapsulating a private field as a public property without having to write any additional code (Microsoft provides a VB add-on that includes these features, but it doesn't ship with the product).
Projects often begin with the creation of a class diagram, but two weeks into the actual coding, the classes no longer look like the diagram. Even tools such as Rational Rose, which let you forward-engineer your diagrams and allow you to synchronize the diagram and code later, require you to start a sync process manually and fix any issues that come up. Microsoft's Class Designer features an instant update between a change in the class diagram and the code and vice versa. If you change the code, the diagram updates immediately to reflect the change. The advantage is that your code and diagrams are always synchronized. Developers and architects can really see what a class structure is, and maintenance is far easier because the documentation is always accurate. Additionally, almost all code generators and reverse-engineering tools put GUIDs and other identifiers in the code. Microsoft's implementation doesn't do that, so you get the added benefit of "clean" code.
Tour the Class Designer
We'll take you on a walkthrough of the Class Designer, and we'll show you how to build the class diagram of an EffortTracking Web service (see Figure 1). Note that the VB version won't have the ITaskService interface because it doesn't support interface refactoring.
Start by creating a blank solution called EffortTracking. You can create it as a file-based solution or as an HTTP-based solution (the example code is HTTP-based). Once you do this, add a new ASP.NET Web service by right-clicking on the EffortTracking solution. Select Add | New Website | ASP.NET Web Service. Select http (or File) for the location, and either C# or VB (whichever you're comfortable with) for the language. Enter the name as http://localhost/EffortTrackingService (or the file location if you selected File in the previous step). Click on OK.
You've created a new Web service with a single class called Service. Delete the HelloWorld example from the Service class. Next, right-click on the project, select Add New Item, select the Class Designer from the New Item dialog box, and click on OK. Alternatively, you can click on the View Class Diagram button from the top of the Solution Explorer pane, which also adds a class diagram to the project and generates the diagram based on the current code in the application. This makes it easy to see the entire project laid out at once.
Start the class diagram by dragging the Service.cs (or .vb) file from the Solution Explorer to the Class Designer surface; this creates the Service class. Before you go too far, it is worthwhile to take a look at the single class that you have on the designer and some of the options you have for manipulating it. Later we'll show you the details of adding methods and properties to a class. The class name (Service) is shown in bold at the top of the class, and you can edit it simply by clicking on the name in the class and changing it. Changing the name of the class once you have created it will not change the name of the file in which the class is contained. Microsoft is aware of this and hopefully will have it fixed in the next release.
Below the object name is the type of objectin this case, Service is a class (as opposed to a struct, enum, interface, or delegate). This is not editable. Below the object type is the base class from which the current class derivesin this case, the WebService class. If the base class type is Object, then no base class type will be displayed.
The chevron button in the upper-right corner expands or collapses the class. You can add existing classes to the diagram by dragging and dropping classes from the Class View window (or right-clicking on a class and selecting View Class Diagram) and from the Object Browser, in addition to adding them from the Solution Explorer window.
When building an object model, you frequently want to know what the properties of the base classes are or you want to know what classes derive from a given class. You can see this by right-clicking on the Service class and selecting Show Base Class. This results in the WebService class being added to the diagram.
Likewise, the Service class is re-added to the diagram if you remove the Service class from the diagram (right-click on the Service class and select Remove From Diagram) and then select Show Derived Classes from the WebService class. This makes customizing the class diagram extremely easy and flexible depending on the depth of information you want to display (see Table 1 for a complete description of all class properties available).
You should familiarize yourself with some windows before you get into the details of working with the Class Designer (see Figure 2). The Class Designer toolbox shows a list of all of the items that can be added to your applications. The Properties window shows specific property information for the object (or method) that is selected in the Class Designer window. The Class Details window (at the bottom of the IDE in Figure 2) displays details about the class and is where most of the work involved in adding methods, properties, fields, and events takes place. Finally, you can access other options on the design surface itself either by right-clicking on the designer surface or by accessing the Class Diagram menu.
Add Items to the Class Details Window
You need an understanding of the Class Details window and how to use it before you start adding items. Right-clicking on an object in the Class Designer gives you the option of selecting Class Details, which displays in a window at the bottom of the IDE (see Figure 3). All of the methods, properties, fields, and events of a class are listed in this window. The top icon on the left side gives you the option of entering any new item for the class. The four icons below are used for navigating to different sections of the Class Details window.
The type column provides IntelliSense functionality as you enter the member types. By placing a using statement at the top of the code module (or an Imports statement in VB), you can avoid having to type the complete namespace of the type you're trying to enter. The modifier column is a drop-down list of scope options. The summary column allows you to select an ellipsis, which brings up the Summary dialog. The differences in this dialog box depend on the attributes you've selected for the method.
Start the class diagramming process by creating the basic building blocks of the service that will be used by the service. First, add a simple enumeration that allows the consumer of the service to specify whether the password that is being passed in the ValidateUser method (which you will create shortly) is encrypted or in plain text. (Obviously, you would never send a password in clear text in a real application, but this provides a simple example for using enumerations in the Class Designer.)
Drag an Enum from the toolbox onto the design surface. This brings up the New Enum dialog. When adding a new item to the designer from the toolbox, this dialog will be displayed in one form or another. For this enumeration, set the name to PasswordType and click on OK. Along with the addition of the enumeration to the class diagram, a code file called PasswordType.cs (or PasswordType.vb, depending on the language) is added to the solution. Note that the Class Details window switches to have only four columns: Name, Value, Summary, and Hide. Enter information into the Class Details window. ClearText has a value of 0 and indicates the password is unencrypted. Encrypted has a value of 1 and indicates the password is encrypted.
Now that the information has been entered, you can look at the property window for both the enum and each class (the properties are different for almost every item you can click on in the Class Designer).
Add Structures
Next you need to add a Task structure to the class diagram. This structure holds a single task item that is used to pass a task to or from the Web service from another application (see Table 2). Add the structure by dragging a Struct (Structure in VB) from the toolbox to the designer and enter the name as "Task."
Each item in Table 2 is a field. Enter each item in the Class Details window for the Task structure under the Fields node. A structure is almost identical to a class, so all of the options available to you for a regular class are available to you for a structure.
You can start creating methods in the Service class now that you have the underlying enumeration and structure. The Service class is on the designer already, so you can start adding methods to it. The service supports seven methods (see Table 3).
Add a new method to the Service class that you created by selecting the service on the design surface. Add the ValidateUser method signature to the service (all methods are public) by clicking the <add method> entry under the Methods node in the Class Details, and enter ValidateUser. Enter "int" ("Integer" in VB) for the Type, and click on the ellipsis in the summary column. Enter "Validates that the user is in the system" for the Summary, and enter "0 if the user is not found, otherwise the ID of the user" for the Returns. Expand the ValidateUser node to expose the methods' parameters. Click on the <add parameter> entry under the ValidateUser method, and enter userName. The type defaults to "string." Enter "The users' name" for the summary, and click on the "<add parameter>" entry under the userName parameter and enter "password." Enter "The users' password." Finally, enter a last parameter called PassType with a type of PasswordType. Enter "Indicates if the users' password is in clear text or plain text" for the summary. Repeat these steps for each of the methods listed in Table 3.
Now that you've added all of the methods and descriptions, switch to the code view for the Service class by double-clicking on the Service class on the designer or by right-clicking the class and selecting View Code (see Listing 1 for the ValidateUser method). All of the information entered in the Class Details window shows up here in XML comments or in the method signature. All methods created in the Class Details window are created with the NotImplementedException thrown as the single line of code in the method (C# only). Any changes made to either the XML Comments or the method signature are updated automatically in the Class Designer. Likewise, if you delete a method from the class in code, it is removed from the designer.
It is critical that you understand that deleting a method in the Class Designer causes the method and all of the code in that method to be deletednothing is saved. It's a good idea to ensure that everything is under source code control before you start deleting items from the Class Designer if you have started writing code already. The good news is that you can undo a change to the class diagram.
You also have the option to reorder the parameters of a method. This is only available in C# (you must do it manually in VB). Right-click on the GetTasks method in the Service class (on the designer) and select Refactor | Reorder Parameters. You can use this dialog to shift the parameters and view the signature of the method while you're shifting them. This same dialog is also displayed if you choose to delete a parameter, except a large warning is displayed at the bottom of the dialog.
Refactor Your Code
Refactoring is a term used to describe the process of reorganizing code to make improvements in the architecture of an application. In some cases, it refers to going back and altering code to make it more efficient, but for the purpose of the Class Designer, the first definition applies. Refactoring is one of the options that are available only in C#. (A refactoring add-on from Developer Express is available for free from Microsoft for VB.NET here.) It is available from a variety of locations, not just the Class Designer.
To demonstrate how refactoring works, you will extract all of the methods in the Service class in order to create an interface (the interface is for demonstration purposes only and will not affect the application in any way). First, switch to the designer view, right-click on the Service class, and select Refactor | Extract Interface. Name the interface ITaskService and click on Select All to include all the methods as part of the interface; click on OK. Visual Studio will copy the methods to a new interface called ITaskService; add a new code file to the project with the same name as the interface; and implement the interface on the Service class. However, Visual Studio will not copy over the XML comments; enclose the ITaskService methods in the Service class in a region, or add the ITaskService interface to the Class Designer.
You can display the interface on the design surface by right-clicking on the ITaskService text hanging off the Service class and selecting "Show Interface." You can also double-click on the ITaskService text. You can then expand the interface to see all of the methods.
An interface supports all of the same things that a class does with the exception that interface methods can only be public; otherwise, why have an interface? As you saw when you refactored the ITaskService methods, an interface can be represented as a lollipop attached to the class that implements the interface. This allows you to drag the interface around the outside of the class, which implements it to any position you want. You can also display an interface on the design surface just as you would any other type of object. There are only a few options for working with interfaces that are implemented by a class.
You may expand or collapse the interfaces implemented by the class by right-clicking on the interface icon and selecting expand or collapse. The expanded mode shows you the names of all interfaces implemented by the class, and the collapsed mode only shows the interface lollipop.
You can delete an interface from a class by selecting the interface name, right-clicking, and selecting Delete. The class will no longer implement the interface, but the methods are not deletedthey are simply no longer accessible from the interface definition. To demonstrate how this works, delete the ITaskService interface from the Service classnothing else is deleted. Simply undo the deletion to re-implement an interface.
Right-clicking on the ITaskService name (the one hanging off of the Service class) gives you the option to either implement the ITaskService interface implicitly or explicitly. Selecting implicitly (the default) doesn't make any change to the methods of the implemented interface. Electing to implement the interface explicitly causes the fully qualified name of the method to be used.
Create Graphical Object Relationships
You can relate objects to each other in various graphical ways on the Class Designer. Typically, you do this to call out relationships between classes so that they are understood explicitly. Object inheritance is the "classic" relationship shown in diagrams, and this tool is no different. You can see the relationship between the WebService class and the Service class you created earlier. You can create an inheritance structure manually by clicking on the inheritance tool in the toolbox and selecting the class you want to subclass and then the superclass.
You have three options for dealing with inheritance relationships in the Class Designer depending on the types of classes involved. You can delete the relationship by deleting the connecting line, or you can hide the inheritance line to help improve the readability of a complicated diagram. Both operations are available by right-clicking the inheritance line. If you have a generic base class and a superclass of this class, the inheritance Properties window allows you to edit the type arguments, which are then displayed in the subclass.
For demonstration purposes, let's add a field to the Service class (you can delete it after you're done with this walkthrough). In the Service class, add a field with the name "_task" of type Task with a private modifier. Next, right-click the _task field in the Service class (on the designer) and select "Show as Association" (see Figure 4). This is an alternate way to represent the task field on the designerit doesn't alter your class in any way. You can convert it back to the standard type of design by right-clicking on the connection line and selecting "Show as Field."
You can also show an association with a property or field with the "Show as Collection Association" option. To see how this works, convert the _task field back to a field. In either the Class Details window or the code, change the _task field to an array of tasks:
private Task[] _tasks;
Switch to the Class Designer and right-click on the _task field again. This time, select the "Show as Collection Association" option. Note that the difference here is that the task field is shown as an array with a double arrow. This is yet another way of representing a relationship between two types.
Another tool available to you is the Association tool, which facilitates the creation of properties of a given type. To demonstrate this, select the Association tool from the toolbox. Click on the Service class and then the Task class. Behind the scenes, a read-write property called Task of type Task was created with no implementation in either the get or set. You can convert this relationship into a property of the Service class (on the diagram) by right-clicking on the association and selecting "Show as Property."
Unfortunately, version 1 of VSTS does not let you draw association lines from one type to another that do not have a semantic meaning. Microsoft has heard from developers and architects that this is a feature they want. Microsoft also realizes that the purpose of the designer is to visualize object relationships, so it's a good bet that you can look forward to this in version 2.
Refactor Fields and Properties
Properties and fields share almost identical functionality in the Class Designer. The real difference is that properties have a read-write property. One other difference is the refactoring options. Take a common example: You add a bunch of private fields for which you need to create properties. Microsoft has reduced this effort to zero by allowing you to refactor fields into properties.
To refactor a field into a property, select the _task field in the Service and right-click on it. Select Refactor | Encapsulate Field to display the Encapsulate Field dialog box (see Figure 5). Selecting Apply generates this code (see Figure 6):
//C# (only)
public Task TaskItem
{
get { return _task; }
set { _task = value; }
}
This is a tremendous time saver because you need to code only the fields that persist the data.
To complete the class diagram, you need to add one more class with a single propertythe "Common" class. This class has one static read-only property called ConnectionString that returns the connection string from the configuration file.
You can add a comment to the Class Designer by simply dragging and dropping it from the toolbox and entering a note. You can add comments anywhere in the designer, but unfortunately you cannot link a note to a particular object.
Look Under the Hood
Let's take a look at how the Class Designer works behind the scenes. Unfortunately, the Class Designer in version 1 of Visual Studio Team System is not designed to be extensible. First, close the Class Designer window, right-click on ClassDiagram1.cd, select Open With?, and select the XML Editor (see Figure 7).The header information on the Class Designer is the standard XML header.
Take a look at this statement: HashCode is a hash of all of the properties, methods, fields, and events of the type. You might wonder, how does the designer knows what is contained within the class if it is not held in the XML, and what the heck is the HashCode for? Both are excellent questions, although the answer to the first question is obvious after it's explained. All of the information displayed on the design surface is gathered from the class itselfit is not stored as metadata specifically for the Class Designer. This way, Microsoft ensures that the data displayed on the designer is identical to the information in the code.
The purpose for and the use of the hash code turn out to be a lot more complicated. The hash code is a hash of everything found in the type. It's used to match the object on the designer to the type in the code; in other words, it allows the Class Designer to know what object to go find and interrogate in order to populate the class details. Now you might ask, what if you change the name of the file that your type is stored in, you change the name of the type, and you change the method names, then add or a delete a few methods or properties? The Class Designer uses a fuzzy logic search algorithm to try to match up the type of the Class Designer with the type in your solution. If it doesn't succeed, the type shape still appears in the designer, but it is red. You must attach it manually to the correct type in the solution or delete it and re-add it. You re-add the type by dragging and dropping it from the Solution Explorer or Class View window.
You've seen how each of the features of the Class Designer supports the four goals of the VSTS group that were the guiding factors in the design of the Class Designer. The Class Designer gives you the opportunity to reverse-engineer and visualize existing code in order to better understand it. It allows you to refactor code through the designer without diving into the code itself. It allows you to begin building an application quickly and simply by creating the class structure, and the key feature of the Class Designer is that it ensures that your object model and documentation remain accurate and helpful from the first day of the application development to the release of application development and into the maintenance cycle.