Deliberate Practice for Programmers - Learn a New Language!

In the last post - we talked about why deliberate practice is important, and that I aim to approach my practice with:

  1. Purpose - I’m spending my non-refundable time on something, I want it to count.
  2. Plan - Before I start, I think about how I’m going to structure my practice so that it (hopefully) meets it’s purpose.
  3. Progress - Ensuring I take time to reflect on the practice, and adjust as necessary.

To get specific (we’re programmers, after all) - this translates to:

Defining Purpose

Creating plans to exercise ‘something’ that I encounter in my career - for example (and this list is far from exhaustive):

  1. Learning a new programming language.
  2. Working with different IDE’s to develop and debug.
  3. Traversing and processing data.
  4. Effective automated testing. From unit to end-to-end.
  5. Creating build and deployment pipelines.
  6. Working with different databases and ORMs.
  7. Performance profiling and testing.
  8. Finding memory leaks.
  9. Rapid prototyping.
  10. Paradigm shifts - e.g. object-oriented to functional.

I will find myself in a situation where either I or a colleague needs some help with a specific area - I then go to my list and see if I either have something defined that works, or start defining what I want from the session based on needs.

Defining a Plan

Given the Purpose I then start to think about a Plan.

Let’s say I want to pick up a new language as the client I am working with is on a different stack. I think I generally need to:

1. Get the basics

Can I start to express myself in the new language?

  1. How do I define basic types? (Integers, Floats, Booleans, Strings, Array)
  2. How do I concatenate or interpolate strings?
  3. How do I read from/write to the console?
  4. What are the basic control flow statements? (if/else, foreach, switch etc.)
  5. How do I define functions and methods?
  6. Can I define anonymous functions?
  7. How do I control the visibility of those functions and methods?
  8. How do exceptions work? How do I handle them?

This stage is generally easier if you know how to code already - you’ll often ask “How do I do X in Y?” This can lead to easier searches. However, having a checklist makes as a great teaching aid for fledgling programmers.

By the time I’m done with this list - I’m generally able to bumble my way through a problem.

2. Get Productive and Effective

Now that I can write some code - I am starting to think more about how it’s really working:

  • How do I define, run and interpret automated tests?
  • What data structures do I have available to me? How could/would I implement them if not?
  • What foundation / base libraries do I have available for common things - for example collections, HTTP, serialisation etc.
  • How do I use packages/modules that others have created?

At this stage, I’m probably starting to feel a lot more confident. I’ve got tests backing up my work and I’m using tried-and-tested code from others where possible.

3. Optimise!

I’m writing code - but it’s likely not the ‘best’ code. I’m likely upsetting the veterans in the codebase with every pull request. Now I start to think about:

  • Going ‘native’ - how do I write more idiomatic code for that language? Is the method named IsAuthenticated, isAuthenticated, is_authenticated, is_authenticated? or HOW IZ I AUTHENTICATED YR USER?
  • Thinking about performance - using correct data structures (because not everything belongs in an array, y’all), understanding how they’re traversed etc.
  • Being conscientious with memory usage - how do I get stuff off the heap? Reduce allocations etc.

… Reflect on Progress

I’ll open up some notes, and work my way through the above, in order. Getting “the basics” might take an hour or so. From there, I’ll try and start solving some simple problems via Katas.

As I start to learn more (e.g. more expressive/cleaner ways of saying things) - I’ll continually refine my notes.

I get a real sense of achievement in seeing my notes evolve. Going back to something you’ve personally written and editing/improving proves progress.

I’ll also solidify/verify the growth by tackling random coding problems (e.g. from the likes of CodinGame or CodeWars).
It’s amazing how quickly you can get something going!

Rinse and repeat!

Enough Talk, Let’s Code!

We’ve outlined a plan - let’s go learn the basics of a new language!

Now - my ‘home’ language is C#, but I’ve done some JavaScript, TypeScript, Python, Ruby and Java at varying levels. I’m gonna pick a random just for funsies - Elixir.

🥰 Big thanks to the awesome that is repl.it for enabling me to hack in a browser-based IDE! I highly recommend trying it (or similar) so that you can get to the language without worrying about IDE setup etc.

Run the List

# How do I define basic types? (Integers, Floats, Booleans, Strings, Array)
a_int = 1
a_float = 1.0
a_bool = true
a_str = "Elixir"
a_arr = [1, 2, 3]

# How do I concatenate or interpolate strings?
ans = "Forty-two"
meaning = "The answer to the great question.. Of Life, the Universe and Everything.. Is.. #{ans}."

# How do I read from/write to the console?
user_name = IO.gets("What's your name? ") # Trailing space to look nicer in console
IO.puts("Hello, #{user_name}!")
# Note that you get the trailing newline with gets- so you'll likely want to trim
x = String.trim(IO.gets("?"))
x = IO.gets("?") |> String.trim() # Can also pipe - easier on the eyes?

# What are the basic control flow statements? (`if/else`, `foreach`, `switch` etc.) 
# https://elixir-lang.org/getting-started/case-cond-and-if.html
# https://elixir-lang.org/getting-started/recursion.html
if true do
    # ...
else
    # ...
end

unless true do
    # ...
end

for(i = 0; i < sizeof(array); i++) {
  array[i] = array[i] * 2;
}
# Enum module also has map and reduce functions
# https://elixir-lang.org/getting-started/enumerables-and-streams.html#enumerables
Enum.map([1, 2, 3], fn x -> x * 2 end)
# [2, 4, 6]
IO.puts(Enum.reduce([1, 2, 3], 0, fn x, acc -> acc + x * 2 end))
# 12

beats = case play do
    "scissors" -> "paper"
    "paper" -> "rock"
    "rock" -> "lizard"
    "lizard" -> "spock"
    "spock" -> "scissors"
    "scissors" -> "lizard"
    "lizard" -> "paper"
    "paper" -> "spock"
    "spock" -> "rock"
    "rock" -> "scissors"
end

# How do I define functions and methods?
# (Elixir is functional, and doesn't have concept of Objects, Classes and Methods)
defmodule MyModule
    def sum(a, b)
        a + b
    end
end

# How do I control the visibility of those functions and methods?
defp im_a_private_function
    # ...
end

# Can I define anonymous functions?
sum = fn (a, b) -> a + b end
sum = &(&1 + &b) # Shorthand using &
# Note, these need to be called with .
x = sum.(2, 3) # -> 5

# How do exceptions work? How do I handle them?
# https://elixir-lang.org/getting-started/try-catch-and-rescue.html

raise ArgumentError, message: "Argument out of range"

try do
    # ...Code that might raise
rescue
    ArgumentException -> "Caught the ArgumentException"
end

# Define custom exceptions via a Module with defexception
defmodule MyError
    defexception message: "Default message"
end

Now Go Play…

  1. Define a Purpose - What would you like to learn? Try to keep this in the abstract so it will be reusable for exploring similar scenarios. “Languages” over “C#”, “Build Systems” over “TeamCity”, “Cloud” over “Azure”.
  2. Define a Plan - How will you go about exploring? Make a list - or map - to keep you focused. Iterate and refine this map as you learn more about this “type” of problem. For example - anonymous functions are so useful for cleaning up code, so I added a specific item for in to my list above to make sure I found out if it’s possible, and how to do it.
  3. Reflect - How will you solidify your learning? What’s next? I really like to have some kind of physical output here - working code FTW, but - it’s your practice! Do what you like!

Now go practice.

Happy hacking! 🤩

Comments

Popular posts from this blog

GTD: Speak Your Mind, Your Tasks Will Follow

TDD – Getting Started with Test-Driven Development

Tech Day #3 – Inversion of Control (IoC) Containers