Read this first, please
This is the fifth in a series of articles that hopefully will be educational to novices and helpful to more advanced developers alike. I hope to learn a lot from doing this also. I am taking the approach of maintaining a journal of the day-to-day process of software development starting from a concept and going to a product. I hope you enjoy this series of articles.
A word from the author
Unfortunately, I have returned to my day job which means that the days of this project are going to be spaced out a little. I am not really sure how many articles a week I can post, so please be patient, they are in the works.
What I skipped
Before proceeding, let me just say that I intentionally shortened the prototyping stage to a single day for sake of simplicity and time. When presenting prototypes to users, you will likely find that they have suggestions and changes which you need to incorporate. It may be necessary to go back and forth with the users several times before you are fully satisfied with the results. I have chosen to not include that much detail on prototyping in this article series because I don't believe it would add much to the series and would just bog us down.
Where are we?
Up to this point, we have focused on getting a firm grip on the requirements, scope and user expectations for this project. We have shown our users some early visual prototypes (on paper) and received good feedback. Our model and concept appear to be working out. Now, we must task ourselves with creating a real architectural design for this application. But before we can put together an architectural design, we need a decent technical requirements list. This list should break out important technical details by system component while not going so far as to specify implementation details (though implementation hints may be included). With a good technical requirements list, we are better able to construct an architecture that makes sense encompasses all the requirements.
What's the point?
I am sick and tired of all the stupid and petty religious wars that exist in the software and IT industry. Java vs .C++, J2EE vs .NET, VB vs (well, OK VB sucks), and the list just goes on and on. I try to not get involved in these little wars because I really don't see how they benefit anyone, especially myself. I think it is important to strive to see both sides of the debate in a fair and balanced way. Until someone invents a system that can read the users mind (or at least accurately interpret his/her intentions based on verbal commands), there will always be room for improvement in every area of software development. I don't know a single user who cares what language their application is written in or how it was developed. Users want stuff that works and really does something they need it to do. VB, C++, Java, who cares!
One of the other debates that I am equally sick of is the debate over whether or not to do an architectural and/or detailed design document before coding commences for a project. If there's one thing I see that sets one developer apart from his/her peers, its how they use their brains. Software development is not about hard and fast rules and at least for now its not about the intelligence of the machine. Software development is about the intelligence of the person making it all work. There is a great deal of creativity and innovation in software development, which is a very good thing. That creativity and innovation does not arise from following a hard-and-fast set of rules, but arises from an underlying intelligence that won't give up until the job is done right.
That intelligence must be put to work and used wisely. Harness your talent by having a broad range of abilities that includes all the pre-coding skills as well as solid coding, debugging and testing skills. When you find the time, add some business insight to the mix and you will surely be not just a competent developer, but a damn good one. Don't ignore something because you find it boring, instead jump headlong into the boring stuff so that you can master it and instead of being bored, benefit from it. Even if it still bores you, at least you will have the added knowledge and experience to help guide you down the road. Don't stop learning until you die!
OK, now that I've got you hyped up, I'm going to shoot you down. Don't ignore those rules and guidelines. There are a whole slew of lessons that are better learned by reading than by living. Many of those seemingly stupid rules were written by people who have been burned by common mistakes you will no doubt make (eventually). This whole process of requirements gathering to detailed design was not invented by brain-dead bean counters, but by sane and experienced IT people. Like I said before, going to extremes and becoming zealous is a trait often found in the creative and intelligent, which leads to much of the debate.
My advice is to use that mass of gray-matter you were born with to make intelligent and well-formed decisions. Don't fool yourself about your skill level, be real. Don't underestimate yourself either. Just be reasonable. If you are a novice or are struggling, take a more methodical approach and slow down the process to include as much of the pre-coding process as you can. Once you have put some experience under your belt, you will be able to make better decisions regarding what steps to take and which ones to skip over.
PRIORITY ACCORDING TO WHO?!!! OK, I've got to get this off my chest. There is one person at my office that apparently has high priority set as the default for every @!#$ email they send. Almost every email I get from this person is marked as high priority. Every time I see an email from them, I want to send an electrical shock through the email system directly to them. OK, I know that sounds a little extreme, but this has been one of those days that makes me want to scream. I actually spent 15 minutes today looking for a feature in MS Outlook to auto-respond to high priority emails from them with a very special pay-load. (In case you're wondering, I didn't find it, but I'm thinking of writing an add-in. Call it the anti-email system.)
What does this have to do with our issue tracking system you may ask? Well, it occurred to me that one of the user requirements I listed on day one was the need for a priority field. Every issue tracking system I have looked at includes one of these totally useless fields. Useless you may say? Isn't that a little strong? Well, maybe but I think there has to be a better way to do this. The problem with priority is that it is a constantly changing and highly subjective concept. Depending on what someone puts on my desk on any given day, my priorities change accordingly. In a multi-user system, who defines what a high priority is?
For those of you who use an issue tracking system, take a look and see how many of the issues are marked as high-priority, for the rest of you (your day is coming), take a look at your inbox. If there are more than a few, there's already a problem. How many things can you work on at a time? I can only do one thing at a time, which makes having a list of 50 high-priority issues kind of silly, especially when day-to-day things take precedence (apparently a higher priority than high?!). Even worse is finding an open, high priority issue that is several weeks/months old. Give me a break! What good is a value whose value is so meaningless?!
Anyway...We need to come up with a way to remove the subjectivity or at least limit it. Here are a few of my ideas:
- Eliminate the field all-together. In reality, we can't do this because our users will be able to just add it back in.
- Instead of high, medium, low, use a scale like 1 - 100. I like this idea better than high, medium and low, but it is just as subjective before.
- Allow each user to assign his/her own priority to an issue, maintain the other users settings as well. Too much work, and even more meaningless.
- Use a scale like 1 - 100 that automatically degrades over time, but records the starting value for reference. I like this idea, but I don't see how it really represents the real world.
- Allow for "temporal" priorities that must be set daily/weekly/something, and go away once expired. This could work, but only when the issue list is relatively short.
- Substitute categories for priority (ie. crashes, critical feature fails, important user has this problem, etc.) In fact, I included a couple of these in my prototypes. Then, have priority be a read-only field that is dynamically computed based on this and other criteria. This has the benefit of allowing the user to specify some form of context (maybe by opening a certain project in DevStudio) that then can add or subtract weight from the priority field to provide better sorting.
Anyone with ideas, please submit them below. (Oh, and if you have an email feature as hinted at above, post an article, I may just download it.)
We need to translate all of our user requirements, analysis, UWEs and ultimately our entire vision into terms only computer programmers can understand. As I see it, these are the technical requirements for this project.
The system as a whole
- Automatic login support based on windows login
- TCP/IP based communications between client and server components (could be SOAP, SMTP, POP3, etc)
- Unified logging mechanism between components
- Centralized management of user session state data
- RDBMS for back-end data storage
- Support for fully run-time customized issue structures (Note: there will be a set of always present fields, but this will be a minimal set.)
- Dynamic data-entry forms
- Dynamic list and reporting capabilities
- Persist, present and manage run-time customized issue structures
- System-wide plug-in architecture for extendibility
- Group-based navigation with support for overlapping-groups and sub-sets of groups (automatic assignment to group sub-sets)
- Support for file attachments for every issue type
- Distributed components for client and server
- Clients do not directly connect to RDBMS (except potentially for reporting, though preferably not)
- Notification of issue events (ie. adding event, fixing a bug, etc) through email
- Default user authentication mode should be automatic (ie. if someone logs in to SPS and Windows user account not found in DB, a new account is automatically added)
Server side components
- MS SQL Sever 7 or 2000, specifically MSDE
- Standard email server with SMTP and POP3 support
- Allow other services to subscribe to notifications
- Provide a notification (via TCPIP) to subscribers when messages arrive
- Provide an interface for adding user accounts
- Should be able to use any email server product, but custom one may provide special, unique capabilities (ie. event subscriptions) that enhance the system
- Must not have arbitrary limits on number of email accounts it can handle
State and Persistence Server (SPS)
- Manage user accounts (add users, edit user settings, disable user, delete user)
- Manage user logins (Automatic login via windows user account with automatic user creation the default)
- Manage user session data (Open issues, locks, etc.)
- Manage user preferences (event notification options)
- Provide support for group-bases sets, filtered sets
- Persist dynamic form designs
- Provide facilities for creating new issue types, modifying existing types
- Persists issues to and from database
- Automatic DB schema generation upon issue re-design
- Persist journaling records to/from database
- Provide issue validation support
- Process issue changes into activities
- Provide hybrid pessimistic locking. (ie. First user who asks for record locks it, but others can get read only copies)
- Abstract all database requests so that user requests are mapped to a common API which is extensible to various DB APIs
- Provide a TCPIP interface communications (possibly/probably SOAP)
- Subscribe to notification events from both SPS and email server
- Send emails as configured when events occur
- Translate email messages sent to email server directly to issues
- Notify appropriate clients of events (new issue sent through email)
Client side components
Data entry application (DEA)
- Rich GUI application (ie. Windows GUI)
- All forms can have 1 or more tabs (tab is hidden when only one is present)
- Support for one-step addition of new fields
- Provide dynamic form rendering for data entry
- Light-weight in terms of memory consumption and footprint
- Support for free-form data entry where possible (ie. dates, times, etc)
- SDI (FDI) type interface similar to MS Outlook (and most other email clients)
- Target launch time: 1 second for new record, 3 seconds to modify a record
- Target save time: 3 seconds
Dynamic form designer application (DFDA)
- Rich GUI application
- 2-tier form designer (ie. 1) simple and automatic form layout, 2) total control over forms)
- Support for all standard data entry controls
- Special controls provided for listing/browsing journal entries, issue list browsing, etc
- Issue designer
- Form designs will be persisted through SPS
- SDI (FDI) type interface
- Target launch time: 5 seconds
- Target save time: 10 seconds
List and report application (LRA)
- Rich GUI application
- Custom list column selection and dynamic-auto selection
- Custom report designs and dynamic-auto design
- Sophisticated filtering criteria and filter designer
- SDI (FDI) type interface
- Target launch time: 3 seconds
Task-bar and notification application (TBNA)
- Popup-menus for quick access to desired features (ie. data entry, lists, form design)
- Customization support for customizing menu layouts and options
- Notification target for automatic launch of data entry applications (ie. when email is used to create a new issue)
- Target launch time: NA
- Target popup menu response time: < 1 second
Monolithic management GUI (MMG)
- Conventional Rich GUI like many other issue/defect tracking systems
- Target launch time: < 6 seconds
Journaling service application (JSA)
- Run as a windows service
- Monitor file change activity
- Difference detection and extraction
- Record journal entries through SPS
- Have a plug-in interface for adding additional journaling methods
- Possibly use API hooking (like SysInternals) to detect FileOpen, FileCreate, FileSave and FileClose events and use these events to make change detection and tracking work.
Visual Studio Add-Ins
- Toolbar icons to launch data entry, list puller and main GUI applications
- Docking window for viewing/navigating issues. This should provide easy functions (ala RClick) to fix a bug, add an idea, add details, link issues, etc.
- Docking window for viewing and navigating journal entries. This should make it easy to see what changes you have made over N days/hours/whatever and easily use that list to jump to those changes, add comments, etc.
Windows Explorer Namespace Extension
- Provide a special folder which allows user to easily navigate groups and issues
- User should be able to create new groups/sub-sets here
- User should be able to attach files here
- User should be able to delete and manipulate issues from here
In addition to basic technical requirements, I have included several time-based metrics on the client-side GUI applications. Many specifications I have come across omit metrics of any kind. I feel that this is a mistake. If you're going to take the time to list features and requirements, list metrics too. Metrics perform several valuable functions in the design of an application. First, they set milestones that users can understand and relate to. Second, they give developers a target to work towards. Third, they can affect the design choices, architecture and selection of platforms and toolkits used to implement the project. Fourth, they force developers to measure up or at the very least explain why they could not. So I think metrics are a good thing when used correctly.
The key to using metrics is to set them appropriately and realistically and define how they are measured. Just saying launch time should be less than 5 seconds is not enough. Would that be 5 seconds on a Pentium 100 with 16mb ram, or a P4 3.3Ghz with 768mb ram? Would that be while running DevStudio, Notepad, the Journaling service, and MS Outlook or while the system is completely idle?
Some projects will include metrics for such things as keystroke response times, mouse click response times, dialog appearance and dialog destruction times, DB connection times, DB execution times, how much memory should be consumed on startup, with one record open, etc. As with all things, use your experience to decide how exhaustive your metrics are. I like to focus on the time based metrics (at least for client-side GUI type applications) because I find that they are the most relevant to users and typically have a significant impact on memory consumption as well.
Throughout the development cycle, actual performance should be compared to target metrics to determine if the requirements are being met. Metrics should be treated as "first class" requirements, not secondary concerns. Failure to meet a metric requirement should be treated the same as failing to meet a user or technical requirement. There may not be a way to get around it, but that failure should be closely examined, not as a witch hunt, but so that future problems with setting metrics inappropriately or improper design can be resolved before they become problems.
One problem with setting target metrics is knowing what to set them to. This is a tricky problem because of the chicken-and-egg dilemma. Do you write the metrics before you write the code, or after? How can you predict how fast something will be until it is designed and tested? There are several ways to limit the trickiness of metrics. I can think of several ways to create meaningful and reasonable metrics. Below is a list of the methods I can think of.
- Examine similar applications to the one you are building and determine if the time/memory/whatever for that application is acceptable or not. If is is acceptable, you have an upper limit for your metrics. If it is not acceptable, you know how high not to go.
- Perform a feasibility test using your prototypes. This can be problematic, though, because prototypes typically lack any real functionality to consume time or memory.
- Perform usability testing with your users using prototypes (or real applications) and timing how long users take to perform actions depending on how long it takes for the application to be ready to accept the users input. A way to to this is to use your prototypes and add time delays and memory grabbing to simulate how an application might perform. Then allow users to interact with it like it was the final application. Time not how long the application takes, but how long the user takes to complete a particular task. Optimize your target metrics for that task completion time giving yourself as much room as possible while still achieving similar time-to-complete task times.
- Instead of measuring metrics as in time-to-launch or time-to-save, use user-centric metrics. Similar to above suggestion, but base your entire metrics on user-time, not computer time.
- Make them up. I suspect this is the typical way of doing it and is indeed what I have done up-above. (Note: I believe my metrics are reasonable based on past experience, so I didn't just pull them out of my arse, there is some reasonableness to them.)
For purposes of this project, the target system is a P4 1.8Ghz with 384mb ram while running Visual Studio 6 (or 7) with one project open, MS Outlook open, Notepad open, the Journaling service running and Internet Explorer open.
Desired but optional features
It is quite normal to reach this stage and have a list of ideas and concepts that you think would be cool or nice. Keep in mind that adding features unnecessarily extends the scope of the application, can extend the schedule and many times adds nothing that the end-users care about. Recording those ideas, though, is quite beneficial because I find that when I don't write down my ideas, they often fall off the end of my brain and are lost forever. Another good reason to document these ideas is so that while the software is being designed and coded, you can make decisions which may make implementing these features easier in the future. Besides, if we are successful, there will be a version 2 and these ideas give us a place to start.
Here are some of the ideas I have (and others have suggested) for this project that are not included in the technical specification, but are good ideas that may show up in the next version.
- Support for embedding images, charts, OLE documents as needed within appropriate parts of system
- Support for browsing issues through email client
- Support for on-demand generation of stored procedures instead of using dynamic SQL or manually coding stored procedures
- Import issues from 3rd party defect/issue tracking software
- System-wide console of activity
- Publish group issue/activity history to HTML
- Publish journal histories to HTML
- Extend journaling to include change detection of directory structured, database schemas and registry entries
- Support for RDBMS's other than SQL Server
- ASP.NET web interface
- Download issues to wireless device such as Smart Watch. (OK, I admit I have no use for this feature, but I would like one of those cool watches.)
- Feature to prevent the addition of a priority field, no matter if the user actually wants one (OK, I won't do this, but I should).
I guess I got off track a little today talking about religious wars and the damn priority field, sorry about that. We need to gather up the trail of crumbs we are leaving behind us and put them together in a nice, neat document so that we can easily maintain this information and refer to it as needed. Tomorrow, we will look at ways to organize project data and based on our technical requirements list, begin to build an architectural document.