Every API that we write, is a system within itself. As any system would, it goes through a series of phases; from concept to disposal irrespective of its functionality and complexity. Applying these concepts not only yields a well defined and better designed API but also minimizes the support and maintenance.
It helps to recognize the capabilities and short comings. These are crucial in knowing when and how the API can be utilized to its best. It helps in identifying the test cases and validate with optimal testing. A disposal plan makes sure there is no over designing, and mandates a timely review. This becomes a starting point for the next evolution with different requirements leading to a better design.
Let us review the SDLC concepts and apply them to our API development. A simplistic view of SDLC is shown in the figure below.
Applying SDLC concepts to a simple API development:
An API that will take a number and multiply it by power of 2.
For example: 5 multiply by 4 (2^2), 7 multiply by 16(2^4), etc…
Step 1: Analyze the requirements
Looks like an easy task.
Inputs: A multiplicand and a multiplier.
Output: Product of multiplicand and multiplier.
Question: Will the multiplier be provided or the power of 2 provided? In second example above, 4 is provided or 16? Let's say 4 is provided.
Step 2: Design
Block diagram may not be necessary for such a simple task but lets make one.
Question: Will the numbers be signed or unsigned integers? This should have been done at requirements analysis. Let's say they are signed integers.
Step 3: Implementation
To optimize the code, you think of using bit shift instead of multiplication. The pseudo code is shown below
int32 multiplyByPowerOfTwo ( int32 multiplicand, int32 multiplier )
int32 result = 0;
result = multiplicand << multiplier;
Question: What if the multiplier is negative? "Left shift with a negative number is undefined in C". For cases like this, validating inputs becomes important. This needs to be noted as a shortcoming of the API, clearly documented and explained to the user. If the requirement can be changed to accept multiplier as unsigned integer, then new requirements need to be documented.
Step 4: Testing
Here we verify and validate our API. Write a test case that loops the multiplicand and multiplier for all the possible values and logs the result. Compare these logs with the expected result in each case.
Question: Do you see results as expected when the multiplicand is a large number or multiplier is greater than 32? Is it some flaw in the design, bug in implementation or failure to understand the requirements. Sometimes the requirements are vague; as developers we cannot work on vague requirements. Go back to the requirements phase and ask the question, what is expected when there is overflow?
Step 5: Maintenance
In a generic API like this, there may not be any disposal plan, but be clear on the targets this API will be supported on. The targets might move to 64-bit processors and your API may become obsolete. Support and maintenance can be minimized with proper documentation, setting the expectations right and listing the shortcomings.
How much time should you spend on each phase?
As a general rule, spend your most valuable time in design and implementation phases and then the requirement phase, With a proper design and implementation based on clear requirements, the time on maintenance should be minimal.
What happens if we write code without proper requirements and design?
This leads to spending more time than expected in the implementation, resulting in missed timelines, unnecessary pressure and last minute rush to get the code working. This forces less time in testing phase; resulting in release of bug prone code. The end result is spending significant time in support and maintenance.
In our everyday work, we write much complex APIs without clear requirements and design. As expected, we spend significant time in stressful debugging rather than quality work.
So next time you take up an API; ask for clear requirements and design before you implement.
Verification - Are we building the system right?
Validation - Are we building the right system?