Luke 的个人资料lzcd照片日志列表更多 工具 帮助

lzcd

Cheaper than kittens
6月1日

The templating engine that no talks about… at least not in front of the children

Here’s a little experiment for you to try in Visual Studio 2008:

  • Create a project – it doesn’t matter what sort but I’m using C# console app for this example
  • Add a new text file and give it the extension of .tt
  • Add the following lines to it:

<#@ template debug="true" #>

<# WriteLine(“Hello “); #>World

Now if you save the file you should note that there’s a little “code behind” file hiding below the .tt file in much the same fashion as a WinForms or an ASP.Net control.

And if we open it up we can see that it the result of the .tt file being executed as if it was a template:

Hello World

So viola! We have a templating engine built right into Visual Studio and there you were just about to spend big dollars on a third party solution. Don’t you feel silly now?

Well you shouldn’t feel quite so bad… yet… as the templating engine, T4 (as it’s officially known by Microsoft as) is all very nice but it’s not quite what I’m usually looking for in a templating engine. Quite often in such scenarios, what I want to do is grab some templates, grab some data and mix them all together en masse using a funky little console app to generate all sorts of weird and wonderful files for me. T4 just looks like it’s dealing with one file at a time and, even more annoyingly, I seem to need to be in Visual Studio to use it. This just won’t do.

So how we do fix this?

It just so happens that we can host the T4 scripting engine ourselves and do all sorts of weird and wonderful things with it. The “catch” is that if you do a search through the MSDN doco or related blogs on the T4 engine you’ll come across a boat load of API stuff that can all look rather intimidating. The good news is that we’re going to be producing a working host with little to no effort at all.

(Cue fanfare)

Presenting: Luke’s ultra quick starter guide to producing your own template crunching utility!

In this example I’m going to be constructing a console app that takes a template file, a set of command line arguments and combines them together to produce a new file. It’s not exactly the most spectacular bit of technology around but it should hopefully get you on your way enough to produce you very own ultimate templating processing machine.

Sooo…. the steps are as follows:

  • Create a console app project
  • Track down a copy of the Microsoft.VisualStudio.TextTemplating.dll file and add a reference to it. (The MSDN docs will tell you that you can get the file as part of the Visual Studio SDK… but Visual Studio actually secretly places a copy in the GAC which you can copy to you project folder manually if you’re feeling really sneaky)
  • Add the following code your Program.cs file:

static void Main(string[] args)
        {
            if (args.Length == 0 || !File.Exists(args[0]))
            {
                Console.WriteLine("Usage:");
                Console.WriteLine("CodeGen script [field0] [field1]...");
                return;
            }

            var commandLineArguments = new List<string>(args);
            var templateFilePath = commandLineArguments[0];
            var host = CreateHost(templateFilePath, commandLineArguments.Skip(1).ToList());
            var template = File.ReadAllText(templateFilePath);
            Engine engine = new Engine();
            var output = engine.ProcessTemplate(template, host);
            if (host.Errors.HasErrors)
            {
                foreach (var error in host.Errors)
                {
                    Console.WriteLine(error);
                }
                return;
            }

            var outputFilePath = Path.Combine(Path.GetDirectoryName(templateFilePath), Path.GetFileNameWithoutExtension(templateFilePath));
            File.WriteAllText(outputFilePath, output, host.FileEncoding);
            Console.WriteLine(outputFilePath + " Generated");
        }

        private static Host CreateHost(string templateFilePath, List<string> commandLineArguments)
        {
            var host = new Host();
            host.TemplateFile = templateFilePath;
            host.FileExtension = "";
            host.FileEncoding = Encoding.UTF8;
            host.StandardAssemblyReferences = new List<string>() { typeof(System.Uri).Assembly.Location };
            host.StandardImports = new List<string> { "System" };
            host.CommandLineArguments = commandLineArguments;
            return host;
        }

Most of this is quick and nasty throw away code (and not something I usually write… or at least admit to) so you can ignore most of it.

The valuable bit that is worth noting is the code that creates an instance of T4’s template Engine class, feeds it a template file along with a mysterious thing called a host and magically churns out a brand new file from it.

I’d suggest thinking of the Host as the middle man between your utility and the T4 templating engine… which brings us nicely to the next step which is…

  • Create a Host class and paste the following code into it:

[Serializable()]
  public class Host : ITextTemplatingEngineHost
  {
      public string TemplateFile { get; set; }
      public string FileExtension { get; set; }
      public Encoding FileEncoding { get; set; }
      public CompilerErrorCollection Errors { get; set; }
      public IList<string> StandardAssemblyReferences { get; set; }
      public IList<string> StandardImports { get; set; }

      public bool LoadIncludeText(string requestFileName, out string content, out string location)
      {
          content = string.Empty;
          location = string.Empty;

          if (!File.Exists(requestFileName))
          {
              return false;
          }

          content = File.ReadAllText(requestFileName);
          return true;
      }

      public object GetHostOption(string optionName)
      {
          switch (optionName)
          {
              case "CacheAssemblies":
                  return true;
              default:
                  return false;
          }
      }

      public string ResolveAssemblyReference(string assemblyReference)
      {
          if (File.Exists(assemblyReference))
          {
              return assemblyReference;
          }

          var candidate = Path.Combine(Path.GetDirectoryName(this.TemplateFile), assemblyReference);
          if (File.Exists(candidate))
          {
              return candidate;
          }

          return string.Empty;
      }

      public List<string> CommandLineArguments { get; set; }

      public Type ResolveDirectiveProcessor(string processorName)
      {
          if (string.Equals(processorName, "CodeGen", StringComparison.InvariantCultureIgnoreCase))
          {
              CustomDirectiveProcessor.CommandLineArguments = CommandLineArguments;
              return typeof(CustomDirectiveProcessor);
          }
          throw new Exception("Directive processor for " + processorName + " not found");
      }

      public string ResolvePath(string path)
      {
          if (string.IsNullOrEmpty(path))
          {
              throw new ArgumentNullException("path", "Path cannot be null");
          }

          if (File.Exists(path))
          {
              return path;
          }

          var candidate = Path.Combine(Path.GetDirectoryName(this.TemplateFile), path);
          if (File.Exists(candidate))
          {
              return candidate;
          }

          return path;
      }

      public string ResolveParameterValue(string directiveId, string processorName, string parameterName)
      {
          if (string.IsNullOrEmpty(directiveId))
          {
              throw new ArgumentNullException("directiveId", "Directive cannot be null");
          }
          if (string.IsNullOrEmpty(processorName))
          {
              throw new ArgumentNullException("processorName", "Processor cannot be null");
          }
          if (string.IsNullOrEmpty(parameterName))
          {
              throw new ArgumentNullException("parameterName", "Parameter cannot be null");
          }

          return string.Empty;
      }

      public void SetFileExtension(string extension)
      {
          FileExtension = extension;
      }

      public void LogErrors(CompilerErrorCollection errors)
      {
          Errors = errors;
      }

      public AppDomain ProvideTemplatingAppDomain(string content)
      {
          return AppDomain.CreateDomain("Generation App Domain");
      }

      public void SetOutputEncoding(Encoding encoding, bool fromOutputDirective)
      {
          FileEncoding = encoding;
      }

  }

So now we have templates and a way to generate them. The thing that’s missing is a way to feed information from the outside world into the templates and the way we do this via Directive Processors. I’ll leave the fun of reading up about the specifics of these little beasties on MSDN as an exercise for the reader but here’s one I created earlier:

  • Create a new code file named CustomDirectiveProcessor and paste the following code into it:

public class CustomDirectiveProcessor : DirectiveProcessor
   {
       private const string includeArgumentsKeyword = "includeArguments";
       public override bool IsDirectiveSupported(string directiveName)
       {
           if (string.Equals(directiveName, includeArgumentsKeyword, StringComparison.InvariantCultureIgnoreCase))
           {
               return true;
           }

         return false;
       }

       public CodeDomProvider Provider { get; set; }
       public string TemplateContents { get; set; }
       public CompilerErrorCollection Errors { get; set; }
       private StringBuilder codeBuffer;

       public override void StartProcessingRun(CodeDomProvider languageProvider, string templateContents, CompilerErrorCollection errors)
       {
           Provider = languageProvider;
           TemplateContents = templateContents;
           Errors = errors;
           codeBuffer = new StringBuilder();
       }

       public static List<string> CommandLineArguments = new List<string>();

       public override void ProcessDirective(string directiveName, IDictionary<string, string> arguments)
       {
           var options = new CodeGeneratorOptions()
           {
               BlankLinesBetweenMembers = true,
               IndentString = "    ",
               VerbatimOrder = true
           };

           if (string.Equals(directiveName, includeArgumentsKeyword, StringComparison.InvariantCultureIgnoreCase))
           {
               GenerateCommandLineArgumentProperties(options);
           }

       }

       private void GenerateCommandLineArgumentProperties(CodeGeneratorOptions options)
       {
           for (int argumentIndex = 0; argumentIndex < CommandLineArguments.Count; argumentIndex++)
           {
               var property = new CodeMemberProperty()
               {
                   Name = "Argument" + argumentIndex,
                   Type = new CodeTypeReference(typeof(string)),
                   Attributes = MemberAttributes.Public,
                   HasGet = true,
                   HasSet = false
               };

               property.GetStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(CommandLineArguments[argumentIndex])));

               using (StringWriter writer = new StringWriter(codeBuffer, CultureInfo.InvariantCulture))
               {
                   Provider.GenerateCodeFromMember(property, writer, options);
               }
           }
       }

       public override void FinishProcessingRun()
       {
           Provider = null;
       }

       public override string GetClassCodeForProcessingRun()
       {
           return codeBuffer.ToString();
       }

       public override string[] GetImportsForProcessingRun()
       {
           var thisNamespaceElements = this.GetType().ToString().Split('.');
           var thisNamespace = string.Join(".", thisNamespaceElements.Take(thisNamespaceElements.Count() - 1).ToArray());
           return new string[]
           {
              thisNamespace
           };
       }

       public override string GetPreInitializationCodeForProcessingRun()
       {
           return string.Empty;
       }

       public override string GetPostInitializationCodeForProcessingRun()
       {
           return string.Empty;
       }

       public override string[] GetReferencesForProcessingRun()
       {
           return new string[]
           {
               this.GetType().Assembly.Location
           };
       }
   }

So what does this directive processor do exactly? Well I’m glad you asked. :)

It allows us to extend the templating engine with our own functionality. In this case, we’re going to make it so that when some adds the following bit of code to their templates, we’re going to magically read in the command line arguments and supply them as properties:

So the only thing left to is to try it out on a template…

  • Create a textfile somewhere on your machine with the extension of .cs.txt (e.g. HelloWorld.cs.txt) and paste the following code into it:

<#@ template debug="true" #>

<#@ includeArguments Processor="CodeGen" #>

<# WriteLine(Argument1 + " contains " + Argument0); #>

  • Run the utility with the path of the textfile as the first argument and some random words as the second and third command line arguments (e.g. c:\temp\helloworld.cs.txt France Paris )

Hopefully you should see a brand new cs file in the folder your textfile resides in with some content (not entirely useful content I’ll admit… but template driven content none the less)

If you go back and examine the mysterious entity that is the CustomDirectiveProcessor class a little more thoroughly you may notice a few odd looking things:

  • I pass the command line arguments in via static property. Yep. As it’s the templating engine that creates the instances of processors as it needs them, the only way to “communicate” between our application code and the processors is via statics. (Actually there’s quite a few ways… but this was the simplest I could think of at the time and it required the least amount of architectural magic to get it working.)
  • We’re creating the properties using the CodeDom. Yep. The way the DirectiveProcessors influence the templates is via adding code dynamically. If you’re looking to do something slightly more heavyweight… or you just dislike generating code via the CodeDom intensely, there are less ugly ways to do so… but require a whole lot more time and effort than this demo warranted.

So now you know how to harness the inbuilt goodness that is the T4 templating engine for your evil purposes.

Oh… and before I forget: One last little party piece…

  • Add the following line to the end of your template text file:

<# System.Diagnostics.Debugger.Break(); #>

..and rerun your console app.

If you’ve got Visual Studio kicking around you should now be looking at one fully fledged breakpoint. Yep you can break and step through your templates just like any other Visual Studio code. It even supports variable inspections. Pretty cool, no?

Now all that’s left is to go forth and template yourself silly.

Enjoy.

4月8日

Game Writer’s Tip: The three R’s are not invited to the party

Whilst Readin’, wRitin’ and aRithmetic may have helped many people become the fine product members of society they are today, they generally don’t tend to appreciate being forced into doing such things in the course of learning how to play your game.

The first reason for this is the rather boring reality of attempting to read any reasonable amount of text on a television (even one of the lovely wall sized flat panel jobbies) is rarely enjoyable. If it’s any more than about six words or any smaller than around 1/10 of the available screen space in size then a lot of your users are going to either endure horrible amounts of eye strain, skip past as quickly as possible or just plain give up before they’re more than a paragraph into your amazing narrative.

Reason number two is possibly even more annoying but, none the less, just a true: People rarely read anything on a computer screen.

Oh sure they may read the stuff that they’re actively seeking or writing (such as the latest celebrity gossip or the Facebook message to the distant relative some far off land) but just about everything else is either ignored or feared. And it’s not just those luddites or generationally challenged members of your office or family either.

When was the last time you actually took the time to read a dialog window?
I mean *actually* read it.

It’s not that often is it?

Okay so if nobody is going to read anything we put up on screen, how do we inform them of all the good stuff like plot… or how play the game?

If it’s something that you want to the user to do then best way to teach them is the same way as we learn in real life: by doing it.

For example, if you want to teach the user that moving the left thumbstick moves their little avatar around the screen, why not show them the avatar on screen and let them experiment. Maybe provide a little short term goal to motivate them such as picking up an item or moving out of impending (but probably not real) danger?

If it’s something about the plot / narrative of the story that you wish top convey then text can certainly work… but it’s best used vary sparingly (think along the lines of a twitter message or less) and usually as back up for some other means such as a voice over.

Pick practically any really successful console game (from Mario through to Gears of War) and you’ll spot the signs. Very little text up on screen at any one time, Learning via experimentation and so forth.

3月5日

Sordid documentation revealed

We open this little story with David and Ducas having an IM conversation over Ducas' choice of "why is documentation so boring?" as an IM tag line:

David Burela said: you just need to punch it up a little

David Burela said: add a little drama

Ducas said: so, explain a crud wcf service with drama...?

David Burela said:

"They had a contract which destined them to meet. Although they met and shared something important, the encounter was only a temporary connection. Although they are now disconnected from each other, the memory shall persist on"

Which tickled the fancy of David and prompted him to pose the question to the internal Readify Tech list:

Anyone else got some good soap drama between components?
A Romeo and Juliet story between C# & VB?

To which I initially replied:

C# eloping into the night with VB.Net?

I'm having trouble picturing that... although I must admit to finding the thought of a known fan of C# such as... say... Mitch... reciting the something like the following brings a small smile to my face:

But, soft! what light through yonder window breaks?
It is the east, and VB is the sun.
Arise, fair sun, and kill the envious C#,
Who is already sick and pale with case sensitivity,
That thou her maid art far more productive than she:
Be not her maid, since she is envious;
Her rampant punctuation is but sick and green
And none but fools do wear it; cast it off.
It is my lady, O, it is my love!

Me, being the big meanie that I am, couldn't go past the opportunity to have some gentle jest with the words of one of my favourite authors mixed with a product that has consistently broken my geeky heart:

It is important to note that suddenly, and against all probability, a SmartPhone had been called into existence, several miles above the surface of an alien planet. But since this is not a naturally tenable position for a SmartPhone, this innocent creature had very little time to come to terms with its identity.

This is what it thought as it fell:

'Ahhh! Whoa! What's happening? Who am I? Why am I here? What's my purpose in life? What do I mean by 'who am I'? Okay, okay, calm down, calm down, get a grip now. Ooh, this is an interesting sensation. What is it? It's a sort of a tingling in my... well, I suppose I better start finding names for things. Let's call it a... pen! Yeah! Pen! And hey, what's this roaring sound, whooshing past what I'm suddenly gonna call my screen? Wind! Is that a good name? It'll do. Yeah, this is really exciting! I'm dizzy with anticipation! Or is it the wind? There's an awful lot of that now, isn't it? And what's this thing coming toward me very fast? So big and flat and round, it needs a big wide sounding name like 'Ow', 'Ownge', 'Round', 'Ground'! That's it! Ground! Ha! I wonder if it'll be friends with me? Hello Ground!'

But after thinking about for a while over lunch, I came up with following, slightly more serious, response:

Documentation for fun and profit

I'm a huge fan of making documentation interesting (and hopefully fun) and have no idea what the point of producing dull documentation is.

If the point of documentation is to communicate an idea then seems to make very little sense to sabotage that concept with a delivery mechanism that is actively discouraging that very act.

Imagine your intended audience. If they're going to be struggling to stay awake during the discourse of your little phonebook style tome and resentful afterwards for having to loose a portion of their lives wading through it, what do you think the chances them actually retaining any of the supposedly important information is?

There are two objections to producing "interesting" documentation that regularly get put forward and I'm yet to be convinced by either one of the them:

The Corporate Image

The classic 1950's "You're here to work, not have fun! Pull your socks up! Straighten your tie!" attitude continues to haunt a lot of us to this day. We feel guilty about anything that drifts away from the stern approval of the stereotypical "bank manager" type from our (grand) parents day. If it's fun it mustn't be work related.

To that I say "Pfft!".

Documentation is just like anything else your company produces. It has the chance to entice, enrapture and engage your customers and staff... or it can put them to sleep.

It's the 21st century and guess what? Nobody is interested in being bored to death by reams of tedium.

You wouldn't dream of spending hundreds of man-hours and squillions of dollars each year producing bad advertising and marketing would you? Well that's what a lot people do with documentation.

They spend who knows how many hours and dollars describing their wonderful new creations... in a format that so tedious and boring they may as well have just locked the product and the documentation in the basement for all the good it's going to do.

Bob from Accounting

(Apologies for falling back on yet another bad stereotype here but I get the feeling that using geeks as a negative example would be detrimental to my cause :)  )

The second objection to producing interesting documentation is that not everyone can do it. Whether it's a beautiful menagerie of Visio diagrams or a 'page turner' of a description, not everyone has it in them to produce interesting material.

My argument to this is: don't make them.

Just like you wouldn't attempt to force a dentist to fix a jet airliner engine, don't force people who can't write to write.

There's little point.

At best, you and your customers survive the trip. At worst, its a grizzly mess of morale nose dived into the ground and a whirlwind of large paper doorstops scattering across the neighbourhood.

If you don't have someone in your organisation who relishes the chance to produce exciting printed material then hire someone who does. Just like those weird brightly coloured personalities that you hired to market your wares, good technical writers are a very good way to ensure your message actually gets through to your intended audience.

So....

What are you waiting for?

Go forth and write that epic take of love, loss and the inner working of the JRX-382!

You've got nothing to lose and everything to gain. :)

PS: Yes, I too recognise the irony of someone who struggles with the whole communication thing, attempting to tell others how to communicate. Don't blame me. Blame people like Infocom who had the temerity to demonstrate how to get away with such wild and whacky behaviour back in 1989: http://www.mv.com/ipusers/xlisper/zil.pdf

3月1日

A well versed reptile

One of the recent internal discussions kicked off by Russ Blake at Readify has been on what part to play IronPython should have in commercial software development.

Is it ready for the cubicle dwelling masses?

Here's my take on it:

Python (Iron or otherwise):

I think the advantages of Python verses any other language is more a question of commercial environment and fashion than anything else. This isn’t good or bad. It just lumps it in with every other Turing complete language.

Personally I find Python an acceptable language as:

- It’s a good successor to Perl in terms of being a pragmatic scripting “glue” to bind other bits together.

- The syntax, while having slightly different coloured goo than its more “commercial” peers, is readable.

- It scales better than Perl in terms of being to construct medium to large sized applications.

- It also has the advantage of being one of the current “cool kids” of application development (as the attendance of a recent programming comp clearly demonstrated. The only thing sexier than Google in young developers eyes at the moment seems to be Python.)

My only small grumble with it, due to its Perl’esque pragmatic approach to being able to glue bits together, is that it very quickly exposes it ugly underscore ridden underbelly of working gears and levers in the pursuit of decent sized application development.

So my overall response to Python in general is: Meh.

Looking down from a greater altitude:

What I find more interesting is that Python tends to get used quite a lot as a hosted scripting language in other applications.

Everything from games to GIMP to Chumbies seem to be ticking along with Python, LUA or some other scripting language lodged near their heart.

And, hopefully without sounding too much like the crazy guy talking about how poultry controls the CIA, I think scripting languages are where is it’s at.

Crazy Talk:

My dream business application, as I’ve bored many with on previous occasions, is one built in much the fashion as a modern game.

Content designers (aka Business Analysts and Devs) world in their own little self contained bubble world of scripted language goodness.

Framework  developers work around this bubble, wiring up the ‘content’ to the graphics, storage and network bits.

Content designers never attempt to write the binding code for an Infragristics grid and Framework developers never try and write the formula for calculating the rounding on the GST of a baked bread item purchased with a gift voucher.

Now you there’s nothing stopping this from happening purely in the familiar world of C# or VB.NET but it presents a few issues.

CLR without DLR is no fun:

The first is the nitty gritty technical pain of dealing with the shear tedium of attempting to host non-DLR languages in .Net.

It’s just too much work to get a plug-in system working that doesn’t ending up stepping on the toes of memory (Yay App Domain unloading! ), exception handling (Yay App Domains!) or communication (Yay App Domains!).

Secondly, there’s slightly non-intuitive ‘social’ side effects of picking of the same language for both framework and content construction.

Content developers really need to focus on producing the content... not ‘peaking under the hood’ at what the Framework guys are doing and attempting to ‘patch’ into or around any random bits of framework that take their fancy.

Thirdly, making a scripting language (or DSL if need be) your language of choice for how to articulate the solution to your problem is a very powerful idea indeed. In addition to being able to craft the syntax so that more elegantly describes the problem domain, executing your content via a scripting language means you gain a whole more context and control over what’s going on.

Writing interfaces and APIs give you some control... but it’s practically impossible to have any sort of compile time confidence that the content developer hasn’t done something to (un)intentionally thwart the design of the underlying layers. (“So I noticed that if I used reflection and kicked off this on another thread then it all seemed to work... I hope that was okay?... Bob?... Bob?...”)

Expressing the solution to a problem via scripting language or DSL is a higher level of abstraction as well.

Want to add in a funky auto parallel’ising  multithreaded network capable piece of code everywhere the content designer has decided to add some numbers together?

No problems. The language host can specifically keep a look out for when such occasions occur and make a call your new code as required. Zero change the neat elegant highly readable content description of the business process and no need for the content developers to have to refactor their code with weird and wonderful attributes or other languages constructs that have nothing to do with the business problem at hand.

So....

Crazy half-baked conclusion:

My summation is: Hosting scripting languages / DSLs is cool.

Python is okay as a possible scripting language choice... but may not be my first.

 

Random side thought:

I’m thinking the long forgotten hero of scripting languages is Logo.

· It’s relatively easy to implement

· It has clean simple syntax

· Arguments over punctuation and its placement rarely break out

No joke.

2月28日

HR Violations in the name of Stored Procedures

Preface: As my home site of lzcd.com is going to be used for other (possibly evil) purposes, I thought I might christen my new choice of blogging locations with a random thought. Apologies in advance to any DBAs that know me... in particular those who know where I live :)

It amused me when MySQL (relatively) recently introduced stored procedures.

Being one of those poor saps that was "raised" in a commercial world of DB use, I had my expectations set at an early age and found the concept of a DB "surviving" for so long without stored procedures almost unimaginable.

One or more DBAs would patrol the entrance to the DB. Resembling some sort of wizard from the likes of Discworld or Harry Potter, they strutted around in their tattered multicoloured robes, unkempt beards and wrinkled brows. It was only the inexperienced or dim witted that risked attempting entry without the permission of such fearsome guardians.
(The only ones feared more were the network & sys admin ogres that nestled scarily in the shadows of the basement and whose maddened growls of "netstat" and "traceroute" could be heard echoing down the halls on dark and stormy nights)

Asking permission to see what lay behind the connection string was a double edged sword.

If the DBA sensed fear above and beyond the normal levels of terror, as you lay prone upon the ground before him, he would refuse your request with a harsh quip that, if you were lucky, would only strip your self-esteem... and any gains made through that speech therapy you endured as a kid.

"Be gone from my sight oh lowest of the low," he would exhale dismissively "and I shall let you live with execute access to these fine stored procedures that I have crafted from the very elements of the universe and the stars within that mere lowly mortals such as yourself could never understand."

If, on the other hand, the DBA was feeling playful and you looked like you had a little too much spirit in the light of the flickering green fluorescents, he would grant you access to selected portions of the database in much the same way killer whales taunt and tease their prey in the moments before the kill.

Yes, you had access to the database... but it was merely the setup for a cruel ruse. What you thought was a simple construction of a CRUD style stored procedure was in fact a noose of arcane syntax and perverted distortions to set theory slowly tightening around your neck.

Experienced co-workers would look upon your feverish gaze of SQL coding in a worried pitying stare for it was only after you had constructed what you perceived as a minor miracle of well indexed Cartesian beauty (whose elegance was surely going to elicit religious ceremony from those who observed it) that the DBA would tear it all away from you in one brisk belittling put down.

The exact words are lost on you almost immediately as the DBA proceeds to enumerate the many faults that infest your creation to its core. Your entire body goes numb. Your brain, unable to focus on the immediate loss, reminisces in a emotional stupor that tattered remains of the life that you used to know.

The respect that other devs had given you. The small smirk of playful possibility the attractive guy / girl in marketing gave you a few hours before. The honest belief that your could in some small way live up to your parents expectations of being a respected professional.

All gone. Lost forever.

This was not a world of peers and mutual respect. This was a world of restricted privilege and inherited birth rights.

Table schemas were never touched directly and rarely seen in person.

Indexes were akin to magic incantations that only passed the lips of people whose grizzled collection of scars and matted hair could withstand the consequences.

The hallowed gateway to all of this was enshrined in the sharp metallic structure of stored procedures.

They dictated performance. They dictated protocol. They dictated the exact manner in which all applications would need to bow towards the all seeing and all knowing gods of data: The DBAs.

Living in this reality for so long left me unable to spot the wavering edges of the illusion presented before me.

The ancient curses surrounding the evils of different tiers changing at different times never seem to show up in the ways the old ones spoke of.

Instead of a torrent of changing DB systems and continual refactoring of all tiers in an effort to extract the very last drip of performance, events tended to peak and trough.

Long periods of calm would happen in which everyone seemed to almost hold their breath in the hope that if they didn't touch anything then it wouldn't break.

And then, every once in a while, change would erupt from the business requirements and wash across all the tiers at once.

Suddenly people were facing daemons that the ancients never mentioned. Panicked masses running through the streets crying out questions like "How do keep the version of the DB inline with the version of code?", "How do we test each version?" and "How do we roll out versions side by side?".

I had grown up thinking that the only way that SQL could execute efficiently was via the protection and guidance provided by stored procedures. Without the stored procedure, what was there?

A lawless town of missed cache hits, fumbling predicates and roaming hordes of developers feasting at the gory remains of relational theory?

As it turns out, probably not: http://www.databasejournal.com/features/mysql/article.php/3525581  :)

 

Drumm Luke

尚未添加列表。

Xbox Live 玩家卡

lzcd
Xbox Live 玩家卡
声望:
3.25/5 星
得分:
2650
区域:
Recreation
Halo WaypointForza Motorsport 3Halo 3: ODSTCall of Duty 4Sam&Max Save the World