Bridging the Gap Between Software Development and Localization

by on Jul.28, 2011, under facilitative leadership, localization, program management

Erin Vang moderates panel discussion on software l10n

Cross-posted from Lingoport.com

So, you’ve developed a new software application, and have high aspirations in terms of selling your application to a global audience. Now what? Problems often arise between developers, localization managers, and business managers due to perceived lack of support, time, and money.

This lack of understanding can lead to great frustration within the development tiers. Join us for an hour long online panel discussion and learn how some of the best known industry thought leaders are contributing to bridging the gap between software development and localization.

The panel features the following industry thought leaders and experts from the software development, content development, internationalization, and localization industries:

  • Val Swisher, Founder & CEO of Content Rules
  • Danica Brinton, Senior Director of International at Zynga
  • Dale Schultz, Globalization Test Architect at IBM
  • Edwin Hoogerbeets, Senior Internationalization Engineer at Palm
  • Adam Asnes, CEO & President of Lingoport

Online Panel Discussion: “Bridging the Gap Between Software Development and Localization”
Date and Times: Wednesday, August 3rd at 9:30am PT / 10:30am MT / 11:30am CT / 12:30pm ET
Registration: Register for free @ https://www1.gotomeeting.com/register/964415249
Where: Your desktop

Erin Vang, Owner of GlobalPragmatica will be facilitating the online panel discussion. Erin has over twenty years of expe­ri­ence in sta­tis­ti­cal soft­ware doc­u­men­ta­tion, qual­ity assur­ance, project man­age­ment, and local­iza­tion, most recently as Inter­na­tional Pro­gram Man­ager for the JMP Research and Devel­op­ment at SAS, and pre­vi­ously with Aba­cus Con­cepts and SYSTAT. She is currently designing a localization program for Dolby Laboratories.

This presentation is intended for technical managers, software engineers, test engineering managers, QA managers, internationalization and localization managers, technical writers, content developers, and anyone wanting to learn more on how to optimize their global software releases.

We’d love to hear from you. Please send any questions or topics you’d like to have discussed during this panel to Chris Raulf @ chris (at) lingoport.com.

Update 4 August 2011

The recording of our panel discussion is now available here.

Comments Off on Bridging the Gap Between Software Development and Localization :, , , , , , , , , , , , more...

Lessons from smart JSL mistakes

by on Jan.11, 2011, under JMP & JSL

This is a follow-up to my previous post, “A script to check and change a JMP preference ($2).

Background

Marianne Toft asked the JMP scripting group on LinkedIn a question about managing preferences with JSL:

Does anybody know how to read a specific setting from the Preferences? I need to read the status of ‘Use JMP locale settings’ and if 0 then change to 1 and give the user a message to restart JMP.

A $2 solution

I wrote a $2 script that solves the problem, and I sent Marianne a coupon code for a free copy, in thanks for posting such a thought-provoking JSL challenge.

My strategy is described in detail in that previous post, if you’d like to try writing it yourself with a bunch of pointers.

It’s also available as a $2 download if you’d rather just get the final code, fully commented and tested on JMP 8 and 9 on both Windows and Mac. One reason to consider buying this script instead of a tall drip is that the script is abstracted to check and change any preference, not just Use JMP Locale Settings( 0|1 ). That abstraction reveals some scripting tricks that might be helpful in your other scripting projects.

I’ll be delighted if someone else comes up with a more elegant solution, because mine is brute force. That’s because JMP doesn’t return the current preferences as an expression or a string or anything else you could potentially operate on with JSL. It just echoes the preferences to the Log window, so you need to read the text of the Log window and deal with that. If I’m missing something here, someone please enlighten me!

Several smart mistakes and lessons to learn from them

Several other people wrote helpful suggestions. Unfortunately, their code didn’t work, and we can all learn some important things about JSL by studying their smart mistakes.

Mark Anawi suggested using Show Preferences(Use JMP Locale Settings) ) to see the setting for just that preference. It’s a good guess at an argument for the Show Preferences() command, but it’s not actually a supported argument. It doesn’t work. You’ll just get the usual output for Show Preferences() without an argument.

Lesson: when you supply an argument JMP doesn’t understand, sometimes you get errors, but a lot of the time it’s just ignored, silently. You get no indication that you did something that doesn’t work. The only way you can be sure it was ignored is to try it again without the argument, or with a different argument, and check whether anything changed.

Peter Wiebe wrote an elegant solution that uses a For() loop to step through each Arg() of an expression, looking for and if necessary changing the preference in question. His code is concise and beautiful:

jmp_rulz = getpreferences();
For( i = 1, i <= N Arg( jmp_rulz ), i++,
    If( Contains( Char( Arg( jmp_rulz, i ) ),
        "Use JMP Locale Settings(0)" ),
        Preferences( Use JMP Locale Settings( 1 ) );
        New Window( "Restart JMP",
            Panel Box( "Restart JMP",
                Button Box( "OK", << closewindow )
            )
        )
    )
);

His code is far more elegant than mine. It’s an efficient strategy! Unfortunately, it doesn’t work, for several reasons.

Get Preferences() isn’t a command in JMP 8 or 9, so the first line returns an error:

Name Unresolved: get preferences in access or evaluation of 'get preferences' , get preferences()

In the following script, error marked by /*###*/
::jmp_rulz = get preferences() /*###*/

I assume that was just a typo, though. Peter meant Show Preferences(), but as I warned at the outset, that command doesn’t return an expression. It just echoes text to the Log window. So, after running the first line (with “get” changed to “show”), jmp_rulz contains . (missing).

Therefore, N Arg(jmp_rulz)i is never < 0, so the For() loop never runs.

I like Peter’s script better than mine. It should have worked—Show Preferences() really ought to return an expression so that his For() loop can step through it and look for the specific preference in question. Unfortunately it doesn’t. I hope our heroes in JMP R&D will consider improving this in a future version.

Why did Peter think this worked? Probably because when he ran it, he didn’t get any error messages. I didn’t either, and at first I was trying to figure out why his script worked when I’d already proven to myself that Show Preferences() doesn’t return anything into the jmp_rulz global.

He probably also checked the Log window after running it to confirm that the preference was on, saw that it was, and figured that it must have worked. He wouldn’t have expected to see his “Restart JMP” window unless it the setting was off to begin with, so he probably figured it had already been on.

Peter’s a clever scripter, by the way—whenever he posts something on LinkedIn, I make sure to read it, because I know I’ll learn something.

Lesson: Not getting error messages in the Log window doesn’t mean your script works.

Why should we care more than “Oops!”?

OK, we all make mistakes, especially when we’re writing JSL. (We do, right? Please tell me it’s not just me!) No big deal.

So why am I writing about these mistakes? Believe me, I’m not doing this to make anyone feel bad! They were both great suggestions, and they looked like they worked. Both Mark and Peter had good reasons to think they were correct.

I see some important lessons for JMP scripters.

Be aware that JMP has a lot of silent error conditions

Mark’s command Show Preferences(Use JMP Locale Settings) didn’t produce any error messages, and it did echo the current settings to the Log, so it was reasonable for Mark to assume that putting a specific preference as an argument to the command was a valid syntax variation that would show the setting of that specific preference.

This is a type of mistake I make all the time: I come up with a syntax improvement in my imagination or in my failing memory, one that isn’t real, and it seems to work, so I think it is real.

But it’s not. There are a lot of situations where JMP is silent about errors in JSL. Sending an unrecognized argument to a command is a typical example. Another is when you put something that needs to be evaluated—say, an arithmetic expression to set a parameter from a global—inside an object message or platform launch command, and it turns out that the particular message or command you’re using is not actually capable of evaluating its arguments. (JMP is inconsistent that way, unfortunately. Sometimes you can get away with it, sometimes you can’t, and you can only find out by testing.)

Be sure you know which kinds of errors are silent (and deadly)

This article would go on for a hundred pages if I tried to list every possible error and whether JMP will report an error message or not, but here are some of the most important things to know:

Some typical mistakes that usually produce error messages:

  • Operators that don’t exist, e.g. Until() instead of While()
  • Globals that don’t exist or haven’t been assigned values yet (or have had their values cleared with Clear Globals()
  • Using = instead of == as a conditional test, e.g. If(a=1, write("a"), write("not a")) would assign 1 to a, but JMP alerts you to the fact that you probably meant to test whether a equals 1 with a==1

Some typical mistakes that do not produce error messages:

  • Messages that don’t exist, e.g. Distribution[1]<<close; instead of Distribution[1]<<close window; just silently pretends to run, returning the name of the object (in this example, Distribution[]) as if it had done something to it
  • Arguments that don’t exist, e.g. Show Preferences(Initial Splash Window) instead of Show Preferences(All) simply runs as if you hadn’t included the unrecognized argument
  • Scoping mistakes, e.g. inside Formula(), any variable that you don’t explicitly scope, such as by putting :: before a global’s name, is going to be interpreted as a column name, and unless that leads to an error condition or some kind of unexpected behavior that you notice, you will never realize your mistake
  • Conditional mistakes, e.g. For() loops or other loops that never need to iterate simply don’t iterate, and they don’t tell you that they haven’t—unless you write some code to report on the iteration, e.g. you could set some global inside the For() loop and then check the global after the For() loop

Is it a bug when JMP doesn’t report an error?

Not necessarily.

In the case of invented messages not being flagged, my opinion is yes, that should be reported as an error. It’s too dangerous to think you’re accomplishing something and never realize JMP’s just ignoring you. But consider what the JMP developers are up against: JSL is so flexible that you can send lists of messages like obj << {mesg1, mesg2, …, mesgN}, and you can send messages to an obj << mesg group, and that’s just for starters. It would be hard to make the error-checking and reporting bulletproof.

What about invented arguments? Well, again, I’d say yes, if JMP can’t interpret something, it should say so. But again, consider what the developers are up against: most, but not all, commands in JSL can take arbitrarily complex expressions inside their parentheses. For example, myList={}; InsertInto(myList, 4) is a straightforward way to put something in a list, but you could also have it calculate the thing it needs to insert, e.g. myList={}; InsertInto(myList, 1+3). That calculation could be incredibly complex, involving If() tests and For() loops and all kinds of insanity. Any number of things could go wrong inside those calculations. How is JMP’s InsertInto() supposed to know that the problem is you made up an argument and not that you attempted a calculation that didn’t work out?

What about unscoped, mis-scoped, or insufficiently scoped variables? Hard to say. The name-resolution and scoping details of JSL keep improving with each new version of JMP, so that careful scripters can get better and better control of these kinds of problems, but for most scripters (and I include myself), the bigger problem is that we don’t realize when we’re not scoping carefully enough. For example, inside a Formula expression, any variables that aren’t scoped otherwise will get interpreted as operators (if one by that name exists) or as columns (if one by that name exists). If either of those exist, then the global you thought you were calling is not going to come into play. For example:

x=1; column("Age Next Year") << set formula(x + :Age)

That should add 1 to each Age column’s value and put it in the Age Next Year column, right? Right. As long as you don’t also have a column named “x”! If you do, it’s going to add the value in the Age column to the value in the x column and put it in the Age Next Year column; more precisely, it will do that for each row.

Or what about this:

For=1; column("Age Next Year") << set formula(x + :Age)

Will that work? Well, if you want to play along, open good old Big Class.jmp, create an Age Next Year column, and try these two scripts. First try the one with x=1. That’ll work fine since Big Class doesn’t have an x column. Now try the one with For=1.

What happens?

Do you think it worked? Well, you might—after all, the Age Next Year column has the right answers in it, and you didn’t get an error message in the Log.

But did it? Let’s check more carefully. Change the first bit to For=5 and run it again. Do you get values like 17, 18, 19 as you should?

No!

Do you get error messages?

No!

What’s going on? Remember, For is an operator! JMP sees a For() operator even though its () parentheses and arguments aren’t there. Since For has no arguments, it doesn’t do anything, and then it can’t add :Age to it because there’s no “it” to add it to, so the column is unchanged. JMP doesn’t think anything is wrong, because it didn’t see anything it couldn’t interpret. It knows For()! It just didn’t realize that by For what you really meant was 5!

The first time, when For=1, we didn’t realize the problem, because the Age Next Year column already had the answers we expected and we didn’t have any way of knowing they didn’t change because of an error rather than because the answers were the same. The second time, when we were expecting different answers, we had a chance of noticing our mistake—but only if we checked those answers!

What do you do if you actually do want to use a global that shares a name with an operator or a column? You scope it. Change it to ::For inside the Formula(), and you’re back in business.

So, it’s not clear that JMP is in the wrong when errors don’t get messages. It’s not necessarily a bug, although it certainly can be frustrating! We can all hope that these kinds of errors will be trapped better in future versions of JMP, but in the meantime, we need to take that responsibility ourselves.

Tips on interpreting error messages

JMP’s error reporting is quite helpful, but it can be frustrating at times. Here are a few tips:

  • Sometimes it’s hard to find the /*###*/ in the Log to see where your error is. Don’t forget about Edit/Find, or the keyboard shortcut Ctrl-F or Command-F!
  • Sometimes the /*###*/ will be in a misleading place. Start by investigating the thing that comes right before it, but if you’re sure that’s not in error, see if you can find some other problem that’s causing that thing to get read in some way other than what you meant, e.g. if you had a comma instead of a semicolon, it might be getting read as the “else” action in an If(), where you meant it to be an extra command in the “then” action.
  • When you get error messages about an unexpected or a missing ) or , (parentheses or commas), if the /*###*/ marker doesn’t help you, try getting some help from the Reformat Script utility. Try reformatting the whole script, and see where the cursor sits after you get the error message again. If you don’t see the problem nearby, try selecting chunks of the script and reformatting those. Keep going until you find the chunk of script that won’t format; your problem is inside that chunk somewhere.
  • Notice that the Reformat Script utility does helpful auto-indenting of your code, so that things happening inside other things will be indented further than their containers, and the closing ) will appear vertically-aligned to the command and opening ( that JMP thinks it corresponds to. Make sure that JMP’s alignment of )s matches what you think you’re doing. Getting messed up inside the parentheses is an especially common mistake when you’re writing custom display boxes.
  • Also try using the fence-matching feature: double-click on a parenthesis, and the Script Editor should highlight everything up to the matching parenthesis. See if it matches what you think it should; if it doesn’t, you’ve got one missing or extra somewhere. Note: one problem with the Script Editor’s fence-matching is that it won’t always select all the way up to a matching parenthesis; it’ll just do nothing when you double-click. This seems to happen when the chunk is too big—if the matching parenthesis is scrolled too far off-screen, JMP doesn’t even try. I hope this will be improved in a future version of JMP. In this situation, using an external programmer’s editor (such as jedit on Windows or BBEdit on Mac) can be helpful.

Be sure to test that your code is doing something

The smart JSL mistakes we saw above didn’t report errors, so the scripters didn’t realize anything was wrong. This brings up an important point: you need to test not only that the results you get are correct, but also that you’re getting results!

Mark’s error was to invent an argument. JMP’s response was to ignore the fictional argument. So how did he know it was a nonexistent argument and not just an undocumented one? The only way to be sure is to try the command twice—first without the argument, and again with the argument—and see if the results actually differ. If they don’t, that argument isn’t doing anything. Either it doesn’t exist, or you’re making some kind of a mistake in how you’re using it.

Peter’s mistake was not checking that his For() loop actually did any iterations. Since NArg() was zero, his i counter that started at 1 was never less than zero, so the loop didn’t do a single iteration. JMP skipped right over it. There are several ways to test for this kind of problem. The easiest way is just to put Write() statements inside the For() loop that will report what’s going on to the Log window. As long as you make sure to look at the Log and see that the messages you expect are showing up, that’s good enough.

But if your For() loop is happening as part of a larger program, you might not think to look for the absence of a message, right? In that case it would be better to lay a trap. For example, you could set a global right before the For() loop, do something to that global inside the For() loop, and then test the global after the For() loop. For example:

test=0;
For( i=1, i<6, i++,
    [ do whatever you need to do here ];
    test++;
);
if( test==0, throw( "The For loop did not iterate" ));

(Note: it wouldn’t necessarily be a mistake for a For() loop never to iterate. There might come a situation where you want to write an iteration test that takes advantage of For()‘s ability to decide whether to iterate or not.)

What are your issues with JSL errors?

What kinds of silent-but-deadly errors have you noticed? What kind of errors have you found it hard to track down? What tips do you have for trapping silent errors, or figuring out reported errors?

Please ask your questions and share your experiences in the Comments below. We’ll be happy to follow-up with replies to your comments or at greater length in future blog posts.

Comments Off on Lessons from smart JSL mistakes more...

A script to check and change a JMP preference

by on Dec.23, 2010, under JMP & JSL

Marianne Toft asked the JMP scripting group on LinkedIn a question about managing preferences with JSL:

Does anybody know how to read a specific setting from the Preferences? I need to read the status of ‘Use JMP locale settings’ and if 0 then change to 1 and give the user a message to restart JMP.

Several people had helpful suggestions, but unfortunately it’s just not a trivial problem. It’s a surprisingly tricky problem.

Challenges

First, by default Show Preferences() only shows the preferences that you’ve taken to change. You need to use Show Preferences(all) to see the defaults listed, too.

Second, Show Preferences(SomeSpecificPreferenceHere), although a good guess, doesn’t actually work. You’ll just get the usual output for Show Preferences() without an argument.

Lesson: when you supply an argument JMP doesn’t understand, sometimes you get errors, but a lot of the time it’s just ignored, silently. You get no indication that you did something that doesn’t work. The only way you can be sure it was ignored is to try it again without the argument, or with a different argument, and check whether anything changed.

Third, Show Preferences( [all] ) doesn’t return an expression. It returns missing. The information you need is echoed to the Log window, but it’s not returned as a string or an expression or a list or anything else you’d be able to do some work on. So you need to overcome that.

How to solve the basic problem

In JMP 9, you can Get Log(), which returns a list of strings, one for each line of whatever’s in the log. So to work efficiently, you need to Clear Log() first, then Show Preferences(all), then do Get Log().

Well! Now you have a list of strings, and you need to find the item in that list that is relevant, so you need to put a Contains() test inside a For() loop.

It’s a string, so you have to transform it into an expression with Parse() and some other bookkeeping, so that you can probe its argument with Arg().

Then check whether the argument is the desired one, and if not, change it, by editing the expression with Substitute() and then immediately doing Eval() on the result of that.

Now we need to let the user know we did something, and perhaps that they need to restart. So, put up a New Window() with a Text Box() saying that a preference has changed and they need to restart. Include a Button Box() for “OK” that closes the alert window.

So, that’s the gist of the strategy.

Abstract the script

But, why write all this just for this one specific preference? Why not write it to check and if necessary change any preference?

So, start out with a couple globals that set the preference and the desired value.

But wait! Marianne’s example involves a numeric argument, but other preferences have text arguments; consider Use JMP Locale Settings(0) vs. Report Table Style("Plain"). So we need to make sure our script can work properly whether the particular preference takes a numeric or string value.

And while Marianne’s example requires a restart for the changed preference to take effect, most preferences do not. Might as well set a restartNeeded=1 if it’s important, or 0 if it’s not.

In that alert window, we only need to tell them to restart if it’s important, not if it’s not, so let’s add an If Box() around the Text Box() that only shows the instruction if it’s needed.

If the preference was what we wanted in the first place, we should probably echo something to the Log window, just so we know it ran, if nothing else. We need a Write() statement for that.

Which version of JMP?

But wait, there’s more! The Get Log() command didn’t come along until JMP version 9. If you haven’t been able to upgrade yet, then you need to take another strategy to this whole problem.

There might be a better way to do this, but the only way I could find was to Save Log() to a text file, then Load Text File() to a string, then use Substr() and a bunch of arguments with Contains() to chop out the single preference we care about. From there, the script runs about the same way.

And we need to put all this inside a test for JMP Version(), which returns a string, and usually we need to Trim() it and then do an inequality test, e.g. If( Trim( JMP Version() ) > "9", …), where the first argument is the Get Log() strategy described first, and the second argument uses the Save Log() strategy.

What about nested preferences?

Yet another problem! The script so far deals with top-level preferences with simple, single arguments, either numeric or character. But some preferences are trickier, e.g.,

Preferences(
  Fonts(
    English(
      Monospaced Font("Courier", 10)
    )
  )
);

In this case, the Parse() line will need to be more elaborate, and you’ll have to nest more Arg()s around it to dig down to the particular setting value of interest. Conditioning for such a situation is left as an exercise for the reader, primarily because it’s a hassle, it’s not what Marianne needs, and the syntax of the Preferences() command in JMP is arbitrary enough that we can’t really write code today that will be future-proof; we don’t know how deeply nested a given preference might be, nor what kind of arguments it might expect.

Buy now!

Contact me if you’re interested in purchasing this script or commissioning one like it.

Comments Off on A script to check and change a JMP preference more...

Erin Vang to moderate upcoming events

by on Dec.09, 2010, under facilitative leadership, localization

I’m pleased to announce that I’ve been asked to facilitate several upcoming roundtable events:

Virtual Roundtable: Shrinking the triangle; Is it possible to achieve good, quick, and cheap in localization? on the web on 20 January 2011

From Chris Raulf:

I recently posted the following question on LinkedIn: How do you achieve good, quick, and cheap in localization?

Having worked in the industry for the last decade (on the customer-side as well as on the vendor-side in production, sales, and marketing), it seems that one has to pick and choose two out of the three: Good, quick, and cheap. My intention by posting this question on LinkedIn was to get the opinions and insights of a wide variety of fellow industry professionals (customer and vendor-side) and, oh boy, it seems like everyone has a strong opinion on this topic.

Well, the LinkedIn discussion is still going on but I’d like to take this discussion to a different level and actually have industry experts talk about it in a virtual Roundtable.

I’m currently working on assembling a panel group of opinionated and expert industry players from the translation-side, localization vendor-side, internationalization-side, content development-side, tools and technology-side, as well as from the customer-side.

So far I’m happy to present the following panelists:

Roundtable facilitator: Erin Vang, Owner of GlobalPragmatica

Renato Beninatto, President of the European Language Industry Association (ELIA)

Jennifer Beaupre, Director of Global Marketing at acrolinx GmbH

Adam Blau, Director of worldwide sales at Milengo

Adam Asnes, President & CEO at Lingoport

Michael Fruhwirth, Owner of Technical Translations

Mylène Vialard, Owner and Senior Translator at Mylene Vialard Translations

Daniel Goldschmidt, Co-founder at RIGI Localization Solution

The goal of this virtual Roundtable is to stimulate debate, learn about our challenges, discuss potential solutions, etc. and see if we can come away with new ideas that will help us cope with the “Fast, Cheap, and Good Quality” triangle.

Localization Technology Roundtable in Palo Alto on 3 February 2011

The best conversations happen when the right people get together

The Localization Technology Round Table brings together 5 industry leaders to present an open technology framework that speeds up time to market and drastically reduces your localization costs.

Together, Lingoport, Acrolinx, Clay Tablet, Milengo and Asia Online will show how advanced, modular localization technology addresses the challenges faced when launching products or services to international markets in multiple languages.

You’ll learn the key considerations when taking an international product from design to launch through, Internationalization,  Information Authoring,  Content Management,  Localization and Translation Automation.

And you’ll learn how this is achievable quickly, and with fewer resources, while maintaining a consistent brand and user experience that builds value, saves time and reduces costs.

  • Access a wealth of localization experience from industry experts
  • Discover new technologies and new ways of working that are already changing the localization landscape
  • Learn strategies that can streamline your localization efforts and help you quickly launch products worldwide
  • Share information with like-minded peers and learn proven practices that you’ll find nowhere else

Agenda for the Localization Technology Round Table in Palo Alto

Speakers’ biographies

Please contact us if you’d like to hire me to moderate and/or facilitate your event.

Comments Off on Erin Vang to moderate upcoming events more...

Mandelbrot and music: on listening in fractal dimensions

by on Oct.25, 2010, under random

Benoit Mandelbrot died this month. He was the guy who came up with fractal theory, which led to all those gorgeous computer graphics like this one, from Wikimedia Commons:

A Mandelbrot set

Last week, my friend and contradance bandmate Tina Fields wrote an essay about Mandelbrot’s ideas on her blog, Indigenize! I found it quite thought-provoking, and it surprised me how much I learned from her post, since I’m the one with the math degree. My next surprise was how Tina’s thoughts on this mathematician inspired me to think about listening to music.

This essay is in response to ideas she raises in her essay, so go read hers first and then come back here!

First I’d like to amplify her comment about coastlines by quoting this passage from Mandelbrot’s obituary in the New York Times, about how coastlines played a role in the genesis of his theory:

Dr. Mandelbrot traced his work on fractals to a question he first encountered as a young researcher: how long is the coast of Britain? The answer, he was surprised to discover, depends on how closely one looks. On a map an island may appear smooth, but zooming in will reveal jagged edges that add up to a longer coast. Zooming in further will reveal even more coastline.

“Here is a question, a staple of grade-school geometry that, if you think about it, is impossible,” Dr. Mandelbrot told The New York Times earlier this year in an interview. “The length of the coastline, in a sense, is infinite.”

In the 1950s, Dr. Mandelbrot proposed a simple but radical way to quantify the crookedness of such an object by assigning it a “fractal dimension,” an insight that has proved useful well beyond the field of cartography.

To me, that’s the real genius of his discovery—viewing scale as a dimension. If we measure the coastline or the surface of the broccoli from a mile away we get a much different answer than if we measure it from close up and far different still if we measure under a microscope.

So what is scale, really, but a matter of perspective?

Let’s consider the metaphorical potential: if perspective is a dimension, how does it change the way we view truth about our world? You have some truth, I have some truth, and the differences are not necessarily contradictions but spectral variations along the perspective dimension.

Tina’s big gift to me in her essay isn’t so much her point about Mandelbrot’s focus on verbs rather than nouns, although I enjoy that, too, but her encouraging us to think about new things fractally. The first thing that comes to my mind is Beethoven. (Perhaps I should explain that besides working in statistical software and facilitative leadership, I’m also a professional horn player and hold degrees in music performance and music history.)

Beethoven leads my pantheon, and here’s a bit on why: his compositional technique is extraordinary, and the more you know about musical composition and performance, the more you hear in his work. In addition to doing all the usual classical things—the usual structural designs (four-movement symphonic architecture with movements in sonata, menuet or scherzo, sonata-rondo, etc. forms, linked in a progression of related tonalities, yada yada Haydn, blabbety-blabbety Mozart, blah blah Bach), German-Italianate phrases, symphonic devices of his environment and era—he throws in a few more tricks all his own, chief among them his idea of motivic development.

His every melodic gesture is built up from the smallest motives, e.g. his Fifth Symphony‘s four-note “ba-ba-ba-BOM!” opening. That simple four-note figure is sequenced, layered, mutated, and warped all throughout the first movement, each phrase a new assemblage of basic building blocks, each harmonic gesture arising out of layers and layers of sequences of this tiny musical block and several others.

You can easily find YouTube and other recordings of Beethoven 5 if you’d like to remind yourself how it goes, but I’d recommend buying yourself a great recording. There are many excellent options; one I’d particularly recommend is Bernstein’s with the New York Philharmonic.

All the composers of Beethoven’s time (and throughout most of history, with differing vocabularies, of course) have adhered to various conventions from the largest possible scale (the arc of their developmental style through their lifetimes) down through the structure of each opus, each movement within, etc., down to the smallest-scale assumptions about harmonic structure, idiomatic styles of individual instruments, and so forth, but Beethoven brings it all to a whole new level, honoring all those formal rules while also constructing everything both melodically and harmonically, both vertically and horizontally in each case, out of these tiniest of musical blocks.

(We later see Wagner up Beethoven’s ante with his Romantic adaptation, the leitmotiv, where each character, event, place, and even philosophical concept is represented by its own fragment of musical DNA, all these leitmotivs swirling in a pan-theatrical operatic swamp of continuous through-composition, rejecting while also embracing formal conventions in a megalomaniacal Gesamtkunstwerk.)

Struggling valiantly now to pull back from this tangent to return to fractal theory, I might suggest that we appreciate Beethoven and indeed all music along fractal dimensions. For many, Beethoven’s Fifth Symphony is, simply, its opening four notes and the loud romp to follow. The scale of observation is large; the perspective is simple. “Fun music!”

Indeed, who wouldn’t appreciate it on such simple terms? When I was hospitalized with pneumonia as a second grader, my parents brought me the best of all possible get-well presents: a portable cassette deck, including a cassette of the first movement of my favorite symphony, which dad had recorded by sitting next to the phonograph (mono, of course) holding the mic near the cabinet speakers while the needle rode its groove. I listened to that tape over and over during my several weeks of long days alone in a hospital room. I’m not sure what I heard, exactly, but I know that by the time I was discharged, I could have sung the whole movement. (I wish he’d recorded the whole symphony for me, because I’l never know the rest of it nearly as well.)

As I’ve developed as a musician, I’ve lost touch with how I used to hear music. I often wonder what normal people hear, and I like to ask people to tell me why they like certain music or what they noticed in a concert.I know that I used to hear the pretty music, and while I can tell you to the minute when it all changed, I can’t for the life of me remember what I used to hear.

It changed the summer after eighth grade. I was at orchestra camp, sitting in a muggy auditorium on a hot summer night, and probably intoxicated by the pheromones of my new friends. We listened to a piano quartet recital. First I noticed that I was hearing a group whose intonation was so tight, they made the freshly, expertly-tuned Steinway sound out of tune. All pianos are out of tune, but it was the first time I heard it for myself. Then I realized I was hearing four virtuosi playing the crap out of their instruments as both individuals and as a collective.

Then my trumpeter friend leaned over and said, “You know, we’re never going to hear music like normal people again,” and for only a moment I wondered what he meant. I spent the rest of the concert hearing, seeing, feeling the compositional structure, the interplay of themes, the exploration of key areas, the work of the individuals and their ensemble, and on and on. The only limits to the depth of scale in my listening were my musical intelligence and attention span.

That night was my awakening as a listener. In the decades that followed, my musical intelligence has evolved tremendously, but I still find that the richness of what I hear is limited only by my abilities and attention span.

So, locating my metaphor in the area of musical perception, I might suggest that our listening has a fractal dimension. Anyone can hear the sounds. But our perspective—the granularity of our musical knowledge and the intensity of our focus—determines in how large a range along the fractal dimension we perceive the music; how much we hear of the infinite possibilities depends on how large or small is the scale of our listening.

How do you hear?

As I said, I’ve long since forgotten how I used to hear music. How do you hear music? What do you hear in Beethoven’s Fifth Symphony? Do you have any musical training? How does this affect your listening (or not)? I’d love your answers, reactions, ideas—please comment!

Comments Off on Mandelbrot and music: on listening in fractal dimensions more...