Welcome to MSDN Blogs Sign in | Join | Help

Nigel and Zach talking about SDS

Hey, check out a new video of Nigel and Zach chatting about some of the changes that we're in the process of making to SDS.

Posted by jcurrier | 1 Comments

SDS Java JDBC examples

In my previous blog entry I mentioned that I would post some Java & JDBC examples for connecting to and interacting with the SDS service.  Since that post (roughly an hour ago) I’ve been called a, “slacker” by David Robinson one of the PM’s on the team.  Therefore, to show that I am not a, “slacker” I’ve decided to just post the code today.  Happy Dave :-)

So, in this example I’m using Java 1.6, NetBeans as the editor and the latest JDBC driver for SQL Server which you can download from here.  The only jar file I’m currently using to compile (and run with) other than the expected JRE jar files is the, “sqljdbc4.jar” jar file which comes along with the download I’ve linked to above.  NOTE: That if you choose to use an earlier version of JDBC it *must* support SSL.  This is a requirement for the service.

Now, I’ve purposely made this example to be the exact same as the C# example I did previously so you could focus more on the differences with the client technologies and less on the actual data I’ve created.  As you can see the only significant difference relative to SDS is the format of a couple of connection string values (namely the database, user id format and the initial url for the server).  Other than that it’s the same code that we would use to connect to locally. 

Now, with no further delay.  The Java code for working with SDS.

    public static void main(String[] args)
    {
        String createTableSql = 
                "CREATE TABLE [dbo].[tbl_Person]    " +
                "(                                                    " +
                "     [FirstName] NVARCHAR(64) NOT NULL,              " +
	            "     [LastName] NVARCHAR(64) NOT NULL                " +
                "    CONSTRAINT [personName_PK] PRIMARY KEY CLUSTERED " +
                "    (                                                " +
                "        [FirstName] ASC,                             " +
                "        [LastName] ASC                               " +
                "    )                                                " +
                ")";     
        
        String insertSql = 
                "INSERT INTO dbo.tbl_Person(FirstName, LastName) VALUES ('Jeff', 'Currier'); " +
                "INSERT INTO dbo.tbl_Person(FirstName, LastName) VALUES ('Nigel', 'Ellis'); " +
                "INSERT INTO dbo.tbl_Person(FirstName, LastName) VALUES ('David', 'Robinson');"+ 
                "INSERT INTO dbo.tbl_Person(FirstName, LastName) VALUES ('Jeff', 'Smith');";
                
        try
        {
            // First, format the connection string note that the server name here again is, “myserver”.  The database name (my user database name) is mydatabase.  
            String connectionUrl = "jdbc:sqlserver://myserver.data.dev.mscds.com;" +
                    "database=mydatabase;encrypt=true;user=jeff@myserver;password=*****";

            // Next, make the sure the SQL Server Driver is loaded.
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            
            // Then attempt to get a connection.  This will null or throw if we can't
            // get a connection.
            Connection sqlConn = DriverManager.getConnection(connectionUrl);
            if (sqlConn == null)
            {
                System.out.println("Unable to obtain connection.  exiting");
                System.exit(1);
            }

            // Begin by creating the table we'll use.
            Statement sqlStmt = sqlConn.createStatement();
            sqlStmt.execute(createTableSql);

            // Then, insert some rows into the table that we just created.
            sqlStmt.execute(insertSql);

            // Now, select all of the, "Jeff' data from the table and print them out.
            ResultSet results = sqlStmt.executeQuery("select FirstName, LastName from tbl_Person where FirstName='Jeff'");
            while (results.next())
            {
                System.out.println("FirstName: " + results.getString("FirstName") + " LastName: " + results.getString("LastName"));
            }
            // Close the ResultSet up.
            results.close();

            // Finally drop the table and close the conneciton.
            sqlStmt.execute("drop table tbl_Person");
            sqlConn.close();
        } catch (SQLException ex)
        {
            System.out.println("Error: Unable to execute query ");
            ex.printStackTrace();
        } catch(ClassNotFoundException ex)
        {
            System.out.println("Error: Unable to load JDBC Driver!");
        }

    }
Enjoy,
--Jeff--
Posted by jcurrier | 3 Comments
Filed under: , , , ,

SDS coding examples – Part 1 (C# & ADO.NET)

So, as I did with the original SDS I want to outline some code examples that other developers can use to get a sense of how to interact with the service.  In general, this will be much easier now that we have shifted more to the relational model as some of the more abstract (okay maybe not sooo abstract) concepts don’t necessarily need to be explained from scratch.  Having said that, there are a few concepts that are worth covering before we dive into the code.

 

Servers, and Masters, and User Databases,  oh my!

There are really two different types of databases that we have present in SDS now.  The first, and the one that you’ll generally interact with the most, is the user database.  This is really where your user data resides.  You’re in charge in this space.  You define the tables, schemas and what have you that appear in this database.  We may insert some data into locked down tables (and present them to you with views) here to help assist you with debugging and provide some metrics data but by in large this is your house.  NOTE: The name you choose here for your user database (“mydatabase” in the example below) is the name of the database you specify in the connection string.

connStringBuilder.InitialCatalog = "mydatabase"; // Specify your user database to connect to. 

The second type of database is really what we refer to as the logical master database (or server database) but it actually encapsulates two different things.  The first thing is that the server represents a logical master database.  This is the database where we keep track of all of the user databases that you have on this logical server. It’s important to note that this is *not* a real server and is more logical in nature.  We will also store things your metrics here as well as login information NOTE: Because we store login information here this is why you have specify your server name in the user id as certain elements don’t come across in the initial TDS packets we receive.

The second important thing to note about the server database is that is associated (along with each of the user databases managed by it) with a particular geo-location.  You will pick the geo-location when you go through the provisioning process and requests will be routed to your servers by taking advantage of the DNS system as once done previously.  The code snippet below illustrates how the server presents itself in the connection string.

connStringBuilder.DataSource = "myserver.data.dev.mscds.com"; // Specify the DNS name of my SDS server (which holds my master db).
connStringBuilder.UserID = "jeff@myserver";                   // Specify my user id (and the server name which holds my master db)
On to the code

So now with no further delay is some sample code.  It’s simple (on purpose) but it illustrates the types of operations that you’ll be able to do (DDL & DML).  In this example, I simply create a table, insert some rows, select some rows from that table, and finally drop the table in the end.  Here you go!  If you have other questions around the code please feel free to comment and I’ll try to reply as soon as I can.

        static void Main(string[] args)
        {
            // Begin, by constructing the connection string using the SqlConnectionStringBuilder class for
            // simplicity.  I could just use String.Format but this makes it a bit easier to explain what
            // we're doing with each parameter.

            SqlConnectionStringBuilder connStringBuilder = new SqlConnectionStringBuilder();
            connStringBuilder.DataSource = "myserver.data.dev.mscds.com"; // Specify the DNS name of my SDS server (which holds my master db).
            connStringBuilder.InitialCatalog = "mydatabase";              // Specify your user database to connect to.
            connStringBuilder.Encrypt = true;                             // Specify that I would like the channel to be encrypted.
            connStringBuilder.UserID = "jeff@myserver";                   // Specify my user id (and the server name which holds my master db)
            connStringBuilder.Password = "****";                          // Finally, specify my password.

            string createTableSql =
                @"CREATE TABLE [dbo].[tbl_Person]
                (
                     [FirstName] NVARCHAR(64) NOT NULL,
	             [LastName] NVARCHAR(64) NOT NULL
                    CONSTRAINT [personName_PK] PRIMARY KEY CLUSTERED
                    (
                        [FirstName] ASC,
                        [LastName] ASC
                    )
                )";

            string insertSql =
                @"INSERT INTO dbo.tbl_Person(FirstName, LastName) VALUES ('Jeff', 'Currier');
                  INSERT INTO dbo.tbl_Person(FirstName, LastName) VALUES ('Nigel', 'Ellis');
                  INSERT INTO dbo.tbl_Person(FirstName, LastName) VALUES ('David', 'Robinson');
                  INSERT INTO dbo.tbl_Person(FirstName, LastName) VALUES ('Jeff', 'Smith');";
            try
            {
                // New up a connection to my previously provisioned user database just as I would to any other database.
                // and then open it.
                using (SqlConnection conn = new SqlConnection(connStringBuilder.ToString()))
                {
                    conn.Open();

                    // Construct a new SqlCommand object that we'll use to execute execute our Sql code.
                    using (SqlCommand cmd = conn.CreateCommand())
                    {
                        // Use the above defined SQL to create a simple table that we'll to construct a table for this
                        // example
                        cmd.CommandText = createTableSql;
                        cmd.CommandType = CommandType.Text;
                        cmd.ExecuteNonQuery();

                        // Insert some simple data into that table.
                        cmd.CommandText = insertSql;
                        cmd.CommandType = CommandType.Text;
                        cmd.ExecuteNonQuery();

                        // Next, perform a simple select finding all of the persons in the table whose first name is Jeff.
                        cmd.CommandText = "select FirstName, LastName from dbo.tbl_Person where FirstName = 'Jeff'";
                        cmd.CommandType = CommandType.Text;
                        using (SqlDataReader reader = cmd.ExecuteReader())
                        {
                            while (reader.Read())
                            {
                                Console.WriteLine("First Name: {0} LastName: {1}", reader["FirstName"],
                                                  reader["LastName"]);
                            }

                            reader.Close();
                        }

                        // Finally, drop the table since we no longer need it.
                        cmd.CommandText = "Drop table dbo.tbl_Person";
                        cmd.CommandType = CommandType.Text;
                        cmd.ExecuteNonQuery();
                    }

                    conn.Close();
                }
            }
            catch (SqlException ex)
            {
                Console.WriteLine(ex);
            }
        }

Now, this example was in C# and used SqlClient (ADO.NET) but my next example will use Java & JDBC.  If there are other languages (toolkits) you would like to see us illustrate please comment here or on the main SDS blog and we’ll try to get them out as soon as we can.

Enjoy!

--Jeff--

Posted by jcurrier | 6 Comments

Check out Nigel's Talk on SDS from MIX09

Looks like the MIX folks have posted up Nigel's talk on the newly revamped SDS from MIX.  You can watch it now here.

Posted by jcurrier | 0 Comments
Filed under: , ,

It’s been awhile…

So, it’s been quite awhile since I’ve posted but with the recent SDS announcement I trust you now know why that is.  While I’ll be posting some code samples shortly for accessing the new SDS service via ADO.NET as well as with Java I’d like to give a plug for Nigel’s upcoming MIX09 talk on SDS. 

I don’t want to steal any thunder from the talk next week so I’m going to hold off on talking much more about the service until after Nigel’s talk is completed.  Keep posted though as you will see more details coming out from the team post MIX.

Finally, I’ve seen quite a bit of traffic in the blog community recently with concern that our new model doesn’t scale.  I’ll just say this, we are all familiar with CAP conjecture, we do know what it takes to scale a relational store.  We’ve done this once (with the initial version of Sitka which was built on the same technology) we will do it again.  The larger question is getting the right application patterns in place so apps perform well on the system.  That’s it for now but stay tuned.

Posted by jcurrier | 1 Comments

SDS Channel 9 Video is up

A little while ago Jason and I recorded a Channel 9 video to discuss some of the newer features in SDS (SQL Data Services).  Now that all the Azure components have been announced this is now available up at the Channel 9 site.  You can view it here.

Channel 9 interview for PDC

Jason and I just finished recording a session on some of the new features of the services that will be announced at PDC next week (along with some others such as Blobs).  Keep in eye out for it.  I think you'll enjoy it!

--Jeff--

Posted by jcurrier | 2 Comments

Tour De Peaks

This is a non-SSDS related posting today :-)  I did the Tour De Peaks today with my wife and Stan another member of the SSDS team.  It was a great ride, though it didn't start off the way.  After a brief stint of rain and wind the weather let up and we had a great ride.  We decided to do the metric half century (34 miles) and I think everyone agreed in the end that it was a great ride.  I'm really looking forward to doing the same race again next year.

Posted by jcurrier | 1 Comments
Filed under: ,

What happened to SSDS PUT/POST responses?

Since the rollout I've seen at least one or two messages regarding the altered responses we're now sending with the REST head of the service.  There are several reasons why we've changed the service to now not return the entity body back to you again.  These are as follows:

  1. Version - Prior to this rollout the only mechanism that we had to communicate version information to you was via the entity body of the response (specifically the version element in the body).  However, now that we have true ETag support we now can simply return this value back to caller via the ETag header per the Http spec.
  2. Cost - Although at this point we don't charge for the service we eventually will.  Included within this billing structure are charges for ingress & egress (bandwidth usage in essence).  Therefore, by not returning the body to the caller (which the caller originally provided us with anyway) this is a net cost savings for you the caller. 

Hope this helps to explain a bit more of the thinking behind the change.  As always we're open to feedback.

--Jeff--

SQL Server Data Services Upgrade has been completed!

We completed the latest upgrade to the service yesterday afternoon.  Listed below is the notification that went out along with a brief discussion of what we've added.

 

SQL Server Data Services (SSDS) Maintenance
Status: Complete


We have completed upgrading the SSDS Service

Impact Alert:

  • As per our prior communications, this upgrade removed all existing data in the service.  All Authorities, Containers and Entities will be deleted. User account, user ID’s, and passwords will be preserved.  This is necessary due to the enhanced functionality we are providing. 
  • Special characters in SSDS User Ids are no longer supported (Special character this impacts: @). The ‘@’ character in the existing user ids will be replaced by an “_”.  For example, user id “Joe@Business” will become “Joe_business”.
  • While the “application/xml” content type will still be supported in the short term, we highly recommend that you migrate your applications to the new “application/x-ssds+xml” content type with this service update.

New features in this upgrade:

Blob Support via the REST interface

· In this release, Blobs are limited to 100 megabytes in size.

· Blob Support via the SOAP interface will be delivered in a later update.

Version metadata property has changed from a large integer to a container-wide dbtimestamp value:

· Version numbers are now based on a dbtimestamp and will increase monotonically on a container-wide basis. No two entities in the same container will ever receive the same version value. The dbtimestamp increases monotonically, however not necessarily sequentially. Clients should no longer assume entity version numbers are sequentially assigned. It does not start at 0, but may be any non-zero integer value for a newly created entity.

ETag support via REST, with similar functionality provided on the SOAP interface

· Support for If-Match and If-None-Match via the REST interface. This will allow you to verify that you have the latest version of an Entity enabling you to use resources more efficiently.

· Support for “Accept” header via the REST interface. This will allow you to denote what content you want returned from the service. For instance when retrieving a Blob, the “Accept” header will allow you to choose between the Blob content, or the metadata properties associated with it.

· Support for ETag semantics on the SOAP service via the new Version Match object on the Scope object.

HEAD support via REST interface

· Support for the “HEAD” verb via the REST interface.  This provides a lightweight way of validating existing entity version information without requiring entire entities (or blobs) to be retransmitted to the client.

A new content type – “application/x-ssds+xml” has been added to the service

· This content type is for storing XML content in the service.

· Existing “application/xml” content type is being phased out in a future sprint.

· The "application/x-ssds+xml" content type should be used for all entities except those containing blob content.  Blob entities should instead use a content type value which best reflects the type of blob data stored.  It's important to note that the value chosen here will be used later when attempting to retrieve the different parts of an entity by using the, "Accept" header.

For more information, please see the updated documentation at the DevCenter - http://msdn.microsoft.com/sql/dataservices

Thank You,

The SSDS Team

Posted by jcurrier | 4 Comments

Check out the SSDS coverage in the latest issue of MSDN magazine.

Hey all,

If you have a subscription to MSDN magazine, heck even if you don't, you read a bit more about using SSDS in the latest issue.  If you don't have a subscription then you can still read the article on-line here.

Enjoy!

Posted by jcurrier | 1 Comments

Optimistic Concurrency with SOAP in SSDS

In my last post I described how ETag's can be used in the upcoming sprint 3 version of SSDS.  In this post I'd like to talk about how this same functionality is exposed through our SOAP service head.

In many ways designing this particular feature for the REST head was much easier than for the SOAP service head.  This is because the Http specification describes, in a fair bit of detail, what the semantics are around things like ETag's.  The SOAP specification provides no such guidance and as a result we've rolled our own implementation here to support this feature in a way that makes sense for our service. 

VersionMatch

As I mentioned earlier, since there is no ETag concept natively in SOAP we've introduced a new object called, "VersionMatch".  We've augmented the Scope struct in the system to now include this so that version is now also considered a qualifier for operations that take place via the SOAP service head.

The VersionMatch object, as shown in the class diagram below, captures two things.  The first, is the version of the entity in question.  This could be the version of the entity we've just created, the version that I, as a caller, want to retrieve, or finally the one I want to update or delete. 

The second concept is something we refer to as the, "MatchType" or VersionMatchType.  This is used to determine how the service should compare the version when executing the requested operation.  This could mean that we only perform the operation if the version matches the version in the store (the VersionMatchType.Match case), or only perform the operation if it doesn't match (the VersionMatchType.NotMatch case) or finally to ignore the version completely when performing the operation.  NOTE: By default we use the Ignore semantic unless otherwise instructed.

Class Diagram of the modified Scope object along with the new VersionMatch object and VersionMatchType enum.

image

 

Now, that we've covered a bit of the changes to how we address things in the system let's see how we can apply these new features to some common scenarios.

Conditional Get

Conditional retrieval is an interesting case if a mid-tier or client application is maintaining a cache.  This shows up many times in the web browser case where large files are cached until they've been either refreshed or updated on the service side. 

We can now perform a similar operation now using the SOAP service head.  I've created a sample below which illustrates how a caller can now conditionally retrieve an entity only if the version has changed.

            using (SitkaSoapServiceClient client = new SitkaSoapServiceClient("SitkaSoapEndpoint"))
            {
                try
                {
                    // Create a reference to some entity that we know exists and one that
                    // we have a reference to in our cache (the version we have is 2000).
                    Scope entityScope = new Scope();
                    entityScope.AuthorityId = "some_authority";
                    entityScope.ContainerId = "some_container";
                    entityScope.EntityId = "123";
                    entityScope.VersionMatch = new VersionMatch();
                    entityScope.VersionMatch.Version = 2000;
                    entityScope.VersionMatch.MatchType = VersionMatchType.NotMatch;

                    // Then, retrieve the entity *only* if the version doesn't match the
                    // one that I already know about.
                    Entity theEntity = client.Get(entityScope);

                }
                catch (FaultException<Error> ex)
                {
                    if (ex.Detail.StatusCode == ErrorCodes.EntityNotModified)
                    {
                        // there is no later version.
                    }
                }
            }

Conditional Update and Delete

The next two cases are really very similar to one another.  In both of these cases we really only want to update (or delete) the entity if we know that there has been no other modifications to the entity in question.  This way we can be certain that we've not overwritten someone else's changes (in the update case) or perhaps deleted an entity which now (since the update) may not have needed to be deleted. 

The code listing below illustrates both of these cases.

Conditional Update in SOAP

            using(SitkaSoapServiceClient client = new SitkaSoapServiceClient("SitkaSoapEndpoint"))
            {
                try
                {
                    // Create a reference to some entity that we know exists.
                    Scope entityScope = new Scope();
                    entityScope.AuthorityId = "some_authority";
                    entityScope.ContainerId = "some_container";
                    entityScope.EntityId = "123";

                    // Then, retrieve the entity (any version will do).
                    Entity theEntity = client.Get(entityScope);

                    // Update some properties on the Entity.
                    theEntity.Properties["FavoriteStorageService"] = "SSDS";

                    // Next, update the version match properties on the scope we'll be using to update
                    // the entity with.
                    entityScope.VersionMatch = new VersionMatch();
                    entityScope.VersionMatch.Version = theEntity.Version;
                    entityScope.VersionMatch.MatchType = VersionMatchType.Match;

                    // Finally, update the entity if the version check clears.
                    client.Update(entityScope, theEntity);

                }catch(FaultException<Error> ex)
                {
                    if(ex.Detail.StatusCode == ErrorCodes.PreconditionFailed)
                    {
                        // Our version check failed so we don't have the latest and greatest.
                    }
                }
            }

Conditional Delete in SOAP

            using(SitkaSoapServiceClient client = new SitkaSoapServiceClient("SitkaSoapEndpoint"))
            {
                try
                {
                    // Create a reference to some entity that we know exists.
                    Scope entityScope = new Scope();
                    entityScope.AuthorityId = "some_authority";
                    entityScope.ContainerId = "some_container";
                    entityScope.EntityId = "123";

                    // Next, set the version match properties on the scope we'll be using to remove
                    // the entity with.
                    entityScope.VersionMatch = new VersionMatch();
                    entityScope.VersionMatch.Version = 2000; // the version of the entity we know about.
                    entityScope.VersionMatch.MatchType = VersionMatchType.Match;

                    // Finally, remove the entity if the version check clears.
                    client.Delete(entityScope);

                }catch(FaultException<Error> ex)
                {
                    if(ex.Detail.StatusCode == ErrorCodes.PreconditionFailed)
                    {
                        // Our version check failed so we don't have the latest and greatest.
                    }
                }
            }
 

That covers the optimistic concurrency examples for the Sprint 3 bits of SSDS.  I'm certain that there are other scenarios here that I'm not covering and I'd really like to hear other scenarios if you have them to share. 

Next time, I'll cover perhaps the biggest feature of the sprint (and one of our most requested features of the service that we have now completed for sprint 3....).  Look for more shortly :-)

ETag's, Optimistic Concurrency and SSDS

I've been kind of quiet the last month or so but that's because I've been totally heads down implementing some major features for this sprint in SSDS.  Our next release to production, which should be in the next few weeks,  is coming up fast so I thought over the next few posts to the blog I would cover some of the highlights of the release.

We've covered a lot of ground in this sprint.  We've added some features, which I believe, that people will be pretty excited about.  I've decided to start the ball rolling with one of the features that was requested early on of the service... ETag support. 

ETag's in SSDS

It may be useful to quickly review the role that ETag's play in a RESTful service.  The ETag header value is typically used by a client application to determine if the content of a give resource has changed over some period of time.  In SSDS we use the value of the, "Version" property as the ETag header value for a given entity.  As documented previously, the version value will be changed when a update takes place to a entity. 

At this point, you may be asking yourself when do I get one of these things back to me?  Beginning with the next rollout ETag's will be returned to the caller on all POST, PUT, and single entity GET operations.  Now, with query operations we can't return back a ETag value simply because the response doesn't actually refer to any one particular entity in the service.  Instead, if you would like to determine what would be the ETag value for any one entity in the EntitySet simply extract the Version property value from the entity of interest.

Now that we know when ETag's come back to us we likely should review how we would get the ETag value from the response.  ETag's are a common Http header and are well supported as shown in the sample below which retrieves an ETag from a HttpWebResponse.

HttpWebRequest request = CreateRequest();
using(HttpWebResponse response = request.GetResponse())
{
    string etagValue = response.Headers[HttpResponseHeader.ETag];
    // do something interesting with the ETag.
}

Conditional Operations

Now that we have ETag's we can use these to execute operations in a conditional manner.  In order to support these sort of operations we've added support for two other headers to the service the, "If-Match" and, "If-None-Match" headers.  We support these headers over all operations except for query though the following scenarios will likely fallout to be the most common:

  • Conditional GET - This is actually the most common case, browsers typically operate in this manner.  In short, they first retrieve a entity which retrieves a entity with a ETag.  Then, on any subsequent calls to the same resouce a, "If-None-Match" header is provided on the request with the ETag from the initial GET operation.  If, and only if, the resource has changed then the complete entity definition is returned to the caller. 

If the entity hasn't been updated then a 304 (NotModified) is returned and only the headers are returned to the caller. 

  • Conditional PUT - In this case, we only want to update the contents of an entity if we know that we have the latest and greatest.  In this case we would provide a, "If-Match" header value with the ETag value of the entity that we wish to update. 

In this case, if a later version of the entity is found in the service then we will return a 412 (PreConditionFailed) to the caller and the caller will have to retrieve the entity again and decide if they still need to update the entity again.

  • Conditional DELETE - This is case pretty much the exact same as the Conditional PUT case.  The only difference here being that the verb we've chosen to use is the DELETE verb rather then PUT.  I wanted to explicitly call out though just to illustrate our support for it.

HEAD support

There are some cases where the caller wishes to discover if the content they have is the latest greatest.  Typically, you would like this operation to be light weight in nature (which would exclude the returning of the entire entity) and only give you back the ETag or other relevant headers.  The Http specification provides a verb for this called, "HEAD" and with this sprint we've added support for it to the service. 

You use the HEAD verb just like you would the normal GET operation except that we will only return back to you the headers that are of interest.  This verb, will perhaps not so obvious in usefulness here, will become more obvious in my one of my next posts.

What about SOAP?

While I haven't covered SOAP in this post we have added support for these operations to the SOAP service.  I'll be covering the specifics of how this works in my next post.  Keep an eye out for this shortly!

Posted by jcurrier | 5 Comments

Late in blogging these days

Hey all,

Just wanted to drop a line to say that I realized I haven't been blogging much these days.  I've really been heads down on getting features ready for our next sprint.  The feature is quite big and has been one of our most requested features in the reviews we've had with customers so I hope all of you will be a bit understanding.  Look for more here shortly!

--Jeff--

Posted by jcurrier | 0 Comments

Do I have high Movie standards?

Okay,

This post is a bit off topic from my usual SSDS type posts (which I will be returning to shortly).  However, this post will focus on two movies which I recently rented and I have to say I was a bit disappointed with both.

The first movie, Cloverfied, which had all kinds of internet buzz around it was my first disappointing rental.  The Blair Witch style movie style coupled with the, IMO, lame storyline really sunk this one for me.  Also, I watched the special features at the end and there was all this talk that the monster was supposedly calling out for its mother or something to that effect.  How in the heck were you supposed to glean that from the storyline???

The second, which I just finished watching, was 30 days of night.  This looked pretty cool from the trailer, famous last wordsI suppose, but I was kind of left hanging at the end.  Don't get me wrong, I think this one was better then Cloverfield but still I feel like it didn't quite make the grade for me. 

So, do I have high Movie standards?

Posted by jcurrier | 1 Comments
Filed under:
More Posts Next page »
 
Page view tracker