Monday, October 31, 2016

RBTLIB - A Client-Side Library for Review Board

I've been experimenting with a simple client-side library for Review Board. I named this library RBTLIB (RBTools Library). I have a basic implementation for obtaining the Root and Review Request resources from a Review Board instance.

RBTLIB started life as a project to answer how many review requests were entered into Review Board during a fixed period of time. I extended this project to see if it could become a passable RBTool replacement.

In creating RBTLIB, I mean no disrespect to the RBTools authors. RBTools provides a rich set of use cases to guided the development of RBTLIB.

During the development of this library I discovered Click, a command-line tool for Python applications. Click is super simple to use and develop command-line tools.

I spent time studying Eli Bendersky's PSS tool. If you enjoy learning by example, Eli's code is an excellent place to start.

RBTLIB is primarily an experiement in developing a client-side library for a RESTful API. I set out to develop a small tool to query a Review Board instance for any reviews added during a 24 hour period. The command-line tools built using RBTLIB can answer this question.

Some challenges remain.

First, the command-line tools return JSON objects. I don't have an answer to this challenge. It might be reasonable to leave the command-line tools as examples for other client development but this just skirts the problem.

Second, these tools provide support for a few Review Board resources. I'm looking at ways to represent resource data programatically. At present, I'm thinking it might be nice to write "root.json" or "root.capabilities.git" to access the entire root resource as a Python dictionary or just the git capabilities.

I like the layered implementation for the Root request and the Review Request request I created. For an example:

Source: rbt/rbtlib/root/links.py

It does a nice job of leveraging the structure of the Root resource and its links. So nice that I can write a Review Request getter in a single line:

get = root.links.key(
    'review_requests',
    'application/vnd.reviewboard.org.review-requests+json')

Source: rbt/rbtlib/review_requests.py

Two design objectives I set for myself in writing this library were:

  • Keep the Python implementation simple. RBTLIB is written in a simple style that enables additional getters for resources to be written in a single line.
  • Expose the entirety of the resource to the client. RBTLIB exposes the Python dictionary created from the JSON response to the client. While this approach achieves the objective the current implementation is deficient because the command-line tools simply pass this dictionary along to the user.
The next revision of RBTLIB may include an implementation of the Composite design pattern that allows the library to dynamically generating a structure for accessing the elements of the Review Board response. I'm going to try and maintain simplicity by avoiding the use of Meta Classes and if successful, I should be able to improve the results returned by the command-line tools.

Source: RBTLIB v0.1

Tuesday, October 25, 2016

Defensive Programming Done Right

I watched John Lakov's two part video on Defensive Programming Done Right [1, 2]. The first part provides motivation for defensive programming. The second, shows how to use BSLS to introduce defensive programming into C++. A definition of defensive programming is in Part I.

Part I looks at design by contract and observes that undefined behaviour in a contract can be advantageous, particularly if you structure your implementation so that sensible behaviour occurs whenever preconditions are violated.  Sensible behaviour is delegated to the application. Doing so simplifies library construction. For example, the Standard C Library's handling of null pointers provided to string functions is implemented this way.

A model is discussed for pre- and post-conditions applied functions and methods.
  • A function's postcondition is simply its return value. 
  • A method's postcondition is subject to the preconditions of the method and the object state when the method is called. 
The extension of pre- and post-conditions to methods introduces the notion of essential behaviour. Essential behaviour includes method postconditions but also other behavioural guarantees beyond these postconditions. These behavioural guarantees are essential to ensuring the method's correctness.

Both talks provide an introduction to the C++ proposal for Centralized Defensive-Programming Support for Narrow Contracts. Indeed, the implementation of BDE (of which BSLS is a component). The experience gained at Bloomberg using BDE provides the practical element of this proposal.

Centralized Defensive-Programming Support for Narrow Contracts defines a narrow contract as a combination of inputs and object state that can result in undefined behaviour detectable only at runtime. There is an excellent argument in this paper for not artificially widening a contract--an argument that the Standard C Library supports and which the Standard Template Library may have missed (for example with the introduction of the Vector container's at method).

In all, I had a great deal of difficulty finding value in Lakov's videos but think that this is a result of his presentation style rather than the content contained therein. Lakov is a co-auther of Centralized Defensive-Programming Support for Narrow Contracts and the value of that work and the ideas contained therein made clear what the videos did not.

I haven't done any research on what prompted the Vector at methods and the notion of artificially widened contracts but I am convinced that the C Standard Library embodies better solutions.

[1] Defensive Programming Done Right, Part I
[2] Defensive Programming Done Right, Part II

Sunday, October 2, 2016

The Abstract is 'an Enemy' (With a nod to LibAPI)

I discovered The Abstract is ‘an Enemy’: Alternative Perspectives to Computational Thinking in the references to Robert Atkey's talk on Generalising Abstraction.

The Abstract is 'an Enemy' is an argument against creating generic names for abstractions. The paper begins with a module name 'ProcessData'. I laughed on reading this having encountered a library called 'API' in my own work. The example struck a chord.

The compelling argument in The Abstract is 'an Enemy' is that software should be designed so that names are specific. The rationale for the specific is two-fold: it forces the design to encapsulate a single thought and it aligns what is being defined with something in the real world.

The paper goes to provide examples on how the increase in abstraction in an effort to simplify leads to complexity. In one example they discuss how the concept of a user is generalized to the point with the resulting concept in the implementation embodies two very different users.

The abstraction of user leads to complexity in the system but also diminishes the ability of the software to serve these users. The shared representation of user in the system resulted in the system not supporting the user's way of thinking about the world.
A misfit is a correspondence problem between abstractions in the device, abstractions in the shared representation (the user interface) and abstractions as the user thinks about them. Here, the abstractions in the ‘shared representation’ (the user interfaces ...) don’t match the users’ way of thinking about the world. Such misfits are known to cause usability difficulties.
 The provides a description of the tension between the need to model the real world and the need to limit complexity in an implementation. It's a good walk through how the design process goes awry and offers some insight on how to correct these challenges.

In my experience, I am confounded by the need to create arbitrary abstractions that obscure the real world. In the domain I work, in I am faced with electronic signals and devices that make up the physical interface to the product. In many cases the signal names presented in the schematics are never captured in the software and an abstraction for a physical device (such as a button) are non-existent.

I don't have an answer other than to suggest that the software implementation is very out of touch with reality. The resulting complexity in the product and simple misunderstanding that results is costly.