Monday Links: NDC Copenhagen

These are four NDC conferences from the past Copenhagen edition.

Iron Man or Ultron: Is AI here to help us or hurt us?

“We want our AI’s to be like an IronMan suite. Not like Ultron. If IronMan does something cool in his suit, he gets the credit for it. If IronMan is not in the suit, then the suit is just this empty shell”

Is everything difficult, or is it just me?

This is a walkthrough of some mental health issues we all could face while working on a knowledge job. From Anxiety to Sleep. This is a subject we all should put on the table and talk about without any shame.

7 Things Technical Leaders Can Learn from Disney Princesses

I really liked this one. I never thought that Disney princesses could teach us about leadership. I have to confess that I skipped the singing parts from this talk. These are some of the main points:

  • “Don’t turn too many knobs at once…don’t expect immediate results when dealing with teams of people”
  • “Lean on your own self-worth and validation because the higher up in leadership you get the less external validation there will be for you”
  • “A lot of great leaders don’t have superpowers. They’re just generalists.” Instead, they can unlock other people’s potential. “You’re role is a catalyst.”
  • “Find support mechanisms when you move into leadership. This may be coaches, mentors, support groups”
  • “If you’re passing on orders, you’re not leading, you’re just managing”
  • “There’s no such a thing as a perfect team.” “Great leadership is about figuring out how to make teams from of a group of people”
  • “One of your main things is to make crystal-clear and sure that the agendas between your primary and secondary teams are aligned”

How Work Works

This talk uses Queue Theory to tune how complex organization works. These are some of the main points:

  • “IaaS platforms are M/M/c where c approaches to infinite”
  • Recommended books: Continous Delivery, Building Microservices, Building Evolutionary Architectures, Principles of Product Development Flow, Accelerate, Team Topologies
  • “Change request boards predict low performance”

Voilà! Another Monday Links episode. Do you AI as part of your daily work? What leadership lessons can you share?

Want to receive curated links like these? Get 4 more delivered straight to your inbox every week. Don’t miss out on next week’s links—subscribe to my email list here.

Happy coding!

Best of 2023

In 2023, I realized that I’ve been blogging for five years. I started this blog to keep some notes online. Since then, I’ve used my blog to share my learned lessons, answer questions, and rant out loud. I consider my blog as my time capsule.

Last year, I wrote 23 posts. I tried to write one post every other week.

I wrote a series of posts about NullReferenceException, “the billion dollar mistake,” and expanded it into a mini-course on Educative.

I updated my ASP.NET posts to use .NET 6.0, the most recent LTS version the last year.

In one of my client’s projects, I worked with ORMLite. I wrote about passing a datatable as parameter and joining to subqueries. I was too lazy to write SQL queries by hand for those two edge cases. Also, I shared five lessons I learned while working with ORMLite.

I got an interesting question through my contact page. I could shared my advice on how to start an ultralearning project.

Five posts you read the most

These are the five posts I wrote in 2023 you read the most. In case you missed any of them, here they are:

  1. Goodbye, NullReferenceException: What it is and how to avoid it.
  2. Goodbye, NullReferenceException: Option and LINQ.
  3. Goodbye, NullReferenceException: Nullable Operators and References.
  4. Too many layers: My take on Queries and Layers. While working with one of my clients, I had to write a lot of response objects and mapping methods to implement read-only API endpoints. This post contains my thoughts on taking layering to the extreme.
  5. Goodbye, NullReferenceException: Separate State in Separate Objects. This is how to apply the “make illegal state unrepresentable” mantra to avoid the NullReferenceException.

Last year, I continued working as an independent contractor and content writer. I continued writing for NCache official blog. I started offering onsite courses and training in my city. Unfortunately, I saw a lot of coworkers being laid off. I hope they all had found “greener pastures.”

Voilà! That’s my 2023 in review and your five favorite posts. I hope you enjoyed them as much as I did writing them.

If any of my posts have helped you and you want to support my work, check my courses on Educative, download my ebooks and buy me a coffee on my Gumroad page.

Don’t miss my best of 2021 and best of 2022.

Thanks for reading, and happy coding in 2024!

TIL: How to color a website based on its URL. A visual aid and time saver

These days, I spent a while debugging an issue. After a couple of minutes of scratching my head, I realized I was looking at log entries in the wrong environment. I know! A facepalm moment. I decided to look for a way to change the colors of a browser tab or a website based on the URL I visited. This is what I found.

Coloring a website per URL

After a quick search, I found the URLColors extension in GitHub. It adds an opaque rectangle on top of a website. We only need to configure a keyword for the URL and a hex color. Optionally, it can make the rectangle blink.

For example, this is how I colored Hacker News,

// <site>, <color>, <flash|no>, <timerInSeconds>, <border-width>, <opacity>
news.ycombinator.com, #b58900, no, 0, 10px, 0.5

I used this extension to color the OpenSearch dashboard and other websites I work with. I use the Solarized theme and different color temperatures and rectangle width per environment.

This is what an OpenSearch dashboard looks like,

An OpenSearch dashboard with a red rectangle around it
An OpenSearch dashboard for a non-development environment

I go with a red and thick rectangle that blinks for Production-related environments.

Coloring Management Studio bar per connection string

I use a similar trick with SQL Server Management Studio. When connecting to a new server, under the “Options” button, we can change the color of the status bar,

SQL Server Management Studio 'Use custom color' option
SQL Server Management Studio 'Use custom color' option

Voilà! No more changes in the Production environment by mistake. No more time wasted looking at the wrong website. Colors are helpful for that.

Even we can change Visual Studio title bar color with the SolutionColor extension.

For more productivity tricks, check How to declutter sites with uBlock Origin filters and how to automatically format SQL files with Git.

Happy coding!

TIL: How to declutter sites with uBlock Origin filters

These days while procastinating on HackerNews, I found this submission. It points to a GitHub repo with some uBlock Origin filters to clean up websites.

I learned that I not only can block elements in a page with uBlock Origin, but also restyle them. Ding, ding, ding! These are the uBlock Origin filters I’m using to declutter some site I visit often.

1. uBlock Origin filters to restyle elements

A uBlock Origin filter to restyle an element looks like this,

<domain>##<selector>:style(<new-css-here>)

Here are the filters I used to restyle HackYourNews and HackerNews,

hackyournews.com##body:style(width: 960px; margin: 0 auto;)
hackyournews.com##.title:style(font-size: 18pt !important;)
hackyournews.com##.ratings:style(font-size: 12pt !important;)
hackyournews.com##.subtext:style(font-size: 14pt !important;)

news.ycombinator.com###hnmain:style(background-color: #fdf6e3; width: 960px !important; margin: 0 auto !important;)
news.ycombinator.com##.rank:style(font-size: 14pt !important;)
news.ycombinator.com##.titleline:style(font-size: 16pt !important;)
news.ycombinator.com##.sitebit.comhead:style(font-size: 12pt !important;)
news.ycombinator.com##.subtext:style(font-size: 12pt !important;)
news.ycombinator.com##.spacer:style(height: 12px !important;)
news.ycombinator.com##.toptext:style(font-size: 12pt !important;)
news.ycombinator.com##.comment:style(font-size: 14pt !important;)
news.ycombinator.com##span.comhead:style(font-size: 12pt !important;)
news.ycombinator.com##.morelink:style(font-size: 14pt !important;)

2. How to install custom uBlock Origin filters in Brave

To install these filters in Brave, let’s navigate to brave://settings/shields/filters, paste the filters, and hit “Save.”

This is how HackerNews looked without my filters,

HackerNew front page
HackerNews front page without any restyling

And this is how it looks after restyling it,

HackerNew front page after restyling
HackerNews front page with some uBlock Origin filters

I reduced the page width and increased font size for more readability.

For other sites, I install these extensions: Modern Wiki to restyle Wikipedia, StackOverflow Focus, and Distraction-Free YouTube.

Voilà! That’s how to use uBlock Origin filters to declutter websites. I like clean and minimalistic designs. Before learning about uBlock Origin filters, I started to dabble into browser extension development to restyle sites. With these filters, it’s easier.

What site would you like to declutter with this trick?

For more productivity content, check how to replace keywords in file with Bash, how to rename C# project files with Git, and how to format SQL files with Git and Poor Man’s T-SQL Formatter.

Happy coding!

TIL: Five lessons while working with OrmLite

Back in the day, for my Advent of Posts I shared some lessons on Hangfire and OrmLite. In this year, for one of my client’s project I’ve been working with OrmLite a lot. Let me expand on those initial lessons and share some others.

1. IgnoreOnUpdate attribute

When using SaveAsync() or any update method, OrmLite omits properties marked with the [IgnoreOnUpdate] attribute in the generated SQL statement. Source

For example,

public class Movie
{
    public string Name { get; set; }
    
    [IgnoreOnUpdate]
    // ^^^^^
    public string OrmLiteDoesNotUpdateThisOne { get; set; }
}

I used this attribute when inserting and updating audit fields to avoid messing with creation dates when updating records.

Also OrmLite has similar attributes for insertions and queries: [IgnoreOnInsertAttribute] and [IgnoreOnSelectAttribute].

2. QueryFirst vs SqlScalar

OrmLite QueryFirst() method requires an explicit transaction as a parameter. Source Unlike QueryFirst(), SqlScalar() uses the same transaction from the input database connection. Source

I learned this because I had a DoesIndexExist() method inside a database migration and it failed with the message “ExecuteReader requires the command to have a transaction…“

This is what I had to change,

private static bool DoesIndexExist<T>(IDbConnection connection, string tableName, string indexName)
{
    var doesIndexExistSql = @$"
      SELECT CASE WHEN EXISTS (
        SELECT * FROM sys.indexes
        WHERE name = '{indexName}'
        AND object_id = OBJECT_ID('{tableName}')
      ) THEN 1 ELSE 0 END";
    
    // Before
    //
    // return connection.QueryFirst<bool>(isIndexExistsSql);
    //                   ^^^^^
    // Exception: ExecuteReader requires the command to have a transaction...

    // After
    var result = connection.SqlScalar<int>(doesIndexExistSql);
    //                      ^^^^^
    return result > 0;
}

3. Create Indexes

Apart from reading and writing records, OrmLite can modify the database schema, for example to create tables and indexes.

To create an index for a table, we could either annotate fields or classes. For example,

[CompositeIndex(unique: false, fieldsNames: "ReleaseYear", "Name", Name = "AnOptionalIndexName")]
// ^^^^^
public class Movie
{
    public int ReleaseYear { get; set; }

    [Index]
    // ^^^^^
    public string Name { get; set; }
}

Also, OrmLite has a CreateIndex() method that receives an expression, like this,

_connection.CreateIndex<Movie>(m => m.Name);
// or
_connection.CreateIndex<Movie>(m => new { m.ReleaseYear, m.Name });

By default, CreateIndex() creates indexes with names like: idx_TableName_FieldName. Source We can omit the index name if we’re fine with this naming convention.

4. Tag queries to easy troubleshooting

To identify the source of queries, OrmLite has two methods: TagWith() and TagWithCallSite().

For example,

var movies =  _connection.From<Movie>()
                    // Some filters here...
                    .Take(10)
                    .TagWith("AnAwesomeQuery")
                    // Or
                    //.TagWithCallSite();

With TagWith(), OrmLite includes a comment at the top of the generated SQL query with the identifier we pass.

For the previous tagged query, this is the generated SQL statement,

-- AnAwesomeQuery

SELECT TOP 10 "Id", "Name", "ReleaseYear" 
FROM "Movie"

With TagWithCallSite(), Ormlite uses the path and line number of the file that made that database call instead.

This is a similar trick to the one we use to debug dynamic SQL queries. It helps up to traceback queries once we found them in our database plan cache.

5. LoadSelectAsync and unparameterized queries

OrmLite has two convenient methods: LoadSelect() and LoadSelectAsync(). They find some records and load their child references.

Let’s write the Movie and Director classes,

public class Movie
{
    public string Name { get; set; }

    [Reference]
    // ^^^^^
    public Director Director { get; set; }
}

public class Director
{
    [References(typeof(Movie))]
    // ^^^^^^
    public int MovieId { get; set; }

    public string FullName { get; set; }
}

Now let’s use LoadSelectAsync(),

var query = _connection.From<Movie>()
                        // Some filters here
                        .Take(10);
var movies = await _connection.LoadSelectAsync(query);
//                             ^^^^^
// It loads movies and their child directors

When using LoadSelect() and LoadSelectAsync(), OrmLite doesn’t parameterize the internal query used to load the child entities. Arrrggg!

I’m not sure if it’s a bug or a feature. But, to load child entities, OrmLite “inlines” the parameters used to run the parent query. We will see in the plan cache of our database lots of unparameterized queries.

See it by yourself in OrmLite source code, here and here.

After finding out about this behavior, I ended up ditching LoadSelectAsync() and using SelectAsync() instead, like this,

var moviesQuery = _connection.From<Movie>()
                        // Some filters here
                        .Take(10);
var movies = await _connection.SelectAsync(moivesQuery);
if (!movies.Any())
{
    return Enumerable.Empty<Movie>();
}

var directorsQuery = _connection.From<Director>()
                        .Where(d => Sql.In(d.MovieId, moviesQuery.Select<Movie>(d => d.Id)));
var directors = await _connection.SelectAsync(directorsQuery);

foreach (var m in movies)
{
    m.Director = directors.Where(r => r.MovieId == m.Id);
}

Probably there’s a better solution, but that was my workaround to avoid a flooded plan cache. I could afford an extra roundtrip to the database and I didn’t want to write SQL queries by hand. C’mon!

Voilà! These are some of the lessons I’ve learned while working with OrmLite. Again, things we only find out when we adventure to read our libraries source code.

To read more content on OrmLite, check how to pass a DataTable as parameter to an OrmLite query and how to join to a subquery with OrmLite.

Happy coding!