New Developers Looking for a Mentor: Here's a (Free) Mentorship Session in 8 Lessons

You don’t need to meet your mentors.

I read that Napoleon Hill, the author of “Think and Grow Rich,” talked to his mentor only once, and he said it changed his life.

I’d be happy to share some advice over a virtual coffee in an “ask-a-friend” style. But to preserve my keystrokes and help more than one person, here I go.

I’m writing for my 20-year-old self joining his first corporate job, pretending that talent was a shortcut to break the rules of the corporate world. I thought my first job would be like in a Silicon Valley startup, working barefoot and sliding between offices. It was far from that.

This is free Internet advice, so handle it with care.

If you could take away only one lesson, take this first one,

1. Learn It and Teach It

“The moment you learn something, teach it.”

That’s from the book Show Your Work by Austin Kleon. “A book for people who hate the very idea of self-promotion.”

Teaching is the most effective way to learn. When you teach what you’ve learned, you consolidate your learning and, if you choose to teach online, you start building an online brand.

If you’re still here for more lessons, let’s continue…

2. Google “How To Be a Good Developer”

I remember doing this exact same search, back in the early 2010s when I started my journey.

I remember finding “write technical specs” and “learn functional programming.” It gave me ideas and subjects to explore. That’s why I’ve always had Functional Programming in the back of my head.

I’d tell my younger self to do it again.

Google or DuckDuckGo or Bing “How to be a good developer” and see how deep the rabbit hole goes.

Be careful, you will find one post saying “Document your code” and another one, saying “Don’t document your code.” Separate the wheat from the shaft.

3. Practice a Lot

The barrier to entry into the coding world is low, and lower and lower with every day that passes.

Anyone can potentially start, but getting good at it takes years.

Another googling task: search for “Teach Yourself Programming in Ten Years.”

Start by writing an end-to-end project: a coding project that reads data from a webpage, calls a backend, persists data into a relational database, and displays it back.

You will learn a lot from this simple exercise. HTML/CSS, a UI library, HTTP/REST, a backend language, SQL, and a database engine. Quite a lot!

I can’t remember how many hours I spent coding a recipe catalog back in the day with PHP and MySQL.

4. Master the Fundamentals

Frameworks and libraries come and go.

Study subjects that stand the test of time. Design patterns, data structures, and SQL, for example.

For some reason, we’re still talking about stoicism thousands of years later.

Probably in the next decade, we will still be writing code on text files, using some flavor of Unix/Linux, and writing SQL. I wouldn’t bet all my money, though.

5. Invest in Your Soft Skills

You won’t be locked in your basement coding. This is a collaborative endeavor.

You will spend most of your time communicating and collaborating: 1-1s, estimations, and SCRUM “ceremonies.”

Invest in your soft skills. Start by reading “How to Win Friends and Influence People.” My biggest takeaway from that book is never telling someone is wrong.

6. Read the Clean Code

This is the book we all start with.

It opened a whole new world for me. Nobody taught me about good variable and function names until I found that book. I even remember one of my teachers using “stu1” and “stu2” as variable names during classes. Uncle Bob would be pissed by those names.

Don’t just read it. Study it.

But don’t become a Clean Code police officer issuing infractions around you and using your book copy as your baton. There’s always a tradeoff.

7. Ask Yourself What You Want

Start by experimenting with roles and tech stacks. You will find the one that you like the most.

I started writing PDF reports by hand, drawing lines and cells, one pixel and line at a time. I don’t do that anymore, by the way. Then, I did a bit of mobile development with Xamarin and frontend development back in the day of Bootstrap and Knockout.js. Eventually, I got tired of styling and coloring issues and moved to backend development.

Ask yourself what you want out of your career. Is it money? Connections? Growing your own business? Write a 5-year plan and be willing to correct the course. “No plan resists contact with the enemy” or reality, I prefer to say.

8. Climbing the Corporate Ladder Is a Myth

You don’t control anything about the ladder you climb. Anyone can add a new step or replace the entire ladder, at any time.

Software Engineer I, II, III, IV, V…

You will hit a point of diminishing returns and a glass ceiling as a software developer.

I’d tell my younger self eager for a fancy title: a new title comes with more meetings, extra hours, and the same salary.

Instead of optimizing for a title, optimize for a lifestyle. The best ladder to climb is the one you build for yourself.

Takeaways

Voila! That’s what I’d tell my younger self. I hope I haven’t discouraged you. Software Engineering is a great career. It’s the future. Well, that’s what I’ve been hearing for quite a while.

The most satisfying thing about this career is seeing a smile on your users’ faces when what you code helps them save hours of repetitive work.

For more practical advice…

Refactor your coding career with my free 7-day email course. In just 7 emails, you’ll get 10+ years of career lessons to avoid costly career mistakes.

See you around and happy coding!

Testing DateTime.Now Revisited: .NET 8.0 TimeProvider

Starting from .NET 8.0, we have new abstractions for time. We don’t need a custom ISystemClock interface. There’s one built-in. Let’s learn how to use the new TimeProvider class to write tests that use DateTime.Now.

.NET 8.0 added the TimeProvider class to abstract date and time. It has a virtual method GetUtcNow() that sets the current time inside tests. It also has a non-testable implementation for production code.

Let’s play with the TimeProvider by revisiting how to write tests that use DateTime.Now.

Back in the day, we wrote two tests to validate expired credit cards. And we wrote an ISystemClock interface to control time inside our tests. These are the tests we wrote:

using FluentValidation;
using FluentValidation.TestHelper;

namespace TimeProviderTests;

[TestClass]
public class CreditCardValidationTests
{
    [TestMethod]
    public void CreditCard_ExpiredYear_ReturnsInvalid()
    {
        var when = new DateTime(2021, 01, 01);
        var clock = new FixedDateClock(when);
        var validator = new CreditCardValidator(clock);
        //                                      ^^^^^
        // Look, ma! I'm going back in time

        var creditCard = new CreditCardBuilder()
                        .WithExpirationYear(DateTime.UtcNow.AddYears(-1).Year)
                        .Build();
        var result = validator.TestValidate(creditCard);

        result.ShouldHaveAnyValidationError();
    }

    [TestMethod]
    public void CreditCard_ExpiredMonth_ReturnsInvalid()
    {
        var when = new DateTime(2021, 01, 01);
        var clock = new FixedDateClock(when);
        var validator = new CreditCardValidator(clock);
        //                                      ^^^^^
        // Look, ma! I'm going back in time again

        var creditCard = new CreditCardBuilder()
                        .WithExpirationMonth(DateTime.UtcNow.AddMonths(-1).Month)
                        .Build();
        var result = validator.TestValidate(creditCard);

        result.ShouldHaveAnyValidationError();
    }
}

public interface ISystemClock
{
    DateTime Now { get; }
}

public class FixedDateClock : ISystemClock
{
    private readonly DateTime _when;

    public FixedDateClock(DateTime when)
    {
        _when = when;
    }

    public DateTime Now
        => _when;
}

public class CreditCardValidator : AbstractValidator<CreditCard>
{
    public CreditCardValidator(ISystemClock systemClock)
    {
        var now = systemClock.Now;
        // Beep, beep, boop
        // Using now to validate credit card expiration year and month...
    }
}

We wrote a FixedDateClock that extended ISystemClock to freeze time inside our tests. The thing is, we don’t need them with .NET 8.0.

1. Use TimeProvider instead of ISystemClock

Let’s get rid of our old ISystemClock by making our CreditCardValidator receive TimeProvider instead, like this:

public class CreditCardValidator : AbstractValidator<CreditCard>
{
    // Before:
    // public CreditCardValidator(ISystemClock systemClock)
    // After:
    public CreditCardValidator(TimeProvider systemClock)
    //                         ^^^^^
    {
        var now = systemClock.GetUtcNow();
        // or
        //var now = systemClock.GetLocalNow();
        
        // Beep, beep, boop
        // Rest of the code here...
    }
}

The TimeProvider abstract class has the GetUtcNow() method to override the current UTC date and time. Also, it has the LocalTimeZone property to override the local timezone. With this timezone, GetLocalNow() returns the “frozen” UTC time as a local time.

If we’re working with Task, we can use the Delay() method to create a task that completes after, well, a delay. Let’s use the short delays in our tests to avoid making our tests slow. Nobody wants a slow test suite.

With the TimeProvider, we can control time inside our tests by injecting a fake. But for production code, let’s use TimeProvider.System. It uses DateTimeOffset.UtcNow under the hood.

person holding glass ball
Time from another perspective. Photo by Jossuha Théophile on Unsplash

2. Use FakeTimeProvider instead of FixedDateClock

We might be tempted to wrie a child class that extends TimeProvider. But, let’s hold our horses. There’s an option for that too.

Let’s rewrite our tests after that change in the signature of the CreditCardValidator.

First, let’s install the Microsoft.Extensions.TimeProvider.Testing NuGet package. It has a fake implementation of the time provider: FakeTimeProvider.

Here are our two tests using the FakeTimeProvider:

using FluentValidation;
using FluentValidation.TestHelper;
using Microsoft.Extensions.Time.Testing;

namespace TestingTimeProvider;

[TestClass]
public class CreditCardValidationTests
{
    [TestMethod]
    public void CreditCard_ExpiredYear_ReturnsInvalid()
    {
        // Before:
        //var when = new DateTime(2021, 01, 01);
        //var clock = new FixedDateClock(when);
        var when = new DateTimeOffset(2021, 01, 01, 0, 0, 0, TimeSpan.Zero);
        var clock = new FakeTimeProvider(when);
        //              ^^^^^
        // Look, ma! No more ISystemClock
        var validator = new CreditCardValidator(clock);
        //                                      ^^^^^

        var creditCard = new CreditCardBuilder()
                        .WithExpirationYear(DateTime.UtcNow.AddYears(-1).Year)
                        .Build();
        var result = validator.TestValidate(creditCard);

        result.ShouldHaveAnyValidationError();
    }

    [TestMethod]
    public void CreditCard_ExpiredMonth_ReturnsInvalid()
    {
        // Before:
        //var when = new DateTime(2021, 01, 01);
        //var clock = new FixedDateClock(when);
        var when = new DateTimeOffset(2021, 01, 01, 0, 0, 0, TimeSpan.Zero);
        var clock = new FakeTimeProvider(when);
        //              ^^^^^
        var validator = new CreditCardValidator(clock);
        //                                      ^^^^^
        // Look, ma! I'm going back in time

        var creditCard = new CreditCardBuilder()
                        .WithExpirationMonth(DateTime.UtcNow.AddMonths(-1).Month)
                        .Build();
        var result = validator.TestValidate(creditCard);

        result.ShouldHaveAnyValidationError();
    }
}

The FakeTimeProvider has two constructors. One without parameters sets the internal date and time to January 1st, 2000, at midnight. And another one that receives a DateTimeOffset. That was the one we used in our two tests.

The FakeTimeProvider has two helpful methods to change the internal date and time: SetUtcNow() and Advance(). SetUtcNow() receives a new DateTimeOffset and Advance(), a TimeSpan to add it to the internal date and time.

If we’re curious, this is the source code of TimeProvider and FakeTimeProvider from the official dotnet repository on GitHub.

If we take a closer look at our tests, we’re “controlling” the time inside the CreditCardValidator. But, we still have DateTime.UtcNow when creating a credit card. For that, we can introduce a class-level constant Now. But that’s an “exercise left to the reader.”

Voilà! That’s how to use the new .NET 8.0 abstraction to test time. We have the new TimeProvider and FakeTimeProvider. We don’t need our ISystemClock and FixedDateClock anymore.

If you want to read more content, check how to Test Logging Messages with FakeLogger and my Unit Testing 101 series where we cover from what a unit test is, to fakes and mocks, to other best practices.

Happy testing!

I applied at a FAANG and failed: Three interviewing lessons

Overconfidence killed all my chances of success.

I applied for a role as a software engineer at a FAANG or MAGMA or insert-newest-acronym here.

And I failed.

I thought: “I have more than 10 years of experience. I’ve seen quite a lot.”

A “short coding assessment” got me off guard. 80 minutes and 3 exercises made me feel like an impostor. An uppercut and 10-second countdown.

I don’t want this post to be another “hiring is broken” and “life is unfair” post. So…

If I could go back in time, this is what I’d tell myself before that coding assesment:

1. Review data structures, especially those you don’t use often.

Take the time to review data structures. Lists, hash maps, queues, trees.

Trees, is this you?

I haven’t used trees since my data structure class back in university. And probably, I wouldn’t use them if I had passed the interview and joined.

But, surprise, surprise. That was one of the questions.

2. Practice using a timer and a coding editor without auto-completion

I know it’s unrealistic. These days, we have IDEs with autocompletion and even AI at our fingertips.

But MAGMAs insist on hiring using coding platforms without autocompletion. The old way.

Since practicing a skill should be as “real” as possible, close your IDE and practice using a bare-bones text editor. And with a timer on.

3. Read all questions first. I know!

Yeah, I wanted to be an A-student playing with the rules. I jumped right to the first question.

50 minutes in and I had barely an answer for the first question. I had to decide between solving only one question or moving on and trying to solve another one. One and a half questions are better than only one, I guess.

I could have nailed the second one first. It was way easier. And definitively, I could have solved the last two questions and skipped the first one. If only I had read all the questions first.

Read all the questions and start with the easy ones. Old advice that I forgot.

Voila! That’s what I’d tell myself before that coding assessment. Yeah, hiring is broken, but we have to go through gatekeepers. Or ditch our CVs and interviewing skills and build a place for ourselves.

For more interview content, read remote interview types and tips and ten tips to solve your next interview coding challenge.

Happy interviewing!

Steal This 6-Step Reading Process To Retain More From Books

Reading more books isn’t the answer.

In the last two or three years, I read dozens of non-fiction books. The truth is I don’t remember reading some of them, even when I took notes. I don’t even remember their front cover or why I decided to read them.

I was reading to increase a book count. Pure FOMO. Without realizing it, I was trying to copy those YouTube videos: “I read <insert large number here> books, here’s what I learned.”

After that realization, I adapted the slip-box or Zettelkasten method, described in How to Take Smart Notes by Sönke Ahrens, and other reading techniques into my own reading system.

This is the six-step process I follow to read and retain more from non-fiction books:

Step 1: Intention

Start by asking why you want to read a book.

We don’t jump into a book with the same attitude if we’re just curious about a subject or want to answer a particular question.

That intention will set the tone for our reading. And based on that, we could decide if we want to read the book from cover to cover or jump into a particular section.

Step 2: Overview

Ask if the book you’re about to read can answer your questions or satisfy your curiosity.

For that, understand the purpose of the book and its content. Use reviews, summaries, or anything else to understand the overall book content.

Often book authors go on podcast tours to promote their books, and listening to those podcast episodes helps us understand what their books are about.

A good experiment to try is to use ChatGPT or Copilot for this step. We could use any of the two to generate an executive summary of a book, for example.

Step 3: Note

Create a new place for your notes, either a text file or a piece of paper.

For this step, I use old plain-text files. Obsidian, Notion, or any note-taking app works here.

For the new note, use the date and the book title as the note title. Then divide the note into two halves. The first half is for questions and connections, and the second half is for the actual notes.

Also, link to the new book note from a book index and a subject index. The book index is a note that links to all books you’ve read. And the subject index is a note that references all other notes related to a specific subject. These notes work like “index” notes.

a rectangle divided into two halves
My note structure and links between notes

Step 4: Question

Read the table of contents, introduction, and conclusion to look for the book’s structure and interesting topics.

Also, skim through the book to find anything that grabs your attention: boxes, graphs, and tables.

In the first half of your note, write questions you have about the subject and questions that arise after skimming the book.

If you decide not to read the book from cover to cover, in the first half of your note, create an index of the chapters and sections to read or the ones to skip. Keep this index for future reference.

I learned this idea of asking “pre-reading” questions from Jim Kwik’s Speed Reading program and the idea of a custom index from the post Surgical Reading: How to Read 12 Books at Once.

Step 5: Read

Then, read the book while taking note of interesting parts and quotes.

Use the second half of your notes to write down those interesting bits. Avoid copying and pasting passages from the book, except for quotes. Use your own words instead.

After every chapter, stop to recall the main ideas from that chapter.

If you find the answer to any of your questions from the “Question” step, go back to the first half of your note and write those answers there.

Step 6: Connections

While reading or after finishing a chapter, notice connections with other subjects. Ask yourself how that expands or contradicts anything else you’ve learned.

Use the first half of the note to write these connections.

If you’re familiar with the Zettelkasten method, to write your connections, we should use a separate set of notes: the permanent notes. For simplicity, I keep these connections in the same file but in the first half.

This way, the next time you open your note, you will find your connections and critique first.

Parting Thought

The key to retaining more is reading actively. Don’t just pass from page to page. Read with intention, not to grow a book count. Read for answers and connections.

The next time you’re about to jump into a new book, remember to set an intention and then capture and connect.

Reading more books isn’t the answer. Reading for retention and action is.

For more content, check my takeaways from Pragmatic Thinking and Learning and Show Your Work.

Happy reading!

AI Won't Take Our Coding Jobs Yet. But The World Will Need Different Coders

On March 12th, 2024, the coding world went nuts.

That day, Cognition Labs announced in their Twitter/X account the release of Devin, “the first AI software engineer.”

That announcement made the coding world run in circles, screaming in desperation. It also triggered an interesting conversation with a group of colleagues and ex-coworkers.

Here’s a summary of how a group of senior engineers viewed Devin and AI in general, and my own predictions for coding in the next 10 years.

If You Think You’re Out, You’re Out!

We all agreed that Devin and AI in general won’t take out jobs yet, but it will change the landscape for sure.

This is when the meme “AI needs well-written and unambiguous requirements, so we’re safe” is true.

One part of the group believed that software engineering, as we know it, would disappear in less than 10 years. They expected to see more layoffs and unemployment. They were also planning escape routes away from this industry.

If you’re reading this from the future, a bit of context about layoffs:

Around the 2020 pandemic, we enjoyed a boom in employment. We only needed “software engineer” as the title in our LinkedIn profiles to have dozens of recruiters offering “life-changing opportunities” every week.

But, in 2023 and 2024, we experienced massive layoffs. Either we were laid off or knew someone in our inner circle who was. It was a crazy time: one job listing, hundreds of applicants, and radio silence after sending a CV.

Most people claimed that AI took those jobs. Others claimed tech companies were so used to free money that went crazy hiring and then, when money wasn’t free anymore, they went crazy firing too. In any case, it was hard to get a new job in that season of layoffs.

Ok, end of that detour and back to the AI story.

While one part of the group was thinking of escaping routes, the other part believed the world would still need software engineers, at least, to oversee what AI does.

We wondered if AI needs human oversight, what about the working conditions for future software engineers? Maybe will they come from developing countries, with an extremely low wage and poor working conditions to fix the “oops” of AI software engineers? And if unfortunate software engineers were already under those conditions, wouldn’t all future software developers (at least the ones still standing) face the same fate?

Our conversation was divided into despair and change.

The World Will Need a Different Type of Coders

In 2034, knowing programming and coding by itself won’t be enough.

We will need to master a business domain or area of expertise and use programming in that context, mainly with AI as a tool.

Rather than being mundane code monkeys, our role will look like Product Managers. The coding part will be automated with AI. We will work more as requirement gatherers and writers and prompt engineers. Soft skills will be even more important than ever. Essentially, we all will be engineering managers overseeing a group of Devin’s.

We will see more Renaissance men and women, well-versed in different areas of knowledge, managing different AIs to achieve the goal of entire software teams.

In the meantime, if somebody else writes requirements and we, software engineers, merely translate those requirements into code, we’ll be out of business sooner rather than later.

Voilà! That’s how Software Engineering will look like in 2034: more human interaction and business understanding to identify requirements for AI software engineers. No more zero-value tasks like manual testing, code generation, and pointless meetings. Yeah, I’m looking at you, SCRUM daily meetings. AI will handle it all. Hopefully.

This is what Programming was like in 2020 and how I used AI to launch my courses in 2024.

Yes, I know! Making predictions about the future is hard.

“Open in 2034”