Posts containing CGM
Debugging problems is really easy once you "have them under glass". Get all the input data, get all the code, build it on your computer, and you can bisect down on the problem in the debugger until you have fixed it. (Ok. This is an over simplification. Assume that you are really smart, can talk to someone who knows about the code you are looking at, and have an unlimited supply of time and coffee :-).)
In ACIS, journalling really helps with these problems but it has its limitations. Journalling is a feature of ACIS where you can call APIs with a special option setting which tells them to print a scheme script describing the operation, and save a sat file for the inputs. What are the problems? It is time consuming and unusual work to support. (How often to most ACIS programs manipulate strings? The c library for strings is really dangerous which makes this even more fun.) In addition, only APIs are journalled, but customers can all sorts of functionality. There are sg functions which are lower level and generally are not journalled. Then there are call backs (e.g., MESH_MANAGERs) which we don't even try to journal.
I dislike using C++ samples because it consumes a lot of time, but they have their place. Scheme scripts (or JS scripts for CGM Component) can distill a customer situation to just a bunch of solid modelling operations. A sample application often illustrates context. Sometimes an API call that seems to reveal a bug as a scheme script was actually caused by an application trying to do a workflow that doesn't make sense. Experience maintaining a solid modeler gives a person a warped perspective about what is natural.
I write this because I spent the better part of a day debugging a sample application which showed a problem that could have been journalled. I didn't know the problem could have been journalled, because I couldn't reproduce it. I had the sat file and the same code level of ACIS and a description of what the user was trying to do. It turned out that using facet_options_expert rather than facet_options_precise caused a significant change in the answer. Since the customer was using a GLOBAL_MESH_MANAGER that they wrote, I assumed some of the difference in behavior could be caused by that.
I guess it takes practice asking the right questions and getting a little creative about how to debug a problem. What is the craziest thing you have had to do to reproduce a bug?
Posted: March 20th, 2013 |
Today, I’m going to talk about the way my attitude towards using namespaces has pretty much done a complete reversal over the last couple of years. I started off thinking that they looked great, progressed to mild concern that they seemed to be causing unexpected difficulties, and eventually realized that they can become unmanageable if allowed to grow out of control. Just like a bunch of tribbles. (Yes, the title is a Star Trek reference :).
To jump to the punch-line, I’ve come to the conclusion that highly fragmented hierarchies of namespaces (such as are found in .Net and encouraged by the Visual Studio C# IDE) make life harder rather than easier. Instead, I would recommend either name mangling strategies (incorporating an identifying string in the object name) or always using fully qualified names in your code (instead of “using” statements).
Phase I: Infatuation
When namespaces were first introduced into C++, I thought they looked like a great idea. It seemed wonderful to not have to worry about managing name collisions. Unfortunately, for over a decade I didn’t have an opportunity to use them; my Physics codes were standalone executables (and so name conflicts weren’t an issue), and ACIS was written before they were portable to all compilers. Actually, ACIS was written before they were introduced into C++. In the tribble analogy, everyone else got to play with these cool critters but I didn’t have one.
Phase II: Nagging Doubts
This changed when I started working with C#, especially in my personal projects at home. The .Net library makes extensive use of namespaces to indicate areas of functionality, plus the Visual Studio IDE assumes you want this sort of hierarchy in your code. If you create a folder within your solution to manage an area of functionality, for example a Market component in an economics simulator with root namespace Econ, then the Visual Studio class wizard “helpfully” puts any classes you add to that folder into the “Econ.Market” (sub-)namespace. And that is where the trouble started. (If anyone knows how to turn this behavior off, please post a reply – I’ve been unable to find a way to do it.)
I quickly found myself getting frustrated by not having the correct set of “using” statements in my code, and having difficulty figuring out which “using” statements I needed to include. For example, if I had a Trader class in a Actors folder (and corresponding namespace) and a Pit class in the Market folder, then I would regularly get compile errors when I tried to use the Trader class without “using” statement for the Econ.Actor namespace. And the really frustrating part was that it wasn’t immediately obvious which namespace was missing – I would have to find the class then look to see which namespace it was in. I now realize that the problem that I was running into is that namespaces (or more precisely “using” statements) lead you to write non-self-documenting code. In other words, if I write the code
Market market = new Market();
GoodsType goodsType = new GoodsType();
Pit pit = market.GetPit(goodsType);
I don’t have any visual indication in that region of code as to which namespace Pit, Market, or GoodsType live in. And if they come from several namespaces, I don’t know which “using” statement corresponds to which class.
This is very similar to the C++ “which header file declares this class” problem, for which a really good solution is to simply make the header name identical to the class name. CGM uses this naming convention and I highly recommend it – you don’t have to think when writing your include statements.
Phase III: Regret
The final driver on my voyage of discovery was C3D development (in C++). When we first started writing strong commands, I had the bright idea to use a namespace hierarchy to put a structure on the vast sea of commands we would be writing. Unfortunately, it didn’t work out as planned. Even though we only introduced a few namespaces, they still made life much more difficult than a simple name mangling scheme would have. Part of the problem is that the compiler errors when you get the namespace wrong are not helpful: we had to train ourselves to ask “did we get the namespace right” when we see an “undefined symbol” error for a class that we’re sure has the header included. An especially nasty error occurs when you try to include a header file inside a namespace block (this typically happens if you’re using templates and so want to do another round of includes for the method definitions). If I had it to do over again, I’d settle for a simple “_SPA” or “_CGM” at the end of each class name, e.g. Property_SPA rather than Spatial::Commands::Property. In tribble language, I feel like Kirk standing awash in a sea of tribbles.
Phase IV: Lessons Learned
The first thing to make clear is that I am NOT saying that namespaces are bad. The fundamental problem that namespaces solve is the ability for application writers to manage naming clashes between libraries from different vendors. I think it’s a great idea for every company selling component software to put everything into a single company namespace.
The problems I see come from trying to group classes into complex hierarchies, especially if you then use “using” statements to erase knowledge of the hierarchies. I’ve come to the conclusion that any such grouping should be as simple as possible, and that the primary goal of the grouping should be avoiding name clashes rather than imposing a component structure on the classes. The reason for this is that classes move between components fairly easily, especially if the component structure is very fine-grain. If every time a class moves you have to do a major renaming effort (either to fix using statements or to rename the class) then you’ll generate a lot of worthless work for yourself.
With this in mind, I currently think a name mangling scheme, with the disambiguating string at the end is best, i.e. something like ClassName_NS. The reason for putting it at the end rather than at the beginning is to help search – if you’re looking for class “Beagle” but are not sure which namespace you’re in, then you just need to look for “Bea*” in a list of all class names.
All of the above being said, I shudder to think about trying to solve this problem in a huge organization. Would .Net really be easier to use if they had used the above naming scheme rather than relying on namespaces?
Posted: February 22nd, 2013 |
In this post I’m going to talk about how we use C3D Toolkit to generate 'live' sample code snippets for our CGM documentation.
One of the things we’ve done with the CGM documentation from the start is to focus on what we call “HowTos”. These are standalone sample functions in our DocWiki that illustrate how to use CGM functions to accomplish some task – the idea is that customers can paste the function into a *.cpp file in their application and modify it to suite their particular needs. This initiative has been very successful – our customers really like the HowTos. It is also not rocket science – sample usage code as part of the documentation of an API is standard stuff. The interesting part comes from the word 'live' that I used above.
What do I mean by live sample code? I mean sample code that is used in a real application and so is called by end users every day, as opposed to sample code that is motivated by a documentation requirement “every interface method must have sample code which calls it”. How many times have you looked at the sample code for a method and seen some silly little program that is obviously contrived to just set up a bunch of inputs and call the method? If we think of a testing analogy, live samples are analogous to contract checks, in that they are an integral part of the application code, while contrived samples are analogous to unit tests, in that they are isolated executables that set up data structures for the express purpose of calling a particular method.
One of our goals in developing C3D Toolkit was to give ourselves a platform with which to develop live samples. The way we’ve done this is to turn the implementation of the C3D Toolkit extensions (commands) into HowTos which are placed in our DocWiki; the goal is that every modeling extension has a corresponding HowTo. For example, we have a “Fillet” extension in C3D that fillets (rounds) sharp edges. The C++ code underneath this extension eventually (after extracting argument lists etc.) calls a standalone function “HowToFillet”, which contains the code that a customer would use in his application to implement a fillet feature. Voila – we’ve got a live code snippet for the fillet operator.
As you’ve probably figured out, I think that live sample code is vastly superior to contrived samples. By making our samples part of our C3D Toolkit application, we gain the following advantages:
- Our sample code is built every night. If an interface changes that breaks the sample our nightly build process will catch it.
- Our sample code is tested every night. We have tests that do fillets in C3D Toolkit – these tests ensure that our sample code doesn’t regress (against the tests).
- We have a good chance of detecting subtle mistakes in our sample code. Our sample code is being used every day in C3D Toolkit. If there are subtle, 1-in-a-1000 bugs in the sample code, we have a good chance of someone stumbling across them while using C3D Toolkit. If, in contrast, the samples were simply contrived executables built and run in isolation, there would be no opportunity for discovering such nasty bugs. We just benefitted from this a couple of months ago; we had written a sample without realizing that the operator being called might return multiple bodies. As part of fixing the C3D Toolkit bug, we automatically fixed the bug in our sample and the improved sample was automatically included in our documentation. This is the core advantage of live over contrived samples, in the same way that contract checks are superior to unit tests. By integrating the samples in an end-user application, the selection pressure of lots of users using the application is applied to continually improving the samples.
Finally, live samples directly support rapid prototyping for customers. Let’s say a customer wants to prototype a new workflow that he will include in his application. We recommend the following steps:
- Prototype the workflow as a C3D Toolkit script (i.e. get it working in C3D Toolkit).
- For each extension called in the script, look up the corresponding HowTo.
- Write a (C++) workflow function in the application that calls these HowTo functions in the appropriate order.
As easily as that, the customer has a working C++ prototype for the workflow that they’re coding up. In practice the customer might need to do some clean-up to get the C++ function working, but this process brings him very close to where he needs to be.
As you can see, I really like the idea of live samples; I hope I’ve convinced you that they’re an important documentation tool as well.
Posted: November 16th, 2012 |
Those of you who are ACIS customers are probably familiar with acis3dt.exe – our Scheme-based demo application (which I’ll call A3DT). For those of you who aren’t, it’s an interactive application, written in the mid-90s, that lets you view and manipulate ACIS models by typing script commands (Scheme expressions). The view window provides mouse-driven picking and view manipulation, but anything you can do with the mouse can also be done through a Scheme expression. There is also a helper application which can be used to edit scripts and send them to A3DT (either entirely or line-by-line) for execution, or scripts can be run from the command line in “batch” mode (for testing).
A3DT has been VERY useful over the years for ACIS, in many ways:
- Most of our tests are written in scheme
- Customers submit bugs as scheme scripts
- Customers are encouraged to prototype their workflows in scheme, then examine the C++ behind the script (the extensions are shipped as source code) and use that to guide their application development.
- Scheme is the primary demo tool for ACIS – our Technical Account Managers (TAMs) often find themselves writing scripts “on the fly” to answer specific customer questions about ACIS’ capabilities.
- When developers want to “play with” ACIS (e.g. create 100,000 blocks to test performance) they do it in scheme.
And now, let’s fast-forward to when we began working on componentizing CGM. In CGM we didn’t have such a scripting engine – instead we had an in-house unit testing engine that could run unit test executables. If you think about it, this made perfect sense. CGM was not developed as a stand-alone product; instead it was part of a GUI-based feature modeling application. In other words, CATIA filled most of the roles for CGM that A3DT fills for ACIS.
For CGM component, however, this was not sufficient. We first noticed this when writing tests – we found ourselves trying to write unit test executables for tests that were really acceptance tests. This was extremely expensive in developer time – being able to see the models you’re creating and do graphical picks on them is extremely important when writing tests of even mildly complicated workflows (e.g. create a block then fillet one of the edges). A more technical way to think of this is that the overhead due to violations of Once and Only Once involved in setting up the input scenarios (which I’ve discussed in the context of design-by-contract) is prohibitively expensive.
A more important problem is that unit tests don’t use the code the way that our customers do: in an application. This is the heart of App Driven Development: you should try to use your own product in the way your customers will.
At the same time, our TAMs were used to having a demo application available for use in presenting our products to customers.
One of the things that surprised me (but probably shouldn’t have) in all this is how rarely people think about scripting interfaces in terms of supplying a command-line interface to applications. In our experience with A3DT (and now C3D), the primary utility is in the ability to sit in front of the application and interactively figure out, line-by-line, what you want to do, while capturing what you’ve figured out in a script. In contrast, it seems like most people think of the utility of scripting in terms of being able to write scripts that will be processed in “batch” mode; in other words it’s very similar to programming, except you don’t have to recompile the executable when you change (or extend) the program. I imagine that a lot of this is driven by the browser-based application market; in such applications the scripting language isn’t the actual interface that’s presented to the user; it’s simply an intermediate programming language that can be run on the browser. I think ignoring the potential of scripting as an interactive interface is a mistake – there are a lot of benefits to having a scripting “hook” into your application.
Posted: August 20th, 2012 |
While procrastinating (avoiding writing this blog entry for as long as possible), I debugged an interesting problem. This gives me something to talk about here. What follows might be simple or obvious, but I find that considering tiny details very carefully is a good way to improve the quality of the code I write. Consider the following code snippets
sphere* make_sphere( double radius, double x, double y, double z);
void do_something( /* ... */ )
sphere* my_sphere = make_sphere(10,0,0,1);
position( double x, double y, double z);
sphere* make_sphere( position const& p, double radius);
void do_something( /* ... */ )
position center( 0,0,1);
sphere* my_sphere = make_sphere();
With the second version of the code, you actually need to have a class structure defining your objects (which requires more code), but strong type checking can help you. There is also an annoyance with the second version of the code that you may have to write code converting between various types of geometric operators. This (having well thought out basic types for mathematics) is one area where CGM does particularly well.
The actual bug I looked at was closely related (class names changed to protect the guilty).
nifty_curve_calculator( double convergence_epsilon, double fitol_desired, ...);
In nifty_curve_calculator, exact points on a curve are calculated to convergence_epsilon. The nifty_curve_calculator then concatenates a bunch of exact points on the curve into a bspline fit for the curve. The fitol is the requested distance of the bspline from the exact curve being calculated. The two tolerances mean completely different things, but the compiler will happily accept code which switches the two tolerances. In the case I looked at today, the two parameters were swapped which resulted in code that worked most of the time, but caused a hang with more poorly behaved geometry. We should expect that convergence_epsilon is a lot smaller (10^3 times smaller or more) than the fitol_desired.
There is a whole constellation of bugs like this that can be avoided by making a careful object model. A simple way to improve type checkability is to avoid argument lists where convertable types are right next to each other. Avoiding void* arguments like the plague also fits into this line of design improvement. An additional help is to only require arguments in a constructor which are absolutely mandatory and use get/set methods to control the other parameters.
One area where I run into problems with this is writing code (e.g., for MESH_MANAGERS) where large objects are stored using arrays of indices into other arrays. If everything has type int (or size_t if that is how you roll), then compiler type checking doesn't help much. Pointers are slightly better for this, but then you get into ownership issues. I really wish you could do typedefs that aren't convertable to each other but have the same operations as integers.
Does you have any suggestions or comments for improving type checking in geometric code?
Posted: June 19th, 2012 |