Thanksgiving Turkey in the Smoker

Thanksgiving Turkey in the Smoker

And now for something completely different. This past week was Thanksgiving in the states, and for almost all of us it was different than normal as COVID-19 prevented us from getting to see our families. Here in the Mack household, we took the opportunity to try something new, and used my pellet smoker, to Smoke a turkey.

And I thought I would share the results.

Turkey Brine:

Basically the process was this, we started the night before with a turkey brine, which was the following:

Now for this we took inspiration from Alton Brown’s recipe found here. But made some slight adjustments:

Here are the ingredients:

  • 1 gallon hot water
  • 1 pound kosher salt
  • 2 quarts vegetable broth
  • 1 pound honey
  • 1 (7-pound) bag of ice
  • 1 (15 to 20-pound) turkey, with giblets removed

Now we combine the boiling water, salt, vegetable broth, and honey into a cooler and mixed everything until it had all dissolved.

Next we added the ice to keep the brine cool and let it come down in temperature to normal. We then took the turkey, and put it in and waited 16 hours.

From there the next step was to remove the turkey from the brine and dry it off. We did not rinse the bird, as my family likes it a little on the salty side, but if you don’t, you’ll want to rinse your bird.

Marinade Injection:

I’m of the belief that Turkey dries out really easy, so we decided to do everything humanly possible to get this bird to stay moist. And the next step was to put together an injection. We got inspiration from here.

Here are the ingredients:

  • 1/2 cup Butter
  • 1/2 cup Maple Syrup

And then we melted both together and allowed it to cool slightly. The idea here being it needs to be a liquid for the injector and don’t let it cool too far or you’ll be injecting sludge into your bird.

We then injected the bird over 50 times, doing small little injections about ever inch across the breast, legs, thighs, and pretty much every part of the exposed meat.

Next we put on a rub, and for this we put together about a half a cup of butter and a store bought turkey rub, we found at lowes. But really any rub that you would use on poultry is a good idea here. And rubbed under the skin of the bird.

Smoking the bird

I got my pellet smoker up to 250 degrees Fahrenheit, and then put in the bird. We used a aluminum disposable pan to keep the drippings around the bird and help with moisture. And then every hour, I would spray the turkey with apple juice.

We kept the turkey cooking until we got it to an even 165 degrees Fahrenheit.

Finally we did increase the temperature when it got to 165 degrees to 325 and let it go for another 30 minutes to make the skin crispy.

After that, enjoy!

Generating Dummy Data for Event Hubs or Blob Storage

Generating Dummy Data for Event Hubs or Blob Storage

So I was working on this as part of another project, and I thought I would share. Basically, one of the most annoying aspects of building data pipelines is getting test data to verify the results of that data.

So nothing overly ground breaking, but I thought this might be useful for anyone trying to pipe data into a data pipeline, whether that be blob storage or event hub.

So what I did was build a small generic utility to build text files full of JSON objects and then parse those files putting them onto event hub.

Now for the sake of this instance, I decoupled the code for the event hub, so that I could get more utility, and implemented this as part of a dotnet core console application. Below is the method for generating the files:

static void Main(string[] args)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
            var configuration = builder.Build();

            var appSettings = new AppSettings();

            ConfigurationBinder.Bind(configuration.GetSection("AppSettings"), appSettings);

            for (var f = 0; f < appSettings.NumberOfFiles; f++)
            {
                var fileName = $"{appSettings.FilePrefix}-{f}-{ DateTime.Now.ToString("MM-dd-yyyy-hh-mm-ss")}.txt";

                Console.WriteLine("-----------------------------------------------------------------------");
                Console.WriteLine($"Creating file - {fileName}");
                Console.WriteLine("-----------------------------------------------------------------------");
                Console.WriteLine("");

                //Create records for entry
                var list = new List<LogEntryModel>();
                for (var x = 0; x < appSettings.MaxNumberOfRecords; x++)
                {
                    var logEntry = new LogEntryModel();

                    logEntry.LogDateTime = DateTime.Now;
                    logEntry.LogMessage = $"Test { x } - { DateTime.Now.ToString("MM-dd-yyyy-hh-mm-ss")}";
                    logEntry.SequenceNumber = x;

                    list.Add(logEntry);
                    Console.WriteLine($"Creating line entry - { logEntry.LogMessage}");

                    var randomTime = RandomNumber(1, appSettings.MaxWaitBetweenEntries);

                    Console.WriteLine($"Thread sleep for { randomTime }");
                    Thread.Sleep(randomTime);
                    Console.WriteLine($"Sleep over - Processing file");
                }

                var filePath = $@"C:\temp\{fileName}";
                //Create text file"
                using (StreamWriter file = File.CreateText(filePath))
                {
                    JsonSerializer serializer = new JsonSerializer();
                    serializer.Serialize(file, list);
                    Console.WriteLine("Pushing Json to file");
                    Console.WriteLine("");
                }

                //Push to blob storage
                BlobServiceClient blobServiceClient = new BlobServiceClient(appSettings.BlobConnectionString);

                //Create a unique name for the container
                string containerName = "logs";

                // Create the container and return a container client object
                var containerClient = blobServiceClient.GetBlobContainerClient(containerName);

                BlobClient blobClient = containerClient.GetBlobClient(fileName);

                Console.WriteLine("Pushing File to Blob Storage");
                Console.WriteLine("");
                using FileStream uploadFile = File.OpenRead(filePath);
                var uploadTask = blobClient.UploadAsync(uploadFile, true);

                uploadTask.Wait();

                uploadFile.Close();

                Console.WriteLine("File Uploaded to Blob storage");
                Console.WriteLine("");

                var randomFileTime = RandomNumber(1, appSettings.MaxWaitBetweenFiles);
                Console.WriteLine($"Thread going to sleep for - { randomFileTime}");
                Thread.Sleep(randomFileTime);
                Console.WriteLine("Thread sleep down, moving onto next file");
                Console.WriteLine("");

                Console.WriteLine($"Started Deleting file {filePath}");
                File.Delete(filePath);
                Console.WriteLine($"Finished Deleting file {filePath}");
            }

            Console.WriteLine("All Files Processed and uploaded.");

            Console.ReadLine();
        }

In addition to creating staggered entries, it additionally outputs in an easy readable format to the console screen. Below is the method I use to generate the random numbers:

static int RandomNumber(int min, int max)
        {
            return _random.Next(min, max);
        }

Overall nothing to special, but it at least creates an easy method of generating the json objects required for pumping through a data pipeline.

Below is all I leverage for a data model for this but this could easily be swapped for any data model you like with some random elements:

public class LogEntryModel
    {
        public DateTime LogDateTime { get; set; }
        public string LogMessage { get; set; }
        public int SequenceNumber { get; set; }
    }

Now on the back end, I needed to take these blob files and parse them. And did so by doing the following:

using (var sr = new StreamReader(logFile, Encoding.UTF8))
            {
                var logs = new List<LogEntryModel>();

                var str = sr.ReadToEnd();

                logs = JsonConvert.DeserializeObject<List<LogEntryModel>>(str);

                await using (var producerClient = new EventHubProducerClient(connectionString, hubName))

                {
                    using EventDataBatch eventBatch = await producerClient.CreateBatchAsync();

                    foreach (var logEntry in logs)
                    {
                        var txt = JsonConvert.SerializeObject(logEntry);
                        eventBatch.TryAdd(new EventData(Encoding.UTF8.GetBytes(txt)));
                    }

                    await producerClient.SendAsync(eventBatch);
                    log.LogInformation($"Log of {name} with {logs.Count} rows processed.");
                }
            }

Anyway, I hope you find this helpful to get data pushed into your pipeline.

It’s that time of the year, What I learned from Hallmark movies 2020

It’s that time of the year, What I learned from Hallmark movies 2020

So much to my wife’s dismay, I actually got a lot of traffic for the previous post. So I decided to do a follow-up.

Here are my 2020 lessons from Hallmark movies:

  • If you want to marry into a royal family, and have known the prince or princess your whole life and been childhood sweethearts, then you must be a cold heartless person.
  • If you work for a royal family in any capacity involving kids you are guaranteed to marry a prince or princess at Christmas time.
  • A king or queens endorsement of your business is the only way it will be successful.
  • All websites can only be built by high price consultants that have corner offices in New York.
  • Futures are not built in “the city” they are ruined.  Living in a small town is a requirement to be happy.
  • If you own a restaurant or food truck, or work in the service industry.  Despite working a full crazy shift… your hair, teeth and clothes will be perfect with any sign of sweat.
  • Kids always love the new person in your life and become obsessed with you marrying that person within 10 minutes of meeting them.
  • Any job that requires you to move will immediately reconsider that decision based solely on the fact that you found your true love.
  • All schools teach a Christmas only curriculum starting at thanskgiving.
  • All corporate jobs will require you to be away from your family on christmas eve.
  • Despite budget cuts in music programs or other arts programs, every school has unlimited budget for Christmas decorations.
  • If your father owns the company you work for, he will require you to work through Christmas.
  • If someone assumes you are a couple, you will fall deeply in love in few days.
  • All cookie baking involves flower disasters where it ends up caked on your face, and guaranteed it will turn out culinary perfection.
Securing Blob Storage

Securing Blob Storage

So one question, that I find is largely overlooked but very much critical is specifically how to secure blob storage. The idea being that you are storing data in the cloud, using blob storage, but the question becomes how does an application make use of those storage accounts in a secure way.

And just like anything, there are a lot of steps you can take to secure your blobs to make them accessible without adding a lot of complexity to your application.

Encryption-At-Rest

So by default the azure blog storage, will encrypt your data at rest. And there’s a great write up for that here. But more than that, you can also use customer managed keys. Now the biggest benefit to that, being that you have complete control over the keys used for encryption.

Encryption-In-Transit

From a client side and transit perspective, all of the SDKs, and client communication with Azure Blob Storage is done enforcing https. So by default, the communication is secured using https. So this is abstracted for the most part.

Securing the Endpoint

You do not have to expose your blob storage accounts to the internet via a public endpoint if you don’t want to.  As denoted here (or here), you can use service endpoints to lock down traffic to a blob storage account to only traffic within a specific virtual network.  So you are not required to use public endpoints.  We also now have additional options of using Private Link to further provide isolation to allowing traffic to move through the azure backbone only. 

Just-In-Time Blob Access

Every security technology will point to “Just-In-Time” access as being a strategy for preventing breaches. And storage is not different, and the recommendation is to not use the key that could grant access to an entire blob account or container.

Instead the recommendation would be that you leverage SaaS tokens, which can be configured to control the access, scoping down to a specific blob, and setting an expiration time.  This ensures that you can leverage a single token for a single use, and lock down the actions that token can be used for.

Here is an article that goes over how to do this in C# as an example using the SDK.  Additionally, you can leverage Stored Access Policy to standardize and lock your SaaS tokens, so that no developer can create an application that violates your standards on this to ensure traffic is secured. 

This ensures that you are giving a “single use” token that cannot be violated as you’ve mentioned above.  Additionally you can make this more secure by using Service Principals and Azure AD to secure the token generation, and block all access to the blobs without Azure AD or Ad Hoc SaaS tokens. 

The best thing that we can do here is to make sure you are using short lived tokens, which is the common practice I have leveraged in the past to prevent the ability for people to be able to “crack” the key.  We also have a listing of the recommendations we have for access with blob storage. There is also additional options to enable Threat Protection and Security Center around Azure Storage.

Enabling Remote State with Terraform

Enabling Remote State with Terraform

So I’ve made no secret of my love of TerraForm. Honestly, I really like TerraForm for using infrastructure as code. Now one of the features that I really like about TerraForm, is the ability to execute a plan and see what’s going to change.

What is state in Terraform?

Terraform leverages using state to enable the ability to have the “plan/apply” functionality. Which makes it such that you can see the changes before they are applied.

How do we enable remote state?

So the process of enabling state remotely isn’t necessarily hard, and is requires a simple piece of code. For my projects, I add a “Terraform.tf”, that contains this information. NOTE: I do usually add this to the gitignore, so that I’m not checking in the keys:

terraform {
    backend "azurerm" {
        resource_group_name  = "..."
        storage_account_name = "..."
        container_name = "..."
        key = "..."
    }
}

It really is that simple, and the key part of this is it becomes very important if you are working with more than one person on deploying to the same environment. In that scenario, if you have two developers using local state, then your state can become out of sync. But this is an easy way to make sure that you manage state in a way that allows collaboration.

A simple trick to handling environments in Terraform

A simple trick to handling environments in Terraform

So for a short post, I wanted to share a good habit to get into with TerraForm. More specifically this is an easy way to handle the configuration and deployment of multiple environments and making it easier to manage in your Terraform scripts.

It doesn’t take long working with TerraForm to see the immediate value in leveraging it to build out brand new environments, but that being said it never fails to amaze me how many people I talk to, who don’t craft their templates to be highly reusable. There are lots of ways to do this, but I wanted to share a practice that I use.

The idea starts by leveraging this pattern. My projects all contain the following key files for “.tf”:

  • main.tf: This file contains the provider information, and maps up the service principal (if you are using one) to be used during deployment.
  • variables.tf: This file contains a list of all the variables leveraged in my solution, with a description for their definition.

The “main.tf” file is pretty basic:

provider "azurerm" {
    subscription_id = var.subscription_id
    version = "~> 2.1.0"

    client_id = var.client_id
    client_secret = var.client_secret
    tenant_id = var.tenant_id

    features {}
}

Notice that the above is already wired up for the variables of Subscription_id, client_id, client_secret, and tenant_id.

Now for my variables file, I have things like the following:

variable "subscription_id" {
    description = "The subscription being deployed."
}

variable "client_id" {
    description = "The client id of the service prinicpal"
}

variable "client_secret" {
    description = "The client secret for the service prinicpal"
}

variable "tenant_id" {
    description = "The client secret for the service prinicpal"
}

Now what this enables is the ability to then have a separate “.tfvars” file for each individual environment:

primarylocation = "..."
secondarylocation = "..."
subscription_id = "..."

client_id = "..."
client_secret = "..."
tenant_id = "..."

From here the process of creating the environment in TerraForm is as simple as:

terraform apply -var-file {EnvironmentName}.tfvars

And then for new environments all I have to do is create a new .tfvars file to contain the configuration for that environment. This enables me to manage the configuration for my environment locally.

NOTE: I usually recommend that you add “*.tfvars” to the gitignore, so that these files are not necessarily checked in. This prevents configuration from being checked into source control.

Another step this then makes relatively easy is the automated deployment, as I can add the following for a YAML task:

- script: |
    touch variables.tfvars
    echo -e "primarylocation = \""$PRIMARYLOCATION"\"" >> variables.tfvars
    echo -e "secondarylocation = \""$SECONDARYLOCATION"\"" >> variables.tfvars
    echo -e "subscription_id = \""$SUBSCRIPTION_ID"\"" >> variables.tfvars
    echo -e "client_id = \""$SP_APPLICATIONID"\"" >> variables.tfvars
    echo -e "tenant_id = \""$SP_TENANTID"\"" >> variables.tfvars
    echo -e "client_secret = \""$SP_CLIENTSECRET"\"" >> variables.tfvars
  displayName: 'Create variables Tfvars'

The above script then takes the build variables for the individual environment, and builds the appropriate “.tfvars” file to run for that environment.

Now this is sort of the manual approach, ideally you would leverage keyvault or vault to access the necessary deployment variables.

Leveraging a stream deck to assist productivity

Leveraging a stream deck to assist productivity

So I’ve always been the type to play around with new technology. And one of the things I’ve been toying with is doing some video recordings of a variety of topics.

And one of the newest pieces of technology that I got was an Elgato Stream Deck XL. And I have to tell you, its really kind of nice from a general productivity standpoint. And I thought I would do a write-up for others. So I bought this, expecting to use it for 3 use cases:

  • Normal Work
  • Development Work
  • My Dungeons and Dragon’s Game (done remotely)

And I have to tell you I’ve been pretty impressed with how much it does right out of the box. When you install it, you install a simple utility that allows for configuring the device. And below is a screen shot of that utility:

Now no surprise, there are a lot of features right out of the gate that are built around the idea of streaming. Things like being able to send a tweet or leverage of OBS streaming software. And all those are cool, but right out of the gate, I was looking to leverage things that make my day-to-day life easier.

To that end, it makes use of items like “Open”, “Website”, and “HotKey” which I found made integrating the StreamDeck with my normal workflow surprisingly easy.

All I did was start grabbing a bunch of the commonly used programs, or websites to make them faster access. And then using “HotKey” I was able to automated a lot of my activities. Like being able to create a new chat in teams, create a blank email, view my calendar, etc.

This made a huge impact right out of the gate, I felt like it was a lot easier to manage the different actions I was doing and jump faster to things. I have to say I’m a day in and I really like it.

And then further I was able to implement specific hotkeys in Windows 10 to engage better use of other features. For example, I started using multiple desktops as it lets me switch between the interface I use for calls and meetings, and the coding / engineering work I do. But I struggle to remember all the hotkey combinations. So here I was able to map them to the stream deck and make it a button push:

Which is really kind of awesome. The other feature I like that it supports is profiles, which enables me to have separate key configurations for the various uses. Like I can break it up along use case lines.

Overall I’m really happy with this device and am looking forward to finding new ways to use it.

Career Lessons I’ve learned from TTRPGs

Career Lessons I’ve learned from TTRPGs

So I’ve made no secret of the fact that over the past two years I’ve gotten back into Dungeons and Dragons and role-playing games in general. And to be honest for my core group, this COVID-19 situation made our group a lot tighter and since March we have now been playing weekly.

Now I will say, that I’ve talked about the benefits of TTRPG (table top role playing games) during COVID-19, that it’s a great way to step out and have fun with people in a way that doesn’t feel forced. But I’ve also noticed that I’ve learned a lot by running these games that I take as life lessons.  And I definitely recommend this hobby as a way to grow and have some fun.

Let’s start with the connection here, in a TTRPG, like Dungeons and Dragons, you and a group of others are building a story. The game is about you all building the best story you can, and along the way dealing with outcomes that are decided by a mixture of planning and chance.

Let’s talk high level, just to make sure we’re all on the same page, for example, if you know your characters going to be doing lots of sneaky things, you might take a stealth skill, which gives you a +5 to stealth. So now when you are presented with a situation like that in the story, and the Dungeon Master says “give me a stealth check”, you roll a 20-sided die, and add the +5 to it. Now when you built your character you had to make choices, so using the above, I might have spend points to make myself stealthy, but odds are I’m not intimidating, so an “Intimidation check” might be a 20 sided die, and a -2, much lower chances of success.

To this end if you want to get technical about it, a Dungeons and Dragon’s campaign is a lot like a project, we have a goal, and we have a team of people all bringing unique talents to the project. And we have a dungeon master that is there to help us organize around a goal and work towards it. This should sound a lot like a work project, at least this is the similarity that really struck me.

So I’ve learned a lot being a dungeon master that I feel has direct parallels to my chosen careers and leadership, and I wanted to share those here.

But here are the top seven things I learned by playing these games:

Lesson 1 – What true collaboration looks like?

Ultimately, at the end of the day, when you play a game like Dungeons and Dragons, the game is communal story telling. We are all collectively telling a story. That means that although I control the settings, the non-player-characters, and monsters, the players are just as much in control of the story as I am. In this game, they are the protagonists of the story.

So if we consider this as a collaborative effort, its not unlike your teams at work, your manager is responsible for setting the guidelines, defining the goals and supporting the team (much like the Dungeon Master). The players are responsible for tackling the challenges that are thrown their way and moving towards those goals. Again not that different from your office if you think about it. Sure you’re delivering a product, report, a software solution, and they are fighting goblins, but overall the principles are the same.

So one of the things I learned here was what it means to be in that position and truly collaborate. Because as a Dungeon Master (DM), it was my job to make sure that everyone contributed to that story. And what I learned quickly is that to do that you need to truly collaborate, and make sure that you are giving space for others ideas. One example of this, is that I had very much an idea of the direction that I wanted to take things, but I had to be open to anything. So one of the things I decided early on was to “Find a way to say yes.”

And this did a couple of things, that really embraced creativity and collaboration:

  1. My team mates really felt invested: Nothing makes you more invested in the outcome than to know that you’re ideas are being heard and appreciated.
  2. They came up with ideas that I never thought possible: Some of the things they came up with were really awesome, and I never would have. And that made the story better, or made it possible for us to do more than I thought we could.
  3. It Challenged me in a new ways: By forcing myself to find ways to enable their ideas, it presented me with new challenges I never thought possible before.

Lesson 2 – What it means to empower and say yes?

Now just like managers, there are lots of different types of dungeon masters out there. Some see their role as being against the players, others see it as their story that they need to force the players to follow, and I’m betting you’ve had managers who work the same way.

I don’t know about you, but I’ve had managers that believe they have to be better than anyone who works for them, and feel threatened by their success. I’ve had other managers that felt that “I’m the leader, and make all decisions for every aspect of this project.” And too be honest those were terrible experiences, and I’ll be honest early in my career I could be accused of being one of these, and it wouldn’t have been far off.

But I’ve been lucky to have a lot of really good managers in my career too, and one in particular always said “It’s my job to see you successful.” And that was always inspiring to me. So when we started this dungeons and dragons game 2 years ago. I decided that I was going to be a “Try to say yes” leader. And what that meant was a very simple rule.

Anything reasonable the players wanted to do, before I could say no, I had to do everything in my power to say yes.

Now just like the real world there are limits. If a person on your work team said, “I want to make $1M a week.” That’s not reasonable, and I saw this as an impossible situation to make a “Best Effort” to say yes.

But I decided when my players decided to roll characters, I would find a way to say yes. So when a player came up with a character concept, I would try to find a way to make it work.

For example, I had a player who had a very long backstory they wanted to do with a illustrious history, and normally any online advice on the game would say “Never allow this for level 1”, but we figured out a way to explain how they had gotten older and fallen in levels. And to be honest, I found the challenge of trying to find a way to say yes, really fun and empowering myself.

This also meant as a leader that my team members saw me fight for their success. They saw me trying really hard to make their ideas reality, and this made them invested in the project.

If you are an employee and every you go to your manager with a new idea, they tell you “That won’t work.” Are you really committed to delivering on that project? Are you committed to helping that person? Probably not.

But if you go to your manager with a new idea and here, “That might be tough, but let’s talk it through? Or let me see what I can find out?” Are you going to do more to help? Do you feel more invested in the outcome? Probably yes.

Lesson 3 – People communicate differently

Another key lesson I learned was specifically around communication. Right now my core dungeons and dragons group is 7 players, plus myself as dungeon master. And over the past two years, we played monthly for about a year and a half, and then played weekly since COVID-19 hit in the US.

Our group is pretty eclectic, and we have made some really strong friendships over that time. And I’ve learned a lot about communication and experience with regard to everyone. Some people communicate differently. And as a dungeon master, I’ve had to learn to communicate in the ways that make them feel most comfortable.

For example, I have one friend who will randomly message me on discord (our chosen app) during the week to ask random rules questions, or talk about ideas he has revolving around his character.

My wife, who has become a big fan of the game. Prefers to talk at night before we go to bed, and brainstorm ideas about our character and discuss events in the game face-to-face.

I have another player, who I have to reach out to them as it is harder for them to ask for help or express their opinion during the game.

And I have a third, who would rather ping me to ask if things would work before they do them because they are afraid of looking like they don’t know the answer.

Now reading that list above, I’m sure if you’re like me you can think of at least one person in your work and that statement lines up perfectly. The simple fact is that communication preferences aren’t unique to a game, they are likely the same for all parts of that person’s life. If people don’t have a lot of confidence they are more likely to stay quiet in a meeting. And “cold-calling” that person, likely isn’t going to do them any favors.

So being a dungeon master, I’ve had to learn that my preferred communication style matters, but I have to be empathetic to how others communicate if I really want to get the benefits of collaboration for everyone. And to be a good leader, you should absolutely want to meet people where they are, and it’s been great practice that in this kind of setting.

Lesson 4 – How to make sure everyone is in the conversation.

Along with the need to focus on how others communicate, one thing I’ve learned playing Dungeons and Dragons, is how to make sure everyone is at the table.

Stop me if you’ve heard this one before:

You all get together for your regular meeting for a working session on the project and as the meeting progresses, you are all moving things forward, and things seem to be going well. But you’ve noticed the past few meetings that one of the members of team has been quiet, and isn’t contributing much to the project. You really like this person, they are a fantastic resource, so you assume their silence means they agree with everything being said. At the end of the project, you discover you are missing key requirements in this person’s area of expertise, and the project is in trouble due to these missing pieces. The manager of the project is frustrated and feels like your friend didn’t do their job and wants to fire them.

When you approach the person, they confide in you, that they were afraid that no one would accept their ideas, and although things went different than they thought they should. They didn’t feel comfortable speaking up.

Sounds like a work scenario that we can all relate to right? I’ve seen this same thing happen at the gaming table. And one of the most valuable leadership lessons I’ve learned is how to identify situations where someone is not contributing because of a blocker, and how to navigate that. Looking at the above, most would say “All that could have been avoided by stopping and calling that person out to offer an opinion.” But for some people that is a terrifying version of hell.

Another way to address that would be to become an ally for that person. Like I had this situation with a player, and I reached out to them, 1-on-1, and had a conversation. “What do you think about what happened?” and “Let me get your thoughts?” And then our next game, I started with “______ and I were talking, and they had some really great thoughts about this…” In this way, I’m helping them to feel like someone in the room is validating their ideas and giving strength to them. Which is a key to leadership.

Lesson 5 – People are motivated and enjoy different parts of the project.

This was something that I found very helpful. When you have a group playing a game like this, they are all measured by different things. For me, first hand I saw the following:

  • Some people love to play out combat in the game, and to them every thing with story is only there to provide more opportunities for combat.
  • Some people love the story and roleplay moments, and are interested in character arcs and live for roleplay moments.
  • Some people are there for the whole process of building and optimizing their characters.
  • Some people are just there to be part of a team.

So as the leader you need to make sure that you are aligning activities and opportunities with people who want them. Like for example, if I have a player who lives for combat, a great roleplay situation is going to fall flat for them, and be a missed opportunity for the roleplayer.

It’s not a stretch to see how this impacts your ability to lead a team in a professional setting. Some people are there to punch a time clock, others enjoy coordinating and running meetings, while others want to just roll up their sleeves and code. And to get the best out of the members of your team, you should make sure that people are given the opportunities to engage in the types of work they enjoy and excel at.

Now as we talked about before, just like communication styles, it isn’t always obvious want people want or what drives them. But its really important to take the time to do that. By doing so, you accomplish the following:

  • Further show the members of the team, that you care about them, and how to maximize their contribution to the team.
  • Allow opportunities for people to stand out for their accomplishments, and to be the hero.
  • Provide new opportunities for people to try things without fear of failure. By allowing them to take risks you empower them to do more as members of your team.

Lesson 6 – It’s not my success to own.

This is one, where a lot of Dungeon Masters get it wrong. But as part of playing these games, and being the leader. It’s my job to create the challenges and things they have to deal with on the journey. And during those times, the players have to rise to the problem and defeat the monster, break into the citadel, etc.

And in the course of running these games for the past 2 years, I’ve seen things go a wide variety of different directions. And a lot of times, they go directions I never thought possible. And the biggest ones I’ve seen success for, are things like this:

I had a situation where I built a game for my players, and had planned this long combat encounter, and it was going to be intense, and I didn’t know if the players would survive. And when we ran the game, my players took a bunch of different directions I’d never thought of, and the multi-session encounter I had planned was over in 1 hour. The players were thrilled, and ecstatic. They had rose to the challenge and overcome it in an interesting way.

And to be honest, if you search for these types of situations on forums or blogs, they will talk about how much this sucks as a Dungeon Master. They will point to all the work you did and how they “beat me.” I have to be honest, I couldn’t have been more proud of my players. They did great, and the success was theirs. The team had accomplished something great, and honestly it was their success. Had I helped enable this? Absolutely I had helped them build and grow as players to the point that this was possible. And honestly, it made me feel proud and accomplished, but nothing about this game is my success it’s ours.

And honestly if you look back, I think you will find that the best leaders in your career had one thing in common, they took their ego out of it. You can’t be a good leader in your career and allow your ego into the equation. You need to be proud of the work you do with others, and you need to be proud of their accomplishments.

And here’s something I’ve learned from one of the best bosses I’ve ever had…”The best leaders take the team out to celebrate, and pick up the tab.” And the way I view this ultimately, is that the best leaders are the ones who even empower and facilitate the celebration of their team. They don’t say “Look what I did with my team!”, they say “Look what my team did!”.

Lesson 7 – How to draw the lines on the field, not control the game.

We’ve all had majors in our careers that have tried to control everything. They must approve every detail of a design, they must review every line of code, and they must be involved in every aspect of the project so that they can “Control” the outcome.

I’ve always known that the best managers don’t do that, they draw the lines on the field, they set the value and direction, but they let their team play the game. And there are a million sports metaphors about this. But I found that TTRPG, give a real quick lesson in this, because during the game I have no control over my players, I setup the scenarios, I adjudicate the rules, but I have no ability to control what they do, or how they react to situations. And it creates a situation where I get to see the success of my team and am always put in a position where I have to accept this fact.

In other situations in my life, regardless of how much I knew this to be true, the nature of TTRPGs, requires you as the dungeon master to only engage in this way, as I don’t have a player in the game, and I can’t control their actions, and it was a great learning experience.

Learning comes from strange places…

So honestly, this is something I wanted to write about, because over the COVID-19 crisis, I’ve found that I learn a lot of new things from a variety of places. And overall I’m trying to make myself more open to these. But I was surprised by the amount of team and leadership learnings I got by putting together a game where people kill dragons.

See the source image

Debt is bad, and Technical Debt is no different

Debt is bad, and Technical Debt is no different

So there are a lot of posts out there on the topic of technical debt, and to be honest it’s a perfect example of a term that has been abused and given all kinds of unintended meanings. One thing I wanted to accomplish here was tackle the topic of what Technical Debt actually is, and some strategies to manage it.

So if you look out there at almost any blog on financial planning of any kind, they will tell you that debt is a very dangerous thing, and it can devour your income over time because of high interest rates, and take your paycheck and kill it with the death of a thousand cuts. The biggest problem with Debt is that it can creep up on you.

For the sake of an example, let’s look at a simple scenario. If you get a credit card with a balance of $500 and an interest rate of 15%, and let’s say you can only pay $200 a month on it. Each month the balance goes up by $75, so that means your only really paying $125 dollars. So that credit card would take you a lot longer to pay off, and you will end up paying when more than $500 on that debt. And that whole time you lose the ability to generate income with the money being thrown into the “credit card pit.”

Now this is not a financial blog, cause god knows I’m no expert. But I do want to use the above to illustrate a point. In software engineering, we have this concept of “Technical Debt” and if we look, wikipedia, actually has a pretty good definition of it. The definition is:

“Technical debt (also known as design debt or code debt, but can be also related to other technical endeavors) is a concept in software development that reflects the implied cost of additional rework caused by choosing an easy (limited) solution now instead of using a better approach that would take longer.”

Wikipedia / Technopedia

Now, I like that definition, but I will change it slightly, I don’t believe that technical debt is limited to only choosing the “Easy” solution, but can actually be caused by any constraint that causes a decision to be made. And I would give the following reasons:

  • Budget: Every project has a budget, whether that’s in time and dollars, everyone would do things differently if they never had to worry about time or money, but that’s not how the world works.
  • Delivery / Contractual Timelines: Sometimes you just have to ship it, and requirements force you to ship something that is not perfect or the way you want it. And you plan to get to it later.
  • Complexity: One of the biggest things I’ve seen that some developers do to avoid technical debt, actually causes it to be significantly worse. Many architects and developers will over complicate their design just for the sake of “making it easier to maintain”, but this can cause further issues later by making the code complicated to test, maintain, and change because baseline assumptions turned out to be wrong.
  • Competing Requirements: Sometimes you just get requirements that force your hand in such a way that you can’t avoid practices and patterns you normally would have avoided. For example, you might want to take advantage of the cloud, but be stuck with requirements for OnPrem.
  • Skill level: I’m going to flat out say this, when I look at old code that I’ve written, but haven’t touched in a long time. I usually think to myself “Man, I was a terrible programmer.” And to quote Red vs Blue, “Were you smart 10 years go, no you were an idiot…and the truth is your just as much of an idiot now, it will just take you 10 more years to realize it.”
  • Available technology: Look at the end of the day, we can only build with the tools we have, and most of the good programmers I know try really hard to have crystal balls, but sometimes our predictions don’t pan out.

Now I’m going to hazard a guess, but if you go back and look at most of the refactors you’ve taken on, I’ll bet that more than a few were up there in that list. And if not, I’d love to hear your reasons in the comments below.

So to a certain extent, the nature of technical debt is impossible to avoid, but what we can do is take strategies to minimize it. We need to accept that technical debt will happen, but if we do a few practices, I find that it can be a lot more manageable. And I’m going to give a few tricks I’ve learned over the years here.

Tip #1 – Create backlog stories around debt, and tag them if possible

Let’s be honest, most development shops maintain a backlog of some kind, and in that backlog are items, user stories, or some kind of baseline unit for work.

Now stop me if you heard this one before, but the following events occur:

  1. Developer gets new story for a feature.
  2. Developer designs feature with architecture and business analyst.
  3. Developer codes feature.
  4. Time lines or priorities shift, and developer doesn’t get to put as much work in as planned this sprint.
  5. Developer gets code to point that meets the requirements, but has a few things they wish they did differently.
  6. Developer ships code, maybe (if your lucky) makes notes of things to look at later.
  7. Repeat at step 1.

Now the problem is that these problems will continue and the technical debt will continue to pile up to a level that you can’t do anything without massive re-work, or re-architecting.

Now all of this could have been avoided, if right after step 6, we added a step 6.5 – “Developer creates user stories and tags them as ‘technical debt’.”

The idea here is this, Agile development was built on the principal that we assume that requirements are going to change, and build towards that reality. To that same end, we should assume that we aren’t going to be able to do everything we plan, so let’s plan for, and build in a process to ensure that we can get back to that technical debt wherever possible. If we had our developer go back in, and log 2-3 backlog items, tagged as “technical debt” it would accomplish a couple of things:

  1. It allows us to keep an eye on how our technical debt is growing.
  2. Allows us to address it in a manageable fashion.
  3. Allows for transparency to management and the business.

Tip #2 – Deal with it a little at a time

This should surprise no one, based on the item above. I recommend that we focus on making sure a few technical debt items make their way into every sprint. That way we can tackle these items in a way that ensures that these items don’t pile up on you for later.

Pick out your main sprint based on backlog priority, and set aside a certain amount of time in the sprint, and fill in with technical debt. This approach would say, if I have 3 people in a team, and 40 hours a week, that means I have 280 hours per sprint. So if I said, 210 hours of that sprint is on new feature work, and then 30 hours (10 hours per person) is on technical debt. I could continue to pull down the technical debt to a manageable level.

And there are two schools of thought here on how to pick those items:

Option A – Take as many small items as you can to fill those 30 hours, so if I have small 1-2 hour jobs, I can get more of them in a sprint.

Option B – Sort the list in descending order, and take the largest debt items first. If I have one that costs 10 hours, 8 hours, and 2 hours, those should be the first 3 I take on.

Personally, I find that Option B, tends to work better on the teams I’ve worked on. But you’re mileage might vary. I find that those little stories, tend to cause a vicious cycle of the following:

  1. Developer gets 2 feature stories, and 5 technical debt stories.
  2. Developer designs features, and reviews technical debt items.
  3. Developer works on feature, and pushes off technical debt stories because they are little, and can be done at the end.
  4. Developer gets caught up in a changing deadlines, and must push off something, technical debt stories get bumped.
  5. Now not only do the 5 small stories get put back on the pile, but any additional stories are now added.

In my experience giving less stories, and having them be more impactful tends to motivate them getting addressed. But again, your mileage might vary. I would work with your teams on a strategy.

One way to make this fun I found was to make a game out of it, similar to estimation poker. We had a “Debt Wheel”, and each sprint, one developer spun the wheel, and whom ever it landed on, had to pick a big technical debt item to work on this sprint. And then at the end of the sprint, if they finished it, they got to spin the wheel (with their name off it) to see who got the next item. If they didn’t finish it, they had to keep it into the next sprint.

Tip #3 – Use things like nuget packages

I wrote a really in-depth blog post on this, found here. And in it I explain at length how private nuget feeds can help manage technical debt. So I’m going to direct you to that post.

Tip #4 – Single Responsibility

A class (or service) should have only one principle. And should have only one job. The intention here being that it makes it easier to take these pieces out and swap them for something else later. The idea here being that you should focus on building smaller services that can be pulled out and replaced as needed.

Along these same lines, communication between services is another key to keeping technical debt under control, and the idea here is to make sure that there is an abstraction between each service. For example, if I have a service that is supposed to send a request for processing to another service.

One option would be to enable http calls directly between services, but honestly this causes quite a few issues:

  • Not Fault Tolerant
  • Changes between services aren’t backwards compatible .
  • Harder to track and monitor.

But ultimately, if we used a messaging layer, like Service Bus or Kafka, we could eliminate those issues and make our application services into more a black box where each piece functions independent of the others.

Tip #5 – Leverage dependency injection

I have to tell you, I’ve seen a disturbing trend lately where people are saying, “We use micro-services, so we don’t have to use DI.” And I honestly don’t understand this, DI makes it very easy to clean up your code and enforce a plug-and-play architecture that can have classes swapped out at any given moment.

The idea is this, even within a microservice smaller classes can be updated easier. If you are using nuget packages, and the other patterns above, DI is something very easy to implement that has massive impacts on how you build your code making it easier to make changes later, which in turn make it easier to remove the technical debt later.

If you ignore debt it will only get worse!

That right there is the number one thing I hope you take away from this post. All too often in my career have I seen technical debt be the reason that applications are rewritten, or completely rebuilt from scratch, which I’m convinced is a massive risk and rarely works out.

Navigating Career Decisions without analysis paralysis

Navigating Career Decisions without analysis paralysis

We’ve all had to navigate career decisions at one time or another, and those kinds of decisions are never easy. For many, careers are one of those things that generally are foundational to our livelihoods, and are the tools by which you support your life and family. More than that, for many, your career is where you will spend most of your time. So given that, its not uncommon for decisions in your career to be fraught with stress and dread.

I know there have been a lot of times in my life, where my wife and I have had to stop and examine our options and decide what the next step will be. I don’t pretend to be an expert on this kind of thing, but I do think that my wife and I have developed a pretty good process for weighing these options, and I thought I’d share some thoughts here.

What do I mean by “Career Decisions”?

So before we go any further, I think its worth taking a step back and defining terms. What do I mean by “Career Decisions”? For me, a career decision is a decision on a current or next step in your career. And ultimately where you see things going next. Some examples of these kinds of decisions are:

  • Do I take a new position with my current company?
  • Do I take a management position?
  • Do I change employers?
  • Do I change teams?
  • Do I move into a new industry?
  • Where do I see myself in 6 months, 1 year, or 5 years?
  • Do I ask for a raise?
  • Do I take on more responsibility?

These kinds of decisions are the kind, that when they come along, can change the course of your career. They affect not just your current situation, but also the next steps and opportunities in the future. And a lot of times, these types of decisions I find can inflict pretty significant “analysis paralysis” (speaking from Experience).

For this blog post I wanted to take a step back and look at some of the things I’ve learned to keep in mind, and consider the alternatives that I’m faced with. This is by no means an exhaustive list, but it is meant to give you a starting point for these kinds of decisions.

Careers are like sharks, they move forward…or die.

The first part of this discussion, I almost didn’t write here, but it goes to general mindset, and keeping a good frame of mind for ensuring success. If you look at life in general, all living things in this world essentially have 2 states of being, they are growing or they are dying. There isn’t a third option that works. And over my professional career, I’ve come to realize that careers are no different.

When I graduated college, my father looked me and gave me two pieces of career advice, and this is the first.

“A career is like a shark, if it stops moving forward, it dies.”

Now, when I was a kid, I was a shark fanatic, and when I got older and they offered shark week on discovery…that was mandatory television for me every year. For those who haven’t spent countless hours studying sharks as a kid, here’s the basics.

The way a shark’s gills are structured, they have to have water moving through them for the Shark to breathe. Unlike fish, who are able to extract the air from the water even while sitting still. What this means, is that if a shark ever stops moving, it will suffocate.

See the source image

And in much the same regard, Careers function the exact same way. If you aren’t moving forward, and by that I mean:

  • Growing in your knowledge
  • Being challenged in new ways
  • Learning new skills
  • Investigating new ideas
  • Embracing change

Then your overall value is diminished as a whole. Think about it this way, take car buying, which is a topic most can relate to. You have two cars in front of you, both owned by different owners.

Honda Accord A: Is a nice car, it runs and will get you from point A to point B. The owner did an oil change about once a year, and it was inspected every year. But that’s all that was done. The interior is stock standard, the seats are faded, the interior is clean but has some stains.

Honda Accord B: Is a nice car, same year as car A. But the owner took it in for regular checkups, oil changes, etc. But in addition the previous owner, upgraded the interior to leather, replaced the stereo system. Upgraded the engine to be more fuel efficient, and other optional improvements.

Now of the two cars, if you are in the market, which would you rather have? And if it was only $5000 more for the second car, would you consider paying more.

At the end of the day, this is largely how employers will view you. The most important fact is that there is a direct correlation between how valuable of a resource you are, and the opportunities you will have. So everything about what you are doing in your career now feeds the future and that value.

When you are presented with a new opportunity / decision, it’s ok to take “some” time to think?

In my experience, no one should ever put you on the spot, and that’s just bad business etiquette. It is 100% reasonable to take some time to think about any major changes you are planning to make. This is your life and you have a right to take a breath and think about it.

Now that being said, one thing to be careful of, you have the right to a reasonable amount of time. I once had a situation where I recommended a friend to my current employer, and they made them an offer. And my friend wanted 1 month to make a decision. This caused a lot of frustration with between both parties, as they wanted too long to make a decision. A good rule of thumb I’ve found is to do the following:

  • Be transparent with the other person: If you need to talk to your spouse, tell them that. I once had a case where my wife was away for a week and I got presented with an opportunity. I told them, “I would like to talk to my wife, she’s out of town, can I get you an answer next week?”
  • Give them an indication when they can expect a response: I never understood the “I’ll think about it” and walk away. It’s very reasonable and easy to give the other person a time frame to expect a reply.

I find that this communication will make it easier on everyone, it gives a clear framing of when responses are coming through. It creates an opportunity for both sides to show respect and courtesy, and if they aren’t willing to do that, it’s another data point in the decision.

Everything has trade-offs… even staying where you are

Now that you’ve been presented with a decision or opportunity, you have to start into thinking about it and making a decision. This is the hard part, and to be honest I do want to take a step and identify the number one mistake I’ve made, and I’ve seen other make in this situation.

When we start looking at the choice, say it’s to take a new job with a new company, we start looking at things like pros / cons, which is a very good thing, and start looking at:

  • How much will I make?
  • What is the commute like?
  • What kind of work will I be doing?
  • Is it something I want to do?
  • What’s the work life balance?
  • How much travel?

But the number one mistake here is that we will fill out that T-Chart and then make a decision based on that alone. But the biggest thing I find is important to understand is that I should do this exercise twice. For the following:

  • Pros / Cons of taking the new job
  • Pros / Cons of staying where I am

There are trade-offs to staying where you are, and those trade-off should figure into your decision. For example, some questions you should examine when you consider the question of “Should I stay where I am”:

  • Is there opportunity for advancement?
  • Do I see myself growing if I stay here?
  • Does it benefit my family to stay?
  • What does my financial growth opportunity look like?
  • Will rejecting this impact potential new opportunities?

And these question should be come part of your decision, as to what to do next. Let me give you an example, if you decide to stay at your current position, instead of taking a move that would increase your payment potential. Do that once, not a problem, but due it to often and you’ll find normal raises price you out of moves later. There’s something to be said for a “being a bargain” in job market.

Here’s an example, let’s say for the sake of argument, you have a job that’s “fine”, doing support that makes $40,000 / year. You want to eventually be a developer and move from support to feature work.

NOTE: This is not a commentary on support, I worked support and its a great and challenging profession, and I have friends who have worked in support for their whole careers and are way more successfully then I could ever hope to be.

But if you have your current job, making $40,000 / year, and ever year that you do good work, you get roughly a $1,000 cost-of-living increase.

So not bad overall, and you are working in the background, on side projects and other opportunities to build your skills for your next move to being a developer.

After a few years, your pay scale looks like this:

  • $41,000
  • $42,000
  • $43,000
  • $44,000

And now you find out about a developer opportunity, but aren’t sure if the timings write, and they are willing to hire you at $46,000 / year. A little pay bump, and a chance to move over. But you decide the timing isn’t right, and decide not to take it. But you find out that the normal developer salaries in your area are around $47-50,000 / year. If you continue in your current job for 5 more years. Your salary is around $49,000 / year, and you are on the higher end of the salary range, and now are more of a risk to a new employers. The reason I say that is that you don’t have the direct experience that they are going to see from other employers.

Fast forward another 5 years, and you are now priced out and having to consider a pay-cut to move to the job you want.

So there was an unseen cost to staying in the current position, and passing on that opportunity. If you had gone to the development position, you could have grown your experience and made yourself grow faster and had more opportunities available to you.

Now I realize the above has a lot of assumption and is very simplistic, but I do believe it illustrates the point, that the cost of doing nothing, does have a cost, it is not cost neutral.

Money is not the only factor

Now I realize this is an odd segue given the above discussion, but one of the things my wife and I do when we consider career moves and decisions is to make a list and leave off the financial component. At the end of the day, there are a lot of elements to a career other than the financial component, and honestly if finance is your only motivation, its going to make for a pretty miserable existence.

This relates to the other elements of the job, things like:

  • Does the job require travel (could be a good thing or a bad thing)?
  • Will this help me grow?
  • What new opportunities will this move afford me?
  • What is work life balance going to be?

I once had a person interview to work on my team at a previous company, and he took the week to think about the employment offer as he had a competing offer. On Monday, the next week, he came back and took our offer and weeks later confided in me that it was at lower pay. When I asked why he gave the most eye opening answer.

That Friday night, at 6pm, he went to both places of employment to see how many cars were in the parking lot, and every night that weekend. The other employer while offering more money, had the same cars in the parking lot all week and most of the weekend, people leaving at 7-8pm at night after 12-14 hour days. Which was a really amazing observation, while our offer was lower, everyone went home to their families most nights.

How does this set me up for the future?

Another key question, that I learned very early on in my career is that you should always take a step back and ask yourself this question. Everything you do in your professional life is a part of a portfolio of work that can open up new opportunities in the future. That’s why its important to make sure that the things you are doing, are ultimately building that portfolio.

So let’s talk an example here, if I’m going back to that example (which was me at one point). You work in a support job, and you want to become more of a developer, and you are presented with the choice from above.

If you stay in the support role, the following happen with regard to your next job:

  • Learn more about how to work with escalations.
  • Continue to learn about the low level details of software applications.

Now if you took the developer job, it would mean:

  • Focus on growing my skills as a developer.
  • Work on development projects.
  • Potential mentors for growing in that space.

I know overly simplistic example, but it makes my point. The idea is here you should have a clear picture of the kind of work you want to do, and make sure that the current job sets you up for the future.

Loyalty is a two-way street

This is the tough one, that I find impacts a lot of decisions for careers, and that’s a sense of loyalty to your current team, employer, manager, company, etc. And I want to stress that loyalty is absolutely important, and something I value very much. Ultimately I find that its the glue that holds a team together. I’ve also personally had a lot of relationships over my career that I would gladly take a bullet for those people.

That being said, I do find too that loyalty is a two-way street and something that should measure into your decisions, but you need to make sure that you are taking care of yourself as well. And sometimes misplaced senses of loyalty can be a very dangerous thing.

At the end of the day, I’m of the belief that there is a responsibility and an “agreement” between yourself and your current employer to do the following:

  • Provide growth opportunities
  • Provide learning opportunities
  • Provide ability to recognize achievements
  • Provide a safe and constructive work environment

And then in turn, you as an employee are agreeing to the following:

  • Do your best work to achieve the goals and objectives.
  • Be a professional and do your part to support the work environment.
  • Take advantage of the growth and learning opportunities provided.

Now over the past few years I’ve always tried to have very open discussions with my managers around these items on a regular basis. The idea being that they should get a return on their investment in me, and I should get a return on my investment in them.

And then that agreement to me is the foundation of the loyalty with the team I work with.

Now given the above, I do believe there is a certain amount of responsibility from your current employer to provide the best opportunities they can, and I would recommend having an open discussion about those opportunities. Ultimately at the end of the day, if someone is able to offer you a better return on your investment, it should at least be considered.

But I’ve been in scenarios, where I had managers that would “gaslight” their team into a misplaced sense of loyalty that convinced them t hat considering leaving was an “act of treason.” And those kinds of things can be avoided pretty easily if you think of this in investment terms.

If you’re the smartest person in the room, find a new room.

I mentioned at the top of this post, that my father gave me two pieces of career advice when I graduated. And this is the second. The most important thing to remember is that you must grow for your career and ultimately you need to be challenged. And if you are the smartest person in the room, you are not being challenged.

There is something amazing, about being in a room where you aren’t the smartest person, and the opportunity to learn new things. A great term a college professor gave for this is “productive discomfort”, which fundamentally is the idea that the only way you grow is by putting yourself into a situation where you aren’t 100% comfortable.

It’s very much akin to the idea of learning to swim, my son who stands 3 feet tall, can’t learn to swim in 12″ deep water. There’s no challenge that forces him to push himself, but if we put him in water where he can touch if he needs but is high enough to justify swimming, it might not be as comfortable in the beginning, but it will yield returns.

So as you start to build out your career, one practice that has served me well is to seek out situations of Productive Discomfort to make sure that I push myself in new directions.