I have just landed and got my bags rather quickly. I’m standing in a rather long line waiting for a cab in sweltering heat (comparatively speaking that is). I have been reading tweets from those who have been here and already joined in the excitement — from Scott Hanselman tweeting about his rehearsals to random conversations I started with those who couldn’t make it. The anticipation is killing me but one thing is for sure, I have arrived at Mix!! The cab line is filled with chatter about design, development and plans for a geek-long getaway. I brought my trusty Nikon D-7000 which at this point weighs a ton on my shoulder. I’ll be sure to put it to use and give you all regular updates. Stay tuned!
Posted from WordPress for Windows Phone
I Have Arrived … At #Mix11 that is
On My Way to Mix11
Be on the lookout for new posts this week. OK, this is really a placeholder post for the “mix11” tag I just added. Move along now. Nothing to see here. 😉
PMing my Technical Skills: a guide to ramping back up technically speaking
I’ve been transitioning away from a solely technical skillset to a PM skillset at Microsoft for a while now. That said, I have found that personally, I prefer to still keep my technical chops. Why should I have to sacrifice one for the other? My love for the technical world should drive my passion for the PM role. In fact, I’ve now found that I’m using my PM skills to compliment my technical skills as well. I don’t mean to say that I’ve applied all of the PM principals to my technical studying. However, I have realized that I inadvertently used those things I’ve learned in my PM career in a very lose way to help my technical skills.
Competitive Analysis
I like to see what other people are doing. Not just from a purely social standpoint, but also to understand what skills other’s find valuable and easy to use, and what skills are most common among everyone. I often also cruise the job boards (Microsoft Career Site, TheLadders.com, Monster.com, Dice.com, etc). I tend to look in various places around the country just so I know if certain skills are hot in one area, but not in another. So, I composed a spreadsheet of available positions, skills required (soft and technical), optional skills, pay, benefits, region, etc. I don’t do this because I’m looking for work, I do this because by gathering enough information, I can find that jobs that require iPhone app development skills pay more than say, Silverlight development skills. Once I had this data, I could see what skills were most valued. This serves as a rudimentary competitive analysis or “potential performance” and represents part one of a good gap analysis.
Skill Inventory Assessment (actual performance)
Part two of creating a good gap analysis, involves determining your actual performance to compare against your potential performance. To do this, I find it useful to also look at what skills I have in my inventory, see where they intersect with my “potential performance” from above, and see if I somehow missed your other skills as potentially valuable in the market. So, I made another sheet in my spreadsheet to list skills that I had and the self-assessment level at which I rank myself. For any skills that I added which were not in my “competitive analysis”, I did further research to see if those skills were found in the job boards or on friends blogs, or anywhere that I could assign some value to the skill. I use this as a secondary sanity check for skills that I might need to beef up on. Once I had this done, I moved on to the actual gap analysis.
Gap Analysis
I compared the competitive analysis against the skill inventory assessment and came up with a reasonable gap analysis of skills that I either needed to improve or acquire, and a list of other skills that I had which I needed to deemphasize in my studies for the next year. This list represents the gap that I have between where I want to be and where I am – otherwise known as the gap.
Action Plan
Once I had a my gap analysis complete, I had to create a plan to get from point a to point b. I looked first at books. While many people don’t learn well from books and prefer other methods, I still prefer a good solid technical book at least to start, and then I move on to other resources. So, for each skill, I set out to collect a list of books for each skill area on amazon. To assess each book, I looked at the number of ratings, amazon ranking, average rating, release date, and a number of other factors (including glancing through the table of contents to see if I felt those skills would be adequately covered in the book. Once I had the list of books, I didn’t stop there. I created a new sheet in my Excel file for each book that I intended to purchase. I listed each chapter and it’s length so that I could determine how fast I could read each book – giving myself milestones to complete by certain dates for each book. I made sure to account for downtime, upcoming vacations, goofing off (all work and no play…), and various other factors to give me a reasonable burn down rate on my learning plan.
Prioritizing the Plan
This is one area I thought about for a while. I could simply make this all about money and learn the most valuable skills first. However, I like to have fun, and I have specific projects in mind where some of these skills could be put to good use. That said, I opted away from prioritizing in any way that would be meaningful to anyone else. I am my own customer and I think it’s fair to let me set my own priorities in this instance. For others, however, you might want to prioritize based on projects you have at your job, getting a specific job, or just for pure fun. The option is yours.
Metrics / Performance Analysis
I’ve set clear goals for what I want to accomplish and set a timeline for completion. I have milestones that can help me determine my progress and help me assess risks. I have a project calendar and a burn down chart. I stopped short of creating a project file or creating work items in TFS. I’ll just use my spreadsheet to keep me in check for now.
Summary
This obviously doesn’t represent solid PM work, but I realized after the fact that I had just done a great deal of the same type of work I would do when I start a real project. It’s easy to say that you need to pick either PM or Development, but I’m finding that skills from both disciplines can compliment themselves quite well.
Azure Storage Client helpers
In my last post, I described how the configuration setting publisher worked. More specifically, I covered how to use the typical use-case of retrieving connection strings from Azure or local configuration and the typical errors you might produce when you use this incorrectly. I found myself writing the same code very often so I encapsulated this into a simple set of fluent-ish extensions (I say “ish” because by technical definition of fluent, these aren’t self-referencing… yet). That said, I thought I’d share this code as it helps me get my apps started pretty quickly.
// Author: Tobin Titus <tobin.titus@gmail.com> // Copyright (c) 2010 Tobin Titus // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.StorageClient; using Microsoft.WindowsAzure.ServiceRuntime; using System.Configuration; namespace AzureNinja.Storage { public class Client { public const string DEFAULT_CONNECTION_STRING_NAME = "StorageConnectionString"; static Client() { CloudStorageAccount.SetConfigurationSettingPublisher( (configName, configSettingPublisher) => { var connectionString = RoleEnvironment.IsAvailable ? RoleEnvironment.GetConfigurationSettingValue(configName) : ConfigurationManager.AppSettings[configName]; configSettingPublisher(connectionString); }); } public static CloudStorageAccount FromConfig( string configSetting = DEFAULT_CONNECTION_STRING_NAME) { return CloudStorageAccount.FromConfigurationSetting(configSetting); } public static CloudStorageAccount FromString(string connectionString) { return CloudStorageAccount.Parse(connectionString); } } public static class CloudStorageClientHelpers { public static CloudBlobClient ForBlobs(this CloudStorageAccount account) { return account.CreateCloudBlobClient(); } public static CloudQueueClient ForQueues(this CloudStorageAccount account) { return account.CreateCloudQueueClient(); } public static CloudTableClient ForTables(this CloudStorageAccount account) { return account.CreateCloudTableClient(); } } }
You can then construct your requests for a CloudXxxClient as follows:
CloudBlobClient client1 = Client.FromConfig().ForBlobs(); CloudQueueClient client2 = Client.FromConfig().ForQueues(); CloudTableClient client3 = Client.FromConfig().ForTables();
This uses “StorageConnectionString” as the default configuration key. And you can specify configuration key as well:
Client.FromConfig(“myConfigKey”).ForBlobs();
Furthermore, this allows you to concentrate on your calls to an otherwise fluent Azure API:
Client.FromConfig().ForBlobs().GetContainerReference(“myContainer”).Delete();
or
Client.FromConfig().ForBlobs() .GetContainerReference("myContainer").CreateIfNotExist();
Let me know if you have any questions or input.
CloudStorageAccount.SetConfigurationSettingPublisher
Those venturing into Windows Azure development for the first time may find themselves in a bit of a quandary when they try to devise a strategy for getting their storage account credentials. You dive into the Windows Azure APIs and determine that you must first get a reference to a CloudStorageAccount. You are all aglow when you find the “FromConfigurationSetting” method that takes a single string parameter named “settingName”. You assume that you can store your connection information in a configuration file, and call “FromConfigurationSetting” from your code to get dynamically load the connection information from the config file. However, like most of the Windows Azure documentation, it is very light on details and very heavy on profundity. The documentation for “FromConfigurationSetting” currently says:
Create a new instance of a CloudStorageAccount from a configuration setting.
That’s almost as helpful as “The Color property changes the color.” Notice that it isn’t specific about what configuration setting this comes from? The documentation is purposefully generic, but falls short of explaining why. So I’ve seen multiple questions in forums and blogs trying to figure out how this works. I’ve seen developers try to put the configuration setting in various places and make assumptions that simply providing the configuration path would get the desired result. Then they try to run the code and they get the following exception message:
InvalidOperationException was caught
SetConfigurationSettingPublisher needs to be called before FromConfigurationSetting can be used
Of course, this causes you to look up “SetConfigurationSettingPublisher” which also is a little light on details. It says:
Sets the global configuration setting publisher.
Which isn’t entirely clear. The remarks do add some details which are helpful, but don’t go as far as to help you understand what needs to be done – hence this blog post. So that was the long setup to a short answer.
The FromConfigurationSetting method makes no assumptions about where you are going to store your connection information. SetConfigurationSettingPublisher is your opportunity to determine how to acquire your Windows Azure connection information and from what source. The FromConfigurationSetting method executes the delegate passed to SetConfigurationSettingPublisher – which is why the error message says this method needs to be called first. The delegate that you configure should contain the logic specific to your application to retrieve the storage credentials. So essentially this is what happens:
- You call SetConfigurationSettingPublisher, passing in the logic to get connection string data from your custom source.
- You call FromConfigurationSetting, passing in a setting name that your delegate can use to differentiate from other configuration values.
- FromConfigurationSetting executes your delegate and sets up your environment to allow you to create valid CloudStorageAccount instances.
So, going back to a typical application, you want to store your configuration in a .config file and retrieve it at runtime when your Azure application runs. Here’s how you’d set that up. When your application starts up, you’ll want to configure your delegate using SetConfigurationSettingPublisher as follows:
CloudStorageAccount.SetConfigurationSettingPublisher( (configName, configSettingPublisher) => { var connectionString = RoleEnvironment .GetConfigurationSettingValue(configName); configSettingPublisher(connectionString); } );
If this is an ASP.NET application, you could call this in your Application_Start event in your global.asax.cs file. If this is a desktop application, you can set this in a static Constructor for your class or in your application startup code.
In this example, you are getting a configuration string the Windows Azure configuration file, and using the delegate to assign that string to the configuration setting publisher. This is great if you are executing in Windows Azure context all the time. But if you aren’t running your code in the Windows Azure context (for instance, you are exercising your API from NUnit tests locally) this example will throw another exception:
SEHException was caught
External component has thrown an exception.
To solve this problem, you can set up the delegate to handle as many different environments as you wish. For example, the following code would handle two cases – inside a Windows Azure role instance, and in a local executable:
CloudStorageAccount.SetConfigurationSettingPublisher( (configName, configSettingPublisher) => { var connectionString = RoleEnvironment.IsAvailable ? RoleEnvironment.GetConfigurationSettingValue(configName) : ConfigurationManager.AppSettings[configName]; var connectionString = RoleEnvironment .GetConfigurationSettingValue(configName); configSettingPublisher(connectionString); });
For your unit tests to work, just add an appSettings key to your configuration file:
<configuration> <appSettings> <add key="DataConnectionString" value="DefaultEndpointsProtocol=http; AccountName=<accountName>;AccountKey=<accountKey>;"/> </appSettings> </configuration>
Note: Make sure to replace <accountName> and <accountKey> with your custom values.
In the context of your Windows Azure application, just make sure that you configure the same configuration key name there. In Visual Studio:
- Right click your Windows Azure role and choose Properties from the dropdown menu.
- Click on the Settings tab on the left.
- Click the Add Setting button in the button bar for the Settings tab.
- Type “DataConnectionString” in the Name column
- Change the Type drop down box to Connection String
- Click the “…” (ellipsis) button in the right hand side of the Value column
- Configure your storage credentials using the values from the Windows Azure portal
- Click OK to the dialog
- Use the File | Save menu option to save your settings then close the settings tab in visual studio.
With this code, you should now be able to retrieve your connection string from configuration settings in a Windows Azure role and in a local application and retrieve a valid CloudStorageAccount instance using the following code:
var account = CloudStorageAccount .FromConfigurationSetting("DataConnectionString");
Of course, you aren’t limited to these scenarios alone. Your SetConfigurationSettingPublisher delegate may retrieve your storage credentials from anywhere you choose – a database, a user prompt, etc. The choice is yours.
For those of you who need a quick and dirty way to get an CloudStorageAccount instance without all the hoops, you can simply pass your connection string in to the Parse or TryParse method.
var account = CloudStorageAccount.Parse( "DefaultEndpointsProtocol=http;" + "AccountName=<accountName>;" + "AccountKey=<accountKey>");
This should give you all the information you need to get a CloudStorageAccount instance and start accessing your Windows Azure storage.
Hacking Polar Watch WebSync Software
I recently purchased a Polar FT-40 watch to monitor my fitness level and track my workouts better. I like the watch so far although I’m not ready to give a thorough review on it just yet. Today, I received the Polar FlowLink data transfer unit that allows me to transfer the data on my watch to Polar’s website. It allows you to chart your progress and do all sorts of interesting things with the data. I was surprised how easy and smoothly the software worked. However, I wanted the data on my desktop so I could do more with it. I wanted to provide my own charts and data views in Excel. I wanted to be able to post it to my blog easily or write a WordPress widget to display my data. That said, I decided to look at what the WebSync software was written in. I had a sneaking suspicion that it might be .NET — I was right!
So, I decided to look under the hood and see if I could tackle writing my own front end to their devices. What I found should horrify anyone who has ever read past Chapter 1 of a reasonable “C#” book.
I started by pulling in the obvious assemblies to see what was built. The project looked reasonably well built. There was enough evidence ot see that there was at least SOME design put into the application. I even found some tests in tone assembly — at least there were some tests (checked that off on their requirements eh?). When I took a look at the EXE, however, what I saw shocked me. So I started drilling down into WebSync.exe. I found a Polar.WebSync.Program class with a static Main() method. Bingo – my entry point. I immediately saw some minor concerns. For instance, they were using a Mutex to provide the functionality of a Singleton pattern. Worse yet, they were calling GC.KeepAlive() on the Mutex. Interesting. They did, however, have what looked like an external exception reporting framework, so that at least gave me SOME hope.
I found Application.Run that was starting a new WebSyncTrayForm() so I naturally followed to the form constructor. In a big Try/Catch block (with no code executing in the “catch” portion), I found a TextBox-style TraceListener was added to the form — mmkay. That’s a decent idea I suppose, but let’s look at the form’s Load event. Oh my! I closed my eyes and looked again. I closed then and then looked one more time. Oh, these folks must have written some VB code with “DoEvents” called more than a few times in their past history. Tell me what you see wrong with this:
WARNING: Not good example code!!
private void WebSyncTrayForm_Load(object sender, EventArgs e) { base.Visible = false; this.notifyIcon.Tag = this.notifyIcon.Icon; this.toolTip = this.notifyIcon.Text; this.notifyIcon.Text = this.toolTip + "n" + Resources.StatusInitializing; this.timerDaemon = new Timer(); this.timerDaemon.Interval = 0x2710; this.timerDaemon.Tick += new EventHandler(this.timerDaemon_Tick); this.timerDaemon.Start(); this.timerDaemon_Tick(this.timerDaemon, EventArgs.Empty); }
Seriously? These guys set up a timer, and then start it, and then MANUALLY call the Tick function they just set up! (how do they know it hasn’t been executed already between the start call and a thread interuption that might have caused the Tick event to get executed next.
Then I looked at the tick event and I couldn’t believe what I was seeing.
WARNING: Not good example code!!
private void timerDaemon_Tick(object sender, EventArgs e) { this.retryCount++; try { if (this.retryCount == 6) { this.timerDaemon.Interval = 0xea60; } this.mounter = new WristUnitListener(); this.mounter.WristUnitMounted += new WristUnitConnectionEventHandler(this.WristUnitMounted); this.mounter.WristUnitUnmounted += new WristUnitConnectionEventHandler(this.WristUnitUnmounted); this.mounter.Start(); this.DoInitialConfig(null); this.timerDaemon.Stop(); this.timerDaemon.Dispose(); this.timerDaemon = null; this.notifyIcon.Icon = this.notifyIcon.Tag as Icon; this.notifyIcon.Text = this.toolTip + "n" + Resources.StatusRunning; Trace.WriteLine("Connected to Polar Daemon.", "WebSync"); } catch (ConnectionException exception) { if (this.retryCount < 6) { Trace.WriteLine( string.Format("Couldn't connect to Polar Daemon ({0})", exception.CodeString), "WebSync"); } if (this.retryCount == 6) { Trace.WriteLine( string.Format("Couldn't connect to Polar Daemon ({0})", exception.CodeString), "WebSync"); Trace.WriteLine( string.Format("WebSync couldn't initialize properly." + "Please check that Polar Daemon service is running.", new object[0]), "WebSync"); this.notifyIcon.Icon = Resources.IconExclamation; this.notifyIcon.Text = this.toolTip + "n" + Resources.StatusInitError; this.notifyIcon.ShowBalloonTip(0x2710, Resources.ToolTipProblemTitle, Resources.ToolTipInitError, ToolTipIcon.Warning); this.notifyIcon.BalloonTipClicked += new EventHandler(this.notifyIcon_BalloonTipClicked); } } }
OK. These guys are on crack! They have a retry counter that apparently will never be more than 1. Because the tick event will go away and there is no loop in this code, the retryCount will always be 1 (taking note that they decided to start with a 1-based counting system rather than zero because n-1 is a bit complex). That at didn’t stop them from checking to see if it was equal to 6, and if so, changing the interval.
In the tick event, they create a new instance of a WristUnitListener and hook up events to it EACH time. They call start on the WristUnitListener instance and then STOP the timer and dispose of it! Never mind the fact that this timer execution is owned by the main thread rather than the timer tick function — when a timer stops itself, disposes of itself, and then nulls itself, it’s time to reevaluate your understanding of background-thread polling. This is insane! I have no idea how this even works. I can only hope that, as I dig in further WristUnitListener actually works the way it is supposed to and the only thing that sucks is the WebForms code.
Update January 13th, 2010 1:15AM PST:
I was able to successfully hack around with the API and get data off the watch with little effort. The trick was to working around some wonky and non-working APIs. To their defense 1) this API and software has to work with multiple watches 2) wasn’t intended to be consumed by other devs 3) was written with interop for the native libraries accessing the hardware, 4) does show signs of some intelligent thinking (although does need considerable amounts of re-work). As you can see by the image, I can even pull the bitmap logo off of the watch and, if I so desire, set it.
This is far from complete but I will work it over some this week and this weekend before publishing the source on Codeplex. Let me know if there is something in particular that you’d like to see.
Update July 7th, 2010 12:01AM PST:
I have posted this code to codeplex as-is. You can find it here: http://polarsync.codeplex.com/
If you would like to contribute source code or improve the project for others in the community, please send me a request and I’ll approve you. I don’t intend to maintain the code or improve it.
Poll: Where would you categorize SQL Azure?
I own the sites for all of the data stack on MSDN. I’m trying to categorize the SQL Azure technology where it makes the most sense to put it. I can obviously categorize this under SQL Server (as it currently sits), or I can move it to the Azure development center. Obviously I can link to it from either place, but I’m trying to decide where it belongs in the overall scheme of things. Your thoughts are appreciated. Vote, comment, do whatever you want, but please speak up and retweet this (link above) so others can too!
[poll id=”3″]
Thanks for your assistance!
Life hack: Getting better gas mileage
On my way to a metric-based lifestyle, I started taking a closer look at my gas mileage. This was a metric that I have been collecting for a while and thought I should be able to improve rather easily – lending itself to improved daily discretionary spending.
I recently purchased a 2010 Ford Fusion Sport. According to Ford’s specs I should be getting 18mpg in the city and 27mpg on the highway. I’ve put 11,000 miles on my car in 6 months – most of them highway driving so I should be getting near that top MPG range in this car. However, I rarely broke 300 miles on a single 17.5 gallon fuel tank (I usually filled up with 14-15 gallons). In fact, most of my fuel-ups netted me 270 miles. For the longest time, I couldn’t get above 18.x miles per gallon according to the sensor on my car. This left lots of room for improvement in a car that says it can do a lot better.
I keep a journal of my gas fuel-ups. Here are the metrics before my changes:
Avg Miles/Tank | Avg Gallons/Fuel-up | Avg Miles/Gallon | Est. Gallons/Year* | Est. Fuel Cost/Year** |
---|---|---|---|---|
272 | 14.53 | 18.71989 | 1282.059 | $3,653.87 |
* Based on 24,000 miles a year (my current pace)
** Based on $2.85/gallon average price tag
I just had to do better. I used to get a thrill out of getting 300 miles out of a tank of gas. I wanted to know what it was like to get 350 miles — maybe more. Without any research on the web, I just tried a few things – things that might be common sense for others, but were just not a big deal for me. Here is what I decided to do.
No More Distracted Driving
I have a ton of gadgets that can vie for my attention while I’m driving. In the past, those gadgets would get my attention – particularly if I was in stop and go traffic. I decided to make a habit of ignoring everything but driving. After driving through three tanks of gas, I noticed that I was consistently getting around 300 miles per tank. Distracted driving seems to have cost me about 10% of my fuel efficiency!
No More Aggressive Driving
I’ve lived in a lot of big cities where it was eat-or-be-eaten when it comes to driving. Again, in stop and go traffic, I would tend to stay very close to the bumper of the next car so others wouldn’t cut me off. I made a conscious decision once again to start driving far less aggressively. I use my cruise control when I can. I stay far behind the cars in front of me. A defensive driving instructor would be proud! Oddly enough, I feel a lot less stressed when I just acknowledge that people are going to keep cutting me off and that’s ok. The result? My last two fill-ups gave me over 350 miles per tank and my current tank is on target to give me about 365 if it keeps on pace! This is amazing.
Results
I’ve nearly squeezed an extra 100 miles out of every tank just by changing driving behavior! Let’s put this in perspective. Here are the metrics after my changes (assuming I get the 365 miles out of this tank):
Avg Miles/Tank | Avg Gallons/Fuel-up | Avg Miles/Gallon | Est. Gallons/Year* | Est. Fuel Cost/Year** |
---|---|---|---|---|
357.5 | 14.53 | 24.60427 | 975.4406 | $2,780.01 |
If you compare that against my previous cost, I’m on track to save $873.86 this year – and that’s if I don’t change anything else. Being that this is an iterative process, I’m going to try more behavior tweaking to try and get my MPG up.
Life Hack: A metrics-based lifestyle this decade
I’ve never considered myself to be a “life hacker” by any means. I have been concentrated on my career and comfort in the past decade and that came at some great costs. So, I decided to start formulating a plan to make changes to my life based on metrics. I will become a life hacker — for better or worse.
Metrics imply measurability and that’s what I intend to concentrate on at first — things that I can measure, change behavior, then measure again. While there is non-empirical consequence to many decisions that I make on a daily basis, I decided to start here. For instance, my first metric-based decision of the decade was to avoid stopping at Starbucks this morning. I estimate that a stop at Starbucks averages 15 minutes of my time, $5 of my wealth, and a negative drag on my health (250 calories, 47 carbs, and 180mg of sodium taken from my daily allowances of those items). A case could be made that this has decreased my momentary happiness. I’m not measuring that. In fact, I’m trying to do away with decisions based on immediacy. While my short-term aggrivation is great, I am speculating that over time this will turn into a net-positive for my happiness.
There are a lot of things that I want to change in my life this decade. But I’m going to concentrate on a few major areas, and break them down further as it makes sense to do so. Hopefully at some point I’ll be able to come up with an automated process to view my progress and give myself “triggers” to remind me when I’m slipping. Eventually, I’d like every decision I make to tigger a flurry of facts in my head before moving forward. That should also make its way into my structured planning for the day, week, month, quarter and year.
So here are the areas where I’m going to concentrate:
- Health – I’d like to improve my health through better nutrician, exercise, and sleeping habits. I will be measuring:
- Daily intake of calories, carbohydrates, protein, fat, fiber, sodium, and water.
- Daily exercise in the form of pedometer-tracked steps, cardio minutes, weight lifted and reps per exercise, and stretching minutes.
- Weekly weight
- Hour slept and number of times I woke up
- Wealth – I need to start planning and budgeting better. While I’m not exactly a spend-aholic, I can do better in my planning and spending decisions. I will track:
- Monthly savings contribution as a $ amount and a percentage of income
- Weekly investment changes
- Daily discretionary spending
- Quarterly credit score
- Time – This is where I hurt the most. I don’t have enough time in the day to do everything I want. I’m hoping making metric-based decisions will free up some time and help me better plan. I will track:
- Time spent blogging
- Time spent learning
- Time spent on household chores
- Time spent commuting
- Others – I will add additional metrics as I think of them or as I see a need to improve this process.
Obviously each of these are going to need base-lined for a month or so. I will be using whatever tools I can to accomplish this base-line. I’m planning on using an Omron HJ-720ITC Pocket Pedometer with Health Management Software to track my steps. I’m using the iPhone LiveStrong app as well as CalorieKing to track my daily nutrition and exercise metrics. I’m considering the Zeo Sleep Coach after Scott Hanselman recommended it, but for now I’ll just use some plain old pen/paper tracking, so to speak. I may also pick up on the Nike+iPhone app at some point, but not just yet.
If you are interested in tracking my progress and keeping me honest, I will be posting what I can under the “life hack” category on this site.
Happy new year everyone!
Government:origin,growth& form in the United States
I received a very thoughtful Christmas gift from Kamila this year. It was a book titled “Government : its origin, growth, and form in the United States, Ohio Edition“. The book showed an amazing amount of perspective into who I am. Books are very valuable to me — particularly books of this age (printed in 1902) with regards to government.
First, the book is a historical view of government in the United States. Anyone that knows me well knows this is important to me. I love history , and more specifically United States history.
Second, it was entertaining that it was an Ohio edition since that is where I grew up.
Third, I love the book’s perspective. The book still describes our founders as men with character and conviction — men who put country first. While I’m interested in truthful historical perspective, I don’t like the concentration placed solely on the negative information we can find about our founders.
For instance, I’m well aware that Ben Franklin was womanizer. I don’t overlook it. I take in perspective, however, with my admiration for the man. He was one of America’s biggest life-hackers in history. He was an inventor. While today LifeHacker.com might point to iPhone apps developed to improve your life, others were and still are pointing to Franklin’s inventions as aides in every day life. I also consider the fact that to the day he died many ridiculed Franklin (in spite of his obvious contribution to the country) for being an abolitionist (after owning slaves earlier in life). I admire a man who can examine his own beliefs and take difficult positions after careful introspection.
All of that points out that while I am aware of how Mr. Franklin behaved in the presence of women, I am more prone to talk about the positive. I would want me kids to emulate the positive, not the negative.
Lastly, I love this book because it demonstrates her understanding that I don’t need expensive gifts — thoughtfulness was key here. I only wish I could return that sentiment – I’m a horrible gift giver. I’ll endeavor to do better next year!
This book was the perfect gift for me. Thanks Kami!