If you're interested in keeping up with my writing, you can subscribe to my newsletter 👇, find me as germsvel on twitter, or follow my RSS feed.

Want my latest thoughts, posts, and projects in your inbox?

    I will never send you spam. Unsubscribe any time.

    Introducing PhoenixTest

    PhoenixTest provides a unified way of writing feature tests -- regardless of whether you're testing LiveView pages or static pages.

    Don’t silo your team

    I have worked in teams where a product manager assigns tasks to developers. On paper, that works. And it's likely done in the name of parallelizing work -- "look at all the projects we're working on at once!" But in my experience, that top-down approach to assigning work has a huge downside: it discourages team collaboration.

    The Phoenix testing pyramid

    A look at the tranditional testing pyramid with a Phoenix twist. This is a good guideline when adding tests to Phoenix projects.

    Prefer LiveView's assert_redirect over assert_redirected

    Someone in my Testing LiveView course recently asked me, "When would you use assert_redirected instead of assert_redirect?" Just by looking at the helpers, you might think we want to use assert_redirected. But I always prefer using assert_redirect. Here's why.

    Build your own lazy operation evaluator in Elixir

    I've always been fascinated by how Elixir's Stream module handles lazy operations by storing the operation data in a struct. 🤯 It's so simple but so brilliant! So, I wanted to see what it'd be like to write a simple implementation of a lazy math evaluator.

    Phoenix 1.7's verified routes

    Phoenix 1.7 is dropping path helpers in favor of a new concept called verified routes. Let's see how it handles typos, missing paths, arguments, and query params.

    Phoenix 1.7 is View-less! 😱

    Phoenix 1.7 is dropping Phoenix.View, but it's for a good reason! Controllers and LiveViews will now render function components. And the aim is to collocate templates next to the controller that renders them!

    Adding `gh` to my pull request workflow

    In the past, I used `hub` to create GitHub pull requests. Recently, I decided to replace `hub` with GitHub's newer, official CLI (gh). At first, I found `gh` to be too verbose. But soon enough, I found the correct commands and flags to fine-tune my workflow. Here are some of my favorite commands and flags to deal with PRs.

    A short introduction to BDD

    When I first learned BDD (behavior-driven development), I saw a graph in The RSpec Book that helped me understand the flow of BDD. I don’t have that book anymore, but I still remember what the graph looked like, and it’s so helpful! Let me show you what I remember.

    They own the problem. You own the solution.

    The title of this post is a quote from The Mom Test, a book that teaches the art of having useful conversations with customers so they won't lie to us about that business idea we're eager to explore.

    Is the test LiveView immutable or not?

    Someone from my Testing LiveView course recently asked me about the immutability of the `view` we get from `live/2` in LiveView tests. It's not the first time someone's asked me that question, so I wanted to try to clarify things a bit.

    Minimize context loss when opening a Pull Request

    You're working in a codebase. You stumble upon something you'd like to change. The code change will only take 2 minutes. Do you make the change and open a Pull Request? The answer likely depends on how costly it is to open that Pull Request. And that cost is commensurate with the loss of context of our current work.

    Reduce the friction of executing a test

    To practice test-driven development (TDD), I recommend developers reduce the friction involved in running an individual test. Since TDD uses test failures as guidance for implementation, it is most helpful when we have a tight feedback loop. But if running tests takes a long time, we don't run them as frequently, and we miss out on the tests' feedback.

    Ecto's uniqueness constraint vs Rails' uniqueness validation

    I really like how closely Ecto integrates with our database. That was a surprising difference when I first came from Rails. Ecto’s constraints are a great example of that. Like Rails, Ecto has validations. But unlike Rails, Ecto also has constraints. Validating uniqueness is the example that most easily comes to my mind.

    TDD changes code design from invention to discovery

    I was reading the paper Mock Roles, not Objects, and there's a description of TDD that captures an important concept I haven't been able to put into words before: TDD changes code design from invention to discovery.

    Mocking External Dependencies in Elixir

    A reader recently asked me about mocking external dependencies in Elixir. So, I wanted to discuss two popular mocking libraries and how to mock without a library (and which option I like best).

    Dependency Inversion with Elixir Protocols

    I've always liked the Dependency Inversion Principle (DIP). Once understood, it helps us decouple code in surprising ways. Let's take a look at how Elixir protocols decouple code through DIP.

    Using mix aliases to improve your workflow

    When developers onboard new projects, we are uniquely positioned to help improve the onboarding experience for future developers. So, when I join a new project, I relish the opportunity to clarify and simplify setup instructions.

    elixir lunch is now elixir social

    elixir lunch is now elixir social. I renamed it because very few people brought lunch 😅. It seems most weren't interested in that part. But they were interested in hanging out with other Elixirists. So, I figured I'd roll with the punches.

    Testing Singleton Processes with Dependency Injection

    Named singleton processes are wonderful for Elixir applications, but they often make it hard to test their behavior. Since singletons are started as part of the supervision tree, they become a globally shared resource for our tests. And that can lead to intermittently failing tests due to race conditions.

    Starting elixir lunch

    I've been thinking of starting something called "elixir lunch" for some time – a low-key lunch gathering of Elixirists. Now, let's make it happen.

    Taking LiveView's JS commands for a spin

    I'm excited about LiveView's JS commands (introduced in 0.17.0) because they allow us to express JavaScript within our LiveView code. And that makes it easier to create certain types of interactions.

    BDD and just-in-time development

    Behavior-driven development (BDD) has a powerful by-product – building just what we need to support our customers. Nothing more.

    What is Elixir? For my Ruby friends.

    Many Ruby friends think of Elixir as just a functional Ruby. So they see it, maybe try it, and walk away. But that's just the surface. Beneath the surface, Elixir brings a runtime system that we can design and control to build applications that heal themselves.

    CSS Selectors for Tests

    Testing web pages often requires targeting elements with CSS selectors. But which CSS selectors should we use? Are some better than others? I think so.

    Deadlines vs Appetite

    One of the concepts I found most interesting about Shape Up is the concept of appetite. Like a deadline, appetite talks about the amount of time we're going to spend on a feature or project. But the process is wonderfully reversed.

    Culture is a 50-day moving average

    In a recent interview, Jason Fried said that culture is a 50-day moving average of our actions. That is incredibly freeing and compelling.

    Using has_element?/3 for better LiveViewTest assertions

    It's tempting to write `LiveViewTest` assertions that specify too much of our HTML. But that couples our tests to the implementation specifics. There's a better way: the `has_element?/3` helper can help us be specific without adding coupling.

    A minimalist LiveView testing guide

    Let's apply Sandi Metz's minimalist unit testing guide to LiveView. There are so many parallels and our tests benefit from Sandi's wisdom.

    Break apart your features into full-stack slices

    Our communication practices can be very disrupting. Remote work has taught me to be more considerate of how I communicate with others. We should treat other people's time as we like ours to be treated.

    Pay the cost up front. Don't distribute it to others.

    Our communication practices can be very disrupting. Remote work has taught me to be more considerate of how I communicate with others. We should treat other people's time as we like ours to be treated.

    On Quitting Vim

    Vim has a reputation for being hard to quit. But it turns out there are so many ways to get out of it — it's like vim wants you to quit. Let's look at a few.

    Breaking Out of Ecto Schemas

    With Ecto, 🎶 you _can_ always get what you want. And if you try sometimes, well, you might find, you can _select_ want you need 🎶.

    Splitting a Commit

    My workflow usually involves squashing many commits into a single one. But sometimes, the workflow calls for the opposite action -- splitting a single commit into many. This is how I do it.

    5 Tips for More Helpful Code Reviews

    Having your code reviewed can be daunting. But it can also be very helpful. As reviewers, we can make the difference. Here are five tips to make your code reviews more helpful to the author.

    Faking External Services in Tests with Adapters

    When faking external services in tests, start with something simple. I like having a public interface to adapters and having an in-memory adapter for tests. Let me show you an example.

    Finding the Time to Refactor

    Many people ask, "How do I find time to refactor?" I think the question itself betrays a misunderstanding of refactoring. Let me tell you when I refactor.

    Let's Not Misuse Refactoring

    Refactoring has a specific meaning. When we misuse the word, we lose the ability to communicate an important concept. Let's revisit what refactoring is and what it is not.

    Back to basics: psql

    The right tool for the right job, right? Well let me introduce you to psql.

    Is Elixir a scripting language?

    Elixir is known for being a language made for building distributed applications that scale, are massively concurrent, and have self-healing properties. But is Elixir good enough for the mundane scripts of this world?

    Long-lived processes in Elixir

    Long-lived processes are everywhere in Elixir. Let’s look at why they’re needed and how to create them!

    How to organize your functional code

    When coming from object-oriented languages, I often hear people ask the question, “How do I organize my code? Modules are just bags of functions!”. That is a question I asked myself as well, but after using Elixir and Elm for a while, I have noticed that there is a principle of organization that I keep using and that I see in the wild. I like to think of it as the principle of attraction.

    An introduction to concurrency in Elixir

    Concurrency is a first-class citizen in the Elixir platform. The concurrency model is that of isolated, independent processes that share no memory and communicate via asynchronous message passing. In other words, a process can run concurrently without concern of others, and processes communicate with each other only via send-and-forget messages.

    Tests as Counselors of Design

    One of the benefits of tests is that they are the first piece of code that will interact with our application. As such, they can offer valuable insights into the application's complexity.

    Elixir simple_one_for_one Supervisors

    Supervision trees are awesome. For a while I was a bit confused as to how to use the simple_one_for_one supervision strategy. Let’s look at it step by step by creating a simple bank account from which we can deposit and withdraw money.

    Tests as Tools for Understanding

    When working on a feature, I often find pieces of code that I have not seen before. In order to better understand the class or method, I like to use tests as documentation and as a way to explore the code's functionality.