In coding reality, we are often too optimized to complete the work on time.
One fact is, the cost is accumulated when we keep coding it. If we take a look at each step of coding, it probably like this:
Create the structure of the application
Create the module to handle different functionality
If the problem is complex, then the module will be complex as well, this time, the Level will be increased dramatically high, because to maintain it, will cost even more time.
Is there any way to reduce this cost?
The cost is all about understanding the use of the functionality and its logic.
Usually the function is an abstract description of the functionality, if we have a function like:
void buildXml(Dictionary<string, string> screening, Dictionary<int, Dictionary<string, string>>[] records);
We still don't know how to use it, then we will have to write some examples to use this function. The example shouldn't just put in the code where it has been used, it should independent from the codebase, in another module, for example, in test case:
Dictionary<string, string> screening = new Dictionary<string, string> () { {"Type", ""}, {"Product", ""} }; ... buildXml(screening, ...)
Clearly here we can see, how to use it, and it will reduce the cost to understand its usage. To put the HowTo code in Test isn't clear for code organization, a better way, to put them in an separate module named "Howto", could be better.
If the module is complex, then to understand the logic will cost a lot time.
To describe the logic, we can add comments at the top of each module/class/function, and it helped, but not much. Especially when the comments are at the top of each function, and its headache as they described each of the function not the problem and the solution.
More better way, is to describe the problem, and the solution inside the module, if the module design is clearly, then we can put it at the top of the beginning of the module file, like:
/** * @problem ...... * @solution ...... * @revision ...... */
Even more, when we have more than one module, then to write the Developer Guide and describe the system design and relationship of those modules, and their functionality will be necessary, unfortunately those big codebase I have taken to maintain so far, they all don't have any document, some of them, just have function or class description, and its less useful.
To describe the inner logics of the module, I think TDD/BDD do show that possibility, but they are not designed to do so. Lets take a look in this example:
The problem: we will build the Xml, and its data coming from RDBMS database tables.
When we start to build the module, we first will look into the Xml structure, and know how to build data in it. We probably can have a very quick idea to write functions like that:
buildXml(....); buildScreening(...); buildResponseData(....); buildRecords(...); buildRecordBefore(); buildResults(); buildCollectionSiteInfo(); buildLabInfo(); buildRequestData();
But if we go any further along this idea, start writing code by that, we probably lost the sense to reduce the cost of the maintenance. I am thinking we should slow down and see the thinking process of how to build the Xml and Why.
When we have the Xml, to build the structure of it with data, is easy, if it didn't have duplicated name, and repeated nodes, the quickest way is to replace the {Token} in the template:
<Type>{Type}</Type>
If it do have duplicated name, for example:
<Type>{Type}</Type> <Item> <Type>{Item.Type}</Type> <Item>
Then we only need to change the Token name.
But if it had repeated items:
<Type>{Type}</Type> <Items> <Item> <Type>{Item.Type}</Type> </Item> <Item> <Type>{Item.Type}</Type> </Item> </Items>
Then we will have to use loop to insert data to it. One way to do so, we can have a part of the repeat body as a small template, and insert data to it then loop until its complete.
<Item> <Type>...</Type> <Item> for (int i = 0; i < 3; ++i) { buildItemXml(); }
In reality, the Xml will not be that simple, so it could have a lot different repetitive parts, or duplicate names, thus we will have to use many more different functions to make it. To remember that, when this happened, the complexity level arise, and the cost arise as well. Be sure, we have clearly description on it to reduce the cost of maintenance, the better way is to have a separate module to save those templates along with the descriptive comments.
We can call it "Model", and it don't have any code in it. It much more easier to understand it in a separate module than inside another module and code.
To continue, when we have the template, and next we will try to insert data into it, to describe the data structure of the data, is depended on what the template look like. If the template had pattern for each item, then we can use Dictionary<string, string>
.
For simple Xml at this case, it already good enough.
So we can define the function parameter as Dictionary<string, string>
. Sometimes, we might need extend this data structure because of the repetitive parts in the template, Dictionary<string, string>[]
, or Dictionary<string, Dictionary<string, string>>[]
, that depended on the level of Xml too.
Dictionary<string, string> item = new Dictionary<string, string> () { {"Type", ""} }; buildItemXml(Dictionary<string, string> item);
Till now, we already had function and its parameters, the definition and code is capable for test. Even though TDD or BDD required we code it strictly by Test-Driven strategy, that usually means to write the Test Case first, but for the practical use, I think we should write the module first, and then use Test Case to test and refractor the module. Be clear, this doesn't obey the principle of software quality measurement, as if we keep the module functionality small and compact.
This time, we will start to think of the module in TDD/BDD thoughts, and test it, refractor it, also write "How to" code by the test examples.
When we defined the module, we don't really consider where the data coming from, the reason, is to reduce the cost of thinking, to think one step then another is easy for think them all at once. But we can't make sure this is the best solution.
When the data is coming from RDBMS, and across different tables, the straightforward thinking is to map the data to the function parameter definition by SQL, from "SQL" to "Dictionary" or else. Sometimes, one data could map to many SQL, but we won't consider that at this case.
The way to keep the code better maintenance, so to reduce the cost, we should know that, data table could change, and the Xml could change too, so to embedded each SQL in code is obviously not good idea, when changes coming, to change the code, will cost more than to change data model.
So a better way, we can keep the mapping all in the data model level, for example:
Dictionary<string, string> item = new Dictionary<string, string () { {"Type", "SQL: SELECT type FROM tableA WHERE id=:id"} }
When we are going to fetch the data, we only have to analyze the SQL, get the data, and then add it to the parameter instance. Because the Map is based on parameter data structure, so to do this, is easy.
Now when changes happened in data table, we probably only need to change the SQL, and if the Xml structure changed, we only need to change the data model, and a few less changes in code probably.