Thursday, January 14, 2010

Object Data Store using Google's App Engine I have a working version of the webservice component of my google apps engine project now. Essentially, it means you can post xml to the webservice and it saves/retrieves/deletes it for you. Here's a simple overview: Let's say, for example, you had the following Class: public class Contact { public string Author; public string Notes; public int NumOfBooks; public datetime Date; public bool isAuthor; } With the following values: Contact.Author = "Kenny Jacobson"; Contact.Notes = "Computer Programming"; Contact.NumOfBooks = 14; Contact.Date = "2008-05-22 21:35:33.796000"; Contact.isAuthor = True; You would then format an XML doc as below and Post it to the "persist" function of our webservice (http://myGoogleApp/persist): Kenny Jacobson Computer Programming 14 2008-05-22 21:35:33.796000 True Since the value is blank, it knows this is a new record and will add it to the data store. After posting it, the webservice will return to you the unique Key it generated for your object. Let's say it gave us the key "aghvb2RzdG9yZXITCxINVEVTVDFfQ29udGFjdBglDA". Then if we want to update the object we just added, we would include the key value when we post it again to the "persist" webservice (http://myGoogleApp/persist): Kenneth Lance Jacobson Computer Programming 14 2008-05-22 21:35:33.796000 False aghvb2RzdG9yZXITCxINVEVTVDFfQ29udGFjdBglDA This will now Update our object. Now, let's say we want to retrieve our object from the data store. We post an XML doc to the "retreive" function of our webservice (http://myGoogleApp/retrieve). The XML document will contain the structure, but not the data and it will also include the Key of the object we what to retrieve: aghvb2RzdG9yZXITCxINVEVTVDFfQ29udGFjdBglDA This will return to us the structure with the data filled in. There are two other options for the Key property when retrieving data, we can use the "All" keyword or we can use a "Where [property] [operator] [value]" (ex., "Where NumOfBooks > 10") For example, to get all the objects of the type "Contact" you would send the following XML to the "retreive" function of our webservice (http://myGoogleApp/retrieve). All Which would return something like this: Kenneth Lance Jacobson Computer Programming 14 2008-05-22 21:35:33.796000 False Michael Washington Computer Programming 27 2008-05-23 21:35:33.796000 True Harper Lee To Kill A Mockingbird 1 2008-05-24 21:35:33.796000 True Using the Where clause would look like this: Where NumOfBooks > 10 And return something like this (since Harper Lee only wrote one book...unlike the prolific two of us ;): Kenneth Lance Jacobson Computer Programming 14 2008-05-22 21:35:33.796000 False Michael Washington Computer Programming 27 2008-05-23 21:35:33.796000 True To delete, you post your XML to the "remove" function of the webservice (http://myGoogleApp/retrieve), with either the unique Key: aghvb2RzdG9yZXITCxINVEVTVDFfQ29udGFjdBgpDA Or a where clause WHERE Author = 'Kenneth Lance Jacobson' Anyway, that's what I got so far it in a nutshell. It probably doesn't seem like much yet, but when I finish the next parts, I think it will come together a little more. What I'm looking at is eventually when you define your classes, you'll add a couple methods that will call the .NET "OO DataStore" class I create (in the example below I call it"KennysOODStore") that will allow you to the retrieve/persist/remove your objects. The KennysOODStore class (which is part of my mini framework) will format your class object (through reflection) into the XML doc and post it to my googleAppEngine webservice it will also retrieve the results and (again through reflection) "re-hydrate" your class object with the data it retrieved and return it to your calling client. So your class that once looked like this: public class Contact { public string Author; public string Notes; public int NumOfBooks; public datetime Date; public bool isAuthor; } would now look something like this: public class Contact { public string Author; public string Notes; public int NumOfBooks; public datetime Date; public bool isAuthor; public void Persist() { KennysOODStore.Persist(this); } public void Remove() { KennysOODStore.Remove(this); } public static Contact Retrieve(KennysOODStoreKey key) { return KennysOODStore.Retrieve(key); } } And your client code might look somethign like this: Private void Page_Load(Object sender, EventArgs e) { Contact[] contacts = Contact.Retrieve("All"); /*Code to load your UI from the contacts you retrieved*/ } Private void SaveContact_Click(Object sender, EventArgs e) { Contact contact = (Contact)myUIElement.Tag; contact.Persist(); } And that's it! No worrying about databases or data access layers or mapping your object to a relational model. Now of course, I've created a very trivial example and objects get more complex since they can have properties which themselves our objects. So the developer would have to write the logic to persist the children objects too when the parent object is being persisted, but that's part of the fun of programming. To me the goal is to allow the developer to stay in the OO realm and not be bothered by the plumbing code that we always seem to have to write when when take OO stuff into the Relational world and then take Relational stuff back into the OO world. It also, of course, takes advantage of Google's speed, redundancy, high availability, indexing, low cost, etc. Now, for asynchronous calls to the OO Datastore, it will require a couple more steps: probably five lines of code on the Client side, instead of the one line of code in the Client side. But hey, it's still going to be a very fast and efficient way to code your Silverlight front end with a Google backend.


Object Data Store using Google's App Engine
I have a working version of the webservice component of my google apps engine project now.  Essentially, it means you can post xml to the webservice and it saves/retrieves/deletes it for you.

Here's a simple overview:

Let's say, for example, you had the following Class:
    
public class Contact
{
    public string Author;
    public string Notes;
    public int NumOfBooks;
    public datetime Date;
    public bool isAuthor;
}
With the following values:
 
Contact.Author = "Kenny Jacobson";
Contact.Notes = "Computer Programming";
Contact.NumOfBooks = 14;
Contact.Date = "2008-05-22 21:35:33.796000";
Contact.isAuthor = True;
You would then format an XML doc as below and Post it to the "persist" function of our webservice (http://myGoogleApp/persist):




  Kenny Jacobson
  Computer Programming
  14
  2008-05-22 21:35:33.796000
  True


Since the value is blank, it knows this is a new record and will add it to the data store.  After posting it, the webservice will return to you the unique Key it generated for your object.  Let's say it gave us the key "aghvb2RzdG9yZXITCxINVEVTVDFfQ29udGFjdBglDA".

Then if we want to update the object we just added, we would include the key value when we post it again to the "persist" webservice  (http://myGoogleApp/persist):




  Kenneth Lance Jacobson
  Computer Programming
  14
  2008-05-22 21:35:33.796000
  False

aghvb2RzdG9yZXITCxINVEVTVDFfQ29udGFjdBglDA

This will now Update our object.

Now, let's say we want to retrieve our object from the data store.  We post an XML doc to the "retreive" function of our webservice  (http://myGoogleApp/retrieve). 

The XML document will contain the structure, but not the data and it will also include the Key of the object we what to retrieve:




  
  
  
  
  

aghvb2RzdG9yZXITCxINVEVTVDFfQ29udGFjdBglDA

This will return to us the structure with the data filled in. 

There are two other options for the Key property when retrieving data, we can use the "All" keyword or we can use a "Where [property] [operator] [value]" (ex., "Where NumOfBooks > 10")

For example, to get all the objects of the type "Contact" you would send the following XML to the  "retreive" function of our webservice  (http://myGoogleApp/retrieve).




  
  
  
  
  

All

Which would return something like this:
 



  Kenneth Lance Jacobson
  Computer Programming
  14
  2008-05-22 21:35:33.796000
  False


  Michael Washington
  Computer Programming
  27
  2008-05-23 21:35:33.796000
  True


  Harper Lee
  To Kill A Mockingbird
  1
  2008-05-24 21:35:33.796000
  True

Using the Where clause would look like this:




  
  
  
  
  

Where NumOfBooks > 10

And return something like this (since Harper Lee only wrote one book...unlike the prolific two of us ;):




  Kenneth Lance Jacobson
  Computer Programming
  14
  2008-05-22 21:35:33.796000
  False


  Michael Washington
  Computer Programming
  27
  2008-05-23 21:35:33.796000
  True

To delete, you post your XML to the "remove" function of the webservice  (http://myGoogleApp/retrieve), with either the unique Key:



  
  
  
  
  

aghvb2RzdG9yZXITCxINVEVTVDFfQ29udGFjdBgpDA
Or a where clause



  
  
  
  
  

WHERE Author = 'Kenneth Lance Jacobson'

Anyway, that's what I got so far it in a nutshell.  It probably doesn't seem like much yet, but when I finish the next parts, I think it will come together a little more.  What I'm looking at is eventually when you define your classes, you'll add a couple methods that will call the .NET "OO DataStore" class  I create (in the example below I call it"KennysOODStore") that will allow you to the retrieve/persist/remove your objects.  The KennysOODStore class (which is part of my mini framework) will format your class object (through reflection) into the XML doc and post it to my googleAppEngine webservice it will also retrieve the results and (again through reflection) "re-hydrate" your class object with the data it retrieved and return it to your calling client. 
So your class that once looked like this:
public class Contact
{
     public string Author;
     public string Notes;
     public int NumOfBooks;
     public datetime Date;
     public bool isAuthor;
}
would now look something like this:
public class Contact
{
     public string Author;
     public string Notes;
     public int NumOfBooks;
     public datetime Date;
     public bool isAuthor;
     public void Persist()
     {
          KennysOODStore.Persist(this);
     }
     public void Remove()
     {
          KennysOODStore.Remove(this);
     }
     public static Contact Retrieve(KennysOODStoreKey key)
     {
          return KennysOODStore.Retrieve(key);
     }
}

And your client code might look somethign like this:
Private void Page_Load(Object sender, EventArgs e)
{
     Contact[] contacts = Contact.Retrieve("All");
     /*Code to load your UI from the contacts you retrieved*/
}
Private void SaveContact_Click(Object sender, EventArgs e)
{
     Contact contact = (Contact)myUIElement.Tag;
     contact.Persist(); 
}

And that's it!  No worrying about databases or data access layers or mapping your object to a relational model. 

Now of course, I've created a very trivial example and objects get more complex since they can have properties which themselves our objects.  So the developer would have to write the logic to persist the children objects too when the parent object is being persisted, but that's part of the fun of programming.   To me the goal is to allow the developer to stay in the OO realm and not be bothered by the plumbing code that we always seem to have to write when when take OO stuff into the Relational world and then take Relational stuff back into the OO world.  It also, of course, takes advantage of Google's speed, redundancy, high availability, indexing, low cost, etc.

Now, for asynchronous calls to the OO Datastore, it will require a couple more steps: probably five lines of code on the Client side, instead of the one line of code in the Client side.  But hey, it's still going to be a very fast and efficient way to code your Silverlight front end with a Google backend.

Thursday, November 12, 2009

Cookies With Silverlight 2.0


I was looking to set and retrieve cookies with Silverlight 2.0 and came across the following article by Nikola. Unfortunately, it did not work out of the box for me, so I modified it.  Here is my updated version:


using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;

/* www.datawinconsulting.com */

namespace Datawin
{

    /* 
    Thanks to Nikola  -  http://blogs.msdn.com/nikola
    http://blogs.msdn.com/nikola/archive/2008/04/14/setting-cookies-through-    silverlight.aspx
    */

    public class Cookie
    {
     

        /// 
        /// sets a persistent cookie with huge expiration date
        /// 
        /// the cookie key
        /// the cookie value
        public static void SetCookie(string key, string value)
        {
           
            string oldCookie = HtmlPage.Document.GetProperty("cookie") as String;
            DateTime expiration = DateTime.UtcNow + TimeSpan.FromDays(2000);
            string cookie = String.Format("{0}={1};expires={2}", key, value, expiration.ToString("R"));
            HtmlPage.Document.SetProperty("cookie", cookie);
        }

        /// 
        /// Retrieves an existing cookie
        /// 
        /// cookie key
        /// null if the cookie does not exist, otherwise the cookie value
        public static string GetCookie(string key)
        {
            string[] cookies = HtmlPage.Document.Cookies.Split(';');
            key += '=';
            foreach (string cookie in cookies)
            {
                string cookieStr = cookie.Trim();
                if (cookieStr.StartsWith(key, StringComparison.OrdinalIgnoreCase))
                {
                    string[] vals = cookieStr.Split('=');

                    if (vals.Length >= 2)
                    {
                        return vals[1];
                    }

                    return string.Empty;
                }
            }

            return null;
        }

        /// 
        /// Deletes a specified cookie by setting its value to empty and expiration to -1 days
        /// 
        /// the cookie key to delete
        public static void DeleteCookie(string key)
        {
            string oldCookie = HtmlPage.Document.GetProperty("cookie") as String;
            DateTime expiration = DateTime.UtcNow - TimeSpan.FromDays(1);
            string cookie = String.Format("{0}=;expires={1}", key, expiration.ToString("R"));
            HtmlPage.Document.SetProperty("cookie", cookie);
        }


    }
}

Here is how I call the Cookie Code:

private void SetCookie_Click(object sender, RoutedEventArgs e)
        {
            Datawin.Cookie.SetCookie("FoodName", txtBox1.Text);
            

        }

        private void GetCookie_Click(object sender, RoutedEventArgs e)
        {
            txtBox2.Text = Datawin.Cookie.GetCookie("FoodName");

        }

Hope that helps some of you out there. It sure helps me.

Thursday, October 8, 2009

Update Your Latitude and Longitude using Google

Untitled Page
My client had a "Entity Locator" on their site and needed additional data imported into the database. The data they gave me had the Entities' addresses but no Latitude and Longitude, which were essential for the program to work. In the past, I've had to use purchased data that gave zip code lat and long, but no more! With Google Maps API, I was not only able to get a more accurate Lat and Long (based on the full address, not just the zip code), but it was free!
First of all, you need to sign up for a developer key: http://code.google.com/apis/maps/signup.html
Here is a function that I wrote to get the Latitude and Longitude for a given address using the Google API. It's quite simple. You build the URL along with the query string parameters, make a request to Google's API, when the response comes back you process the results.
The parameters that you send to Google's API are:
key - the App key you got from Google when you signed up for the service.
output - the format of your results. For ease and size, I choose cvs.
q - the address you are looking for.
using System.Net;

private void GetLatAndLongGoogle(string address, string city, string state,
                                string zip, ref string inLat, ref string inLong)
        {
            /* 
             * Pass in the paramters: address, city, state, zip
             * 
             * The Longitude and Latitude will be passed back out through: inLat, inLong
             * (don't forget to pass these last two as "ref")
             */


            /* appID is the API Key you get from Google */
            string appID = "YOUrKraZYKey1w";
            
            /* Here we build the URL with the query string parameters*/
            StringBuilder url = new StringBuilder("http://maps.google.com/maps/geo?");
            url.Append("output=csv&key=");
            url.Append(appID);
            url.Append("&q=");
            url.Append(CleanForURL(address));
            url.Append(",");
            url.Append(CleanForURL(city));
            url.Append(",");
            url.Append(CleanForURL(state));
            url.Append(",");
            url.Append(CleanForURL(zip));

            /*Create HttpWebRequest object*/
            HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url.ToString());
            myReq.Credentials = CredentialCache.DefaultCredentials;

            try
            {
                HttpWebResponse response = (HttpWebResponse)myReq.GetResponse();
                Stream receiveStream = response.GetResponseStream();
                StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
                string httpString = readStream.ReadToEnd();
                if (httpString.StartsWith(@"200,"))
                {
                   
                    string[] AddressArray = httpString.Split(',');
                    inLat = AddressArray[2];
                    inLong = AddressArray[3];
                }
                else
                {
                    inLat = "0.0";
                    inLong = "0.0";
                }
            }
            catch (Exception e)
            {
                inLat = "0.0";
                inLong = "0.0";
            }
        }



        private string CleanForURL(string inStr)
        {
            inStr = inStr.Replace(@"&", "");
            inStr = inStr.Replace(@"/", "");
            inStr = inStr.Replace(@"\", "");
            inStr = inStr.Replace(@"?", "");
            return inStr;
        }
Here is a sample of how you would call the function:
int myAddressKey = 1234;
            string myAddress = "401 Main St";
            string myCity = "Huntington Beach";
            string myState = "CA";
            string myZip = "92648";
            string myLatitude = "";
            string myLongitude = "";
 
            GetLatAndLongGoogle(myAddress, myCity, myState, myZip, 
            ref myLatitude, ref myLongitude);
 
            MyProcedureThatUpdatesDBWithLatAndLong(myAddressKey, myLatitude, myLongitude);

Thursday, August 13, 2009

Automatic LightWindow Popup

Do you need LightWindow to pop up as soon as the page loads? The following hack to LightWindow will help you do that...
The LightWindow library allows the developer to launch a LightWindow programmatically. When the lightwindow.js library loads, it automatically instantiates a LightWindow object called myLightWindow. You can then use the activeWindow method to open a url in a LightWindow:
myLightWindow.activateWindow({
    href: 'http://www.google.com', 
    title: 'Google', 
    author: 'Datawin Consulting', 
    caption: 'This is Google's Home Page.', 
    width:995, 
    height:610
    });
You can easily execute this code from a button or link on your web page. So if you wanted the LightWindow to pop up as soon as the user lands on the page, you would think that all you have to do is call myLightWindow.activateWindow(…) in the main page’s onLoad event. Unfortunately, this doesn’t work. The onLoad event fires before the LightWindow library can load and instantiate the myLightWindow object so all you get is a javascript error and no LightWindow.
So what do we do? Well, our solution is to hack the LightWindow library (lightwindow.js) and add our own “pseudo-event” to fire right after the myLightWindow object gets instantiated. Here is the code in the lightwindow.js file (hint: it is at the very bottom of the file).
Original code:
var myLightWindow = null;
function lightwindowInit() {
 myLightWindow = new lightwindow();
 }
Our changes to the code:
var myLightWindow = null;
function lightwindowInit() {
 myLightWindow = new lightwindow();
 
 // The following was added to run code immediately 
 // after this library loads and instantiates the 
    // myLightWindow object.  
    // ***********************
    // In the code on the main page we’ll need to create a 
 // lightWindow_DoneLoading() function that catches 
 // the the pseudo-event.
 // ***********************
 // Not elegant. 
    // Tightly coupled. 
 // But at least we check for the existence of
 // the lightWindow_DoneLoading() function before 
    // we try calling it.
 if(('function' == typeof window.lightWindow_DoneLoading)){
     lightWindow_DoneLoading();
 }
}
In the main code we need to create a function called lightWindow_DoneLoading(). This is our pseudo-event handler that will handle the pseudo event that we raised. The code in our main page (including the loading of the necessary libraries) will look like this.
<link rel="stylesheet" type="text/css" href="css/lightwindow.css" />
 <script type="text/javascript" src="/dnn/Portals/0/javascript/prototype.js"></script>
 <script type="text/javascript" src="/dnn/Portals/0/javascript/effects.js"></script>
 <script type="text/javascript" src="/dnn/Portals/0/javascript/lightwindow.js"></script>
 <script type="text/javascript"> 
     function lightWindow_DoneLoading() {
         myLightWindow.activateWindow({
             href: 'http://www.google.com',
             title: 'Google',
             author: 'Datawin Consulting',
             caption: 'This is the Google Homepage.',
             width: 995,
             height: 610,
             top: 10,
             left: 200
         });
     }   
 </script>
To modify the appearance of the LightWindow you would change the following values in the “activeWindow” method above:
  • href – the url of the site you want in your LightWindow.
  • title – the text for the Title that shows on the left, directly above the LightWindow.
  • author - the text for the Author that shows in the bottom, right hand side of the LightWindow.
  • caption – the text for the Caption that show in the bottom, left hand side of the LightWindow.
  • width – the width of the LightWindow in pixels.
  • height – the height of the LightWindow in pixels.
  • top – the top position of the LightWindow relative to the browser window.
  • left – the left position of the LightWindow relative to the browser window.
That’s it! The LightWindow should now pop up as soon as the page loads.
p.s. You will note that since our hack to the LightWindow.js checks for the existence of the function before trying to call it, it will not throw an error if the function does not exist in your main page. That means you can use the hacked version even on your pages where you don’t necessarily want an automatic LightWindow pop up.)

Saturday, August 1, 2009

Changing The Background Opacity for LightWindows


When the LightWindow pops up, it darkens the original page underneath it. This has the cool effect of drawing your attention to the newly popped window, while reminding you that you are still on the same site. LightWindow makes the original page pretty dark, though, and our clients wanted it lighter than that.

Behind the scenes, LightWindow creates the "page goes dark" effect by stretching a transparent black squared completely over the browser window. IE and Firefox use different methods to make this square transparent, though. In IE, you load a black opaque image and then set the opacity to a decimal between 0 and 1. The lower the number, the more transparent it becomes. For instance, .7 would make the image 70% opaque or in other words, 30% transparent, .2 would make it 80% transparent. In Firefox, on the other hand, you create an already transparent .png file and just stretch that over the browser window. That means for Firefox, we’ll have to modify the .png file with a graphics editor like Fireworks. Since LightWindow seeks compatibility with both (and so do we), you will have to make a few steps to make the change.

For our project, we want to lighten the page from 70% opacity to 20%.

First we will create the transparent image that Firefox uses, adjusting the opacity to 20% and saving it as "black-20.png":

  • Open "black.png" (in "images" directory) with Fireworks.
  • Select the Black bitmap object.
  • In the Properties window (probably at the bottom) you should see two dropdown boxes, one has "100%" in the box and the other has "Normal".
  • Click on the down arrow by the "100%" box and move the slider down to "20%".
  • Click somewhere else in the program. You will see the bitmap become more transparent.
  • From the menu: File-->Save as "black-20.png

Next we will modify the code in "lightwindow.js"

  • Open "lightwindow.js" (in the "javascript" directory) with your favorite text editor or Visual Studio.
  • Search for "opacity" to locate the following block of code:

overlay : {
    opacity : 0.7,
    image : 'images/black.png',
    presetImage : 'images/black-70.png'
   }
  • Change "opacity : 0.7" to "opacity : 0.2" (For IE).
  • Change the "presetImage" value to "black-20.png" (For FireFox).
  • Save.

overlay : {
    opacity : 0.2,
    image : 'images/black.png',
    presetImage : 'images/black-20.png'
   }
That should do it! Reload the page and verify that it works.

Monday, July 14, 2008

Computer Programming Vs. The Humanities, Part II


So my new friend, Sanjay, liked by response (found in my earlier post) and ask me so more specific questions...I hope I gave him some specific answers...
Sanjay wrote:
Thanks Kenny for detailed response.
Would you also like to reflect upon  if your background in literature plays any role  in requirement definition phase?   Would you like to recall some specific incidences where the literature training gave an additional edge in any phase of Software Engg?
For quite some time, I have been thinking to propose  educational programs mixing Humanities and Software Engg.   Real experiences like yours will help in building the case.
regards,
-Sanjay

My response:
Let's see, literature and requirements gathering....
Well, with literature, we'd often come to class having read a story/poem/novel and be met with some questions from our prof like "what was the author trying to say?", "what in the author's background might have lead him/her to write this way?", "why does the character behave this way?"  What we couldn't figure out on our own, the prof would help fill in.  In this way we became more adept at asking questions of the text and drawing out the answers.
Often when we meet with our clients during the requirement definition phase, they like are like a poem, explicit in some of their details, yet hiding many others.  Of course, it's not their fault, they just how to explain everything they need from the system.  As programmers in an analyst role, we need to be able to anticipate what other requirements might be hiding beneath surface.  We need to have the ability to ask them more questions and draw out the answers.  Perhaps the training that literature provides in having us constantly asking questions of the text to draw out meaning also helps us in these endeavors.
A quick anecdote on drawing out meaning from a poem, or in this case a poet.  One of my favorite classes was taught by the Chilean Poet, Gonzalo Rojas (http://www.amazon.com/Lightning-Selected-Poems-Green-Integer/dp/1933382643/ref=sr_1_3?ie=UTF8&s=books&qid=1216105264&sr=1-3).  For years the University had asked him to teach a class on his own poetry, but he always declined.  Finally, he agreed and I was one of the lucky ten grad students that was allowed to take the class (though, usually about 10 to 20 other students stood in the conference room just to hear him speak).  Anyway, I recall one time we were discussing one of his poems and one of the students said "Profesor Rojas, when you wrote this line, did you mean to say..." and he went on with his explanation, the details of which I cannot recall anymore.  When the student was finished, the poet sat back in his chair and thought about it for a moment, then he responded "yes, you are right.  That is probably what I was trying to say.  I never realized that before".  I learned a lesson that day, that even great artists don't always know the whole meaning of what they produce.  Likewise, I have found that clients don't always know the whole list of requirements for the system the are asking us to build.
Another practical application of literature classes to requirements definition is the idea of "brain storming" that is common to both literature and software development.  Before we ever start writing a paper for a literature class, we are asked to jot down ideas, any ideas that come to us.  Even if these ideas seem stupid.  At the brainstorm phase, there are no stupid ideas.  I do this all the time for software development too.  After all ideas have been exhausted, we then start sorting them out into related ideas.  The ideas often form our paragraphs in writing and our subsystems or classes or data tables in software dev.  We then look for the details that become the sentences of our paragraphs for literature or the functions/methods/fields/procedures in our computer system.
Anyway, I hope that helps...
Kenny

Sunday, July 13, 2008

Computer Programming Vs. The Humanities


I responded to a question someone raised on LinkedIn and I'm cross-posting it here on my blog. It's a topic I've discussed with bosses, clients, co-workers, and friends through the years.  "How are you a computer programmer, when you studied Latin-American Literature in college?!? Did your college education help you at all?!?"

The original question: "Are humanities useful for computing engineers?" [sic]

My response:
I seem to find myself in this discussion quite often as I have a Master's Degree in Latin American Literature, but have been working as a software programmer for over ten years now.

I'll lead with what seems to be the most convincing argument: the brain is like a muscle and needs routine exercise to get stronger, or at least to stay in shape. Just as your muscles in time will adapt to the same daily exercises and receive less and less benefit from that exercise, your brain starts to tune out repetitive thought processes. Giving your brain some different types of problems to think about helps it get stronger. The Humanities can offer very different problems than what your "engineering" brain is used to. Your stronger brain can then help you out more when it comes to figuring out that next algorithm.

Secondly, our work as programmers (and other engineers) requires us to be creative. Nearly every day we are faced with a problem we've never encountered before. From architecting a huge inventory system to fine tuning a long running function, the fun part of our job is making things and watching them work. The problem is… I don't think creativity can be taught...I believe it grows through inspiration, and inspiration comes from experiencing the creativity of other talented people. The Humanities have been pretty good about letting time sort out the great, creative minds of the centuries. The guided study of the Humanities (whether formal or otherwise) allows us to appreciate even more what makes these great minds so great.*

Number three...research and organization. My clients and past employers always seem to get a kick out of the fact that I studied Spanish Lit, and ended up programming computers. My usual response is, "hey, whether it's Spanish or SQL, French or C#, they are all languages, right?". Then I usually tell them that the single most valuable part of my college education was that d#@% Thesis paper I had to write. When you write a Thesis (usually over 100 pages long), you are expected to become the authority on the very narrow subject you carved out for yourself. My Thesis chair pointed me in the right direction with a couple books to read first and then said essentially "you need to become the expert now...figure out how to become an expert..." Well, I found that meant doing a lot of research. In the days before Google, I learned how to follow a trail of one author quoting another, then finding the second author and reading his or her references, and so on. This skill has helped me immensely as I now have the Internet at my finger tips and am constantly looking up how to troubleshoot problem X or how to use the methods of class Y. I've even picked up whole languages (like javascript and python) through internet research. I'm convinced that the Humanities, more than any other discipline, help you learn how to learn.

Oh, I failed to address "organization" in that last paragraph, but that paragraph was getting entirely too long (just like this response as a whole)...ANYWAY!...the Humanities demand that you write, and write a lot. I also usually end up explaining to my amused clients, bosses, and colleagues that the d#$% Thesis also forced me to learn how to organize my thoughts. To take something big and overwhelming and to break it into smaller parts, and then break those smaller parts into even smaller parts, and on down until things are manageable. And that is the same exact process I use when I'm faced with a new project. The client has a rough idea of how they want the system to behave, but no idea of how to get there. That's when I grab a pen and paper and find a quiet area to start thinking the problem through. I'm telling you, the process is nearly identical to writing a big paper, only, to me, the satisfaction of watching your program run is greater than seeing your paper published, which is why I ended up a programmer and not a professor. ;)

OK, one last argument and then I'm going to bed. I've already eluded to it...Communication. Because you write so much in the Humanities, you just naturally become a stronger writer. And judging from so many confusing, rambling, and/or scatterbrained emails I receive, the business and computing worlds both need stronger writers.

Whew! 

Oh yeah, then there's also the whole "Humanities brings richness to your life" thing that has been true in my case, but who am I to say that it will for others?

I guess to the engineer who hates the Humanities and stubbornly takes only the required classes, there's not much I can say. If coerced, your benefits are probably minimal.

I hope that helps, Sanjay.
 
~K


_______________________
 
*Look at me, I didn't even use the worn out and (by now) meaningless business-speak phrase "thinking outside the box". Let's face it, "thinking outside the box" just means "creative".