Monday, May 20, 2013

Cultured Software, Part IV

Continuing my thoughts upon the subject of fixed points, geometrically a fixed point is any point that remains fixed when a figure is transformed. For instance, under the operation of rotation the center point of a circle is a fixed point.

Algebraically we look for elements that remain unchanged under some mapping that is consistent with the system's assumptions. Group theory calls these mappings homomorphisms, and when they are 1:1 and cover all the elements under consideration, they are isomorphisms or permutations.

Take, for instance, the set ø, A, B, α, β  } under addition defined by:

ø + (any element) = the same element
A + A = B
A + B = α
B + B = β  
A + α β
B + β = A
α + α = A
α + β = B
β + β = α
A + β = ø 
B + α = ø 

The first rule gives the identity element. The last two give inverses. This set of elements is isomorphic to Z5, the set of integers mod 5.  We can show this by a bijective function that preserves identity and inverses (an isomorphism):

{ (ø, 5), (A, 1), (B, 2), (α, 3), (β, 4) }
We can see the symmetry about 0 and the inverses more directly by restating the domain set and the isomorphism as: 
{ (ø, 0), (A, 1), (B, 2), (α, -1), (β, -2) }
A group like Z5 has a unique identity element. An identity element remains fixed under all group isomorphisms. Whatever the identity is in the input it must  map to the identity element in the output. Five is the identity element under addition mod 5 since 0=5 mod 5.

Addition also remains well-defined: inverses and the 'order' of each element (in effect, the way skip-counting works) must be preserved:
{ (ø, 0), (A, -2), (B, 1), (α, 2), (β, -1) }

The structure of the group is maintained across the transformation:
  • ø goes to 0, identity to identity. 0 is its own inverse, and 0 has order 1 (one element results from skip counting 0+0). 
  • A goes to -2 and its inverse α goes to 2, the inverse of -2. Similarly for  B and β.
  • By skip counting  2, 2+2=4, +2=6=1 mod 5, +2=3 mod 5,  +2=5=0 mod 5 we get that the order of 2 (and -2) is 5. Similarly for B and β.
Had this been a slightly different type of group, say, Z6, there would be elements 2 and 3 which, by being factors of 6, are factors of 0 in that group; such elements give rise to sub-structures. The element 2 skip counts to { 0, 2, 4 } and 3 to { 0, 3 }, both of which are a fraction of the complete set Z6 ; neither subset includes 1 or 5, which fall out of the orbits of 2 and 3.

And here is the point: when we grow software, like it or not, we are implicitly defining a kind of broken algebra. Usually it is a messy affair, both incomplete and inconsistent, replete with exceptions. Yet despite the incongruities identifiable structure exists.

Fixed points in software give rise to symmetries analogous to those found in algebras - similarity and congruence in subordinate structures, inverses and zero divisors. If we fix two diagonally opposing corners of a square figure, we define an axis of symmetry. By fixing points we constrain the set of morphisms on the space defined by the square, leaving just one valid movement: a flip about the diagonal.

In a software code base, fixed points act to constrain, inhibit or completely proscribe adaptations. Like local fault inclusions formed in a crystal lattice by too-fast growth or foreign particles, fixed points introduce cleavage planes into the structure. If the system is well-formed the structure may be minimally complex. 

But fixed points in software are often incidental and accidental, leading to anomalous structuring. In a software system,  every random fixed point injected renders it more prone weird structuring. Whether we get a well-structured system with clean cleavage planes, a quizzical Rube Goldberg contraption, or an amorphous mass largely depends upon the environment in which the software is grown and the rate at which decisions crystalize.

Wednesday, May 8, 2013

History doesn't repeat itself...

A contemplation upon a disturbing waking dream, recalling the passing of two twins who were friends.

Quoth George Santayana,
Those who do not remember the past are condemned to repeat it.
But George also said,
History is a pack of lies about events that never happened told by people who weren't there.
Both comprise a subtle truth, for history never truly repeats itself, it just exhibits emergence of self-similar event patterns across time and space.

History is fractal.

Monday, April 22, 2013

Change the default SSH port on OSX

I got some pushback from sys admins about keeping an SSH server open on the default privileged port 22. They said "change it," so here's what I did.

First, I edited /etc/services, and changed the ssh entries to use a new port number. Chose a port above 1000 that isn't in use already. 

Second - and this is useful for people using git and ssh outbound - edit /etc/ssh_config and under Host *, add an entry:
  Port 22

Another method uses /System/Library/LaunchDaemons/ssh.plist, but the above is more Unix-centric way. On my system, the ssh.plist has a "disabled" key anyway. 

Wednesday, April 17, 2013

Fixed Points in a simple script

I had a simple task of taking a database extraction from some Oracle financial database view into  MySQL database tables.

Simple, right?

We're using Perl, which has flexible built-in data types to handle this sort of thing. It aught to be a clean mapping:

my $orahandle = $oracledb->prepare("SELECT * FROM $table") or die('Query failed on '.$table);
$orahandle->execute();
while( $data = $orahandle->fetchrow_hashref() ){
  if ( ! $inserthandle ) {
    @columns = map(lc, keys(%$data));
    $paramstr =  ('?,' x ((scalar (@columns))-1)).'?';
    $inserthandle = $targetdb->prepare("INSERT INTO $mysqltable (".join(',',@columns).") VALUES ( $paramstr )") or die "Problem can not prepare:  @{[$targetdb->errstr()]}\n";
  }
  $inserthandle->execute( values(%$data) ) or die "Error: Failed to insert. @{[$orahandle->errstr()]}\n";  
}

The two tables are isomorphic so the problem scenario is one of a map. Theoretically, we do not need to know the names of the fields, or their data types, because the types are isomorphic too, more or less. The point is that discrete conversion is not demanded by the semantics of the problem scenario.

Having a rule, an isomorphic mapping if you will, is important even when "more or less" means there are exceptions. Treating code as a morphism facilitates articulation of the exceptions differentially, with respect to how they change the mapping, rather than obscuring all in undifferentiated procedural code. 

The problem in this specific case is that there are several DATE data type fields in the table, and the default format for Oracle is 'MM/DD/YYYY'.  MySQL has a fixed constraint upon the format of inserted dates, the ISO 'YYYY-MM-DD' format. It is a fixed point.

Programmers are taught to just hack it. List the field names individually in the SELECT and INSERT (more fixed points). Manipulate each DATE field in a discrete variable and substitute the transformed value through in-line code (even moar fixed points). It works, at the cost of tossing out the inherent symmetry in the scenario. And it adds several gratuitous fixed points - at least a couple for each discretely mangled field.

Now, one might think to coerce Oracle put the format back to:

alter session set NLS_DATE_FORMAT = 'YYYY-MM-DD'

But the upstream supplier of the view decided to make all the dates VARCHAR2's, so none of the normal date formatting is applied. Yet another fixed point. MySQL's fixed point was, at least, a standard. This fixed point is completely gratuitous, and is the real reason the approach breaks: Oracle normally uses the ISO YYYY-MM-DD format by default. My solution is to define functional data-scrubbing callbacks, to inject data manipulation into the otherwise symmetric process.

A footnote: Not all fixed points are undesirable. A couple of the views thrown obliquely over the wall at me don't even have keys. No primary keys. No keys at all. Keys define the symmetries and structure of a relational data set. Without them a view presents no relations, being merely an undifferentiated amorphous mass of records. Such a practice is to IT design, as mud-pies are to fine cuisine.

[edit: Cleaned up code examples. Don't know why Blogger's editor keeps doing this, but it keeps chopping up my markup. ]

Sunday, March 3, 2013

VIM Plugins

I use MacVIM with Austin Taylor's VIM configuration tilde, and recently replaced it with Yehuda Katz and Carl Lerche's Janus VIM configuration on my MacBook. Both add plenty of bells and whistles plugins: keyboard mappings, commands, syntax highlighting, etc. The two motivating factors is that (a) Janus is documented whereas tilde is not and (b) tilde does a few things that mismatch my preferred defaults, such as setting very magic regex mode and altering the meaning of keys that normally do navigation.

The big brick wall that I hit with any of these configurations is that unless you are a vim plugin writer,  the morass of code is an incomprehensibly ugly mess. Note: I can read the code, but VIM script is usually so ugly that the skin on my eyeballs starts peeling from gazing upon it.

The size of these VIM config bundles exacerbates the obfuscation. There are simple means of showing the key mappings in vim. (Incidentally, this wikia is a good read for learning about key mappings in vim.) Type map (or imap/nmap/vmap for insert mode/command mode/visual mode mappings):

:map

...and you'll get a list of the key mappings. Now, with proper grouping a few dozen mappings can be readily accessible to the working memory. It is not unusual for vim configs to have upward of hundreds of key mappings. When you type :map all those mappings get dumped to a pager in the window, without any meaningful grouping. Not so nice for reading. This bloat is perhaps the best reason of all not to simply reuse someone else's VIM config bundle.

Try verbose:

:verbose map

This shows the file responsible for last setting a given mapping. This is nice for debugging why your expected mappings fail miserably and for identifying which mappings belong to a particular plugin (frequently undocumented).

Another problem with VIM mappings is that they are very often convoluted but only very rarely commented. Carlhuda's VIM bundle is an exception. Is a user really expected to read a mapping like this in a listing meant as a quick reference?

ai * :<C-u>cal <Sid>HandleTextObjectMapping(0, 0, 0, [line("."), line("."), col("."), col(".")])<CR>
What is the intention of the mapping? Idunno. Something about text indentation? Idunno. Should I even care? Idunno. The source file for this mapping had a few sparse comments. None of them were especially meaningful, but then again comments in vim mappings don't help the :map output. Ideally, the map command would allow a descriptive label to be attached, but that's not the way it works.



Sunday, February 24, 2013

Pet Pensiveness

We had to euthanize a family pet yesterday, a 55 pound labrador mix we named Molly. Molly had a great many qualities one looks for in a dog: she was submissive, rarely barked except when asked to or when she thought she was defending us. She was as attached to us as we were to her.


When we first found her, she was said to be the last of her litter - a runt no one else chose. We were told her other parent may have been a shepherd mix, but whatever her heritage she bore an uncanny resemblance to an oversized Finnish Spitz.

Molly had a sort of melancholy disposition from the start, as if she had felt abandoned. As she grew up we found her to be calm, obedient, and sociable on one hand, but when she switched it on her playfulness was almost wolf-like.

My waking moments were filled with memories, and one simple thought. So many people try to focus out on vanishingly distant, imaginary end-points, seeking rigid modes of thinking and to maintain narrow perpectives, racing so hard and fast yet giving so little thought to where they are going - under these conditions the lateral realities that pervade and indeed ground our lives become a blur that is easier to ignore.