Software Engineering, Agile, Code Reuse, & Refactoring
An ounce of prevention is worth a pound of cure...
Fundamentally, people want to their best quality work that produces useful outputs to society, the fundamental canon's for Engineers allows for no less
But in real life, we all face a common problem - do we sacrifice on our best quality work, and cut corners to save time and cost on the project? - Are you okay with a bridge that needs replaced every 2-3 years instead of what that lasts 40 years? - How about a dish washer that has a 1-5 chance of catching fire?
For some reason, I have observed, in the software industry, 'cutting corners' seems to be more acceptable, and the philosophy seems to be "push the code out to production as fast as possible - and we will worry about fixing the bugs later" - just get some 'minimal' thing that "works".
Let's look at an specific example - Suppose you have been asked to develop a piece of software that tracks the assets in your office. Specifically, you need to identify how many desks, chairs, laptops, phones, etc that are assigned to a particular department in a particular office. The main functions that the user will be preforming will be adding new assets (with a purchase cost), assigning an identifier to the asset (tag), and updating the location of the asset as it could be re-assigned from one office to another.
Some agile user stories might look like this
- As the office manager, I need to assign new assets, purchase date, and costs to each item, so that I can track when an item needs to be re-purchased for evergreening
- As the sales associate, I need to tag existing assets so that they do not get confused with actual inventory that we are selling to the public
- As the HR personnel, I need to identify which assets belong to which employees, so that prior to leaving can assure all company assets are returned promptly.
Implicitly, the application when designed will require some type of interface, a minimal viable product (MVP) would not necessarily focus a lot of time on the particular look/feel of the interface. Indeed spending months working out the GUI would be months that users cannot yet use the system for its intended function
Even in a non-agile world, larger estimates of GUI design over implementing the actual functionality, should raise red flags, as should multiple rounds of design meetings arguing about where function "X" should be in the GUI before a single line of code is even written. A prototype of a working example early in the design stage can help expand on the design aspects and features needed just as well as an entire 'production - ready' iteration.
So we design our first simple menu:
class MenuItem
{
private:
char ItemName[255];
char OptionLetter;
public:
MenuItem(char _Letter, const char *_Name );
char *GetName();
char GetLetter();
};
And we define some helper functions to display the menu
buildmenu(MenuItem **Items, int *Count)
{
Items[0] = new MenuItem('A',"Add Item");
Items[1] = new MenuItem('E',"Edit Item");
Items[2] = new MenuItem('D',"Delete Item");
*Count = 3;
return 1;
}
void displaymenu()
{
fprintf(stdout,"\n\n *** MAIN MENU ***\n=====================\n\n");
MenuItem *Menu[3];
buildmenu(Menu,&Count);
for (int i=0;i<Count;i++)
{
fprintf(stdout,"%c) %s\n",Menu[i]->GetLetter(),Menu[i]->GetName());
}
}
This is a very simple text-based interface. It lets us focus on the code specific to the functionality of what the user needs - and not get lost in the details of the GUI. As the user adds more stories we can expand the menu as needed.
Regardless of whether Agile or not, it is not uncommon to stand up some type of "faux" menu like the one above at a minimum for programmers and testers to play around with the core functionality. Typically, in a non-agile world, the end user likely would never see this actual menu, while it is "just enough" to get the functionality to work, the end users often don't need to know the nitty gritty details of the development at such an early stage. Because we want to produce our best 'high quality' work, we might even be embarrassed to show such a simple text based menu to the end user without at least a little bit of polishing.
In some circles, this is called a 'driver program', while we know the menu is not the final solution, it drives us to be able to focus first on the core functionality and worry about the menu later. In construction this is a bit like the 'initial gravel road' that gets built for the big trucks to come in and setup equipment etc. It's not the final road that the building will have, just something so that they can get started on the 'real work'.
But there are still several problems with this design:
a) The menu itself is somewhat extendable, but limited, for example as written, if we add menu items, we need to update / add new sections of if/else or case statement to handle the new options
ie:
switch (toupper(choice))
{
case 'A': doadd();break;
case 'E': doedit();break;
case 'D': dodelete();break;
case 'Q': quit=1;break;
default: fprintf(stdout,"Invalid choice\n"); break;
}
}
b) The menu code is tightly coupled to our application itself, once written it cannot easily be re-used in other applications we might make for other clients. It would be much more cost effective to have a re-usable menu item 'component' so that we could create these 'driver menu's' quick and fast without having to re-code from scratch for each new project
So again with both Agile, and Non-Agile worlds, their will come a time to re-factor the code, to make things look 'prettier', and to ensure the appropriate robustness needed for the end product.
The difference is in the 'when'
Typically with agile, each iteration rolls out an update that is production ready. So the first 'stub' menu might actually be in the actual product, and improves upon successive iterations.
With non-agile, this 'stub' menu may only be seen by programmers and/or testers themselves, the final product would not be released until a proper menu is put in place. Note the updates are still occurring iteratively, just not every iteration is a production ready product.
Both Agile, and Non-Agile suffer from the same 'pressure' problem. If stress is applied to the project to 'wrap things up', if corners are cut, the 'stub' menu might never get the appropriate updates it deserves. The end user might get a piece of software that is unnecessarily difficult to maintain and update that was completely avoidable with some upfront design and planning.
This should not detract us from the fact that corners should never have been cut in the first place!
People want to their best quality work that produces useful outputs to society, and fundamentally, when we 'give in' and produce less to meet a deadline, we sacrifice the goose and given up the golden eggs.
In a non-Agile environment, the customer may shrug and complain about the ugliness of the final product, which as developers we can say "it's not our fault, you cut the deadline short", and later the customer is further outraged by the ongoing maintained costs (again we should the same 'short deadline' argument)
I suggest that the transparency of Agile delivers a promise - that even if deadlines get tight, the customer will still get some 'end product' that works. They 'see' the work that went into it, they were closely involved along the way and maybe more receptive to that same 'ugliness' then in the non-Agile world, However - the ongoing DevOps cost is still the same, is hidden from the customer by continuing to preform additional iterations in an operations (non project) world.
But in the worst case (both Agile and Non-Agile) no one ever goes back to to the code, no one ever "has the time" to improve upon it, and it just sites like that for years. Improvement never happens, the code never gets re-used to it's potential and maintenance is a horrific nightmare.
So when your thinking of tightening a deadline for whatever business reason, ask yourself first if the short term gain, is really worth the long time pain - or if an ounce of prevention really is worth a pound of cure.
The original source code for this article can be found here: https://github.com/geekwisdom/menu/tree/main/bak
The updated menu item (that no one ever has the time to write) can be found here:
https://github.com/geekwisdom/menu
Comments
Post a Comment