[ts-gen] [TWS API] Quality of Code in C++ API (fwd)

R P Herrold herrold at owlriver.com
Mon Jul 14 16:46:21 EDT 2008


I need a copy of Bill's post on the tws-api mailing list in a 
static location I may refer to.  As such I repost his commends 
from last week.

-- Russ herrold

---------- Forwarded message ----------
Date: Tue, 08 Jul 2008 17:36:59 -0400
From: Bill Pippin <pippin at owlriver.net>
Reply-To: TWSAPI at yahoogroups.com
To: TWSAPI at yahoogroups.com,
Subject: Re: [TWS API] Quality of Code in C++ API

Noam,

I believe the IB developers for the C++ sample client face a 
number of very frustrating constraints; three come to mind:

(1) a possible lack of users --- I suspect most people on
this list who start from a sample client write in Java.

Posts to this list in the past indicate that Java has been more
popular than C++.  I wish it were otherwise, but the choice of
Java for the tws does give them cross-platform code, and perhaps
that's why the Java sample client seems to be the "official"
specification for the request and message formats of the api
protocol.

(2) an apparent requirement for consistency with and similarity
to the Java sample client --- e.g., the EReader.java and
EClientSocket.java code appear to have been adapted to give
the SocketClient/src/EClientSocket.cpp file.

Although I code in C++, most of my experience with IB's sample
interface code has been in reading the Java sample client sources,
and even there I've focused on the EClientSocket.java and
EReader.java files, as specifications of the wire format for
the protocol.

After all, the java sources are in a very real sense the "official"
sample client sources, as indicated by the facts that the tws is
written in Java, and that the C++ sample client code doesn't even
run on Linux.

So, one problem with the C++ code may lie in the primacy of the
Java sources; given that the C++ code is meant to be a sample
program, and must be kept synchronized with the Java code, IB's
developers seem to have avoided a complete re-factoring of the
code into a completely distinct architecture.  I wouldn't want
to write code under such constraints, and I suspect that the
rest of the C++ developers on this list feel the same way.

> What really got to me recently was that handling of Combo legs
> when working with the Contract struct. I would have expected at
> least a destructor to handle memory allocations, no?

It must be inconvenient to move code from Java, where there's a
garbage collector, to C++ without, especially if the developer
isn't free to refactor, and needs to keep code consistent with
the Java from one api version to the next.

I would have been tempted to link in Boehm's free collector, which
is often integrated with g++, but I suspect this is problematic in
a Microsoft framework.  Given a system without a collector, I would
prefer to make greater use of object stacks, though keeping in mind
the apparent similarity between the C++ and Java code, I believe that
the IB developers wanted more of a drop-in solution, one that
wouldn't change the overall architecture.

The presence of the file Shared/shared_ptr.h indicates a desire
to use smart pointers, but that file doesn't seem to be included
anywhere yet.  Maybe the IB developers haven't seen the need to
finish memory management for the C++ sample client yet.  I'll just
note here that there are problems in using smart pointers for
arrays, and that combo leg contracts in effect include an array
of legs; perhaps the lack of a destructor indicates that the
developers have not yet decided which way to proceed here,
and serves a warning to those who read the code that there are
problems with combo legs.

(3) a need to target the code at novice developers, with the
intent that they be able to adapt the code for their own uses.
So, when you say of the code:

> I was wondering whether it's just me being naive, or if the
> quality of the code in the C++ API is really this bad.
> ... the thing looks as though it has been written by a
> complete novice.

Presumably you're ignoring the generated code, and other
artifacts of the Microsoft tools they've used.  Beyond this,
I'd like to suggest rather that it seems to have been *aimed*
at novices.  This leads me to consider some of the design
decisions IB has made with the Java and C++ sample clients.

In fact I've written a linux C++ tws api interface application,
the trading-shim, which is GPL v3 and available at
http://www.trading-shim.com, so I have some opinions on how
an tws-api program in C++ should be written.  That being said,
I also feel that there are good reasons for IB's having written
their code the way they did.

There are a number of areas where there are fundamental
architectural choices for which IB has quite reasonably gone
one way, and a developer preferring C++ might reasonably go
another.  I'll note the following areas:

     1.  platform
     2.  architectural patterns
     3.  IO abstraction

For the first, they've chosen Microsoft, for the size of the
installed base, where we've chosen Linux, for the quality of
the OS, g++, scripting languages, and other tools.

As for the second point, architectural patterns such as
singletons and RIIA might simplify the code quality for
maintainers once they understood the overall program, but
such abstractions might be an obstacle to understanding
for novice programmers, which brings me to the last point,
IO abstraction.

The choice of whether to use IO abstraction or not is critical
to code quality.  As written, input in the sample client is via an
enormous case switch, and the output boils down to one-per-request
procedures made up of lists of output actions for strings and
numbers.  This is probably because:

     Sample client code *must* specify, if necessary via
     enumeration, the exact format for events to and from
     the tws side of the aps protocol, that is for
     requests and messages, respectively.

This point, that the most important role of the sample client
sources is to be read by api implementors, was made earlier
by mel:

> ... I use it for what it is, documentation ...
> [in] the form of a ... program.

The request/message protocol specification should be as simple
as feasible for even novice programmers to understand, it
should be robust in the face of maintenance errors, and it
must conveniently support gradual version updates while not
discarding the specification of older versions.

These requirements conflict directly with the otherwise
reasonable desire for IO abstraction, with, say, a
parser, scanner, and object factory.  In the trading
shim, we have in addition defined an application-domain
type system with constant type objects for each elementary
attribute of the api, and rules with type vectors for
each event; these are used by the parser to recognize
input and build event objects.  All this abstraction
works to make the procedural portion of the code more
concise, at the cost of more objects and more header
files.

If IB chose to use such architectural patterns, human
readers would need to understand more of the overall
sample client source before they could extract the
request and message formats.  Although this information
is expressed to some degree by the online docs, such
a spec must be exactly correct and up to date, and
they are not.

The sample client, no matter how ugly the low-level
IO, still serves to express the api protocol format
exactly and precisely.  Although I grumbled when I
first saw it, now I'm glad it's there.  It does the
job where fancier IO abstractions such as BNF would
obscure the actual protocol, be fragile under version
changes, and not even provide the functional test
capability that makes the sample client so useful.

Thanks,

Bill


More information about the ts-general mailing list