I was hoping I could have done a post, at least a day ago, reporting a milestone – the full implementation of history (as POC for shape library) in the shape generator. But, alas, it was not to be. It’s been a slow slog trying to get this done.
I made great progress at first. I built all the UI and hooks into shape generator for history, even having to do the underlying stuff of the Run-Length Encoding to compress the shapes to save. That took less than a day. But I was merely: a) building a temporary XML to represent the history (should be persistent, but exactly how became more complicated question than I expected), and, b) just saving the shapes themselves in an in-memory heap so I could find them again. Again that went so smooth I was able, with a late night push, to even build a fairly simple history “browser”. That allowed me to get an idea, esp. as I’m not doing any I/O to get the shapes, of how fast the browser would be (not bad, but slow enough the “real” browser will have to do a lot of caching and have smarter ways to handle a very large number of shapes.
So buoyed by that quick success I thought I’d bang out the needed bits in my “container” (composileFile classes) and then integrate with the shape generator (have the exact hook in it I need). But then things really bogged down. So why?
With my architect hat on it takes less than an hour to setup the technical requirements for the compositeFile (I’d already done some of it but now actually putting some data in it, getting it back, and maintaining its integrity (really critical!) turned out to be much harder than I expected. In a real professional software effort no one would proceed with coding with such a skimpy definition that the (lousy) architect did. Or, at the very least now the person with designer hat on would flesh out the architect’s definition with some very detailed design of all the classes that would be needed. Now, in fact, this is still somewhat a methodological issue – should the architect have to go to that level of detail or is the detail (that the programmers will need, fairly precise definition of classes, all their methods and properties, and the functional requirements)? In some cases that is the job of the architect (and some architects like this part the best).
The role of architect, as a formalized job description, didn’t exist when I first started programming in a structured environment (as opposed to hacking before I had my first job). Over the years as software has gotten more complex the methodology has gotten more and more involved, thus taking a lot of upfront time before a single line of code is written. This is the so-called “waterfall” approach, i.e. think everything through, in detail, write it all up in specs, then start implementing. But, of course, this is slow. It’s especially slow for me in personal projects. So the world, esp. with the different mentality of development for the web (often called the “perpetual beta”) needed a different approach than the slow tedious product (or even IT) software development.
And then there was outsourcing, often to programmers who speak little of the human language of the architecture and/or product manager. So while the web development pushed for “agile” development, even the somewhat ridiculous “extreme programming” methodology (what I’m doing now and what I used to do decades ago before, painfully, learning the development process) there is still tension between various (and often highly dogmatic) “agile” methods, and often many problems when the development effort is multinational.
So the software world debates all this. Academics, who rarely have real experience with large scale software development, pronounce all sorts of “musts”, even down to the way to hold meetings. Meanwhile the people responsible are typically older and more senior, which means they predate much of this methodology and so, a bit, have to force themselves to use it. Sometimes those of us old school types laugh a bit (or a lot) at some of the silliness of these rigid methodologies.
Anyway out of all this the role of architect became more defined, to the point of becoming an explicit job description. I used to define it this way – programmers (done in the mud) develop individual classes or sometimes just parts of complex classes; “designers” (up a 1000 feet in the air looking down at the mud) come up with all the specs for a complete set of classes to build a “server”; “architect” (way up in the air, 10,000 foot level) puts together an entire system composed of many “servers” (until the whole concept of server got refined, architect and designer were pretty much the same job).
Well, I’ve done all these jobs. But now it’s just little old me. And I’m impatient. I want to see pixels on the screen, not slogging through detailed server and class definitions. In fact when I started this project I have no concept of how big it would get, big enough to in fact deserve an architecture, which I’m now building *after* getting individual bits to work, hence the big refactoring I’m having to do (not finished yet) in the shape generator. And the shape library, somewhat like a database (or data model), in other projects, has become central. But I didn’t realize that would happen so I neglected any real architecture specifications.
And, in doing this history, I neglected doing any “design” work and now I’m paying for it. Some people think charging into the code for quick results (the extreme programming model) is fine – the refactor as it becomes clear the code has gotten messy. Fine, BUT, refactoring is no fun, plus lack of design in the original code creates all sorts of bad practices. While I scoff a bit at design patterns there is some point to it all.
So, what does this all mean? Well, four days ago I had some classes (in some cases just stubs) to create this container, the compositeFile, that would be used for many parts of my ultimate project. I had built, without much design, except in my head, the basics to: a) create and initialize the container, b) close it after creation, and, c) open a (now) existing compositeFile. But I hadn’t actually tried to write any data in it. I knew approximately what I needed to do, but was tired of just writing pure code that didn’t do anything tangible, so I switched back to a top-down effort, actually rework the shape generator so it would need the compositeFile, before proceeding with the compositeFile development itself. This seemed reasonable and I thought would be quick. It wasn’t.
Now the compositeFile is more at the 1,000 foot design level than the 10,000 foot architecture level, but I messed up some important OOP considerations, most importantly encapsulation and abstraction, but also from the architectural POV, a very critical concept, “separation of concerns”. I now realize, in typical 20-20 hindsight that how the compositeFile is actually stored absolutely should be invisible to other classes. A compositeFile might just exist in memory, temporarily, or it might be a simple (albeit large) diskfile, or it might be based on a SQL server, or perhaps even something more abstract than that, out in the “cloud” (in more a metaphorically sense). This is the right way to do it. So how did I, somewhat mess that up, due to lack of upfront design and incremental development.
So let’s look at just one bit – blobs, or Binary Large OBjects. To a degree doing these right has plagued a lot of people. My last job was really building a new layer, under Microsoft SQL (really SharePoint, but it was the SQL behind SharePont that was our focus). SQL, somewhat like my little effort here started with focus on the standard relational database concept, i.e. tables, where the data was relatively simple types (numbers, dates, strings, etc). But what happens when you start getting big stuff, like images or videos or sound recordings). These don’t work in conventional databases. So really these blobs are handled differently, now crammed into tables, but shoved off in a different part of SQL with then a reference to them crammed in the table.
But blobs have a big problem with space management. I still laugh at some critics, decades ago, of using “paging” for virtual memory, instead of the more common at the time (both DEC and HP) of segments. I laugh because the criticism was that paging “fragmented” memory, when in fact it was segments that caused the actual problem with memory management in most early OS (like IBM’s MVT (or worse, MFT) before moving on to virtual memory). So blobs are exactly the same issue. If you try to store them on disk (or inside a database) and then blast away, deleting some, creating more, updating them (but their size is changes), pretty soon your storage is mostly wasted holes that are too small to save anything. “pages” (as in virtual memory, but also as now applied to file systems (it’s hard to believe it used to be done differently) break large chunks down into identical size chunks, which, of course, will now be scattered and discontiguous. But the space released by deleting one blob can now be reused for any new ones and in fact there is no “fragmentation” (i.e. some hole you can’t fit anything into).
This is just ancient history the kiddies ignore it, but even today some of these same things have to be dealt with. Sure, especially a couple of generations after I first saw it, SQL would do just what I need (and well), but that isn’t available to the amateur programmer. So I had to build a subset of it myself (or simple DBMs I can get do a lousy job of blob management).
So, in my (in my head) design I had a class ‘blob’ which would have some specialized subclasses based on the kind of data to put in the blob. OK, that’s simple enough. But the blob would have to be broken into ‘blocks’. And now just blobs, but all the internal structures in my compositeFile would be based on blocks, of which there would be numerous subclasses. Again, fine and dandy. But what is the exact relationship between the blob class group, the block class group, and the compositeFile clases – that’s were I fell down. A blob shouldn’t care how it’s stored because it’s just a bunch of blocks. But in reality blocks should also not care about how they’re stored. Both blobs and blocks can do their required function completely isolated from the storage. And that’s what I messed up, I sprinkled I/O code in these classes. Knowing I wanted some isolation, blocks can read and write themselves, but don’t know where – that’s outside (OK, that was appropriate, but I should have gone further). And since my compositeFile: a) may actually consist of multiple disk files, and, b) in fact not all blocks will be the same size, I put the concept of “seek” (i.e. turning a blocks unique id into a location on disk) in a higher level BUT not high enough. In essence I put some of the I/O in blocks and some in blobs and some in composite file, when in fact I should have put all I/O just in the composite file and the blob would have its methods to chase a chain of blocks and blocks would have its methods to read/write its data.
But my other mistake was “headers”. I initially, and over-simplistically defined a standard header for all blocks. But some blocks need more than the standard. So I began to kludge “extended” headers, in non encapsulated way, into each subclass of blocks. Now in fact I should have been much cleaner about this, reading/write a header should be independent of the data and, as well, reading/writing an extended header should be independent of both the standard header and the data. I commingled these two much. And while I’ve straightened it out some, in my new work, now I’ve got to go back and refactor the previous blocks. And in fact, now that I’ve evolved the design by trial-and-error I really need to refactor a lot. Now the concept of refactoring messy, but working, code is fine, but it’s no fun to actually do it, and often it will get forgotten under pressure to just keep moving (in my case I’m the impatient customer putting pressure on me, the developer, to get it done fast).
So that’s been my slog. That and lots of detailed coding messes of how you really build objects (C# is rather adamant I not do workarounds just in a hurry, but then, I have almost everything public (or at best protected) which is not good (I get really sick of type conversion or access violation compile errors, but instead of really fixing them, I kludge them to keep moving).
Now in a personal project, albeit it now a fairly large one, who cares about all this? So I create spaghetti code. This isn’t a product that will go through many generations and with a constantly changing staff (one reason for all the design methodology is the constant loss of the programmers that created one version and having to bring in new ones who have no clue what all this code mess is). But I do care, because I can imagine trying to either fix bugs or do small enhancements in weeks, or at most months, to the mess I just made. I’ll spend days trying to figure it all out just to make a tiny change (in fact, my experience is this still happens with most design and software these days, despite the methodology (and sometimes because of it)).
So where am I. Without any real stress testing it appears I can create and delete blobs, hurrah. But one big problem is a composite file is that any internal damage can cause a lot of data loss (in fact, maybe all). So something saved weeks ago gets lost during a crash saving something new today. I’ve experienced that before. So of course I added (as fun extra complexity) some redundancy (to confirm a blob is actually correct and intact) and also to recover a crashed file. That’s a good idea, but boy did it take a lot to implement. While all delete needs to do is find all the blocks in a blob and free them, that is probably less than 10% of all the code I wrote. The bulk of the code is various kinds of error checking and particular self-consistency checking (i.e. being skeptical that something else has trashed my blob, so don’t run off in the weeds while trying to delete or read it). Again, good idea, but really bogged me down.
So even though my methodology has slowed me down simultaneously I don’t really have as clean code as I need (even with no one giving me a grade on it, or complaining in reviews). If it’s such a mess I can’t easily keeping adding more functionality, without breaking everything else, I’ll end up being my own worst critic.
So, now, once again I’m optimistic – doing read will be a small extension to doing delete. We’ll see. With create, delete and read that’s enough to then integrate the compositeFile into the existing history stuff to actually persist shapes. Maybe tonight I’ll get that done if finally I manage to pick up the pace and I can report the milestone I expected to report several days ago.
I’ll be back
I’m still going to continue this project but have been distracted into something else that has totally adsorbed my attention, Project Euler. But I’m getting close to the end of what I can do there, so I’ll end my digression and return to this project, since all my readers are enjoying it so much.
Rate this: