<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Nathan Power</title><description>The portfolio and blog of Nathan Power, a frontend engineer from Waterford, Ireland.</description><link>https://nathanpower.dev</link><item><title>Working with react-query</title><link>https://nathanpower.dev/posts/working-with-react-query</link><guid isPermaLink="true">https://nathanpower.dev/posts/working-with-react-query</guid><description>Lessons learned while working with the react-query library from Tanstack</description><pubDate>Thu, 10 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;pre&gt;&lt;code&gt;import { useAxios } from &apos;@myorg/authenticated-axios-wrapper&apos;;
import { useQuery } from &apos;@tanstack/react-query&apos;;

const useFlorpsQuery = ({ queryParams }: { queryParams: FlorpQueryParams }) =&amp;gt; {
  const client = useAxios();
  const { openErrorModal, closeErrorModal } = useErrorModal();
  return useQuery({
    queryKey: [&apos;get-florps&apos;, queryParams],
    queryFn: () =&amp;gt; client.get&amp;lt;FlorpsListSchema&amp;gt;(FLORPS_API_URL, { params: queryParams })
  });
};

const FlorpsList = () =&amp;gt; {
  const { data: florps, isLoading } = useFlorpsQuery({ queryParams: { limit: 10, offset: 0 } });

  if (isLoading || !florps) {
    return &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;;
  }

  return (
    &amp;lt;ul&amp;gt;
      {florps.map(({ name }) =&amp;gt; (
        &amp;lt;li key={name}&amp;gt;{name}&amp;lt;/li&amp;gt;
      ))}
    &amp;lt;/ul&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&apos;ve been a fan of the &lt;code&gt;tanstack/react-query&lt;/code&gt; library for a few years, during which time I&apos;ve occasionally noticed that people new to the library (or new to frontend development in general) question the value it brings. I thought it might be useful to outline some of my thoughts on that subject, as well as some potentially useful learnings acquired since I began using it.&lt;/p&gt;
&lt;h2&gt;Why do we need this thing anyway?&lt;/h2&gt;
&lt;p&gt;Much like React itself, the value TanStack Query brings is most keenly felt if you have ever had to hand-roll solutions in the same problem space. Most people who had to maintain large/complex Query event-driven UIs, or indeed codebases using the 2-way data-binding approaches used by frameworks like Knockout or Angular in the early 2010s, tended to appreciate the one-way data-flow and declarative nature of React when it was released. I had a similar experience reading the first paragraph of the docs for &lt;code&gt;tanstack/query&lt;/code&gt; (then &lt;code&gt;react-query&lt;/code&gt; ) because of an experience I had had some years before implementing a data-fetching layer for an application.&lt;/p&gt;
&lt;p&gt;In 2018 or so, I was tasked with implementing an infinite-loading style UI for a list-view in a progressive web app, targeting mobile browsers. Initially I had a pretty standard pagination approach, over a virtualised list. The first page would load initially, and further pages were loaded as they scrolled into view. The page size was not fixed, but rather calculated based on the scroll distance. Items were cached (into a &lt;code&gt;redux&lt;/code&gt; store) once loaded so that you would see previously loaded items when you scrolled back up, but the cache also invalidated after some time, triggering a refresh of the current page.&lt;/p&gt;
&lt;p&gt;This was manageable enough, complexity-wise, until we introduced the ability to sort by different attributes of the list items. Because the cache was items-per-page, and pages were associated with scroll windows, now we needed a separate cache for each sort value.&lt;/p&gt;
&lt;p&gt;Along with this, we also found that de-duplication of requests and limiting requests in flight in general was necessary for the more enthusiastic scrollers out there - it became more of a maintenance burden than we would have liked. Fast-forward a few years, I am on a different project, pondering another data-layer, and I come across this library and the following claim:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;React Query is often described as the missing data-fetching library for React, but in more technical terms, it makes &lt;strong&gt;fetching, caching, synchronizing and updating server state&lt;/strong&gt; in your React applications a breeze.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This paragraph was enough for me to hack together a quick proof-of-concept, and I was pretty convinced. It has since became the de-facto way to handle client-side data requirements in the organisation.&lt;/p&gt;
&lt;h2&gt;So what does it do?&lt;/h2&gt;
&lt;p&gt;TanStack Query is responsible for keeping the client-side representation of server state up to date, and triggering re-renders of the React tree when it updates. This server data is kept in memory in a key-value form referred to as the &lt;code&gt;query-cache&lt;/code&gt;. This means that the developer can offload the following concerns to the library (from the &lt;a href=&quot;https://tanstack.com/query/latest/docs/framework/react/overview&quot;&gt;official docs&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Caching... (possibly the hardest thing to do in programming)&lt;/li&gt;
&lt;li&gt;De-duping multiple requests for the same data into a single request&lt;/li&gt;
&lt;li&gt;Updating &quot;out of date&quot; data in the background&lt;/li&gt;
&lt;li&gt;Knowing when data is &quot;out of date&quot;&lt;/li&gt;
&lt;li&gt;Reflecting updates to data as quickly as possible&lt;/li&gt;
&lt;li&gt;Performance optimisations like pagination and lazy loading data&lt;/li&gt;
&lt;li&gt;Managing memory and garbage collection of server state&lt;/li&gt;
&lt;li&gt;Memoizing query results with structural sharing&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What does it not do?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Actual network requests (bring your own HTTP client)&lt;/li&gt;
&lt;li&gt;Synchronous state updates&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Recommended usage patterns&lt;/h2&gt;
&lt;p&gt;What follows is some opinionated advice based on using the library for a number of use-cases over 2 years or so.&lt;/p&gt;
&lt;h3&gt;Cache the data you use, not the data you fetch&lt;/h3&gt;
&lt;p&gt;If you have expensive business logic that must transform the server response before rendering to the UI, it&apos;s best that this happens between the fetch and the cache layer, otherwise it will run every time your data is returned from the cache aka on every render that reads it. This can significantly improve performance and responsiveness of your interfaces. It&apos;s worth noting here that the &lt;code&gt;select&lt;/code&gt; function runs &lt;em&gt;post-cache&lt;/em&gt; - so put this expensive logic inside your &lt;code&gt;queryFn&lt;/code&gt;. On a related note: nothing says that you only have to make one request inside a &lt;code&gt;queryFn&lt;/code&gt;. You are free to make many requests, and combine them as you see fit, before resolving the promise returned.&lt;/p&gt;
&lt;h3&gt;Wrap useQuery / useMutation in a custom function per resource&lt;/h3&gt;
&lt;p&gt;Lets say you have an endpoint that returns &lt;code&gt;florps&lt;/code&gt;. A good level of abstraction to aim for is &lt;code&gt;useFlorpsQuery&lt;/code&gt;. We have found that trying to make functions more generic than this is not worth the hassle involved with keeping things type-safe, and it inevitably ends up having too many options exposed, making it harder to change and harder to maintain.&lt;/p&gt;
&lt;h3&gt;Use the official development tooling&lt;/h3&gt;
&lt;p&gt;Two very useful tools are available, the &lt;code&gt;ReactQueryDevTools&lt;/code&gt; component, which overlays some floating UI to give visual insights into your query keys and the state of your cache, and an ESLint plugin which will keep devs to best practices and avoid footguns (like unstable object references or excessive re-renders).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tanstack.com/query/v5/docs/framework/react/devtools&quot;&gt;React Query DevTools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tanstack.com/query/latest/docs/eslint/eslint-plugin-query&quot;&gt;ESLint Plugin Query&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Rely on inference, rather than passing generic type arguments&lt;/h3&gt;
&lt;p&gt;Passing generic types for &lt;code&gt;useQuery&lt;/code&gt; or &lt;code&gt;useMutation&lt;/code&gt; is very easy to get wrong, and is usually not required in order for the return type to be correctly typed, which is &lt;em&gt;really&lt;/em&gt; what you want after all. The trick is to strongly type the return of &lt;code&gt;queryFn&lt;/code&gt; or &lt;code&gt;mutationFn&lt;/code&gt;, and all types should flow correctly from there. See the &lt;a href=&quot;https://tkdodo.eu/blog/react-query-and-type-script#type-inference&quot;&gt;excellent article&lt;/a&gt; from Dominik Dorfmeister on this subject.&lt;/p&gt;
&lt;h3&gt;Become familiar with the opinionated defaults&lt;/h3&gt;
&lt;p&gt;It&apos;s really worth taking the time to learn how the &lt;a href=&quot;https://tkdodo.eu/blog/practical-react-query#the-defaults-explained&quot;&gt;default configuration&lt;/a&gt; behaves, and what your options are with regards to tuning for you own use-case. In particular, the default options may be cause issues if your endpoints are performing expensive operations.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Query instances via &lt;strong&gt;&lt;code&gt;useQuery&lt;/code&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;code&gt;useInfiniteQuery&lt;/code&gt;&lt;/strong&gt; by default &lt;strong&gt;consider cached data as stale&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Stale queries are refetched automatically in the background when:
&lt;ul&gt;
&lt;li&gt;New instances of the query mount&lt;/li&gt;
&lt;li&gt;The window is refocused&lt;/li&gt;
&lt;li&gt;The network is reconnected&lt;/li&gt;
&lt;li&gt;The query is optionally configured with a refetch interval&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Remember that you can set application-wide defaults via the &lt;a href=&quot;https://tanstack.com/query/v4/docs/reference/QueryClient#queryclient&quot;&gt;defaultOptions on QueryClient&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Share types with backend&lt;/h3&gt;
&lt;p&gt;If you are not validating the response with something like &lt;code&gt;zod&lt;/code&gt;, an approach we have found to work well is to generate TypeScript types from the API endpoints, and use those to strongly type the return value of &lt;code&gt;queryFn&lt;/code&gt; or &lt;code&gt;mutationFn&lt;/code&gt;. We have a Python / Django backend, so we use a combination of &lt;a href=&quot;https://docs.pydantic.dev/latest/&quot;&gt;pydantic&lt;/a&gt; to define the response types (and validate them at runtime) and &lt;a href=&quot;https://www.npmjs.com/package/openapi&quot;&gt;openapi&lt;/a&gt; to generate the TypeScript. This gets a bit trickier if the API endpoints do not share a monorepo with the frontend code (as ours does), but it is still doable with some extra steps to ensure backwards compatability. Most server frameworks will have a way to generate an OpenAPI representation of your endpoints.&lt;/p&gt;
&lt;h3&gt;Use Mock Service Worker to mock component data dependencies in Storybook&lt;/h3&gt;
&lt;p&gt;Sometimes it&apos;s nice for a reusable component to own it&apos;s own data dependencies. That way, it can be used in various places in the app without the parent components needing to know about the data it needs, or where to fetch it.
This can make authoring Storybook representations of the component a bit awkward, as now there component needs to make a HTTP request for it&apos;s data, rather than having them passed via props.
The &lt;a href=&quot;https://mswjs.io/&quot;&gt;msw&lt;/a&gt; library solves this neatly by mocking such requests at the network layer (rather than having to monkey patch &lt;code&gt;axios&lt;/code&gt; or &lt;code&gt;fetch&lt;/code&gt;), and, for good measure, the mock handlers exposed can also be re-used by integration-style unit tests.&lt;/p&gt;
&lt;h3&gt;Use QueryClient API to ensure better server sync and reduce requests&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;a href=&quot;https://tanstack.com/query/latest/docs/framework/react/guides/query-invalidation&quot;&gt;invalidateQueries&lt;/a&gt; when you know better than &lt;code&gt;react-query&lt;/code&gt; that things need to be refetched, or call &lt;a href=&quot;https://tanstack.com/query/latest/docs/reference/QueryClient#queryclientrefetchqueries&quot;&gt;refetchQueries&lt;/a&gt; directly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To keep requests to a minimum, consider infinite &lt;code&gt;staleTime&lt;/code&gt; for queries you know will not change for the duration of the session.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make params passed to &lt;code&gt;useMutations&lt;/code&gt;/ &lt;code&gt;useQuery&lt;/code&gt; form part of the query key (e.g. &lt;code&gt;searchTerm&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Possible to use as a state manager if you need some global state that does not come from the server&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Set the query-cache value directly and it will be accessible to anything with access to the &lt;code&gt;queryClient&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If you are doing this a lot - probably worth thinking about a more purpose-built tool.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As usual Dominik Dorfmeister has &lt;a href=&quot;https://tkdodo.eu/blog/react-query-as-a-state-manager&quot;&gt;a good article on this&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Further reading&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://tanstack.com/query/latest/docs/framework/react/overview&quot;&gt;Official docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://tkdodo.eu/blog/practical-react-query&quot;&gt;Dominik Dorfmeister’s blog&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Nathan Power</author></item><item><title>Composable component APIs</title><link>https://nathanpower.dev/posts/composable-component-apis</link><guid isPermaLink="true">https://nathanpower.dev/posts/composable-component-apis</guid><description>Should your internal component library have a composable API</description><pubDate>Thu, 10 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For those of us who have followed the evolution of UI component libraries in the React ecosystem, it&apos;s hard not be inspired by the elegant composable APIs exemplified by &lt;code&gt;react-aria&lt;/code&gt; and &lt;code&gt;radix-ui&lt;/code&gt;. Is this also the approach we should follow when authoring internal component libraries, for example internal design-system implementations?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React from &apos;react&apos;;
import * as Select from &apos;@radix-ui/react-select&apos;;
import classnames from &apos;classnames&apos;;
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from &apos;@radix-ui/react-icons&apos;;
import &apos;./styles.css&apos;;

const SelectDemo = () =&amp;gt; (
  &amp;lt;Select.Root&amp;gt;
    &amp;lt;Select.Trigger className=&quot;SelectTrigger&quot; aria-label=&quot;Food&quot;&amp;gt;
      &amp;lt;Select.Value placeholder=&quot;Select a fruit…&quot; /&amp;gt;
      &amp;lt;Select.Icon className=&quot;SelectIcon&quot;&amp;gt;
        &amp;lt;ChevronDownIcon /&amp;gt;
      &amp;lt;/Select.Icon&amp;gt;
    &amp;lt;/Select.Trigger&amp;gt;
    &amp;lt;Select.Portal&amp;gt;
      &amp;lt;Select.Content className=&quot;SelectContent&quot;&amp;gt;
        &amp;lt;Select.ScrollUpButton className=&quot;SelectScrollButton&quot;&amp;gt;
          &amp;lt;ChevronUpIcon /&amp;gt;
        &amp;lt;/Select.ScrollUpButton&amp;gt;
        &amp;lt;Select.Viewport className=&quot;SelectViewport&quot;&amp;gt;
          &amp;lt;Select.Group&amp;gt;
            &amp;lt;Select.Label className=&quot;SelectLabel&quot;&amp;gt;Fruits&amp;lt;/Select.Label&amp;gt;
            &amp;lt;SelectItem value=&quot;apple&quot;&amp;gt;Apple&amp;lt;/SelectItem&amp;gt;
            &amp;lt;SelectItem value=&quot;banana&quot;&amp;gt;Banana&amp;lt;/SelectItem&amp;gt;
            &amp;lt;SelectItem value=&quot;blueberry&quot;&amp;gt;Blueberry&amp;lt;/SelectItem&amp;gt;
            &amp;lt;SelectItem value=&quot;grapes&quot;&amp;gt;Grapes&amp;lt;/SelectItem&amp;gt;
            &amp;lt;SelectItem value=&quot;pineapple&quot;&amp;gt;Pineapple&amp;lt;/SelectItem&amp;gt;
          &amp;lt;/Select.Group&amp;gt;
      &amp;lt;/Select.Content&amp;gt;
    &amp;lt;/Select.Portal&amp;gt;
  &amp;lt;/Select.Root&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Isn&apos;t that lovely? That&apos;s example is copied and condensed from the &lt;a href=&quot;https://www.radix-ui.com/primitives/docs/components/select&quot;&gt;radix-ui examples&lt;/a&gt;. Clear hierarchy, flexibility via composition, looks almost like HTML. Right? RIGHT?&lt;/p&gt;
&lt;p&gt;Well...&lt;/p&gt;
&lt;p&gt;Much as I like it, I am not convinced it is the style I would recommend exposing to teams, particularly if you have to support developers with limited frontend experience.&lt;/p&gt;
&lt;p&gt;Let me outline some of the reasons why:&lt;/p&gt;
&lt;h2&gt;Rules of composition are opaque&lt;/h2&gt;
&lt;p&gt;When you look at the Radix Select example above, it&apos;s not immediately obvious which components are required, which are optional, or what the valid nesting relationships are. Can &lt;code&gt;Select.Icon&lt;/code&gt; exist outside of &lt;code&gt;Select.Trigger&lt;/code&gt;? What happens if you forget &lt;code&gt;Select.Portal&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;These rules exist in the documentation and TypeScript definitions, but they&apos;re not self-evident from the API surface. A developer needs to understand the mental model of how these pieces fit together, which adds cognitive overhead.&lt;/p&gt;
&lt;p&gt;Compare this to a more traditional API:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Select
  options={fruits}
  placeholder=&quot;Select a fruit…&quot;
  icon={&amp;lt;ChevronDownIcon /&amp;gt;}
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The constraints are clear: you pass props, you get a select. No composition rules to remember.&lt;/p&gt;
&lt;h2&gt;Behaviour of composed children is opaque&lt;/h2&gt;
&lt;p&gt;In composable APIs, child components often receive props or context invisibly from their parents. In our Radix example, &lt;code&gt;Select.Value&lt;/code&gt; somehow knows what the current selection is, and &lt;code&gt;Select.Item&lt;/code&gt; components can update that selection - but this magic happens behind the scenes.&lt;/p&gt;
&lt;p&gt;This can lead to confusing debugging sessions. When something doesn&apos;t work as expected, developers need to understand not just their own code, but the implicit data flow between composed components.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Why doesn&apos;t this work? What&apos;s missing?
&amp;lt;Select.Root&amp;gt;
  &amp;lt;Select.Trigger&amp;gt;
    &amp;lt;Select.Value /&amp;gt; {/* No placeholder appears */}
  &amp;lt;/Select.Trigger&amp;gt;
&amp;lt;/Select.Root&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The answer might be that you need &lt;code&gt;defaultValue&lt;/code&gt; on &lt;code&gt;Select.Root&lt;/code&gt;, or that &lt;code&gt;Select.Value&lt;/code&gt; needs a &lt;code&gt;placeholder&lt;/code&gt; prop, but this isn&apos;t obvious from the component structure alone.&lt;/p&gt;
&lt;h2&gt;Internal APIs sometimes benefit from opinions over flexibility&lt;/h2&gt;
&lt;p&gt;Public libraries like Radix need to serve diverse use cases across thousands of applications. They optimize for flexibility because they can&apos;t predict every scenario their users will encounter.&lt;/p&gt;
&lt;p&gt;Internal component libraries have different constraints. You typically know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your design system&apos;s specific patterns&lt;/li&gt;
&lt;li&gt;Your team&apos;s skill levels and preferences&lt;/li&gt;
&lt;li&gt;The specific use cases you need to support&lt;/li&gt;
&lt;li&gt;Your organization&apos;s accessibility and testing requirements&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This knowledge lets you make opinionated choices that reduce complexity:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Opinionated: always includes error state, loading state, proper labeling
&amp;lt;FormSelect
  label=&quot;Favorite fruit&quot;
  options={fruits}
  value={selectedFruit}
  onChange={setSelectedFruit}
  error={validationError}
  loading={isLoading}
  required
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rather than requiring developers to compose these concerns themselves:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Select.Root value={selectedFruit} onValueChange={setSelectedFruit}&amp;gt;
  &amp;lt;Label htmlFor=&quot;fruit-select&quot; required&amp;gt;Favorite fruit&amp;lt;/Label&amp;gt;
  &amp;lt;Select.Trigger id=&quot;fruit-select&quot; disabled={isLoading}&amp;gt;
    {isLoading ? &amp;lt;Spinner /&amp;gt; : &amp;lt;Select.Value /&amp;gt;}
    &amp;lt;Select.Icon&amp;gt;&amp;lt;ChevronDownIcon /&amp;gt;&amp;lt;/Select.Icon&amp;gt;
  &amp;lt;/Select.Trigger&amp;gt;
  {/* ... rest of composition */}
  {validationError &amp;amp;&amp;amp; &amp;lt;ErrorMessage&amp;gt;{validationError}&amp;lt;/ErrorMessage&amp;gt;}
&amp;lt;/Select.Root&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Finding the right balance&lt;/h2&gt;
&lt;p&gt;This doesn&apos;t mean composable APIs are always wrong for internal libraries. They excel when you need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Complex, varied layouts that can&apos;t be anticipated&lt;/li&gt;
&lt;li&gt;Components that need to integrate with diverse parent contexts&lt;/li&gt;
&lt;li&gt;Maximum flexibility for power users&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But for most internal design systems, I&apos;d recommend starting with simpler, more opinionated APIs and only introducing composition where the flexibility is genuinely needed. Your future self (and your teammates) will thank you for the reduced cognitive load.&lt;/p&gt;
&lt;p&gt;The goal isn&apos;t to build the most elegant API - it&apos;s to build the most effective one for your team and context.&lt;/p&gt;
</content:encoded><author>Nathan Power</author></item></channel></rss>