Wednesday, August 15, 2007

Limits Of Unit Diagnosis

Unit-testing can uncover many kinds of deficiencies, gaps and faults. It is not the responsibility of a unit test to verify whether the function actually works or not, that is the domain of functionality-tests. Indeed, a unit may be successfully tested by the unit-test suite and still not work!

1) Inaccurate definitions - If the function succeeds even if some preconditions deemed necessary are not fulfilled, then probably the designer has made an error in the specification.
2) Unaddressed requirements - That lengthy switch-case might be missing a few cases!
3) Certain kinds of bugs - Typos in parts of the code that affect the post-condition enforcement can be caught.
4) Programmer indiscipline - Perhaps that developer might be missing a few basic but essential checks?

If nothing, it provides a way of ensuring complete coverage and execution of the developed code, an objective that would be difficult or time-consuming to achieve otherwise.

Monday, August 13, 2007

Unit Testing As Claim Validation

"Give me a lever long enough and a fulcrum on which to place it, and I shall move the world." - Archimedes (Mathematician and inventor of ancient Greece, 280-211BC)

A function is much like Archimedes's lever, a block of code that claims that it will do something if some things have already been done. A unit test should ensure that the function can actually do exactly what it claims to, when all its conditions are met.

The definition of a function, no matter how complex it is, can be decomposed as
1) Preconditions (Conditions/Environment)- Things which must be done or conditions which must prevail when the function is called. These might include constraints on the input parameters and global state variables.
2) Body (Action) - The main block of code which achieves the functionality.
3) Postconditions (Side-effects)- Things that the function will ensure by the time the body of the function finishes executing. These can be the function's return value or the modification of the state of the system.

Unit-tests should determine whether all the postconditions are fulfilled when all the preconditions are fulfilled by the caller of the function. It is important to remember that unit-tests are more like mathematical verification of the function-model; they check whether the code conforms to the definition of the functions.

Saturday, August 11, 2007

Unit Testing Primer

(Breaking this article into smaller, more readable fragments. Blog-style!)

Unit-testing deals with the verification of what an unit can achieve on its own, without help from other units. In other words, assuming all the other modules required by the unit are available, can the unit achieve what it claims to do? This is the question that unit-testing seeks to answer.

I started off a skeptic, regarding the usefulness of having unit tests, seemed to be such a waste of time. What won me over? Simply put, it helps us to avoid stupid, elementary mistakes. But god knows (as do we!) how common those are, especially during bug-fixes!

My primary motivation to write this series of articles is to-
1) define the scope of a unit-test - There seems to be misconceptions about what unit-testing is all about, what a unit-test should and should not do,
2) list the benefits of unit-testing - there's more to it than meets the eye at first sight. All love is not at first-sight!
3) share my understanding(s) - I had great fun exploring unit-testing, especially regarding what could be achieved with dummy or mock versions of external functions (Harnesses)

Here goes...

Unit testing = Claim Validation

Diagnosis Limits

Unit Testing Environment

Test Scripts

Test Harnesses

Example (Read this first if you will!)

Unit-Testing Frameworks

Run the unit-test suite frequently and regularly, especially at integration-points to ensure that development is proceeding in the right direction. Unit-testing can go a long way in -
1) making your team's code bullet-proof and,
2) importantly, avoiding last-minute-release-time-chaos-induced bloopers.

I must also add here that I am not a fan (yet?) of test-driven development. I would recommend unit-testing for finding errors that could easily escape visual checks or code walk-throughs..

- Thomas Jay Cubb

Please also read Learning To Love Unit Testing.

TODO - Diagrams

Wednesday, July 25, 2007

Draw The Line

While coding within code-frameworks, we will be required to insert functionality into boilerplate code. There might be lots of TODOs marked in the framework code. When doing so,if what you are doing would be long-term, call hook functions to your own non-framework code rather than coding the functionality in-place.

Call your designed functions through a "hook" function and don't code the functionality within the generated code. Draw the line!

Advantages:
1. It will be easier to move to another framework. Otherwise, there'll be lots of last-minute copy-pasting and hence errors introduced.
2. Better visibility. When something goes wrong, you know who to blame!
3. More room for experimentation. You might want to tweak the framework's configuration and generate new code.

Tuesday, July 03, 2007

Principles Of Codeline Management

Might seem like common-sense, but learnt the hard way!

1 Build Inequality
a) What is working on one build might not work on another. We must retain information regarding important working builds to facilitate later investigation!
b) Some codelines are important than others. 10 units of work on a build close to the mainline is probably worth more than 20 units of work on a distant line.

2 Fix Early
Find errors and fix problems at the earliest. Yes, getting things working your build is very important.

3 Merge Early
Get close to the mainline, at the earliest possible stabilization point.

4 Merge And Fix Early
Find errors and fix problems on a build that is as close to the mainline as possible. To paraphrase a proverb, “Early to merge and early to fix makes the release smooth and nice!” ?

5 Useful Artifacts
If an artifact is worth keeping, save it. If it is not worth keeping or it is not likely to be used, remove it.

6 Docubits
Documentation: every bit helps, and a little bit of documentation at every step doesn’t hurt!

Hopefully I will be writing more on each of these points later.

Wednesday, June 20, 2007

CM Synergy Crash Course

Bits and pieces of CM Synergy info picked up. Hope this supplements the sparse Synergy documentation. Also posted at the CruiseControl website

Introduction

CM Synergy aka Telelogic Synergy is, "a task-based configuration management system". But the philosophy of the tool is radically different from other version control systems around. These differences sometimes add up and hit you hard; especially if you have prior experience with any of those other tools!

Synergy-ese (Essential)

CM Synergy uses different terminology from other CM tools. Some of these "new" terms are ill-chosen and may take some getting used to. If you are moving to CM Synergy from another tool or are forced to adapt (new job etc), then these rough translations may help you get to speed faster.

Task (almost)= objects
A task is just a collection of versioned objects. Synergy adds the idea that these objects are grouped together for a purpose and hence it is a "task".

Check-out
You check out objects and make changes to them. Synergy recommends that the checkouts must be made against a task. When you check out an object is that it gets added to the task. In effect, you are making the task as you work. When you check out stuff, it becomes a modifiable "working" copy on your hard disk.

Check-in
After you make those changes, you check them in. You can check in the task, Synergy tracks the objects associated with the task and checks in each of those objects. Alternatively, you can also check in objects individually.

Folder = Label, Tag (Do not draw the "directory" parallel!)
Tasks are put in folders. Since a task is a collection of objects, the folder will, effectively, contain the objects that make up those tasks.

Reconfigure = Update
Reconfigure is how you get files from the repository. A set of folders would have been allotted to you within Synergy; when you reconfigure, you would be getting the contents of those folders. The fancy Synergy-ese term for what you get when you reconfigure is the not-for-mortals-sounding "reconfigure template".

Project
A project is a list of the versions of all the files (objects) being used by you.

Finding Synergy

(TODO)

Advanced Synergy-ese (Non essential)

(TODO)

Sync

Reconcile

Get Out Of Jail Free!

(TODO)

Conclusion?

(TODO)

- Thomas Jay Cubb

Monday, April 23, 2007

Root Or Fruit?

As far as bug-fixes are concerned, there are broadly two ways to go:
1) Remove the cause (Solution!)
2) Mask the effect (Hacks!)

For complex systems, before we can possibly arrive at a complete solution, we will need to work at the problem both ways. Attack the root or attack the fruit? Though it is obvious that fixing the root is the ideal solution, often we have to make do with a combination of the two.

Attacking the cause straightaway may not be such a great idea.
1) Incomplete understanding of the system - You might be familiar only with a part of the system.
2) Time-pressure- How many lines of code can you possibly go through before the deadline?

Magnify the effect! Change the effect into something more drastic. This will trigger new lines of thinking.
Remove the effect! Bugs are caused by code; remove the code!
Take breaks. The a-ha moment will often emerge when you are away!

Friday, December 15, 2006

Biller - Design Of A Receipt Generator

Problem Specification: SALES TAXES


Basic sales tax is applicable at a rate of 10% on all goods, except books, food, and medical products that are exempt. Import duty is an additional sales tax applicable on all imported goods at a rate of 5%, with no exemptions.


When I purchase items I receive a receipt which lists the name of all the items and their price (including tax), finishing with the total cost of the items, and the total amounts of sales taxes paid. The rounding rules for sales tax are that for a tax rate of n%, a shelf price of p contains (np/100 rounded up to the nearest 0.05) amount of sales tax.

Design

Receipt

A receipt can be viewed as a collection of sold items (hereinafter referred to as receipt-items) which contribute to the receipt’s characteristics like the total amount and the total amount of sales-tax.

Figure 1 – Receipt: Collection Of Receipt-Items

Application

In the application, a receipt has to be generated and displayed. The steps involved would be:

  1. Create a receipt-item.
  2. Add it to the receipt.
  3. Repeat 1 and 2 for all items to be added to receipt.
  4. Display the receipt.

The required attributes of the receipt (from the problem-specification) are an item-listing, total amount and total sales tax. All these are dependent on the individual receipt-items and hence must be characteristics of receipt-items.

Receipt-Item

A receipt-item must provide the following information:

  1. Description
  2. Cost
  3. Quantity
  4. Sales Tax (varies according to sales-tax policy)
  5. Price (The shelf-price depends on the sales-tax)

Figure 2 - Receipt Item

Since Sales-Tax and Price are dependent on extrinsic factors, we implement them as methods (the exact implementation-strategy will be detailed in the following sections). Items 1 to 3 may be implemented as attributes of the Receipt-Item abstraction.

Sales-Taxes

There are two types of sales-tax defined in the problem– Import Sales Tax and Standard Sales Tax - any or both or none of these may be applicable on an item. But essentially both imply an amount to be added as tax.

Figure 3 - Sales Taxes

Both these types of sales-tax have to be rounded up to the nearest 0.05, but at a rate defined by the specific type of sales-tax.

Computing the Price of a Receipt-Item

Essentially, the Price of a Receipt-Item = Cost + Sales-Tax(es)

The price of a receipt-item will depend on the sales-taxes applicable on it. But the tax-policy can vary widely (and wildly!). The implementation of a receipt-item should, ideally, not vary based on such an obviously extrinsic factor, if it can be avoided.

Hence we delegate the responsibility of calculating tax to Sales-Tax entities. And since the number of sales-taxes to be applied may vary from none to many, this entity needs to be a list that could vary. This can be achieved by having the Sales-Tax entity point to the next Sales-Tax entity (if any) and so on.

Figure 4 - Sales Tax Computation: Chain of Responsibility

The price of a receipt-item can be easily determined after sales-tax computation.

Thus, the receipt-item would be able to provide information about both its price and its sales-tax.

Receipt-Item Creation: Sales-tax policy isolation

As mentioned earlier, the sales-tax could vary from time to time. It would be beneficial if we could abstract it from the receipt-generation application. Indeed, why need a cashier be required to know the intricacies of taxation and idiosyncrasies of politicians? J The application shouldn’t change each time the policy does!

What this means in the context of our arrived-at design, where each Receipt-Item will be equipped with a Sales-Tax entity, is that we will need to fit it with different kinds of Sales-Tax entities based on the taxation-policy.

We move such taxation-policy dependent logic/functionality into a separate class (Receipt-Item-Creator) which can create an appropriately built Receipt-Item, once it is given basic intrinsic characteristics of the item being sold. (Surely, it is reasonable to expect the cashier to know things like whether an item is imported, whether it is a food-item, its cost etc.)

Figure 5 - Receipt Item Generation: Builder

Displaying the receipt

We can have a function in the application to display (say, displayReceipt) a receipt. This function is not made a part of Receipt itself because having it so would tie the Receipt class to the Application mechanism (console/window/printer for starters).

Conclusion

We are now capable of implementing the steps of the application to demonstrate receipt-generation.

  1. Create a receipt-item === ReceiptItemCreator.create
  2. Add it to the receipt. === Receipt.add
  3. Repeat 1 and 2 for all items to be added to receipt.
  4. Display the receipt. === Function in the application === Receipt.*,

The consolidated class-diagram for the system is given on the following page. Please note that it does not comprehensively list all the methods and attributes in each of the classes.

Figure 6 - Biller System Class Overview

Design Assumptions and Choices

  • The primary objective of the system is sales-tax computation.

  • Sales-tax is calculated per item. In the case where the quantity of the item is more than 1, this makes a difference, whether the sales-tax is applicable on the total cost or on the cost of each item individually. The data in the problem-definition is insufficient to come to a conclusion. Choosing to go with per-item sales-tax.

  • Items have not been classified as Taxable and Non-Taxable. Instead, we choose to embed a suitable Sales-Tax entity via the Receipt-Item-Creator.

  • A similar strategy for modifying the description of the item was also considered. But such modification would have been complex (“Imported box of chocolates” or “Box of imported chocolates”?). For the same reason, “imported” was not chosen as a modifier which would append “imported” to the description and Imported-Tax to the Sales-Tax.

  • It was possible to have a separate class for each Receipt-Item type. The resulting “class-explosion” would not have added much value to the system since we are primarily interested only in sales-tax. In the context of the system, there was not enough difference in the treatment of items based on such type to justify separate classes. The only drawback is that we lose the type (whether it was a book or food etc) in the Receipt.

  • The operation of the system, as mentioned in the algorithm, is simple enough that sequence diagrams are not needed.

Extensibility

  • New types of taxes may be applied by sub-classing Sales-Tax.

  • Major changes in taxation-policy can be handled by sub-classing Receipt-Item-Creator. Slight variations in the taxation-policy can be accommodated by modifying it.

  • If the type of the item (book/medicine/other) becomes of interest, the behavior can be added to the system by sub-classing Receipt-Item.

  • Changes will be localized to Receipt-Item-Creator. The application can remain mostly unchanged.



Thursday, November 23, 2006

Rounding To The Nearest

Programming languages and spreadsheets usually have a function to round to the nearest integer. But the task of rounding to the nearest something else comes up every now and again. Rounding up to lowest higher multiple of n, rounding down to the highest lower multiple of n , rounding to the closest n....

Algorithm roundToNearest
-------------------------------------
1. Multiply the amount by the reciprocal of the rounding base (N) you want to round to.
number = number * (1 / roundingBase)

2. Round the result using the built-in function.
number = roundToInteger(number),
where roundToInteger is whatever rounding function you want to use.
In case there is no such function available, you can simulate it. roundUp = integerPart of (number + 1), roundDown = integerPart of (number - 1), roundToClosest= integerPart of (number + 0.5) etc.

3. Multiply the resulting amount by the rounding base itself.
number = number * roundingBase

4. The resulting number is the original number rounded to the nearest rounding base.
result = number

Example 1 - Rounding 123.68 (up) to the next highest multiple of 40
Step 1: 123.68*(1/40) = 3.092
Step 2: 3.092 + 1 = 4.092, integer part is 4. (Did integerCeiling(3.092) )
Step 3: 4 * 40 = 160
Result: 160 is the answer.

Example 2 - Rounding 46.27 to the closest 0.06
Step 1: 46.27 * (1/0.06) = 771.16666666666666666666666666667
Step 2: Integer part of 771.16666666666666666666666666667 + 0.03, 771
Step 3: 771 * 0.06 = 46.26
Result: 46.26 is the answer.

Generalization (Compulsory Philosophical Reflection)
Often, what we have with us may not be exactly what our tool requires or expects. Adjust, make do and un-adjust! More technically, transform whatever is incompatible into a compatible form, do the required operation, apply the exact reverse transform. This is a strategy that is often needed in problem solving and. generally. it works!

Wednesday, November 15, 2006

U3D - Diagramming & Standardization

# Importance Of Diagramming
* Complexity
o Inadequacy of tables and text
o Things become clearer visually
* Communication
o Bigger projects, Bigger teams
o Typing Speed x Time != LoC
o Not enough that we know it
+ House plan

# Importance of Standardization
* My diagrams are the best!
o Time and effort
o Hard to be consistent
o Reinventing the wheel
o Onus is on us to do the explanation
* UML = "The" Unified Modeling Language

Friday, October 27, 2006

UML Triple Distilled

A few months back I had given some training in (the) UML for my colleagues. The course was named UML Triple Distilled (a la vodka and Martin Fowler's classic UML Distilled).

The objective of the session was to present the UML from a non object-oriented perspective, as a communication and diagramming tool. People won't often say this, but, really, you don't necessarily have to be an OO guru to benefit from the UML.

In the coming days, I will be putting up slides from the session over here along with some reflections on the slides. Here's the introductory slide.

Wednesday, October 04, 2006

SFINAE

Function templates participate in name resolution for overloaded functions, but the rules are different. For a template to be considered in overload resolution, the type has to match exactly. If the types do not match exactly, the conversions are not considered and the template is simply dropped from the set of viable functions. That's what is known as "SFINAE" — Substitution Failure Is Not An Error.