Considerations of the file_wrangler_2 Base Class

CDFileRepresentation is the core, base class upon which file_wrangler_2 is built. For every file and folder a user of the program wants to potentially rename, one CDFileRepresentation stands in for that object. New file names are often derived from metadata of each individual file and folder of interest in a renaming session. For example, one may want the “modification date” or some sort of EXIF data inserted in the template-derived new file names. We don’t want to hit the filesystem repeatedly to request this information for 30,000 files over and over and over again. However, we need the information and CDFileRepresentation objects will cache this data for us.

The CDFileRepresentation class has to be able to instantiate itself quickly, providing the “most likely useful” information to the user immediately, but also needs to minimize its hits to the filesystem when the user requests certain types of data. Apple provides numerous ways of obtaining file metadata, including Cocoa’s NSFileManager’s attributesOfFileAtPath:error: , Core Foundation’s LSCopyItemInfoForRef(), and the Spotlight metadata via MDItemCreate().

I’ve been quite surprised at the amount of overlap in the data obtainable through these various methods, and also a touch disappointed that one or two items of interest (like, checking of an item is an Application or not) are excluded from some methods, but not others and so on. Basically, there doesn’t seem to be the “one true way” to obtain the information about a file that matches the user’s mental model of what is going on.

So, this means hitting the filesystem in at least two different ways to obtain all information that is of interest. An implementation pattern that Apple encourages is that of “lazy loading.” Basically it just means “don’t do the work until you’re asked for the information” and it has proven to be very successful in the design of the CDFileRepresentation class. Before implementing lazy loading, in initial testing under semi-idealized conditions, 1774 CDFileRepresentation objects took 2.7 seconds to instantiate.

After looking at the types of data a CDFileRepresentation needs to be able to model for the user, some ivars could be grouped by “most efficient method of extraction”. By breaking the code apart and extracting like-data upon request of any any arbitrary piece of data (creation date, for example), we can control how much time the user spends waiting for any given request. This has the nice effect of amortizing wait time over the length of any given file_wrangler_2 session. This also helps us to never load certain types of data the user may never request.

After these and other optimizations (for example, switching to the C struct LSItemInfoRecord to obtain certain booleans) I was able to reduce instantiation time up to 16x. It now takes 0.17 seconds to instantiate the 1774 objects and an additional (one-time only filesystem hit) of an additional 0.19 seconds to obtain the full metadata for those objects (additional requests are completed in about 0.09 seconds).

I will, of course, continue to research ways to reduce these times even more, but there will be a limit to what can be done and still provide the functionality everyone needs. This all begs the question, “How fast does it need to be?” and I would like to tackle that in a future post when I have more built around this class.

file_wrangler_2 notes and sketches

I feel I’ve been talking a lot of theory, but not showing anything for my work of late. Today is photo day. Perhaps you will glean a piece or two of information from these snapshots of my file_wrangler_2 design notes. They are (intentionally) fairly small and low-resolution as the intent is simply to reify the work I’m doing, not to show any specific design decisions. Picture #7 is probably the closest to the latest UI designs, and the rest are all observations of similar products and ruminations on file_wrangler’s role in a user’s workflow.

That is a “well” in the bottom 1/4 of the sketch into which “panels” may be placed, dragged, rearranged, twiddled, futzed, modified, and set. “Panels” refer to discrete blocks of interface that represent specific renaming functionalities. More on the specifics, later.

file_wrangler_2, further UI work

I believe I’ve narrowed in on the basic building blocks of the new file_wrangler_2. I’ve been designing and re-designing and re-re-designing, trying to get a handle on how to make the ideas in my mind’s eye fit with reality. Some ideas turned out to be overly ambitious, some were unwieldy, some were just plain BAD ideas.

Ultimately, what I came to realize was that I was defining the “vocabulary” for working with file names; and in the future this may be a similar vocabulary for work with other aspects of a group of files. There are a few things we need in an interface to make that happen:

  1. Define the Scope of the Action
    What is the target of the user’s actions? Yes, its a batch of files, but what SPECIFICALLY does she want to do with those files? Give them new file names? New folder names? Both? and thinking into the future… modify some aspect of metadata? Set the spotlight comments?… Dare I dream to FTP them? This starts to get into the question of, “What is the scope of file_wrangler?” but its liberating to dream of the potential and possibilities.
  2. Define the Target(s) of the Action
    As with the original Filewrangler, the file list is front and center and big, big, big. This is the reason someone is using the program; this is what is most important. There are other aspects of the interface that necessarily need some room on-screen, but we can still emphasize the file list’s importance by promoting it to the top of the window.
  3. Filter the Target(s)
    The same logic that allows certain renaming functions can also be used to target or exclude certain files in the file list. We COULD force the user to pre-filter before bringing files into the program, but that just seems antagonistic. The whole point of the program is to help you “wrangle” your files, which implies the files at that moment are unorganized. Some utility to refine the choice is absolutely necessary.
  4. Define the Data for the Scope
    In the case of file_wrangler_2 (at least, initially) the data is the file name. Tools for common renaming needs tend to be broken into a few concepts:

    • global and local name changes (make the whole name UPPERCASE vs. put the date in this exact spot)
    • custom or extracted data (insert a specific word vs. insert the modification date)
    • specific and relative changes (put a sequence before the name vs. insert the date before the 5th occurrence of the letter “V”, wherever it may occur)

    Further, we need to consider the basic actions performed on any data in any program in all of the course of history: CRUD (create, read, update, delete) which is really just CRD (update is a create and delete combo-action).

These four aspects of the program have essentially driven the design of the UI layout. The window is divided into four sections that correspond with the above mentioned concepts. As much as possible, I am using Apple’s Human Interface Guidelines to drive design decisions and reduce the learning curve. I believe its metaphors and physical behavior will be instantly familiar to most Macintosh users.

Open Apple’s Dictionary program on OS X and look at the Dictionary/Thesaurus scope buttons. This is my intention for defining the scope in file_wrangler_2.

Look at Filewrangler 1 to see how file lists are presented, but let us also look at the Finder to see how one will sort a file list. I envision a right-click on the column headers to add/remove additional data columns. Just as the Finder does, I also envision allowing direct editing of individual file names.

Setting the filters and setting the renaming choices is the big trick, but we can get a sense of how to handle such things by looking at Automator, but with a twist. I am working on “Build-a-Filter” and “Build-a-Name” wells into which filtering and renaming options are dropped, rearranged, and otherwise work a bit like Lego blocks. Each block represents a very focused, very discrete function of the program and the order of the blocks defines the order of those elements within the name. With each additional block, the interface becomes more dense, yet almost by definition its density increases only at the rate the user defines.

Eventually I came to realize that every user of every renaming program has different ideas about what is important and how best to perform renaming actions. I can only hope to satisfy a specific percentage with the first release, then expand my user base with dot releases. This realization was surprisingly liberating for the design process. I can NEVER make EVERYONE happy, but I will certainly do my best to build an excellent program with a consistent vision.

file_wrangler_2 UI Considerations

Spent the better part of last week (and will spend quite a bit of time this week) mocking up the UI for file_wrangler_2. The basic, driving concept behind the design decisions is in understanding how to break down renaming tasks into discrete, actionable units. While studying similar software (A Better Finder Rename, Renamer, etc.) I came to realize that my approach to the renaming process attacks the problem from the reverse angle.

Upon inspecting other file renamers, we can see that a group of folders/files is dropped into the application, then a series of tasks is performed on those folders/files. While this certainly gets the job done, it introduces a lot of repetition in the interfaces, and can make it difficult to understand how one task is affected by other tasks in a multi-step process. Does task C insert something before the 3rd occurrence of some text introduced in task B? Does task D then remove that insertion by mistake? The renaming steps in most programs are performed sequentially, but the process involved in each step may or may not be a relative change to the state of a file name. Some changes are global, some are relative, some are local, some are order-dependent, some are not, and so forth.

What I’ve been working on lately is understanding how to present a methodology that is as clear as possible about how a user-defined change will affect the file names. To do this means to flip over the interface conceptually and re-focus on why the user is using the program in the first place: to rename something. To rename something means she needs to build the blueprint for what the new name should look like. I wish to build a kind of “build-a-name” tool, rather than take that task-oriented approach. In other words, I want you to be able to tell file_wrangler_2, “Look, this is a template of how I want the naming to work. Do it like this.”

In my mock-ups I have created an interface concept that packs 80% of what A Better Finder Rename does into a window 2/3 the size of the Category/Action space on any given window of ABFR. No flipping between screens to get to the renaming actions, yet a definitively clear representation of what the user intends. This sounds like an incredibly dense interface, and it will be but only if the user desires it to be. This will be made clear in the coming weeks as I share a screenshot or two, but for now rest assured that the interface should allow for complex renaming tasks to be defined quickly and intuitively without overwhelming anyone with a hugely complex interface from the get-go.

I look forward to sharing more with you as I refine and finalize the designs.

P.S. – I am considering a name change for file_wrangler (née Filewrangler, née File Wrangler). Suggestions are welcome.

Review of “Core Animation for Mac OS X and the iPhone”

After finishing Aaron Hillegass’ Cocoa book during my “Cocoa Crunch” I hungered for some material that dug into specific frameworks more extensively. Notably, the Core Animation frameworks seemed to be essential knowledge these days for both iPhone development reasons and desktop OS X applications. When objects are manipulated by the user, she wants visual feedback about what will happen when the mouse-button is released, for example. Apple products always feature smooth transitions between states, the genie effect when minimizing a window on the desktop, the ripple effect when adding a new widget to Dashboard, the way menu items “make room” for a new object that will be dropped into a list, and so forth.

Of course, 3rd party developers have embraced these techniques over the past few years and the Macintosh shareware community has been able to raise the overall quality of the user experience as a result. The market now is more competitive from a “slick user experience” perspective than I ever recall seeing in the past. I knew I needed at least a little of this knowledge to provide a first class user experience for file_wrangler_2.

The Pragmatic Programmers website has a nicely designed online store for purchasing watermarked (with the purchaser’s name and time of purchase) downloading PDFs purporting to help one learn a variety of Macintosh technologies. Core Animation for Mac OS X and the iPhone by Bill Dudney is my first experience with one of their books, and I have to admit I feel let down.

Overall, I feel it covers the basic ground one would hope to see in such a book. It starts with a look at how Core Animation can be used at its most basic level, working on NSViews and gradually progresses into “full blown” Core Animation, using CALayer instead of NSView, then showing the different types of CALayer subclasses one can use.

We need an editor, stat! (Or to put it another way, what we need at this moment is a person who knows the skill of editing!)

My largest complaint with the book is that is needs editing, post-haste. Bill Dudney’s writing style is incredibly redundant, inefficient, somewhat poorly organized, and spins off into non-important issues. How many times were we “warned” about overusing animation effects in our applications? No offense to the author, but policing our use of Apple technologies is not his job. Is he so afraid he’s opening some Pandora’s Box upon the development world that somehow he will personally be held responsible when everyone’s interfaces start wiggling and jiggling for no reason? By page 39 of this 190 page book I had encountered such “warnings” enough times that I made a note to myself in the PDF margin, “Enough already!” Page 115, section 8.8, has a grievously redundant paragraph about the actionForKey: method.

Too hard for a beginner, too easy for a non-beginner

Dudney spends an inordinate amount of time explaining very basic concepts. Take the explanation of the Ease In / Ease Out curves, for example. Four pages of the book to show graphs that provide only a cursory amount of data and text descriptions that are redundant. If you tell me about “Ease In” and then tell me “Ease Out” has the opposite visual effect, I don’t ALSO need a full paragraph explaining what Ease Out looks like along with a bland graph. Why did the Ease In / Ease Out effects get so much explanation but other transitions did not? Contrast that with the OpenGL section and perhaps you can tell me who the intended audience of this book is?

In some ways he seems to target the beginner, yet I would argue that the book is not really for Cocoa beginners. He doesn’t explain code in anywhere near the level of detail the Hillegass book does, but he also writes as though he’s holding the developer’s hand a lot. He spares us from writing the code ourselves, as the book only contains a portion of the working code for any example (we really HAVE to download the pre-built examples to see what he’s talking about), but I’m not sure that is conducive to learning the frameworks very well. And that may be my biggest disappointment of the book. It seems too difficult for a beginner, as it assumes (rightly) an understanding of Objective-C, the Cocoa frameworks, AppKit, and so forth. Yet it also feels overly simplified for anyone with intermediate experience.

if (nil == [cocoa.accepted.formatting setFormat:dotVersus([self.format brackets])…

The examples in the book need a lot more polish and professionalism applied. The code is kind of haphazard and I found myself jumping up and down through a file to find a called method. When reading code this simple there tends to be a logical progression from method #1 to #2 to #3, yet the book’s code order does not reflect this logic. The code often contains unused ivars and methods. The code for rebuilding the Front Row menuing system has an ivar reference to a CIFilter for the bloom effect that isn’t used anywhere in the program. Yet I did see this filter being used in Apple’s sample code for building a similar menuing system, which strikes me as an odd coincidence.

The author also jumps around in his use (in my opinion, overuse) of dot notation and bracket notation, making the code kind of difficult to follow. @property and @synthesize make rare appearances and seems to only be injected when the author felt like it. No attempts at memory management seem to have been made. Odd use of syntax like “if (nil == someVariable)…” which is correct, but also reads kind of backwards to anything I’ve ever seen written by any other programmer ever. Basically, it just doesn’t feel like good Cocoa programming practices with any real forethought put into the examples. For that matter, the code in the Layer Scrolling and Geometry section doesn’t work right. Whether by Apple’s updates or not, the code has not been updated since June 2009 to provide a working solution to the problems there. I will post my own solution in the Codeshare later.

Oftentimes I would rewrite the code entirely, reorganizing and standardizing on one style, fixing the indents and removing the unusual end-of-line comments (tags for the publisher?). Suddenly the code’s intent was much clearer and easier to grok. I would have to recommend this course of action for anyone working through the book.

Suppressing the imagination

The examples themselves are kind of boring and seem slapped together. Take, for example, the Keyframe Movement example. A “heart” shape made of straight lines is placed awkwardly in the lower-left-ish corner of the window and a poorly lit graphic of a statue moves along the path. Some images float from right to left on the screen. The genie effect is half-heartedly implemented. Some drop shadows are applied to controls (although I did get a kick of of the pointillism effect on them). It did not exactly fire up my creativity, despite what he says on page 15, “Instead of trying to be your imagination, I attempt to spark your imagination. Often examples are contrived specifically to illustrate how something works or fits together rather than because they are a good fit for any particular application. I often choose the less-used effects or items to illustrate a point to try to spark your imagination…” (you may note the redundant use of the phrase “spark your imagination” in just this small excerpt). However, I can recall perhaps a single “less-used” effect in the entire book.

Should we feel “sparked” or “suppressed” when he claims, “We need to spend some time with this new framework building stuff that is gaudy and crazy to push the limits of what is possible.” then twenty pages later says, “Of course, we have to temper our imaginations by making sure that the animation is useful and not just eye candy.”

I can’t say I didn’t learn anything

I am impressed by Core Animation, but I can’t attribute that to this book. Yes, there were one or two examples that raised an eyebrow once or twice. Yes, I was surprised by how easy certain things can be animated. But that is really just a testament to Apple’s work on Core Animation, not because the author was particularly adept at making something complicated look easy. Basically he just made something that is already easy look easy, and I’m not entirely convinced that was worth the $22. I wanted to love this book, but I cannot recommend it over Apple’s free documentation and the plethora of free tutorials on the web.

How it can be fixed

  • edit the hell out of it
  • develop a few interesting projects that we develop over the course of a few chapters
  • pick a target audience and really cater to it
  • build on the teachings of Aaron’s book, adopting the code formatting and best-practices he teaches