I'm Launching Street-Smart Coding: 30 Lessons to Help You Code Like a Pro (the Roadmap I Wish I Had Starting Out)

Street-Smart Coding cover
Street-Smart Coding: 30 Ways to Get Better at Coding Without Losing Your Mind

I spent five years in college learning to code.

A stupid dissertation delayed my graduation. But that’s another story.

Most of my five-year program didn’t prepare me for real-world coding. My real coding journey began at my first job, with one Google search: “how to get good at coding.”

I found a lot of conflicting advice:

  • “Use comments”
  • “Don’t use comments”
  • “Do this”
  • “Don’t do that”

Arrggg!

It took years of trial and error to learn what worked.

I had to survive on-call shifts, talk to stakeholders, and say “no” politely. More importantly, I had to learn that coding takes more than just syntax.

That’s why I wrote Street-Smart Coding— a roadmap of 30 lessons I wish I had when I started. For every dev who’s ever typed “how to get better at coding” into Google or ChatGPT. (Back in my days, I didn’t have ChatGPT… Wait, I sound like a nostalgic grandpa…)

Scrolling through the first pages of Street-Smart Coding
Preview of the first ~12 pages

Inside “Street-Smart Coding”

This isn’t a textbook. It’s a battle-tested guide for your journey from junior/mid-level to senior.

Some lessons are conventional.

Others were learned the hard way.

And a few are weird.

One lesson comes from a TV show. Nope, not Mr. Robot or Silicon Valley. That’s on Chapter #29. It will teach you about problem-solving.

You’ll learn how to:

  • Google like a pro
  • Debug without banging your head against a wall
  • Communicate clearly with non-tech folks

…and 27 more lessons I learned over ten years of mistakes.

Now they’re yours.

Get your copy of Street-Smart Coding here and skip the years of trial and error. For launch week only: Pay what you want—even $1 or $2.

The #1 Health Tip From the Guy Obsessed With Living Forever

If you could only do one thing for your health, it should be sleep.

Brian Johnson, the guy trying to live forever, teaches in his videos and interviews to be a professional sleeper.

He’s right when he says nobody teaches us to sleep.

For better sleep, build your life around sleep:

Beyond the basics, Brian’s recent videos taught me to aim for a lower heart rate before sleep. Try journaling, taking deep breaths, or meditation. Slow down before going to bed.

Staying late for my writing streak taught me rest is the best productivity hack. Coffee can’t fix a bad night of sleep. So go to sleep!

TIL: How to Set Up a Unilateral One-to-One Relationship with Entity Framework Core

In another episode of Adventures with Entity Framework while migrating a legacy app…

Entity Framework Core only populated a child entity on one item in a result. To honor the 20-minute rule, and for my future self, here’s what I found:

TL;DR: You don’t need the WithOne() and HasForeignKey() when configuring the relationship.

#1. Let’s create an optional one-to-one relationship.

Let’s create a Movie and an Award table.

USE Movies;
GO
CREATE TABLE Awards (
    Id INT PRIMARY KEY IDENTITY(1,1),
    Name NVARCHAR(100) NOT NULL
);
CREATE TABLE Movies (
    Id INT PRIMARY KEY IDENTITY(1,1),
    Name NVARCHAR(100) NOT NULL,
    AwardId INT NULL /* <-- Optional. No FK here */
);
GO

Since the relationship is optional, the AwardId is nullable. This type dictates what JOIN Entity Framework Core uses.

#2. Configure the one-to-one relationship

Let’s configure the relationship using HasOne() and WithOne().

using Microsoft.EntityFrameworkCore;

namespace LookMaWhatEntityFrameworkDoes;

public class Award
{
    public int Id { get; set; }
    public string Name { get; set; }
}
public class Movie
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int? AwardId { get; set; }
    //       ^^^
    // Optional

    public Award Award { get; set; }
}

public class MovieContext : DbContext
{
    public MovieContext(DbContextOptions<MovieContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder
            .Entity<Movie>()
            .HasOne(m => m.Award)
            .WithOne()
            .HasForeignKey<Movie>(m => m.AwardId)
            .OnDelete(DeleteBehavior.Restrict);
    }

    public DbSet<Movie> Movies { get; set; }
    public DbSet<Award> Awards { get; set; }
}

To verify Copilot’s answer, I went through the official docs here.

#3. Retrieve movies and their awards

And now, let’s create an award, add two movies, and retrieve them to check their awards.

using Microsoft.EntityFrameworkCore;

namespace LookMaWhatEntityFrameworkDoes;

[TestClass]
public class MovieTests
{
    [TestMethod]
    public async Task AllAwardsPlease()
    {
        const string connectionString = $"Server=(localdb)\\MSSQLLocalDB;Database=Movies;Trusted_Connection=True;";

        var options = new DbContextOptionsBuilder<MovieContext>()
            .UseSqlServer(connectionString)
            .LogTo(Console.WriteLine)
            .Options;

        // 1. Let's create an "Oscar"
        using (var context = new MovieContext(options))
        {
            context.Awards.Add(new Award
            {
                Name = "Oscar"
            });
            context.SaveChanges();
        }

        // 2. Let's create two movies that have won an "Oscar"
        using (var context = new MovieContext(options))
        {
            var oscar = await context.Awards.FirstOrDefaultAsync();
            Assert.IsNotNull(oscar);

            context.Movies.AddRange(
                new Movie
                {
                    Name = "Forrest Gump",
                    AwardId = oscar.Id
                },
                new Movie
                {
                    Name = "Titanic",
                    AwardId = oscar.Id
                }
            );
            context.SaveChanges();
        }

        // 3. Let's retrieve all movies, expecting to have an Award
        using (var context = new MovieContext(options))
        {
            var movies = await context.Movies
                                // Imagine more filters here			
                                .Include(m => m.Award)
                                // ^^^^^
                                // Yes, I'm including it here
                                .ToListAsync();

            foreach (var movie in movies)
            {
                Assert.IsNotNull(movie);
                Assert.IsNotNull(movie.Award);
                //     ^^^^^
                // Assert.IsNotNull failed.
                // Play sad trumpet sound.
            }
        }
    }
}

Sorry for the foreach inside the Assert. That’s not a good idea. But I’m lazy and I’m taking too long writing this.

Yes, it fails. Play sad trumpet, please. The second movie’s award isn’t populated. Arrggg!

My fault!

#4. Ignore WithOne()

Since I’m setting an unidirectional relationship, one movie/one award/multiple movies, only configuring HasOne() is enough.

Using WithOne() was telling Entity Framework Core that one award could only belong to one movie. And that’s not the case here.

public class MovieContext : DbContext
{
    public MovieContext(DbContextOptions<MovieContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Remove the entire configuration
		// Or,		
        modelBuilder
            .Entity<Movie>()
            .HasOne(m => m.Award);
            // ^^^^^
            // Just this
    }

    public DbSet<Movie> Movies { get; set; }
    public DbSet<Award> Awards { get; set; }
}

And since I’m following default naming conventions, I could even delete the configuration. Ahh, Cascade sets to null, which is fine here.

Yes, the right answer is to do nothing.

Et voilà!

For debugging and problem-solving tips, read Street-Smart Coding. Those two skills are more relevant now in the era of AI-assisted coding.

Building a Reusable Blazor Component for Summernote

In another adventure with Blazor…

While migrating a legacy app, I had to “componentize” an HTML editor. It used Summernote, “a super simple WYSIWYG editor on Bootstrap”.

The fun part was learning JavaScript interop: calling JavaScript from .NET and viceversa.

After some Googling and sneaking into abandoned GitHub repos, here’s what I came up with:

The component

In Summernote.razor:

@using Microsoft.AspNetCore.Components.Sections

<HeadContent>
    <link rel="stylesheet" href="css/summernote.css" />
</HeadContent>

<div id="@_id">@((MarkupString)Value)</div>

<SectionContent SectionName="scripts">
    <script src="js/summernote.js" type="text/javascript"></script>
</SectionContent>

In Summernote.razor.cs:

using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace MyCoolComponents.HtmlEditor;

public partial class Summernote : IAsyncDisposable
{
    private readonly string _id = $"summernote_{Guid.NewGuid()}";

    private IJSObjectReference? _module;
    private DotNetObjectReference<Summernote>? _dotnetRef;
    private bool _editorInitialized = false;

    [Parameter]
    public string Value { get; set; }

    [Parameter]
    public EventCallback<string> ValueChanged { get; set; }

    [Inject]
    public IJSRuntime JsRuntime { get; set; } = default!;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (!_editorInitialized)
        {
            _dotnetRef = DotNetObjectReference.Create(this);

            _module = await JsRuntime.InvokeAsync<IJSObjectReference>("import", "./PutYourPathHere/Summernote.razor.js");
            await _module.InvokeVoidAsync("edit", _id, _dotnetRef, nameof(OnTextChange));

            _editorInitialized = true;
        }
    }

    [JSInvokable]
    public async Task<bool> OnTextChange(string editorText)
    {
        Value = editorText;
        await ValueChanged.InvokeAsync(editorText);

        return await Task.FromResult(true);
    }

    public async ValueTask DisposeAsync()
    {
        if (_module is not null)
        {
            await _module.DisposeAsync();
        }

        _dotnetRef?.Dispose();
    }
}

Here’s where the magic happens.

After rendering the component, it calls a JavaScript function that initializes the Summernote editor. Then, it registers a callback that calls a .NET function every time the editor changes to update the component state.

Notice it stores content in a MarkupString but it binds as a string.

In Summernote.razor.js:

export function edit(id, dotnetRef, callback) {
    let snid = '#' + id;
    $(snid).summernote({
        callbacks: {
            onChange: function (contents, $editable) {
                dotnetRef.invokeMethodAsync(callback, contents);
            }
        }
    });
}

How to use it

And here’s a sample form using the editor:

@using MyCoolComponents.HtmlEditor

<EditForm Model="MyCoolRequest" OnValidSubmit="OnValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <div class="row">
        <div class="form-group col-sm-9">
            <label for="content" class="form-label">Content</label>
            <Summernote @bind-Value="Annotation.Content" />
            @* ^^^^^ *@
            @* Look, Ma! It works! *@
            <ValidationMessage For="() => Annotation.Content" class="invalid-feedback" />
        </div>
    </div>

    <button type="submit" class="btn btn-primary">Submit</button>
</EditForm>

This piece of code is provided “as is”, without warranty of any kind…Blah, blah, blah. Use under your own risk. Steal it.

If this helped you, you’ll love Street-Smart Coding—30 proven lessons to help you level up your coding journey.

Ten Reading Rules to Read More—and Love It

Inspired by Ryan Holiday’s reading rules, I’ve decided to come up with my own to truly enjoy reading.

I’ve had to change my mind about books. From chasing a book count to reading for action and pleasure.

Here are my 10 reading rules:

#1. Always be reading something. At least one page a day. Like Jim Kwik says, reading is like exercise for the brain. And when scrolling and distractions are the norm, reading is a revolution.

#2. Reading over phone time and social media. To reduce my phone time, I use books as conscious replacements. I leave books where I usually leave my phone to break the habit of scrolling.

And after a week off social media, I now read first thing in the morning instead of checking email or social media.

#3. Read two books at once. Balance non-fiction and fiction books. Non-fiction starts my mornings and fiction helps me unwind as night.

#4. Write a book recommendation. While reading a book, write a list of all books mentioned in the book. This is like climbing the inspiration tree as Austen Kleon says in Steal Like an Artist.

#5. Read actively. Write in margins, fold corners, underline, highlight. Your book marks can become a legacy. A book without marks is a book you haven’t read.

#6. Write a 10-idea list. I’m a big fan of 10-idea lists. Instead of note-taking apps, I write 10 ideas that resonate after finishing a book. It forces me to recall and remember what I read. Bonus point when paired with a 7-word summary.

#7. Reread. I’ve had to reconcile myself with rereading. It used to be a sin when I wanted to hit a large book count. The goal is to gain insight, not just hit a book number. Rereading is fine.

#8. Prefer physical books. They give you spatial clues to remember information. You might remember that an important concept is on a left-hand page, near the bottom. eBooks can’t beat that.

#9. No shame in piling books. From How to Be Rich by Ramit Seti, I learned we shouldn’t cut on things we love. I’m not cutting on books.

You’re the books you’ve read. And those you haven’t read yet. Just don’t let your books become “shelve-help.” Build a pile, go through it, then build another one.

#10. Binge-read your favorite writer. I did it when I found James Altucher for the first time. It shows you how their voice change and how your perspective expands.

My February Book Experiment Is Already A Success—But Still in Progress

Last February, I decided to write another book but in a completely different way.

I started from a validated idea. I turned my most popular personal development post, into a mini book. Instead of starting with the first words, I began with the outline, title, sales page, and cover. I wrote it backwards.

Here’s the final result: 10 Surprisingly Simple Ideas That Changed My Life And Could Change Yours Too.

My success metric was a single sale.

Yesterday, I announced my book in my Friday Links email and one reader bought it. A small victory dance.

First sale of 10 Surprisingly Simple Ideas That Changed My Life
First sale

With that milestone reached, here’s how I’m continuing the experiment:

  1. Reach out to my “advance readers” team to get my first review on Amazon.
  2. Promote my book via a book promotion email list for more reach.

This experiment will shape my launching strategy for future books. The real works begins after the writing is done.