Tag AppDev

GUIDs: Not Necessarily Unique

So, you though that GUIDs were supposed to be unique, eh? You aren’t alone. A lot of people assume that GUIDs are unique. Hell, unique is in the name!

On Friday, I had a bug report filed about a UNIQUE constraint violation. Seeing as how I had bigger fish to fry, and this functionality is only rarely used, I put it aside until this morning when I took a closer look at the bug report and the code in question.

The table in question looks something like this:

CREATE TABLE dbo.Widget 
(
  WidgetId BIGINT IDENTITY(1,1) NOT NULL,
  -- other columns
  LegacyIdentifier VARCHAR(50) NOT NULL
);

Before I get yelled at for a VARCHAR(50) in my database let me assure that this is actually a 50 character random garbage string from our legacy COBOl application. Nobody got lazy and just made a VARCHAR(50)… this time.

LegacyIdentifier has a unique constraint on it because all of the Widgets need to be unique between the new system and the old system. In order to keep this uniqueness going I thought to myself, “I know, the U in GUID stands for Unique, I’ll use that since I’m not clustering on it.” I wrote a little piece of code that puts “New_” at the beginning of a GUID and then uses that string as the LegacyIdentifier. That was about 11 months ago. On Friday, we received an exception warning that the application had attempted to insert a duplicate value into the LegacyIdentifier column.

What now? Well, I’m not sure. I’m going to implement functionality to force the database to keep generating GUIDs and attempting inserts until it actually generates a unique GUID.

This solution doesn’t make me happy, though, because GUIDs are not unique. A GUID is, in theory, unique. There are, after all, 2^128 possible permutations, so the probability of the same GUID being generated twice are incredibly slim. However, it can happen. (SQL Server uses a V4 GUID algorithm, which is a pseudo-random number and, as such, is not truly random. Newer GUID algorithms use an SHA hash for randomness, but how random is random?)

What are we to do when we need a truly unique identifier? Frankly, I’m not sure. The thought crossed my mind of generating a random number and casting it to VARCHAR and appending it to the GUID. The statistical likelihood of generating two random values that are the same as a prior value is so astronomically low that I should probably buy lottery tickets if there is ever a collision. As it stands right now, I’ve opted to retry the insert until it actually succeeds (or for 5 times, after which the user is doomed).

So, there you have it, GUIDs are not guaranteed to be unique and you should plan accordingly.

AppDev Virtual Meeting Today @ 1:00PM Eastern

I just wanted to get out a quick update about the AppDev Live Meeting today.

Josef Richberg will be speaking on the subject of SSIS Load Balancing. You can find more details on the Application Development Virtual Chapter home page. Or, at 1PM Eastern time (UTC -0400) you can head on over to LiveMeeting.

Abstract

How is it possible to aggregate 12,000,000 records of sales data in a short time window? In this presentation Josef Richberg will demonstrate the techniques used to randomize the input data and then use the SSIS threading framework to distribute the workload. These techniques make it possible to process a large quantity of data in a very short time frame.

About Josef Richberg

Josef is a DBA for HarperCollins Publishers working with SQL Server and SSIS. He has over 16 years experience designing, building, and tuning SQL Server. Josef is also the recipient of the ’2009 Exceptional DBA’ award and he actively blogs at http://josef-richberg.squarespace.com.

Upcoming Speaking Engagements

Just a quick reminder that I’ll be speaking at the Richmond Code Camp this upcoming weekend. I’ll be giving two talks… here they are:

Indexes and Other Free Performance Boosts

Time & Location

October 4, 2009 at Richmond Code Camp.

Abstract

The database is often viewed as a major performance bottleneck. There are a number of quick, easy, painless techniques that can increase the performance of an application not just by a small amount, but by orders of magnitude. These techniques includes simple indexing techniques, T-SQL techniques, and general database application design patterns that give great gains in performance. In this session, you will learn how to look at a database to identify these problem areas and how to resolve common issues that you will encounter.

From Tables to Objects: Making Your Database Work With You

Time & Location

October 4, 2009 at Richmond Code Camp.

Abstract

A database is far more than a persistent object store for your application; it is capable of data validation en masse, aggregations, and creating different projections of data. By working with your database, rather than against it, it is possible to leverage all of the capabilities of a relational database to provide rich, high performance interaction with your application through an ORM. This presentation will discuss the finer points of building a full-featured data access layer using an ORM and the features of a relational database.

Goals

  1. Teach attendees about database features that make development easier – including views, sparsely populated tables, and user-defined functions and types.
  2. Empower the audience to solve object relational impedance mismatch using data modeling techniques and database features.
  3. Demonstrate how to integrate the database and object oriented software using a custom designed data access layer.

Scripting Objects with Magic

You know what, there’s no magic here. However, it’s kinda magic to me since I didn’t write it and reading other people’s code is something that is almost like magic to me. And, I have to admit that I did not write this code. One of my co-workers, Brent Morrow, came up with this solution. Sadly, Brent does not have a blog. Luckily, I do. So now I will share with you Brent’s solution for keeping track of objects to move from one platform to another.

What’s the goal here? Well, let’s say we don’t have VSTS: Database Developer edition. And let’s further posit that we don’t have access to any of the commercially available schema comparison tools. Apart from pen and paper, how shall we keep track of the changes that need to go into production?

Well, we can use SQL Server to keep track of these changes.

The first thing we need is a table to track this:

CREATE TABLE [Debug].[DBObjects]
    (
      [LocalID] [int] IDENTITY(1, 1)
                      NOT NULL,
      [Schema] [nvarchar](128) NOT NULL,
      [Name] [nvarchar](128) NOT NULL,
      [ObjectType] [varchar](30) NOT NULL,
      [RequestedBy] [varchar](30) NULL,
      [RequestedDate] [datetime] NULL,
      [ProductionReady] [bit] NULL,
      [ProductionDate] [smalldatetime] NULL,
      [InProduction] [bit] NULL,
      [Comments] [varchar](2048) NULL,
      CONSTRAINT [PK_DBObjects] PRIMARY KEY CLUSTERED ( [LocalID] ASC )
        WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
               IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
               ALLOW_PAGE_LOCKS = ON ) ON [PRIMARY]
    )
ON  [PRIMARY] ;

So, here are the rules for the table:

  • Schema – this is the object schema. It’s required.
  • Name – the name of the object to be scripted. Also required.
  • ObjectType – the type of object that we’re scripting. This needs to be one of the following values: STORED PROCEDURE, VIEW, FUNCTION. This is required. Spelling is important.
  • RequestedBy – this shows up in the script, but it’s not required.
  • RequestedDate – this also shows up in the script, but it’s not required.
  • ProductionReady – this is required, it needs to be set to 1.
  • ProductionDate – this is optional, it is just the date that something goes/went into production.
  • InProduction – One the object has been moved into production, set this to true (1). If you don’t do this, and ProductionReady is set to true (1), then the object will be scripted the next time that everything is run.
  • Comments – optional comments, these show up in the script.

So, what is the next step? Well, you need a way to script all of this. Basically, the following script will execute against the DBOjects table and will generate a script for all of the objects in the table with ProductionReady set to true and InProduct set to false. Once the script has been run against the new environment, set InProduction to true (or remove the row) and the object won’t be scripted in subsequent runs. If you have more changes, add a new line with a new comment and new request date. Good times, eh?

So, a big thanks to Brent Morrow for sharing this code with the world. If you have questions, comments, concerns, improvements, or just want to share kudos, put them down in the comments or drop me an email and I’ll make sure that Brent knows about it.

---------------------------------------------------------------
-- DEFINITIONS
---------------------------------------------------------------

CREATE TABLE #EntryHold ( [Text] VARCHAR(4000) )

CREATE TABLE #Entry ( [Text] VARCHAR(4000) )

DECLARE @LocalID INT
DECLARE @Schema VARCHAR(50)
DECLARE @Name VARCHAR(100)	
DECLARE @ObjectType VARCHAR(100)
DECLARE @ProductionReady BIT
DECLARE @InProduction BIT
DECLARE @RequestedBy VARCHAR(50)
DECLARE @RequestedDate DATETIME
DECLARE @Comments VARCHAR(2000)
DECLARE @Counter TINYINT
DECLARE @Supported BIT


DECLARE [EntryCursor] SCROLL CURSOR
    FOR SELECT  [LocalID],
                [Schema],
                [Name],
                [ObjectType],
                [ProductionReady],
                [InProduction],
                [RequestedBy],
                [RequestedDate],
                [Comments]
        FROM    [Debug].[DBObjects]
        ORDER BY [LocalID]
		
---------------------------------------------------------------
-- HEADER
---------------------------------------------------------------
OPEN [EntryCursor]

-- STORED PROCEDURES NOT MOVED
INSERT  INTO #Entry
VALUES  (
          '--- OBJECTS NOT BEING MOVED ---'
        )

SET @Counter = 0
WHILE @Counter < 3
    BEGIN
        FETCH FIRST FROM [EntryCursor] INTO @LocalID, @Schema, @Name,
            @ObjectType, @ProductionReady, @InProduction, @RequestedBy,
            @RequestedDate, @Comments
	
        WHILE @@FETCH_STATUS = 0
            BEGIN
                SET @Supported = CASE WHEN @ObjectType IN ( 'VIEW',
                                                            'STORED PROCEDURE',
                                                            'FUNCTION' )
                                      THEN 1
                                      ELSE 0
                                 END

                IF ( ( @ObjectType = 'VIEW'
                       AND @Counter = 0
                     )
                     OR ( @ObjectType = 'STORED PROCEDURE'
                          AND @Counter = 1
                        )
                     OR ( @ObjectType NOT IN ( 'STORED PROCEDURE', 'VIEW' )
                          AND @Counter = 2
                        )
                   )
                    AND ( @ProductionReady IS NULL
                          OR @ProductionReady = 0
                        )
                    AND ( @InProduction IS NULL
                          OR @InProduction = 0
                        ) 
                    BEGIN
                        INSERT  INTO #Entry
                        VALUES  (
                                  '--REQUESTOR: ' + @RequestedBy + SPACE(12 - LEN(@RequestedBy))
                                  + 'DATE: ' + CONVERT(VARCHAR, @RequestedDate, 101)
                                  + ' | ' + @ObjectType + ': ' + @Schema + '.'
                                  + @Name
                                )
                        IF @Supported = 1 
                            INSERT  INTO #Entry
                            VALUES  (
                                      '--        REASON NOT MOVED:  Not production ready!'
                                    )
                        ELSE 
                            INSERT  INTO #Entry
                            VALUES  (
                                      '--        REASON NOT MOVED:  Not Supported!'
                                    )
			
                        IF ( @Comments IS NOT NULL ) 
                            INSERT  INTO #Entry
                            VALUES  (
                                      '--        COMMENTS:  ' + @Comments
                                    )
                    END
                FETCH [EntryCursor] INTO @LocalID, @Schema, @Name, @ObjectType,
                    @ProductionReady, @InProduction, @RequestedBy,
                    @RequestedDate, @Comments
            END
        SET @Counter = @Counter + 1
    END
INSERT  INTO #Entry
VALUES  (
          '---------------------------------------------------------------------------------------------------'
        )

INSERT  INTO #Entry
VALUES  (
          '--- OBJECTS READY TO MOVE ---'
        )

SET @Counter = 0
WHILE @Counter < 3
    BEGIN
        FETCH FIRST FROM [EntryCursor] INTO @LocalID, @Schema, @Name,
            @ObjectType, @ProductionReady, @InProduction, @RequestedBy,
            @RequestedDate, @Comments
        WHILE @@FETCH_STATUS = 0
            BEGIN
                IF ( ( @ObjectType = 'VIEW'
                       AND @Counter = 0
                     )
                     OR ( @ObjectType = 'STORED PROCEDURE'
                          AND @Counter = 1
                        )
                     OR ( @ObjectType NOT IN ( 'STORED PROCEDURE', 'VIEW' )
                          AND @Counter = 2
                        )
                   )
                    AND ( @ProductionReady = 1 )
                    AND ( @InProduction IS NULL
                          OR @InProduction = 0
                        ) 
                    BEGIN
                        INSERT  INTO #Entry
                        VALUES  (
                                  '--REQUESTOR: ' + @RequestedBy + SPACE(12 - LEN(@RequestedBy))
                                  + 'DATE: ' + CONVERT(VARCHAR, @RequestedDate, 101)
                                  + ' | ' + @ObjectType + ': ' + @Schema + '.'
                                  + @Name
                                )
                        IF ( @Comments IS NOT NULL ) 
                            INSERT  INTO #Entry
                            VALUES  (
                                      '--        COMMENTS:  ' + @Comments
                                    )
                    END
                FETCH [EntryCursor] INTO @LocalID, @Schema, @Name, @ObjectType,
                    @ProductionReady, @InProduction, @RequestedBy,
                    @RequestedDate, @Comments
            END
        SET @Counter = @Counter + 1
    END

INSERT  INTO #Entry
VALUES  (
          '---------------------------------------------------------------------------------------------------'
        )
INSERT  INTO #Entry
VALUES  (
          '--- OBJECT SCRIPTS ---'
        )

---------------------------------------------------------------
-- SCRIPTS THAT ARE PRODUCTION READY
---------------------------------------------------------------
SET @Counter = 0
WHILE @Counter  5 
                            BEGIN
                                INSERT  INTO #Entry
                                        SELECT  *
                                        FROM    #EntryHold
                            END
                        ELSE 
                            BEGIN
                                INSERT  INTO #Entry
                                VALUES  (
                                          '--' + @ObjectType + ' [' + @Schema
                                          + '].[' + @Name + '] was not found.'
                                        )
                                INSERT  INTO #Entry
                                VALUES  (
                                          '---------------------------------------------------------------------------------------------------'
                                        )
                            END
                        DELETE  FROM #EntryHold
                    END

                FETCH [EntryCursor] INTO @LocalID, @Schema, @Name, @ObjectType,
                    @ProductionReady, @InProduction, @RequestedBy,
                    @RequestedDate, @Comments
            END
        SET @Counter = @Counter + 1
    END

---------------------------------------------------------------
-- SCRIPTS THAT ARE NOT PRODUCTION READY
---------------------------------------------------------------
CREATE TABLE #CommentEntry ( [Text] VARCHAR(4000) )

SET @Counter = 0
WHILE @Counter < 3
    BEGIN
        FETCH FIRST FROM [EntryCursor] INTO @LocalID, @Schema, @Name,
            @ObjectType, @ProductionReady, @InProduction, @RequestedBy,
            @RequestedDate, @Comments

        WHILE @@FETCH_STATUS = 0
            BEGIN
                IF ( ( @ObjectType = 'VIEW'
                       AND @Counter = 0
                     )
                     OR ( @ObjectType = 'STORED PROCEDURE'
                          AND @Counter = 1
                        )
                     OR ( @ObjectType NOT IN ( 'STORED PROCEDURE', 'VIEW' )
                          AND @Counter = 2
                        )
                   )
                    AND ( @ProductionReady IS NULL
                          OR @ProductionReady = 0
                        )
                    AND ( @InProduction IS NULL
                          OR @InProduction = 0
                        ) 
                    BEGIN
                        INSERT  INTO #CommentEntry
                                EXECUTE
                                       ( 'sp_helptext @objname = ''' + @Schema
                                         + '.' + @Name + ''''
                                       )
                        INSERT  INTO #CommentEntry
                        VALUES  ( 'GO' )
                        INSERT  INTO #CommentEntry
                        VALUES  (
                                  '---------------------------------------------------------------------------------------------------'
                                )
                    END

                FETCH [EntryCursor] INTO @LocalID, @Schema, @Name, @ObjectType,
                    @ProductionReady, @InProduction, @RequestedBy,
                    @RequestedDate, @Comments
            END
        SET @Counter = @Counter + 1
    END

INSERT  INTO #Entry
        SELECT  '--' + [Text]
        FROM    #CommentEntry

DROP TABLE #CommentEntry

CLOSE [EntryCursor]
DEALLOCATE [EntryCursor]

DROP TABLE #EntryHold

SELECT  *
FROM    #Entry
DROP TABLE #ENTRY

AppDev Virtual Chapter and CBusPASS Round Up

A special thanks to Grant Fritchey and Kevin Kline for their recent presentations.

Understanding Execution Plans

Grant Fritchey's Fists of Fury - putting execution plans in their place

Grant Fritchey's Fists of Fury - putting execution plans in their place

Grant Fritchey gave a phenomenal presentation covering more than just the plain basics about execution plans. Rather than focus on the wealth of potential operators that SQL Server can show in an execution plan, Grant focused on reading actual execution plans and showing the most common operations and what they mean. In addition to covering some ideal scenarios, Grant also discussed potential performance bottlenecks, how to investigate these potential bottlenecks, and what to do when they become an actual problem.

Unfortunately, due to technical mishaps (Grant and I both forgetting to start the presentation recording) there is no recording.

FEAR NOT! There will be a repeat of this presentation in October when Grant will be presenting virtually for the CBusPASS group.

End to End Performance Tuning

Kevin Kline happily donated his evening, skipped part of the DevLink keynote and drove me back to my hotel in order to present remotely for CBusPASS. Kevin outlined a performance tuning methodology that works universally across SQL Server 2005 and 2008. Kevin’s presentation, despite some technical hiccups, covered some great ground and reminded me that it’s alwasy best to start at the most basic level (error logs in both Windows and SQL Server) and move through the general layers of the OS, database, and then application while slowly narrowing down towards the specific problem and a working solution.

Bonus Fact: Kevin is red-green color blind.

A Case of Shifting Identity

- Or -
A Brief Foray Into the Realm of IDENTITY Columns

We all know, or should know, when we insert into a table using using SET IDENTITY_INSERT, that the identity value will be reset to the next available value in the sequence. Meaning that the identity value will either be the next value that it was supposed to be (if we filled a gap in the sequence) or the next value larger than the row we’ve just inserted (so if we inserted 100, the next identity will be 101). Right? Well, sort of. Books Online, somewhat confusingly, states that “If the value inserted is larger than the current identity value for the table, SQL Server automatically uses the new inserted value as the current identity value.” Define larger.

In this case, larger actually does mean the next available value in the sequence. Check it:

IF OBJECT_ID('tempdb..#t') IS NOT NULL
  DROP TABLE #t;

CREATE TABLE #t (
  id INT IDENTITY(1,1),
  val VARCHAR(10)
);

INSERT INTO #t VALUES ('a');
INSERT INTO #t VALUES ('b');
INSERT INTO #t VALUES ('c');
INSERT INTO #t VALUES ('d');
INSERT INTO #t VALUES ('e');
INSERT INTO #t VALUES ('f');

SET IDENTITY_INSERT #t ON;

INSERT INTO #t (id, val) VALUES (-1, 'g');

SET IDENTITY_INSERT #t OFF;

INSERT INTO #t VALUES ('h');

SELECT * FROM #t;

“ZOMG, he’s so smart!” I know, that’s totally what you’re saying, right? Well, by using a straightforward example, I’ve gone ahead and proved nothing apart from showing you that I know how to use SET IDENTITY_INSERT and copy/paste.

So, what happens if you want to use a negative identity seed? Technically the numbers are getting smaller, not larger, right?

IF OBJECT_ID('tempdb..#t') IS NOT NULL
  DROP TABLE #t;

CREATE TABLE #t (
  id INT IDENTITY(-1,-1),
  val VARCHAR(10)
);

INSERT INTO #t VALUES ('a');
INSERT INTO #t VALUES ('b');
INSERT INTO #t VALUES ('c');
INSERT INTO #t VALUES ('d');
INSERT INTO #t VALUES ('e');
INSERT INTO #t VALUES ('f');

SET IDENTITY_INSERT #t ON;

INSERT INTO #t (id, val) VALUES (1, 'g');

SET IDENTITY_INSERT #t OFF;

INSERT INTO #t VALUES ('h');

SELECT * FROM #t;

Witchcraft! I made the numbers decrease instead of increase! But then I used good magic to put a positive number in there and then the witches corrupted the sequence and the numbers got smaller again!

Sensibly speaking, though: it works. The identity resumes the normal sequence and order is again restored in the world. Had I inserted -10 instead of 1, the next value inserted into the id column would have been -11. Which makes sense.

Why the linguistic confusion on the part of Books Online? I don’t know. I would hazard a guess and say that it was implied that they meant “larger in relation to the IDENTITY seed that you have set up” (and probably muttered the words “you pedantic toad” under their breath). But rather than explicitly go out on a limb and define such a thing in the documentation for SET IDENTITY_INSERT, they assumed that people would infer the meaning. You know, they assumed that people would make sense.

Why would you ever want to do something silly like this? I have my reasons, but I’m sharing this as a test of the application functionality that I needed and a useful demonstration of how IDENTITY works.

Links for the Week – 2009.08.07

SQL Server

Commenting Your Code Do it, people. I don’t comment enough of my code, but it’s something I keep in the back of my mind all the time.

Fast Running Totals Solution With Ordered CTE I love Mladen’s solution to this particular problem. I usually would use a nasty self join or some kind of hideous cross join to accomplish this.

Teaser: Left Join..the SQL ego crusher Mmmmm SQL brain teaser.

Development

Software is a Wicked Problem

sqlsharp It’s a port of SQLite to C#. I don’t believe source code has been posted yet, but it’s a great idea for portable development.

TeamReview Ask your co-workers for a code review, and get one, all through VSTS. I’m not a fan of meetings. I hate them. I also hate reading your code. I’d be much happier reading your code from my cube. Now I can.

Stuff & Things

How to Set Someone Straight Correcting people is never easy. Use these four simple steps to lead to success.

title unknown

Teach for America founder on the pointlessness of planning, the importance of saying no, etc. This is interesting because it’s a collection of quotes, but the 37signals folks link back to their own articles. Very interesting stuff.

:::WARNING – RANT:::
Netflix Shares Internal Presentation on Company Culture I was going to try to build an entire blog post out of this. Then I realized it would sound like I rant, so I decided to ran in my weekly link dump instead because it’s my blog and youcantmakemegotobedearlyanymore! So… yeah, anyway. Netflix sounds like an amazing place to work – they do everything they can to let good employees innovate and reward them effectively. For people outside of the consulting world, it doesn’t make sense to hold them to some weird standard of X days of holiday a year. Most of our work is based around meeting goals, not producing sprockets. Does it really matter if I want to take an extra few days off here and there? If I’m a top producer, that should be fine.

The other thing that really struck me about Netflix is how they compensate their employees. They hit a few things on the head that I’ve always agreed with – don’t bonus your employees, pay them. If you tell me, at hiring, that you’ll give me a $5,000 bonus in 6 months, pay me $5,000 more now. I don’t want a bonus. A bonus won’t make the payments on my sweet ride. They also pay their employees what they think they’re worth. Salary negotiations are a game. Playing games with employees that you allegedly trust and who are supposed to trust you is not a good way to conduct business.

Many businesses would do well from reading this slide deck and learning from it.
:::END RANT:::

From Tables to Objects – Follow Up

First off, I want to say thank you to the Central Ohio .NET Developers Group for giving me the opportunity to speak last night. I really enjoyed it and I was glad that I could share some of the things that I’ve learned with such a great group of people.

Everyone at CONDG was very welcoming, as they always have been, and the questions from the audience were fantastic. It’s always good to hear that I’m not the only one who has run into some of the scenarios I mentioned in the presentation, and it’s also always great to hear real life success stories from developers who have made use of the techniques that I’m speaking about – in this case NHibernate.

I have to take this opportunity, as well, to think my host, admin, and brother who took time out of his evening to make sure that the presentation resources automatically posted on time through WordPress. Unfortunately, they didn’t post on time and he looked into to the problem to make sure that the resources would be there by the time the presentation was done. So a big thanks to Mike for keeping things running and going the extra mile to make sure the resources were available for everyone to download when the presentation was over.

97 people were able to make it to the presentation. If you weren’t able to attend and would like to see this presentation, let me know. If there’s enough support I can either schedule a LiveMeeting to do this presentation again one evening, or I can record it and make it available online for viewing. Let me know in the comments or send me an email and let me know.

Links for the Week of 2009.07.17

SQL Server

File/Folder/Share Permissions for DBAs and Database Developers So you thought you knew everything you needed to know about security? Take a look and make sure your assumptions were correct.

Groovy Baby, Yeah Tony Bain hits up the sweet spots from Groovy Corp’s press release for a new relational database platform. New DB?!? That’s right a new, in memory, RDBMS.

Development

The Law of Demeter Is Not A Dot Counting Exercise Phil Haack gives the best explanation I have ever read for the Law of Demeter, which is oft quoted by developers and oft misunderstood by me.

In Branch Per Feature Source Control Introduction and Part 1: Why? Derick Bailey is going over a great idea to isolate source code within source control. Rather than branching for each release, branch for each feature. Hit up the articles for an in depth look at this idea.

Stuff & Things

Insanely Twisted Shadow Planet New Trailer Michel Gagne is an illustrator who is working on what looks like a phenomenally beautiful video game. Check out the trailer for some glory.

A Beautiful Method to Find Peace of Mind

Crash Bonsai Thanks to William Gibson I became aware of this art.

Links for the Week of 2009.07.10

SQL Server

Object Naming Standards Scott Herbert put up an overview of the naming standards that he uses. Like the obnoxious lout that I am, I commented. The point is, of course, to use naming standards. Take a look at Scott’s for an example.

No SQL There’s a big hullabaloo going on about this whole “No SQL” movement. Here’s Andrew Fryer’s take on it.

Performance Counter for SQL Server Ever want to know what those performance counters actually mean?

Development

Thrive for Developers is Online Brian Prince, a great guy and former co-worker, highlights some of the benefits of the newly launched Thrive for Developers program. Check it out for some more info on how to improve your career and how MS can help you do it!

10 Useful Firefox Extensions to Supercharge Firebug Firebug is the best tool for web development that I have found so far. These extensions make it even better.

Stuff & Things

Anticipate Your Interviewer’s Next Question to Ace Your Job Interview Good interviewing advice can be found here.

Day made, mind blown: it’s Portal in ASCII

Oh No You Didn’t! Everyone needs a chair like this.

This site is protected with Urban Giraffe's plugin 'HTML Purified' and Edward Z. Yang's Powered by HTML Purifier. 531 items have been purified.