CoordinateOperationFactory produces a number of "Axis changes" operations. They are produced by calls to swapAndScaleAxis(...) method. Those steps are importants, but may not need to be visible to user's eyes in the operation chain (they are presents in the MathTransform chain however). For example the following operations:
1) swap axis order from (latitude,longitude) to (longitude,latitude)
2) apply a map projection using standard axis and units
3) convert meters to kilometers
are really 3 concatenated math transforms (at least in current Geotools implementation), but may not need to be 3 concatenated operations: conceptually, we can see all those steps as part of the map projection process.
At the difference of MathTransform (which have no clue about source and target CRS), Operation know their source and target CRS. Concequently, steps #1 and #3 above don't need to be visible in the operation chain, since this information can be inferred from sourceCRS and targetCRS. This is an argument for hidding "Affine" operations when used in the context of a map projection.
An other reason for hidding those "Affine" operations is that when many operations are concatenated (e.g. CompoundCRS --> GeographicCRS --> GeocentricCRS), the operation chain may show many consecutive "Affine" operations, which may give to the user a false feeling of inefficiency since two consecutive affine transforms should be merged in a single one by a matrix multiplication. Actually, they are really merged that way in the MathTransform chain, but the CoordinateOperation chain doesn't show that.
We need to trace down all invocation of 'createFromAffineTransform' methods followed by an invocation of 'concatenate' in CoordinateOperationFactory, and find some way to allow 'concatenate' to figure out when he is allowed to not create a ConcatenatedOperation. Special attention must be bring to the properties of the object to construct in replacement. We should probably inherit most properties from the non-affine operation.