Monday, November 30, 2020

Solving the Beverages Prices Refactoring kata (1): composition over inheritance

Introduction.

We are going to show a possible solution to the Beverages Prices Refactoring kata that we developed recently with some people from Women Tech Makers Barcelona with whom I’m doing Codesai’s Practice Program twice a month.

The Beverages Prices Refactoring kata shows an example of inheritance gone astray. The initial code computes the price of the different beverages that are sold in a coffee house. There are some supplements that can be added to those beverages. Each supplement increases the price a bit. Not all combinations of drinks and supplements are possible.

As part of the kata, we are asked to add an optional cinnamon supplement that costs 0.05€ to all our existing catalog of beverages. We are also advised to refactor the initial code a bit before introducing the new feature. Let’s see why.

The initial code.

To get an idea of the kind of problem we are facing, we’ll have a look at the code. There are 8 files: a Beverage interface and 7 classes, one for each type of beverage and one for each allowed combination of beverages and supplements.

Initial code files

A closer look reveals that the initial design uses inheritance and polymorphism to enable the differences in computing the price of each allowed combination of beverage and supplements. This is the inheritance hierarchy:

Class diagram showing the inheritance hierarchy in the initial code

If that diagram is not enough to scare you, have a quick look at the unit tests of the code:

First, we make the change easy[1].

Given the current design, if we decided to add the new feature straight away, we would end up with 14 classes (2 times the initial number of classes). If you think about it, this would happen for each new supplement we decided to add. It would be the same for each new supplement we were required to add: we would be forced to double the number of classes, that means that to add n supplements more would mean multiplying the initial number of classes by 2n.

This exponential growth in the number of classes is a typical symptom of a code smell called Combinatorial Explosion[2]. In this particular case the problem is caused by using inheritance to represent the pricing of beverages plus supplements.

In order to introduce the new cinnamon supplement, we thought sensible to do a bit of preparatory refactoring first in order to remove the Combinatorial Explosion code smell. The recommended refactoring for this code smell is Replace Inheritance with Delegation which leads to a code that uses composition instead of inheritance to avoid the combinatorial explosion. If all the variants[3] (supplements) keep the same interface, we’d be creating an example of the decorator design pattern[4].

The decorator pattern provides an alternative to subclassing for extending behavior. It involves a set of decorator classes that wrap concrete components and keep the same interface that the concrete components. A decorator changes the behavior of a wrapped component by adding new functionality before and/or after delegating to the concrete component.

Applying the decorator pattern design to compute the pricing of beverages plus supplements, the beverages would correspond to the concrete components, tea, coffee and hot chocolate; whereas the supplements, milk and cream would correspond to the decorators.

New design class diagram using the decorator design pattern

We can obtain the behavior for a given combination of supplements and beverage by composing supplements (decorators) with a beverage (base component).

For instance, if we had the following WithMilk decorator for the milk supplement pricing,

we would compose it with a Tea instance to create the behavior that computes the price of a tea with milk:

A nice thing about decorators is that, since they have the same interface as the component they wrap, they are transparent for the client code[6] which never has to know that it’s dealing with a decorator. This allows us to pass them around in place of the wrapped object which makes it possible to compose behaviors using as many decorators as we like. The following example shows how to compose the behavior for computing the price of a coffee with milk and cream[7].

After applying the Replace Inheritance with Delegation refactoring we get to a design that uses composition instead of inheritance to create all the combinations of supplements and beverages. This fixes the Combinatorial Explosion code smell.

You can have a look at the rest of the test after this refactoring in this gist.

Then, we make the easy change.

Once we had the new design based in composition instead of inheritance in place, adding the requested feature is as easy as creating a new decorator that represents the cinnamon supplement pricing:

code after adding the new feature

Remember that using the initial design adding this feature would have involved multiplying by two the number of classes.

What have we gained and lost with this refactoring?

After the refactoring we have a new design that uses the decorator design pattern. This is a flexible alternative design to subclassing for extending behavior that allows us to add behavior dynamically to the objects wrapped by the decorators.

Thanks to this runtime flexibility we managed to fix the Combinatorial Explosion code smell and that made it easier to add the new feature. Now, instead of multiplying the number of cases by two, adding a new supplement only involves adding one new decorator class that represents the new supplement pricing. This new design makes the client code open-closed to the axis of change of adding new supplements.

On the flip side, we have introduced some complexity[8] related to creating the different compositions of decorators and components. At the moment this complexity is being managed by the client code (notice the chains of news in the tests snippets above).

There’s also something else that we have lost in the process. In the initial design only some combinations of beverages and supplements were allowed. This fact was encoded in the initial inheritance hierarchy. Now with our decorators we can dynamically add any possible combination of beverages and supplements.

All in all, we think that the refactoring leaves us in a better spot because we’ll be likely required to add new supplements, and there are usual improvements we can make to the design to isolate the client code from the kind of complexity we have introduced.

Conclusion.

We have shown an example of preparatory refactoring to make easier the addition of a new feature, and learned about the Combinatorial Explosion code smell and how to fix it using the decorator design pattern to get a new design in which we have protected the client code[9] against variations involving new supplements.

In a future post we will show how to encapsulate the creation of the different compositions of decorators and components using builders and/or factories to hide that complexity from client code, and show how we can limit again the allowed combinations that are part of the menu.

Aknowledgements.

I’d like to thank the WTM study group, and especially Inma Navas for solving this kata with me.

Thanks to my Codesai colleagues and Inma Navas for reading the initial drafts and giving me feedback and to Lisa Fotios for her picture.

Notes.

[1] This and the next header come from Kent Beck’s quote:

“For each desired change, make the change easy (warning: this may be hard), then make the easy change”

[2] You can find this code smell described in Bill Wake’s wonderful Refactoring Workbook.

[3] In this context variant means a variation in behavior. For instance, each derived class in a hierarchy is a variant of the base class.

[4] Have a look at the chapter devoted to the decorator design pattern in the great Head First Design Patterns. It’s the most didactic and fun explanation of the pattern I’ve ever found. This kata is heavily inspired in the example used in that chapter to explain the pattern.

[5] We could have also solved this problem composing functions instead of objects, but we wanted to practice with objects in this solution of the kata. That might be an interesting exercise for another practice session.

[6] In this context client code means code that uses objects implementing the interface that both the components and decorators implement, which in the kata would correspond to the Beverage interface.

[7] Also known as a “cortado leche y leche” in Gran Canaria :)

[8] Complexity is most often the price we pay for flexibility. That’s why we should always assess if the gains are worth the price.

[9] Protected variations is another way to refer to the open-closed principle. I particularly prefer that way to refer to this design principle because I think it is expressed in a way that relates less to object orientation. Have a look at Craig Larman’s great article about it: Protected Variation: The Importance of Being Closed

References.

Books I read (January - November 2020)

January
- Waltzing with Bears: Managing Risk on Software Projects, Tom DeMarco, Timothy R. Lister
- An Armenian Sketchbook (Добро вам!), Vasily Grossman
- La flor púrpura, Chimamanda Ngozi Adichie
- El día 3, Miguel Á. Giner Bou, Cristina Durán, Laura Ballester
- A Practical Guide to Testing in DevOps, Katrina Clokie
- La espada de Damocles (Finstere Zeiten: Zur Krise in Griechenland), Petros Márkaris
- The Phoenix Project: A Novel About IT, DevOps, and Helping Your Business Win, Gene Kim, Kevin Behr, George Spafford
- Bartleby, el escribiente (Bartleby, the Scrivener: A Story of Wall Street), Herman Melville
- Señora de rojo sobre fondo gris, Miguel Delibes
- Neverwhere, Neil Gaiman

February
- Personal Kanban: Mapping Work, Navigating Life, Jim Benson, Tonianne DeMaria Barry
- The Art of Peace, Morihei Ueshiba
- Theory of Constraints, Eliyahu M. Goldratt
- Johnny Cash: I See a Darkness, Reinhard Kleist

March
- The Amazing Adventures of Kavalier and Clay, Michael Chabon
- Vampir, Joann Sfar (2nd time)
- Lean Software Development: An Agile Toolkit, Mary Poppendieck, Tom Poppendieck
- Dune, Frank Herbert
- Stoner, John Williams

April
- The Wanderer, Fritz Leiber
- Dune Messiah, Frank Herbert
- Bloodchild, Octavia E. Butler
- Children of Dune, Frank Herbert

May
- Agile Coaching, Rachel Davies, Liz Sedley
- Guía de la buena comunicación, Gerardo Sánchez Lozano
- Go Tell It on the Mountain, James Baldwin.
- Ikigai: The Japanese secret to a long and happy life (audiobook), Héctor García, Francesc Miralles
- Yes to Life: In Spite of Everything, Viktor E. Frankl

June
- Fooled by Randomness: The Hidden Role of Chance in Life and in the Markets Rate (audiobook), Nassim Nicholas Taleb
- A Princess of Mars (audiobook), Edgar Rice Burroughs
- Good Omens: The Nice and Accurate Prophecies of Agnes Nutter, Witch (audiobook), Terry Pratchett, Neil Gaiman
- God Emperor of Dune, Frank Herbert
- Ironmind: Stronger Minds, Stronger Bodies: Stronger Minds, Stronger Bodies, Randall J. Strossen
- Man's Search for Meaning (audiobook), Viktor E. Frankl (2nd time)
- Heretics of Dune, Frank Herbert
- Chapterhouse: Dune, Frank Herbert

July
- Moonglow, Michael Chabon
- Managing Technical Debt: Reducing Friction in Software Development, Philippe Kruchten, Robert Nord, Ipek Ozkaya
- Alone in Berlin (Jeder stirbt für sich allein), Hans Fallada
- Building Maintainable Software, Java Edition, Joost Visser
- The Art of Taking Action: Lessons from Japanese Psychology, Gregg Krech
- The Cat's Table, Michael Ondaatje
- A solas, Silvia Congost
- Starship Troopers, Robert A. Heinlein

August
- Medio sol amarillo (Half of a Yellow Sun), Chimamanda Ngozi Adichie
- The Lady Astronaut of Mars, Mary Robinette Kowal
- How to Be a Stoic: Using Ancient Philosophy to Live a Modern Life (audiobook), Massimo Pigliucci
- Flowers for Algernon, Daniel Keyes
- Una partida de ajedrez, Stefan Zweig
- A Country Doctor's Notebook (Записки юного врача), Mikhail Bulgakov
- Being Wrong: Adventures in the Margin of Error, Kathryn Schulz
- Play It as It Lays, Joan Didion
- Panza de burro, Andrea Abreu
- The Power, Naomi Alderman

September
- I Have No Mouth, and I Must Scream: Stories, "I Have No Mouth, and I Must Scream", “Big Sam Was My Friend”, “Eyes of Dust”, “World of the Myth”, “Lonelyache”, “Delusion for a Dragon Slayer”, and “Pretty Maggie Moneyeyes”, Harlan Ellison
- Functional-Light JavaScript: Pragmatic, Balanced FP in JavaScript, Kyle Simpson
- Professor Frisby's Mostly Adequate Guide to Functional Programming, Brian Lonsdorf
- Enchiridion (audiobook), Epictetus

October
- 10% Happier: How I Tamed the Voice in My Head, Reduced Stress Without Losing My Edge, and Found Self-Help That Actually Works, Dan Harris
- Cat's Cradle, Kurt Vonnegut
- Enchiridion, Epictetus (2nd time)
- To Be Taught, If Fortunate, Becky Chambers
- Sing, Unburied, Sing, Jesmyn Ward
- The 5 Elements of Effective Thinking (audiobook), Edward B. Burger, Michael Starbird
- The Martian Chronicles, Ray Bradbury
- The DevOps Handbook: How to Create World-Class Agility, Reliability, and Security in Technology Organizations, Gene Kim, Jez Humble, Patrick Debois, John Willis
- Overcoming Poor Posture: A Systematic Approach to Refining Your Posture for Health and Performance, Steven Low, Jarlo Ilano
- No Time to Spare: Thinking About What Matters, Ursula K. Le Guin
- El castillo blanco (Beyaz Kale), Orhan Pamuk

November
- Stamboul Train, Graham Greene
- El gatopardo (Il Gattopardo), Giuseppe Tomasi di Lampedusa
- Journal 1935-1944 (Jurnal, 1935-1944), Mihail Sebastian
- Cuando el desierto florece (Splitting the Arrow), Prem Rawat
- Rivers of London, Ben Aaronovitch

Saturday, October 31, 2020

Books I read (January - October 2020)

January
- Waltzing with Bears: Managing Risk on Software Projects, Tom DeMarco, Timothy R. Lister
- An Armenian Sketchbook (Добро вам!), Vasily Grossman
- La flor púrpura, Chimamanda Ngozi Adichie
- El día 3, Miguel Á. Giner Bou, Cristina Durán, Laura Ballester
- A Practical Guide to Testing in DevOps, Katrina Clokie
- La espada de Damocles (Finstere Zeiten: Zur Krise in Griechenland), Petros Márkaris
- The Phoenix Project: A Novel About IT, DevOps, and Helping Your Business Win, Gene Kim, Kevin Behr, George Spafford
- Bartleby, el escribiente (Bartleby, the Scrivener: A Story of Wall Street), Herman Melville
- Señora de rojo sobre fondo gris, Miguel Delibes
- Neverwhere, Neil Gaiman

February
- Personal Kanban: Mapping Work, Navigating Life, Jim Benson, Tonianne DeMaria Barry
- The Art of Peace, Morihei Ueshiba
- Theory of Constraints, Eliyahu M. Goldratt
- Johnny Cash: I See a Darkness, Reinhard Kleist

March
- The Amazing Adventures of Kavalier and Clay, Michael Chabon
- Vampir, Joann Sfar (2nd time)
- Lean Software Development: An Agile Toolkit, Mary Poppendieck, Tom Poppendieck
- Dune, Frank Herbert
- Stoner, John Williams

April
- The Wanderer, Fritz Leiber
- Dune Messiah, Frank Herbert
- Bloodchild, Octavia E. Butler
- Children of Dune, Frank Herbert

May
- Agile Coaching, Rachel Davies, Liz Sedley
- Guía de la buena comunicación, Gerardo Sánchez Lozano
- Go Tell It on the Mountain, James Baldwin.
- Ikigai: The Japanese secret to a long and happy life (audiobook), Héctor García, Francesc Miralles
- Yes to Life: In Spite of Everything, Viktor E. Frankl

June
- Fooled by Randomness: The Hidden Role of Chance in Life and in the Markets Rate (audiobook), Nassim Nicholas Taleb
- A Princess of Mars (audiobook), Edgar Rice Burroughs
- Good Omens: The Nice and Accurate Prophecies of Agnes Nutter, Witch (audiobook), Terry Pratchett, Neil Gaiman
- God Emperor of Dune, Frank Herbert
- Ironmind: Stronger Minds, Stronger Bodies: Stronger Minds, Stronger Bodies, Randall J. Strossen
- Man's Search for Meaning (audiobook), Viktor E. Frankl (2nd time)
- Heretics of Dune, Frank Herbert
- Chapterhouse: Dune, Frank Herbert

July
- Moonglow, Michael Chabon
- Managing Technical Debt: Reducing Friction in Software Development, Philippe Kruchten, Robert Nord, Ipek Ozkaya
- Alone in Berlin (Jeder stirbt für sich allein), Hans Fallada
- Building Maintainable Software, Java Edition, Joost Visser
- The Art of Taking Action: Lessons from Japanese Psychology, Gregg Krech
- The Cat's Table, Michael Ondaatje
- A solas, Silvia Congost
- Starship Troopers, Robert A. Heinlein

August
- Medio sol amarillo (Half of a Yellow Sun), Chimamanda Ngozi Adichie
- The Lady Astronaut of Mars, Mary Robinette Kowal
- How to Be a Stoic: Using Ancient Philosophy to Live a Modern Life (audiobook), Massimo Pigliucci
- Flowers for Algernon, Daniel Keyes
- Una partida de ajedrez, Stefan Zweig
- A Country Doctor's Notebook (Записки юного врача), Mikhail Bulgakov
- Being Wrong: Adventures in the Margin of Error, Kathryn Schulz
- Play It as It Lays, Joan Didion
- Panza de burro, Andrea Abreu
- The Power, Naomi Alderman

September
- I Have No Mouth, and I Must Scream: Stories, "I Have No Mouth, and I Must Scream", “Big Sam Was My Friend”, “Eyes of Dust”, “World of the Myth”, “Lonelyache”, “Delusion for a Dragon Slayer”, and “Pretty Maggie Moneyeyes”, Harlan Ellison
- Functional-Light JavaScript: Pragmatic, Balanced FP in JavaScript, Kyle Simpson
- Professor Frisby's Mostly Adequate Guide to Functional Programming, Brian Lonsdorf
- Enchiridion (audiobook), Epictetus

October
- 10% Happier: How I Tamed the Voice in My Head, Reduced Stress Without Losing My Edge, and Found Self-Help That Actually Works, Dan Harris
- Cat's Cradle, Kurt Vonnegut
- Enchiridion, Epictetus (2nd time)
- To Be Taught, If Fortunate, Becky Chambers
- Sing, Unburied, Sing, Jesmyn Ward
- The 5 Elements of Effective Thinking (audiobook), Edward B. Burger, Michael Starbird
- The Martian Chronicles, Ray Bradbury
- The DevOps Handbook: How to Create World-Class Agility, Reliability, and Security in Technology Organizations, Gene Kim, Jez Humble, Patrick Debois, John Willis
- Overcoming Poor Posture: A Systematic Approach to Refining Your Posture for Health and Performance, Steven Low, Jarlo Ilano
- No Time to Spare: Thinking About What Matters, Ursula K. Le Guin
- El castillo blanco (Beyaz Kale), Orhan Pamuk

Sunday, October 18, 2020

Sleeping is not the best option

Introduction.

Some time ago we were developing a code that stored some data with a given TTL. We wanted to check not only that the data was stored correctly but also that it expired after the given TTL. This is an example of testing asynchronous code.

When testing asynchronous code we need to carefully coordinate the test with the system it is testing to avoid running the assertion before the tested action has completed[1]. For example, the following test will always fail because the assertion in line 30 is checked before the data has expired:

In this case the test always fails but in other cases it might be worse, failing intermittently when the system is working, or passing when the system is broken. We need to make the test wait to give the action we are testing time to complete successfully and fail if this doesn’t happen within a given timeout period.

Sleeping is not the best option.

This is an improved version of the previous test in which we are making the test code wait before the checking that the data has expired to give the code under test time to run:

The problem with the simple sleeping approach is that in some runs the timeout might be enough for the data to expire but in other runs it might not, so the test will fail intermittently; it becomes a flickering test. Flickering tests are confusing because when they fail, we don’t know whether it’s due to a real bug, or it is just a false positive. If the failure is relatively common, the team might start ignoring those tests which can mask real defects and completely destroy the value of having automated tests.

Since the intermittent failures happen because the timeout is too close to the time the behavior we are testing takes to run, many teams decide to reduce the frequency of those failures by increasing the time each test sleeps before checking that the action under test was successful. This is not practical because it soon leads to test suites that take too long to run.

Alternative approaches.

If we are able to detect success sooner, succeeding tests will provide rapid feedback, and we only have to wait for failing tests to timeout. This is a much better approach than waiting the same amount of time for each test regardless it fails or succeeds.

There are two main strategies to detect success sooner: capturing notifications[2] and polling for changes.

In the case we are using as an example, polling was the only option because redis didn’t send any monitoring events we could listen to.

Polling for changes.

To detect success as soon as possible, we’re going to probe several times separated by a time interval which will be shorter than the previous timeout. If the result of a probe is what we expect the test pass, if the result we expect is not there yet, we sleep a bit and retry. If after several retries, the expected value is not there, the test will fail.

Have a look at the checkThatDataHasExpired method in the following code:

By polling for changes we avoid always waiting the maximum amount of time. Only in the worst case scenario, when consuming all the retries without detecting success, we’ll wait as much as in the just sleeping approach that used a fixed timeout.

Extracting a helper.

Scattering ad hoc low level code that polls and probes like the one in checkThatDataHasExpired throughout your tests not only make them difficult to understand, but also is a very bad case of duplication. So we extracted it to a helper so we could reuse it in different situations.

What varies from one application of this approach to another are the probe, the check, the number of probes before failing and the time between probes, everything else we extracted to the following helper[3]:

This is how the previous tests would look after using the helper:

Notice that we’re passing the probe, the check, the number of probes and the sleep time between probes to the AsyncTestHelpers::assertWithPolling function.

Conclusions.

We showed an example in Php of an approach to test asynchronous code described by Steve Freeman and Nat Pryce in their Growing Object-Oriented Software, Guided by Tests book. This approach avoids flickering test and produces much faster test suites than using a fixed timeout. We also showed how we abstracted this approach by extracting a helper function that we are reusing in our code.

We hope you’ve found this approach interesting. If you want to learn more about this and several other techniques to effectively test asynchronous code, have a look at the wonderful Growing Object-Oriented Software, Guided by Tests book[4].

Acknowledgements.

Thanks to my Codesai colleagues for reading the initial drafts and giving me feedback and to Chrisy Totty for the lovely cat picture.

Notes.

[1] This is a nice example of Connascence of Timing (CoT). CoT happens when when the timing of the execution of multiple components is important. In this case the action being tested must run before the assertion that checks its observable effects. That's the coordination we talk about. Check our post about Connascence to learn more about this interesting topic.
[2] In the capturing notifications strategy the test code "observes the system by listening for events that the system sends out. An event-based assertion waits for an event by blocking on a monitor until gets notified or times out", (from Growing Object-Oriented Software, Guided by Tests book).
Some time ago we developed some helpers using the capturing notifications strategy to test asynchronous ClojureScript code that was using core.async channels. Have a look at, for instance, the expect-async-message assertion helper in which we use core.async/alts! and core.async/timeout to implement this behaviour. The core.async/alts! function selects the first channel that responds. If that channel is the one the test code was observing we assert that the received message is what we expected. If the channel that responds first is the one generated by core.async/timeout we fail the test. We mentioned these async-test-tools in previous post: Testing Om components with cljs-react-test.
[3] Have a look at the testing asynchronous systems examples in the GOOS Code examples repository for a more object-oriented implementation of helper for the polling for changes strategy, and also examples of the capturing notifications strategy.
[4] Chapter 27, Testing Asynchronous code, contains a great explanation of the two main strategies to test asynchronous code effectively: capturing notifications and polling for changes.

References.

Thursday, October 1, 2020

Books I read (January - September 2020)

January
- Waltzing with Bears: Managing Risk on Software Projects, Tom DeMarco, Timothy R. Lister
- An Armenian Sketchbook (Добро вам!), Vasily Grossman
- La flor púrpura, Chimamanda Ngozi Adichie
- El día 3, Miguel Á. Giner Bou, Cristina Durán, Laura Ballester
- A Practical Guide to Testing in DevOps, Katrina Clokie
- La espada de Damocles (Finstere Zeiten: Zur Krise in Griechenland), Petros Márkaris
- The Phoenix Project: A Novel About IT, DevOps, and Helping Your Business Win, Gene Kim, Kevin Behr, George Spafford
- Bartleby, el escribiente (Bartleby, the Scrivener: A Story of Wall Street), Herman Melville
- Señora de rojo sobre fondo gris, Miguel Delibes
- Neverwhere, Neil Gaiman

February
- Personal Kanban: Mapping Work, Navigating Life, Jim Benson, Tonianne DeMaria Barry
- The Art of Peace, Morihei Ueshiba
- Theory of Constraints, Eliyahu M. Goldratt
- Johnny Cash: I See a Darkness, Reinhard Kleist

March
- The Amazing Adventures of Kavalier and Clay, Michael Chabon
- Vampir, Joann Sfar (2nd time)
- Lean Software Development: An Agile Toolkit, Mary Poppendieck, Tom Poppendieck
- Dune, Frank Herbert
- Stoner, John Williams

April
- The Wanderer, Fritz Leiber
- Dune Messiah, Frank Herbert
- Bloodchild, Octavia E. Butler
- Children of Dune, Frank Herbert

May
- Agile Coaching, Rachel Davies, Liz Sedley
- Guía de la buena comunicación, Gerardo Sánchez Lozano
- Go Tell It on the Mountain, James Baldwin.
- Ikigai: The Japanese secret to a long and happy life (audiobook), Héctor García, Francesc Miralles
- Yes to Life: In Spite of Everything, Viktor E. Frankl

June
- Fooled by Randomness: The Hidden Role of Chance in Life and in the Markets Rate (audiobook), Nassim Nicholas Taleb
- A Princess of Mars (audiobook), Edgar Rice Burroughs
- Good Omens: The Nice and Accurate Prophecies of Agnes Nutter, Witch (audiobook), Terry Pratchett, Neil Gaiman
- God Emperor of Dune, Frank Herbert
- Ironmind: Stronger Minds, Stronger Bodies: Stronger Minds, Stronger Bodies, Randall J. Strossen
- Man's Search for Meaning (audiobook), Viktor E. Frankl (2nd time)
- Heretics of Dune, Frank Herbert
- Chapterhouse: Dune, Frank Herbert

July
- Moonglow, Michael Chabon
- Managing Technical Debt: Reducing Friction in Software Development, Philippe Kruchten, Robert Nord, Ipek Ozkaya
- Alone in Berlin (Jeder stirbt für sich allein), Hans Fallada
- Building Maintainable Software, Java Edition, Joost Visser
- The Art of Taking Action: Lessons from Japanese Psychology, Gregg Krech
- The Cat's Table, Michael Ondaatje
- A solas, Silvia Congost
- Starship Troopers, Robert A. Heinlein

August
- Medio sol amarillo (Half of a Yellow Sun), Chimamanda Ngozi Adichie
- The Lady Astronaut of Mars, Mary Robinette Kowal
- How to Be a Stoic: Using Ancient Philosophy to Live a Modern Life (audiobook), Massimo Pigliucci
- Flowers for Algernon, Daniel Keyes
- Una partida de ajedrez, Stefan Zweig
- A Country Doctor's Notebook (Записки юного врача), Mikhail Bulgakov
- Being Wrong: Adventures in the Margin of Error, Kathryn Schulz
- Play It as It Lays, Joan Didion
- Panza de burro, Andrea Abreu
- The Power, Naomi Alderman

September
- I Have No Mouth, and I Must Scream: Stories, "I Have No Mouth, and I Must Scream", “Big Sam Was My Friend”, “Eyes of Dust”, “World of the Myth”, “Lonelyache”, “Delusion for a Dragon Slayer”, and “Pretty Maggie Moneyeyes”, Harlan Ellison
- Functional-Light JavaScript: Pragmatic, Balanced FP in JavaScript, Kyle Simpson
- Professor Frisby's Mostly Adequate Guide to Functional Programming, Brian Lonsdorf
- Enchiridion (audiobook), Epictetus