My Design Process – Component Design
In my last post, I outlined my current process for developing a software application. I don’t believe that this is the best strategy for all circumstances, but it is the best that I have found for me personally in the software environment that I work.
I am designing software for a large retail organization for consumption by field personnel. This introduces interesting challenges that, in my opinion, make many modern software practices impractical. The fact that every change needs to be coordinated with training and documentation updates makes it advantages to throttle the release cycle into a few, fairly large deployments throughout the year.
Currently, my design process flows through the following stages
This stage involves the specification of the high-level components that make up the proposed software system and describes, very generally, how they will interact.
In the requirements gathering stage, all available documentation from the business owners are gathered and recorded. This often includes conversations with program management to ensure that each requirement is understood.
The requirements are then distilled down into individual use-cases that the software system will implement in order to meet the requirements. Also, the components that are likely involved in the use-case are identified.
Activity Diagrams and Wireframing
This stage involves the creation of activity diagrams (aka flow charts) to show how the user and system components will actually interact to implement each use-case. Also, since the interaction of the user and the system are starting the be specified, the structure of the user-interface (aka wireframes) are created at this time as well.
The final, and most time intensive stage, is the creation of sequence diagrams. These diagrams contain the detailed information about how the system operates to implement the process illustrated by the activity diagrams.
In this post, I’d like to dive a bit deeper into the stage where I create the component design. As I mentioned above, this is the part of the design process where I start to identify the high-level components in the system and how they interact. To illustrate this process, let’s design a hypothetical software system. In the spirit of “go big or go home”, let’s go ahead and design Facebook. How hard could it be?
Okay, we aren’t going to design all of Facebook, but let’s take a piece of it. For our study, let’s consider only the parts of Facebook that allow users to do the following things:
– create an account
– log on and log off of the application
– create a friend request
– accept or reject a friend request
– post an update to their friends
– see the posts from their friends
So, we have a general idea of what we want to do. So how do we start to create the application?
Let’s start with the basic components that are going to be needed.
1) The user is going to have to have someway to enter information into the application and get information back out, so we need some sort of user interface.
2) The application needs to be able to store information about user accounts, their friends lists, and the posts that they make.
3) We also need to be able to show one person’s posts to their friends.
There are three basic types of application that we can build: client only, server only, or client-server. If we choose a client only application, then we can meet the first two requirements, but sharing would be difficult since we would need to find a way for the client applications to communicate with each other. On the other hand, a server only solution would allow us to meet the second requirement, but not the first or last since we wouldn’t have a user-interface. Therefore, we need some sort of client-server application.
Just like there are several types of applications, there are several sub-types of client-server. I’m going to cut to the chase here. Web-applications are the dominant strategy for solving this problem today, so we’ll go that direction. This does leave open the question about the “client” since that can be a web-browser, mobile device, or client-installed application on a desktop. Since web-browsers allow us to hit the widest number of potential users, let’s go with that.
So far then, we have the following components:
Notice the line between the web browser and the web server. This means that they are allowed to know about each other and talk to each other. We’ll see how that this bi-directional communication will be pretty rare, and why that is a good idea.
So far, so good, but we don’t have a way to actually store the data the user accounts, posts, etc. While we could do that in the memory of the web server, that isn’t really a good idea since we could never update or maintain our application. Naturally, the best way to store this data is in some kind of persistent store. Since we don’t have to make a decision on the format, let’s just add a general description like this:
We have added a “Data Store” that the web server can talk to, but it can’t talk back. While many database technologies would, in fact, allow bi-directional communication, this approach tends to cause functionality to mix over time. If the Data Store can’t initiate communication with the web-server, then it is easier to isolate from the rest of the system. Generally, this lowers the learning curve of the application.
We have the high-level components that we need, but there is more that we can do in this stage of design. Specifically, how are the sub-applications in the web browser and web server going to work?
A good default solution presents itself for the web server, so let’s start there. By far the most popular way to structure a web server application today is by following the model-view-controller (MVC) design pattern. This pattern is supported my many application frameworks due to its flexibility and tendency to drive the application to be well-structured. The components of the MVC design pattern are:
– The controller, which is responsible for receiving a request from the client (e.g. the web browser) and interacting with the model to process that request
– The model is the part (or layer) that is responsible for actually processing the requesting and performing any work that is required. This includes returning any data that is required to honor a request for information that the client has made.
– The view takes the result from the model and converts into a format that the client can use (e.g. an HTML page for a web-browser to show to the user).
We could take time and create a custom design that might be better or our application, but one of the core tenants of design is use standards whenever possible. This design pattern is adequate and well known by web-application developers. This makes it attractive since the ability to understand and maintain the application will be enhanced by its adoption.
Incorporating this decision, we now have this design:
Several things have changed by adding the detail into the web server component. We now have a clear parent-child linkage for all of the components, except for the web browser (which still sends and receives from the web server). Within the web server, the view and model are nice and isolated since they only have one input and one output. The controller is a bit heavier since it is responsible for interacting with two other layers (the view and the model). This level of awareness is going to make it tempting to do a lot of work here, since it knows about the rest of the system. We are going to have to keep this in mind as we move forward. The best way that I’ve found to counter this high level of awareness is to push to do as little work as possible in the controllers. They have enough to do in just coordinating between the web browser, model, and views. Let’s not through more responsibilities there by adding presentation logic (the job of the view) or business logic (the responsibility of the model). We’ll see how this interaction plays out as the design progresses.
As a final step, we need to think about the web browser. It currently has awareness of the server and the server is aware of it. In the past, this was managed by ensuring that the browser had a very simple job. It was presented with HTML from the server and then it posted data back to the server in the form of a new location to browse to and, optionally, some data that the user provided (e.g. username and password when logging in). Our application is currently setup for this kind of design. An alternative is to create what is called a “rich client” in which there is an application running there as well. If we do that, we can get a design like this one:
In short, we have added another MVC application into the design. The model of the web browser plugs in to the server. This doesn’t eliminate the fact that we have one component responsible for bi-directional communication. In general, it actually increases the complexity of the application. The advantage of this design is that, since we have an application running on the browser, we can shift some responsibility from the server to the client, simplifying it. It also gives us the ability to improve the user experience by allowing us to reduce the number of times that we have to completely reload the page. However, we don’t have a requirement for that now, and it might make it more difficult to understand how the rest of the design process flows. As a result, let’s stick with the previous version where we have a rich-server and a thin-client.
Stay tuned for the next post where I’ll walk through how I capture requirements and what I get from that step.