• Safe and reliable side effects using the outbox pattern

    The outbox pattern allows you to safely combine ACID transactions with external side effects. This article describes how it works.
  • Building Aggregates in Elixir and PostgreSQL

    This article explains the concept of a domain invariant, explains the aggregate's role in protecting the invariants, covers possible implementations of aggregates in Elixir, discusses differences between optimistic and pessimistic version control and the importance of domain knowledge in deciding how to design a solution.
  • Absinthe middleware for tagged union input types

    While GraphQL and Absinthe don't support union input types yet, you can simulate them by using a middleware to add automatic validations to your schema.
  • Modular design patterns: Read models for background jobs

    This posts describes a useful technique for dealing with backgroud jobs. By using separate data models and encapsulating entire logic, we can make the code less coupled and easier to maintain.
  • How to use Ecto's Repo.stream/1 to process large amounts of data

    This short post shows a really easy way to process large-ish (max few hours of processing) datasets using Ecto's Repo.stream/1.
  • A guide to event handling in Elixir

    Events are easy to grasp as a concept for integrating different parts of the system. But implementating event handling can be much tricker in practice. Choosing a wrong way can be a serious mistake. This article shows you six different ways of event handling and guides you how to choose the proper one for your needs.
  • 11 benefits of deploying code every day

    Learn how deploying code every day can improve your system and your team efficiency. A short list - one minute read.
  • Domain-driven error handling. Don't handle errors - prevent them.

    Success and failure are not binary. The post describes four techniques that improve error handling in your system by embracing the complexity of the real world. Use domain-driven approach and design software with failures in mind.
  • How to improve software delivery - advice from "Accelerate" by Nicole Forsgren

    Six learnings and actionable advice from “Accelerate” by Nicole Forsgren. Key takeway - you can use technical practices to improve organisational performance.
  • Why and how to avoid 'type' fields on your domain models

    If you see a "type" field on your domain model, you can probably split that model into multiple contexts and use composition to make the design easier to understand and change in the future. This post describes a practical example of such decomposition.
  • Modular software design - 10 common mistakes

    Good modularity is one of the goals of software design. Here are 10 common things that increase coupling and might hurt modularity.
  • Is code review harmful?

    Code review is a great tool. But when it's mandatory, it can hide some problems. In this post, I explore how we can improve the team effectiveness by fixing the underlying problems and using code review for collaboration, not verification.
  • How to get less feedback

    How to prevent people from sharing their feedback? What would make people less honest and open? By inversion thinking, avoiding those things is the best way to encourage more feedback in your team or organisation.
  • How to recognize good boundaries in modular software design

    Is the boundary for your module right? Is the module coherent and loosely coupled with the rest of the system? Will it be easy to change? Here are some things to look at to assess your design.
  • Become a pi-shaped developer

    Being in the top 1% of any field is extremely hard. But you can be really successful if you are in the top 10% of two or three different areas.
  • Decomposing domain models based on lifecycles

    Good decomposition is one of the most important parts of software design. In this post, I describe a practical and real-life example of decomposition by following the lifecycle of a domain entity.
  • The benefits of modular software design

    Modular software design can be briefly described as splitting a software system into multiple well-isolated, autonomous parts (modules) that are loosely coupled with each other.

  • The costs of modular software design

    Modular software design can be briefly described as splitting a software system into multiple well-isolated, autonomous parts (modules) that are loosely coupled with each other.

  • Enabling constraints in software development

    In my work, I draw a lot of inspiration from Systems Thinking and Complexity Theory. In this post, I’d like to describe a concept of enabling constraints and how to use them in software development.

  • A month of remote work - lessons learned

    At the time of writing this, the coronavirus pandemic is forcing many us to work from home. After a month of working fully remotely, I think it’s a good time to write down some observations and lessons learned during this time.

  • Defaults, not rules. Should your team use Scrum?

    When we want to change our behaviour, we have at least two ways.

  • 'Unit vs integration tests?' is a wrong question!

    We argue a lot about how to test code. Some are in favour of typical testing pyramid. Some claim that unit tests don’t give you enough confidence, so you should mainly write integration tests. Neither answer is correct. The problem is that we shouldn’t even look for one answer in the first place.

  • Events and different kinds of coupling

    There’s a common misconception that events reduce coupling. Sure, this statement can be true. But it’s extremely inaccurate.

  • The big ideas in software development

    If you look at the history of Computer Science, you can see that there are few big ideas that keep emerging. Is there a lesson that we may learn from this?

  • On the guarantees of Phoenix Presence

    Phoenix Presence is a feature that allows you to track processes across the cluster. The most common use case is tracking which users are online in a distributed environment without relying on a single source of truth.

  • Handling failures in Elixir and Phoenix

    Fault tolerance is one of the most often mentioned reasons for using Elixir. And this is true — being fault tolerant was probably the most important driving force behind Erlang.

  • Forget CRUD, let's focus on the meaning

    Lately, I’ve been trying to use Command Query Separation (CQS) technique for a few days. In case you haven’t heard of this, CQS, basically, says that you can have two types of operations that clients can run in your system: commands and queries. There are two rules:

  • What’s wrong with a global User module?

    This post is inspired by a code review I’ve done at work today. We generally try to build our applications as a set of loosely coupled components, so when I saw a User schema in the root project directory, it got me thinking about its impact on the overall architecture of the system.

  • On restoring process state in Elixir

    When dealing with failures in Elixir (or Erlang), it’s common to use OTP supervisors and restarts instead of coding defensively and try to predict all that may go wrong. But at the beggining, one might ask a question: “Ok, restarting the process is cool, but what about its state? I don’t want to loose it!” And it’s a perfectly valid question.