Thursday, December 31, 2015

2015 Year in Review

It's time to see how things went this year. That's how we make sure the next year is even better. I feel like I was really busy this year, and I also feel like I didn't accomplish all that much. So let's take a look.

Of course, speaking is at the top of my list. This is something I love to do. It makes me feel really good to watch people learn and to hear about how I was able to give someone new ideas or help them over a technical hurdle.

And I was busy. I spoke at 28 events and did 47 presentations. I did a bit more traveling further from home this year, which means I was on 21 airplanes. (I know that's not a lot to some people, but it was to me.) New states on my speaking list include Florida, Nebraska, Colorado, Michigan, and Wisconsin. You can see a full list of my activities here: JeremyBytes - Demos.

Needless to say, I really enjoyed the events that I went to this year. I met a ton of great people. And speaking of meeting new people...

Becoming a Social Developer
I've had a great adventure breaking out of my shyness at developer events to talk to new people. This year, I formalized things a bit with a website and newsletter:

I've had a chance to share this on the .NET Rocks podcast as well as at the LIVE! 360 conference in Orlando.

As more and more of us talk to each other, we learn from each other's experiences, we get perspectives other than our own, and we become stronger as a developer community.

I hit 2 really big milestones this year (and a few smaller ones).

.NET Rocks!
The first was being a guest on the .NET Rocks! podcast. This is a podcast that I listened to when I was a corporate developer. And 6 years ago, this podcast inspired me to go out and speak publicly for the first time.

I always had a "dream" that someday I would be a guest on the show. It wasn't very a very serious dream when I first had it (back when I was a not-at-all-notable developer). But as my circle grew bigger and bigger, I started to interact more with people who had been guests on the show. And I had a few chances to interact with the hosts (Carl and Richard) as well.

So, when I was hanging out with some folks in Detroit earlier this year, and Carl said to me, "We'd love to have you on the show sometime," I was totally excited. Fortunately, I had a topic to pitch, and we recorded a couple weeks later.

I had a lot of fun on the show, and it was great to share something that I'm passionate about with a huge audience. And I'm honored and proud to be among the list of people who have been on the show.

LIVE! 360
The other big milestone for me this year was speaking at the LIVE! 360 conference. This was my first chance to speak at a professional conference, and it was a great experience. LIVE! 360 is a co-located conference with one of the conferences being Visual Studio LIVE!

Visual Studio LIVE! was one of the conferences that I attended several times back when I was a corporate developer. It was one of the conferences I really liked attending because the quality of the speakers was good and the topics were relevant to what I was doing.

So it was quite an experience to speak at this event in particular. Some of the people I used to go see speak years ago are now people I'm speaking at the same event with. My world has changed quite a bit.

If you want to read a bit more, I put down some thoughts and reactions in the previous article.

Corporate Events
Another smaller milestone is that I spoke at several corporate events. It's really great when someone invites you to come and speak... and they want to give you money to do it.

The majority of my speaking has been at community events (i.e. free). I've spoken at a few regional events that have covered hotel or partial travel (and INETA was also great at helping defer some travel expenses). But ultimately when I speak, I end up at a financial loss. (That goes to show how much I love doing it.)

So it was really great to have a couple of events that covered my expenses plus additional funds. I think the biggest thing for me is that it validates that what I'm doing has value.

Guest Appearances
This year I made several guest appearances on various programs. This included a screencast with Dustin Davis on //c0deporn where we had a good conversation about lambda expressions and delegates. Dustin is someone I know from the So Cal developer community, and I'm glad I had a chance to be on his channel.

I also had a chat with Dave Rael on the Developer on Fire podcast. I had a chance to share a bit about my history, some of my successes and failures, and a bit about what I love to do. I met Dave earlier this year at Denver Dev Day, and it was great to talk to him.

I already mentioned that I was on the .NET Rocks! podcast. I think I've already said how excited I was about that.

Finally, this fall I had a chance to be on Coding 101 on the TWiT network. This was a panel discussion with several Microsoft MVPs. It was an unexpected opportunity that came up at the Microsoft MVP Summit from my friend Sarah Dutkiewicz (@sadukie). I met Sarah at the Microsoft MVP Summit last year, and it's been great to interact with her online and at events. I'll look forward to seeing her again at CodeMash next week.

Blog and YouTube
I haven't been blogging as much as I think I should. I did publish 86 articles this year (including this one). And several of my technical articles have been pretty popular (for me, pretty popular is over 1,000 views -- everything is relative).

The traffic has been increasing, and I'm now getting 16,000 hits per month compared to 8,000 last year. It's really great to see that so many people are reading my articles, and I hope that most of them find them useful.

I also would have liked to publish more videos on my YouTube channel. I did publish 10 videos this year, including a series on Lambdas & LINQ and a series on Task and Await. My viewership on YouTube has been increasing as well. I picked up 1,000 new subscribers this year (for a total of 1,500), and I've had 55,000 views of my videos this year.

Of course, no review of the year would be complete without mentioning my banjo. Back in January, I got a banjo from Amazon. I've been slowly learning to play it. I really should practice more than I do, but I have improved quite a bit. I use the banjo when I'm speaking locally to show people that it's okay to not be perfect at something. We are all new to things at some point (and in our industry, we're new to lots of things a lot of times). It takes practice to get good at something, and we shouldn't be embarrassed if it takes us some time.

To see my progress, take a look at You Aren't Instantly Awesome, and That's Okay and the follow-up article: You Aren't Instantly Awesome, but You Can Get Better With Practice.

And I'll just leave this here:

What's Next
So, 2015 was a productive year. I went to a lot of places and talked to a lot of people. I got to share my experience with new audiences. And I hit a couple of big milestones. There is always room for improvement, and I've got some things on my list to work on for the coming year, including more articles, more videos, and more learning.

2016 is going to start out pretty exciting. Next week I'm headed to CodeMash in Ohio. I'm really looking forward to seeing some people I haven't seen for a while and meeting tons of new people. And the following week, I'm headed to NDC in London. That will be my first international speaking engagement and yet another professional conference under my belt.

Happy Coding!
And Have a Wonderful 2016!


Monday, December 28, 2015

January 2016 Speaking Engagements

It's hard to believe that 2016 is here already. I have several speaking engagements coming up in the new year. Be sure to check my website to see if I'll be at an upcoming event near you.

Tue - Fri, January 5 - 8, 2016
Sandusky, OH
o Abstract Art: Getting Abstraction "Just Right" (session link)

I've heard great things about CodeMash, and I'm really excited to be attending & speaking. I'm looking forward to meeting lots of new people and also seeing some friends that I've made in the area.

Wed - Fri, January 13 - 15, 2016
NDC London
London, UK
o I'll Get Back to You: Task, Await, and Asynchronous Methods in C# (session link)

I'm extremely excited about NDC. I've heard great things about the conference, and I feel very fortunate to be selected to speak. In addition, London!

Thursday, January 28, 2016
Riverside, CA
Meetup Event
o IEnumerable, ISaveable, IDontGetIt: Understanding .NET Interfaces

I'm speaking in So Cal at the end of the month. The topic is currently up-for-grabs. If you have a preference, visit the Meetup event and put in your vote. We've got a topic now; one of my favorite things to talk about: Interfaces.

Past Events
I didn't have any speaking engagements in December, but in November, I spoke at LIVE! 360 in Orlando, FL. I had a really great time and had a lot of fun. I was given a chance to share "Becoming a Social Developer" before one of the keynotes:

This was a great opportunity, and I had people coming up to talk to me about it throughout the week. You can watch the 8 minute video here: Becoming a Social Developer at Live! 360.

And you can read a bit more (including a great testimonial) in the December newsletter. You can sign up for the newsletter at the website: Becoming a Social Developer.

I also had a great time giving my presentations. The topics were very well received, and I'm happy with the feedback that came back. Here are a few of the tweets:

Thanks to everyone who came. And a big thanks to everyone who took some time to talk to me. I met a ton of great people throughout the week.

Upcoming Events
I have several more local So Cal events coming up in February, including Pasadena, Buena Park, and Newport Beach. In addition, I'll be heading out to Las Vegas again to speak at DotNet

If you'd like me to come to your user group or developer event, be sure to drop me a note. And feel free to visit my website to see if I'll be at an event near you.

Happy Coding!

Wednesday, December 23, 2015

Visual Studio Shortcuts: Comment Selection / Uncomment Selection

Another keyboard shortcut that I use in Visual Studio lets me quickly comment out a block of code. There are menu items and toolbar buttons that also let us do this, but the keyboard shortcut lets me keep my hands on the keyboard and not look for icons.

Comment Selection
They shortcut to comment out a block of code is "Ctrl+K, C" or "Ctrl+E, C" (as a reminder, I'm using the default C# settings in Visual Studio).

To comment out a selection, we first highlight the code:

And then just press "Ctrl+K, C":

That's it. Just another one of the many keyboard shortcuts available.

Alternate Methods
If you can't remember the shortcut, you can always use the "Edit" menu. Just go to "Edit -> Advanced":

And by default, there is also a button on the toolbar:

Uncomment Selection
Reversing the process is just as easy: "Ctrl+K, U" or "Ctrl+E, U". Just highlight the block of commented code:

And press "Ctrl+K, U" to uncomment the selection:

As you can see, this uses the single-line comment notation (the //). This means that it will work in most situations. If a line already has a single-line comment, then the comment notations will be doubled-up. This means that if you then uncomment the same block, you will end up with the original code (including the original single-line comments).

One thing to watch out for is when using the delimited-comment notation ( /*  */ ) in our code. If the delimited comments span multiple lines, then we want to make sure to include the entire delimited comment in the selection. Otherwise, we'll end up commenting out an opening or closing tag, and we'll be left with an unbalanced comment.

Ctrl+K or Ctrl+E?
You may have noticed that in this and the previous article about Format Document, we have the option of using "Ctrl+K" or "Ctrl+E" to start off the command. Which one should we use?

That's a question I can't quite answer. Currently, both keybindings work (again with the default C# settings). I'm used to using "Ctrl+K" to start off the shortcuts (whether formatting documents or commenting/uncommenting), so that's my current habit. In addition "Ctrl+K" starts off "insert snippet" or "Surround With", so that's less for me to try to remember.

You'll notice that the menu items in Visual Studio all have "Ctrl+E". This might lead you to believe that Ctrl+K is the old way of doing things and we should use Ctrl+E.

But in Visual Studio Code, the comment/uncomment functions are bound to "Ctrl+K" (from Visual Studio Code Key Bindings):

So at least for the time being, I'll continue to use "Ctrl+K". But either one will work.

Wrap Up
Keyboard shortcuts can make us more efficient as we're typing in code, editing, or debugging. If we find ourselves using a feature frequently, instead of reaching for the menu or tool bar, we should practice using the keyboard shortcuts.

With just a few of these in our toolbox, we can get our work done more quickly.

Happy Coding!

Visual Studio Shortcuts: Format Document

It's time for another one of my favorite Visual Studio shortcuts: Format Document. I use the keyboard shortcut Ctrl+K, D (but there are other options as well).

Compilers Don't Care but Humans Do
Well formatted code makes it easier for humans to read and navigate. Many languages (including C#, the primary language I'm using these days) don't care about white space.

That means that this method is perfectly valid C#:

Ack! This code compiles and runs just fine. But it's very difficult to read.

Note: This code is taken from "I'll Get Back to You: Task, Await, and Asynchronous Methods". The source is on Github:

Format Document to the Rescue!
Fortunately, Visual Studio can fix this. All we need to do is find the "Format Document" option on the Edit menu:

This is under Edit -> Advanced -> Format Document.

You can see the keyboard shortcut listed here is Ctrl+E, D, but Ctrl+K, D also works. There's a pretty extensive list of shortcuts listed here:

Once we "Format Document", things are much easier to read:

Much better!

Controlling Formatting
I generally stick with the default formatting for C#. But if we don't like the defaults, they're pretty easy to change. For this, we look at Tools -> Options.

These are in the tree under Text Editor -> C# -> Formatting. (And of course, we can have different settings for other languages and file types.)

One thing that I like about this dialog is that it gives previews to help us make the selections. For example, let's look at the "Indentation" option. If we select "Indent open and close braces", we see a preview in the bottom half of the pane:

If we check the box, the preview updates:

This lets us see what the code will look like if we select any particular option. And the code samples are different for each option. This makes sure we have a relevant block of code for whatever option we chose.

It can get a little confusing because we can check boxes without selecting the option in the list. In this case, the preview pane doesn't always update. So I would suggest clicking on the item itself before checking/unchecking the box.

Lots of Options
There are a ton of different options. For example, what if we want to take full control over where the opening curly braces go. Here are just a few of the options under "New Lines":

In this case, we always want to have opening braces on their own line (which is my preference), but we can choose individual items if we want something different -- this would let us implement the K&R style (although I don't recommend that).

And when we dig into options a bit more, we see that we have the choice to leave block elements on a single line (meaning, the opening and closing brace are on the same line). Or we can always expand those to multiple lines.

The customization is a little overwhelming, but it's nice to have the flexibility to auto-format the code the way we want.

Sharing Format Options
If we're working alone, it doesn't really matter what formatting options we choose. But once we start to get into a shared environment, Things are a bit different.

For example, if I prefer to have my code formatted differently than my co-worker, we'll end up with a mess in our source control. That's because if we make formatting changes, our diff tools can't always pick out the changes that impact the code and the ones that are simply formatting. So generally, it's best to have a format that everyone agrees on (or run things through a shared formatter before checking in).

To share options with the team (or even just between different computers), we can export our settings. From the Tools menu, just select "Import and Export Settings...":

Then follow the steps in the wizard to save off a file or load a file. When exporting, we can even choose which items we want to include:

This lets us create a file that only has Formatting options. Then when we import it, we only get those particular settings.

Format Document is not Perfect
"Format Document" is really awesome, but it's not quite perfect. It would be nice if Visual Studio could read my mind (actually, that might be kind of frightening -- never mind).

Sometimes we have to do some manual formatting. But it's still pretty easy to do. For this example, we'll look at a lambda expression:

Again, the compiler doesn't care about the formatting of this code, but the humans do.

Note: This is the code that is seen in "Anatomy of a Lambda Expression".

If we use "Format Document" here, I don't quite get the results that I want:

You might say, "That looks okay." But it gets a little more obvious once I move the parameters "(s, e) =>" to the next line.

These are indented a level. And this is actually what I want since this is a continuation of the original assignment statement. But using "Format Document" here doesn't change anything. The indentation for the lambda expression stays the same. But there's a pretty easy workaround.

We'll start by highlighting the lines we want to indent:

And then press "Tab". This will indent the entire block (And we can use "Shift+Tab" to un-indent):

This is what I want.

We'll get similar results when we use class initializers and some other constructs. So it's good to keep this in the back of our minds.

Wrap Up
Visual Studio is a full-featured development environment. There are many shortcuts and helpers that let me focus on the code and quickly perform otherwise tedious tasks.

Formatting code is critical for human readability. For the most part, Visual Studio will format the code as you type it in or paste it in (also customizable under the Formatting options). Sometimes, we want to quickly get a code file into shape. For that, "Format Document" works great.

Happy Coding!

Wednesday, December 16, 2015

Visual Studio Shortcuts: Surround With

I really love snippets in Visual Studio. They save me a lot of typing. But there's a feature that we can use with code snippets that isn't very obvious but is extremely useful: Surround With.

And for those of you who think this is something new, it isn't. It's been around for a long time.

Try/Catch Snippet
The try/catch code snippet is one of my favorites. To use the standard snippet, we just type in "try":

If we look at the note, we see that we just have to press Tab twice to use this. And when we do, it stubs out the code for us:

Also note that the "Exception" is currently highlighted. This means that we can type in a new exception type without moving the cursor.

This is great when we are writing some new code. But usually, we already have a block of code that we want to wrap in a "try" block. So, we probably use the "try" snippet and then cut/paste the existing code to move it into the "try" block.

But there's an easier way: Surround With.

Surround With Try/Catch
Let's look at a shortcut. For this we have a method with some existing code:

We want to wrap the middle part of this method in a try/catch block.

Note: This code is taken from "I'll Get Back to You: Task, Await, and Asynchronous Methods". The source is on Github:

Instead of using the "try" snippet by itself, first, we'll highlight the block of code and then use the keyboard shortcut "Ctrl+K, Ctrl+S". This gives us a popup:

The popup has a pretty long list of code snippets that we can use. In this case, we'll type in "try" (just like we did earlier):

Then when we press "Tab" or "Enter", we see our code is surrounded with a "try" block:

Notice that the "Exception" is highlighted (just like with our original snippet). We can type in a new exception type:

And then when we press "Enter", the cursor moves to the inside of the "catch" block:

And then we just need to type in our own code:

This makes it really easy to add a try/catch block to our code. Let's try this again, but with a try/finally instead.

Surround With Try/Finally
Let's go back to our original method:

We'll take a slightly different approach. Instead of handling the exception here, we'll assume that we have an exception handler upstream that will take care of things. But we still have some code in this method that we have to worry about.

Notice that at the top of the method, we disable a button. Then at the bottom of the method, we re-enable it. We want to wrap this in a try/finally so that the button gets re-enabled even if there's a problem along the way.

So we'll highlight the same block that we had before, and use "tryf" for the try/finally snippet:

The output gives us an empty "finally" block:

Then we can move the code that re-enables the button into the "finally" block:

This way, we know that our button will get re-enabled, even if there is an exception along the way.

Other Snippets
When we use "Surround With", the snippets that come up all have a body of some sort.

For example, we can use the "if" snippet to wrap code in an "if" conditional. We can use the "while" snippet to wrap code in a "while" loop. The same is true for "for" and "foreach", and also for "using" and even creating regions ("#region").

Wrap Up
One of the reasons that "Surround With" isn't well known is because it's hidden pretty well. It's available on the right-click menu:

And it's also available with the keyboard shortcut (which I use all the time).

"Surround With" is one of those great little tools that makes Visual Studio such a great programming environment.

Happy Coding!

Sunday, December 13, 2015

Lazy vs. Careless

I am a lazy developer. I have no trouble admitting that because laziness is what drives me to automate tedious processes. It's what compels me to let my tools do as much work as possible. It's what pushes me to use unit testing for easy regressions.

I try to avoid being careless. Carelessness is what tempts us to cut corners when we know we should be doing something differently. And carelessness often comes back to haunt us.

I made a careless decision 6 years ago that is still causing me problems. Let's see where things went wrong, and hopefully others can learn from my mistake.

But before we do that, let's take a closer look at the differences between lazy programming and careless programming.

Lazy Programming
Laziness can be a virtue as a developer. Over the years, I've learned lots of shortcuts in Visual Studio (my primary development environment). This includes keyboard shortcuts as well as code snippets and code completion.

Visual Studio Helpers
In Visual Studio 2013 (and earlier), it wasn't always obvious where Visual Studio could offer us help. I always tell people to look for the little purple rectangle:

Here we have a class that declares that it implements an interface (IPersonRepository), but it doesn't yet have any of the required methods. The little purple rectangle under the "I" tells us that Visual Studio wants to help us out. (This does have a name, but I always forget what it's called -- and it's very difficult to search online for that.)

Whenever we see this, we can press "Ctrl" + "." to get a popup:

Then if we choose "Implement interface 'IPersonRepository'", it does all the hard work for us:

Now all 6 methods are stubbed out for us. This saves us the hassle of having to copy/paste method signatures whenever we implement an interface.

In Visual Studio 2015, the purple underline has been replaced with a more prominent light bulb:

When we click on the light bulb (or press "Ctrl" + "."), we get a similar popup that allows us to implement the interface. Plus, we get a bit of a preview to show what Visual Studio plans to do for us.

This is just one example of how Visual Studio fills in code for us that would otherwise be tedious to type in.

Keyboard Shortcuts
Another thing I love are keyboard shortcuts. Unfortunately (or fortunately), there are tons of them. I've picked a few that have been most useful in my coding:
  • Ctrl+K, Ctrl+C : Comment current line/selected block
  • Ctrl+K, Ctrl+U : Uncomment current line/selected block
  • Ctrl+K, Ctrl+D : Reformat document
  • Ctrl+K, Ctrl+S : "Surround with" - wraps a selected block in a code snippet
  • Ctrl+Shift+B : Build project
  • Ctrl+Space : Show code completion options
  • Ctrl+Shift+Space : When inside method parens, this pops up the list of parameters
These are the default key mappings when using Visual Studio with the C# settings. Resharper has its own set of keyboard shortcuts.

The point is that we can get a productivity boost when we learn how our tools can make development faster.

Snippets and Completion
I love code snippets. I use them to quickly create properties and "for" loops. I also love the "Surround with" keyboard shortcut in conjunction with the "try" snippet to wrap a block of code in a try/catch block (or the "tryf" snipped to wrap a block of code in a try/finally block).

And when hooking up event handlers, let's let Visual Studio create the methods for us. After typing an event and then "+=", we get some help:

When we press tab, we get a chance to rename the method:

And when we hit tab again, the event handler is stubbed out for us:

This example is from Visual Studio 2013. Visual Studio 2015 handles things a little bit differently; it stubs out the method first and then uses the new rename functionality to give us a chance to pick a new name.

Lazy is Good
So when we look at laziness in this sense, it's good. It gives us motivation to learn our tools so that we can write code quickly and easily. In addition, it's changed the way that I test code. I'm heavily into unit testing, and that's primarily because it's faster and easier for me -- especially when it comes to regression testing.

Probably the best thing about laziness is that it drives us to automate tedious tasks. Let's write a script rather than checking values manually. Let's put together a small application so we don't have to verify values every day. Let's automate deployment -- 1 click to build, test, deploy.

Careless Programming
What we really need to watch out for is carelessness in our programming. This is where we cut corners when we're putting things together. It could be global variable that we put in because it's faster to write than trying to figure out a more appropriate way to handle the functionality.

A global variable doesn't sound like it could cause a ton of problems, but it can. I worked on an application where I used a global variable to hold some shared data. The problems came about when reliance on the global variable meant that a single class kept getting bigger and bigger (because it needed that variable) rather than things getting split up into more appropriate chunks. That made things harder to support as time went on.

But that's not the carelessness that is still causing me problems. For that, we'll need to look at my sample applications.

A Simple Data Set
Way back at the end of 2009, I was working on some sample applications for my first outing as a speaker. Those first presentations were in January 2010, and I put together some simple data to use with them. Here's the output from a Silverlight example on how to use data templates and value converters:

from Intro to Data Templates and Value Converters in Silverlight

This shows a set of 7 records. (And in case you're curious, they are "television outer space commanders".) For this Silverlight application, I needed a web service, and ended up with a method that hard-coded the data:

This looks harmless enough, but I made a careless decision to cut a corner. And that was getting the dates into the data:

I decided to use a DateTime.Parse because I was copying the dates in from somewhere else, and it was a lot easier than splitting the components up with a proper call.

At the time I did this, I knew that I was not doing it the "right" way. But it was a way that would work fine. I justified this by telling myself that the data wasn't the point of the demo (the point was to show data templates and value converters). I told myself that no one who downloaded the code would care about this.

But I wasn't thinking ahead.

Carelessness Compounded by Laziness
Over the next 6 years, I would write many more demo applications. And because I'm a lazy developer, I used exactly the same data set for all of them. This was great for me because regardless of the presentation I was giving, the data would look familiar.

from I'll Get Back to You: Task, Await, and Asynchronous Methods

The look of my applications has changed, but the data has not.

The laziness is good. That means that I didn't need to come up with a new data set for each new demo. I could use what I already had. The bad part was that I was re-using careless code, and that would come back to bite me.

Going International
I think another reason I didn't worry about my careless code is because I never dreamed that my demos would leave the US. But those demos did start to go international -- primarily through Pluralsight and my YouTube channel. That's when things started breaking down.

My code:

Only works if someone is using the US date/time format: MM/dd/yyyy. And that's a problem because most of the world uses a format that makes much more sense: dd/MM/yyyy or yyyy/MM/dd.

The code above will throw an exception in either of these scenarios because it will be treating "17" as the month -- and there is no 17th month.

Some options to fix this include setting a specific culture or date format. But it was better to get rid of the ambiguity by using the constructor for DateTime:

This will work regardless of culture because the constructor parameters are clearly defined as year, month, day.

The updated GetPeople method looks like this:

Tendrils Everywhere
So the fix is pretty easy, but by this time, the bad code was *everywhere* -- in my samples for generics, delegates, lambda expressions, interfaces, design patterns, dependency injection, ugh. When I put my code samples together, I have to goal of someone being able to unzip the download and then build and run the code without having to do anything special.
This means that a copy of the careless code is included in pretty much every single downloadable project that I have.
I have been slowly updating the projects as I can. And I make sure that any new projects have the good code. But the fixes are tedious, and I'm still working on getting code updated.

Most of my code on GitHub is good, but there are still a lot of zip files on my website that are not. I'll get there eventually.

Watch Out for Carelessness
I cut a corner 6 years ago. I knew I was cutting a corner. I knew that there was a better way of doing things. But I made a careless decision that was short-sighted. I wish I could go back and fix it. It would save me a lot of work if I could. But that's how we learn.

I embrace my laziness as a developer. I let my tools do most of the work for me. I embrace unit testing. I look for ways to automate tedious work. These are all ultimately good results.

But I need to watch out for carelessness. I don't want to cut corners that will cause me pain in the future. If the solution feels "wrong", it probably is.

Embrace laziness, but watch out for carelessness.

Happy Coding!