<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Pedro Piñera - Writing</title>
    <link>https://pepicrft.me/blog/</link>
    <description>Software engineer, open source enthusiast, and builder</description>
    <atom:link href="https://pepicrft.me/blog/feed.xml" rel="self" type="application/rss+xml" />
    <language>en</language>
    
    <item>
      <title>The company before the tools</title>
      <link>https://pepicrft.me/blog/the-company-before-the-tools/</link>
      <guid>https://pepicrft.me/blog/the-company-before-the-tools/</guid>
      <pubDate>Sat, 09 May 2026 08:00:00 +0000</pubDate>
      <description>Layoffs are the bill for designing companies in a world that no longer exists. With the cost of building collapsed, small teams can finally design how they want to work first, and shape the tools around that, instead of bending themselves to off-the-shelf opinions.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There has been a wave of layoffs lately, and I keep coming back to it. Coinbase. Cloudflare. A long list of others. I have been part of one of those layoffs myself, on the receiving end, and I can confirm there is nothing fun about it.</p>
<p>What I cannot stop thinking about is the reasoning behind them. Listening to founders and CEOs talk about why they are doing this, the answer that emerges is not really “things got worse.” It is more uncomfortable than that. It is “we designed our company years ago, and the shape we ended up with no longer fits the world we are in.” Some of the people they hired are excellent at executing the old shape. Some do not want to embrace the new one. That is a brutal position to be in, and I understand why it ends in layoffs even when nobody wants it to.</p>
<p>I am writing this from the other side. From the side of designing a small company today, with a clean sheet of paper, while watching this play out.</p>
<h2 id="the-shopify-thing">The Shopify thing</h2>
<p>When I worked at <a rel="external" href="https://shopify.com">Shopify</a>, one of the things that quietly shaped my thinking was how they treated internal tooling. Most companies I had seen, including ones I had been part of, would reach for whatever the market offered. Linear, Jira, the CRM of the moment, the support tool of the moment. The tools came with their own opinions about how work should happen, and the company quietly bent itself around those opinions.</p>
<p>Shopify did the opposite. They thought about how they wanted to operate, and then they built tools that supported that. They had the resources to do it, of course, and at the time that felt like a luxury reserved for companies of their size. If you were a small team or a single founder, the cost of building and maintaining your own internal stack was prohibitive. So you did the only thing you could do: you adopted the tools other people made, and you absorbed their model of work.</p>
<p>That equation has flipped.</p>
<h2 id="the-cost-of-building-has-collapsed">The cost of building has collapsed</h2>
<p>The cost of producing code is at a historic low. The cost of running it on infrastructure is at a historic low. The cost of designing thoughtful interfaces, when you can lean on a design system and a coding agent, is at a historic low. There has never been a better moment to sit down and ask the question that used to be a luxury: how do we want to work, and what would the tool that supports that look like?</p>
<p>This is something we can afford to do at <a rel="external" href="https://tuist.dev">Tuist</a> precisely because we are tiny. We do not have to nudge dozens of people in a particular direction. We can spend a week thinking about how we want to do something, and another week translating that into the tool that supports it. A lot of what makes a company run is common sense and pattern matching from what others have done. There is good literature out there. But there is also something specific to our space, our values, the way we like to work, and that part is not in the literature. Someone has to take the time to think about it, and then translate it into the tools.</p>
<h2 id="what-we-built-first">What we built first</h2>
<p>We built an internal tool we call <a rel="external" href="https://pepicrft.me/blog/atlas/">Atlas</a>. I have written about it already, but let me share what we have actually done with it lately.</p>
<p>I started with the CRM side. We dropped the CRM we were using and moved everything to Atlas. Then we plugged in the sources of signal we already had:</p>
<ul>
<li>Transcripts from <a rel="external" href="https://granola.ai">Granola</a></li>
<li>Conversations on Slack, including the shared channels we have with companies</li>
<li>Email threads</li>
<li>Product usage data</li>
</ul>
<p>From there, Atlas builds a profile for every account, and agents nudge me towards the things that are likely to matter. Not “send a generic check-in.” More like “this conversation three weeks ago was about a feature you just shipped, this is a good moment to follow up.” Because Atlas can read how a customer is using the product, it can also suggest features they have not tried yet but probably should. That is the floor. We will keep raising it.</p>
<h2 id="the-zapier-shaped-trap">The Zapier-shaped trap</h2>
<p>There are CRM tools out there leaning hard into agents. I look at them and I see something that feels broken to me. They are, in essence, Zapier-shaped. Connect this API. Connect that one. Build an orchestrator over the orchestrator. The reason this happens is structural: a tool that wants to fit every company has to be designed against the lowest common denominator of all the other tools out there.</p>
<p>When you build for yourself, the equation is different. You do not need to integrate with every CRM in the world. You need to integrate with the systems you actually use. And ideally, once your tool integrates with them well, some of those systems are no longer necessary. The CRM we were using, in the end, was a database wrapper with a few nice features on top. We copied the features that were useful, and we dropped the wrapper.</p>
<p>There are tools where reinvention does not make sense. We use a service to sync our banking data and give us financial insights, and replicating it would be silly. That is a regulatory and data-source problem more than a product problem. But most everything else, at least in our case, is replicable. More than people realise.</p>
<h2 id="what-is-next">What is next</h2>
<p>We are looking at support next. Then development operations. I can already picture Atlas reading an alert from <a rel="external" href="https://grafana.com">Grafana</a>, doing an initial investigation against the codebase, opening a draft PR with a candidate fix, and pinging the team with the reasoning. I can picture it drafting responses to community questions by reading the code and the docs. None of this requires a research breakthrough. The pieces exist. It is a matter of deciding to compose them around the company you want to be.</p>
<h2 id="where-i-land">Where I land</h2>
<p>The layoffs we are seeing are, in part, the bill for designing companies in a world that no longer exists. I do not say that to be smug, because designing a company is hard, and the world genuinely changed faster than anyone expected. But the lesson, for those of us building now, is hard to miss.</p>
<p>You want people who can leverage these technologies to build first. People who look at the resulting system with curiosity, and want to contribute to making it better. The tools come from the company you want, not the other way around. The companies that internalise this and act on it are the ones I expect to compete on a different curve. The ones that do not, I suspect, will be writing the layoff blog posts a few years from now.</p>
<p>That is the company we want to build.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Caching, productized</title>
      <link>https://pepicrft.me/blog/caching-productized/</link>
      <guid>https://pepicrft.me/blog/caching-productized/</guid>
      <pubDate>Tue, 05 May 2026 12:00:00 +0000</pubDate>
      <description>Build caching is becoming an everyone problem. Here is how we think about productizing it at Tuist for indie developers and small teams, not just enterprises.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Build caching has never been something sexy for medium companies or indie developers. Adopting it usually meant replacing your build system with <a rel="external" href="https://bazel.build">Bazel</a> or something close to it, and that came with a migration cost most teams could not afford to take on. The companies that did it were the ones with the budget and the engineering bandwidth. Large enterprises, almost without exception.</p>
<p>The infrastructure companies that emerged around caching read the room. They built for those enterprises. Contact sales. Book a demo. Long onboardings where the goal was not really to automate anything, but to get you on a call. The product, in the end, was the call.</p>
<p>We think that era is ending.</p>
<h2 id="what-changes-when-you-have-agents-on-the-same-machine">What changes when you have agents on the same machine</h2>
<p>Picture working on a project with multiple coding agents, each on its own <a rel="external" href="https://git-scm.com/docs/git-worktree">git worktree</a>, each running its own builds. It does not matter how fast your laptop is. There is a limited number of cores, and several agents are about to fight for them, compiling the same things in parallel. Your machine becomes unusable, and a non-trivial amount of compute gets burned redoing work that was already done somewhere else, by someone else, ten minutes ago.</p>
<p>The need to optimize for caching, which used to live in the realm of large monorepos, is now showing up on every developer's laptop. If you are a small team and you want your agentic setup to be fast, you need the same kind of infrastructure that until recently was only justifiable at scale. You want your CI to share work with your local machine. You want the agent in container A to share work with the agent in container B.</p>
<p>This is the shift. Caching is becoming an everyone problem.</p>
<h2 id="the-supabase-shape">The Supabase shape</h2>
<p>The thing we have to do at <a rel="external" href="https://tuist.dev">Tuist</a> is productize this. And not just for the large enterprises. For indie developers and small teams too.</p>
<p>A good frame for what that looks like is <a rel="external" href="https://supabase.com">Supabase</a> and <a rel="external" href="https://vercel.com">Vercel</a>. It is not that we did not have hosted databases before they showed up. It is that they made it easy. They wrapped the operational layer in an API, added the conveniences developers actually need, and then once the new wave of platforms like <a rel="external" href="https://lovable.dev">Lovable</a> and <a rel="external" href="https://replit.com">Replit</a> needed somewhere to keep state, Supabase was the obvious answer. You sign up, you create a project, you wire up auth, and you are done.</p>
<p>That is the bar we want for caching at Tuist. Sign up, create a project, authenticate locally, and have your build system pulling cached artifacts within minutes. Convenient for the user, convenient for the agent.</p>
<p>Convenient for the agent is the part most companies still miss. If a user can do something, an agent should be able to do the same thing through a clean interface. That means investing in APIs. It means investing in <a rel="external" href="https://modelcontextprotocol.io">MCPs</a>. It means making sure that every action a developer takes to set up caching, whether that is connecting it to Bazel, Xcode, or any other build system, can also be taken by an agent walking them through it. It also means showing up where the agents do, on every LLM marketplace possible, so that when somebody tells the agent "this is slow," the conversation can drift naturally toward setting up Tuist. Zero to using a cache in a few prompts.</p>
<p>There is one more design constraint underneath all of this that is easy to miss. Caching cannot be fast only in one environment. It has to be fast wherever the build is happening. Your laptop, your CI, your agent's container, your colleague's machine on a flaky hotel WiFi. That is what we are building, on both the infrastructure side and the application side. A system that productizes caching beyond a single build system, with the cache as a primitive that can serve whatever action is happening, wherever it is happening.</p>
<h2 id="what-agents-do-to-bazel">What agents do to Bazel</h2>
<p>Bazel is still the most sophisticated toolchain out there for setting up caching in an existing project. The reason it never quite worked in places like the Apple ecosystem is that the IDE was not designed for a different build system. Xcode wanted to be both the editor and the build system, and Bazel asked you to give that up.</p>
<p>That tension is dissolving. People depend less and less on integrated IDEs. If your day-to-day driver is <a rel="external" href="https://claude.com/claude-code">Claude Code</a> or <a rel="external" href="https://openai.com/codex">Codex</a>, the build system underneath becomes an implementation detail. As long as it is fast, reliable, and the agent can iterate on it, the rest does not really matter.</p>
<p>The other side is that agents are very good at writing <a rel="external" href="https://bazel.build/rules/language">Starlark</a>. The cost of writing Bazel files for your iOS app, your Android app, your Rust server, your desktop app, all of that is being pushed down. We will probably see more Bazel adoption, more plugins, hopefully more contributions to make Bazel itself better. We are new to it, and we are building a real appetite for learning, putting resources behind it, and supporting the community along the way.</p>
<h2 id="where-we-land">Where we land</h2>
<p>When the two ends of this meet, agents lowering the cost of authoring the build system on one side, and Tuist productizing the infrastructure on the other, the result is that caching stops being an enterprise-only conversation. The infrastructure that makes everything fast, not at the compute level but at the level of what is actually happening inside the compute, is something we want to make available to anyone. Indie developers. Two-person startups. Mid-size teams. Whoever needs it.</p>
<p>We also think we are going to see agents start paying for things on behalf of their users. Stripe is investing into the protocol piece of that, and that future is coming whether the rest of the industry is ready for it or not. We want to be ready for it.</p>
<p>The contact-sales model is not where this is going to live. We do not love the word democratize as a concept, but you get it. If caching is going to be a theme for the next few years, anyone should be able to make their agentic setup faster without going through a six-month enterprise procurement cycle.</p>
<p>We are putting the pieces in to make that real.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The convenience tax</title>
      <link>https://pepicrft.me/blog/the-convenience-tax/</link>
      <guid>https://pepicrft.me/blog/the-convenience-tax/</guid>
      <pubDate>Sun, 03 May 2026 10:00:00 +0000</pubDate>
      <description>I keep coming back to the wave of companies that made infrastructure feel easy, and what coding agents are doing to the layer of convenience they were quietly selling.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I have been thinking a lot about the wave of companies that made deploying software feel easy. <a rel="external" href="https://fly.io">Fly.io</a>, <a rel="external" href="https://render.com">Render</a>, <a rel="external" href="https://railway.com">Railway</a>, <a rel="external" href="https://vercel.com">Vercel</a>. They played a real role in shaping how a generation of developers thinks about infrastructure. Push to deploy. No clusters. No pager.</p>
<p>I was a fan. I still think they have a role to play. They are, in many ways, convenience as a service. Some of them, like Vercel and Fly.io, went down the road of running their own hardware, probably for cost reasons but also for the flexibility of deciding where and how to allocate resources. Others, like Render, run on top of AWS, which means you pay a tax on top of the compute you would already be paying for.</p>
<p>For a long time that tax made sense, because the alternative was learning <a rel="external" href="https://kubernetes.io">Kubernetes</a>, or building out your own runner setup, or stitching together something with Terraform and a deep breath.</p>
<p>That equation has changed.</p>
<h2 id="what-agents-quietly-did-to-infrastructure">What agents quietly did to infrastructure</h2>
<p>Coding agents have done something I do not think we have fully appreciated yet. They have codified the knowledge of tools that were traditionally considered too complex to touch. Kubernetes is the obvious example. <a rel="external" href="https://bazel.build">Bazel</a> is another. These tools are still complex, but the ramp is no longer a wall. You sit down with an agent, describe the shape of what you need, and it walks you through the concepts that apply to your specific case. The ones that do not apply, you do not even need to learn.</p>
<p>That eliminates a whole layer of convenience that companies were charging for.</p>
<h2 id="what-happened-at-tuist">What happened at Tuist</h2>
<p>We just lived this at <a rel="external" href="https://tuist.dev">Tuist</a>. We moved off Render and onto a Kubernetes cluster running on <a rel="external" href="https://www.hetzner.com">Hetzner</a>. The cluster is currently managed by another company, and that is the next thing we are going to change. What blew my mind is how easy the whole setup was to navigate. We are a tiny team. A few years ago this would have been a project. Now it was a couple of focused weeks.</p>
<p>There is a motivation behind the move that is worth naming. We are shaping Tuist into a company that captures value by providing infrastructure. To do that well we need to declare our infrastructure as code, reason about it, and understand it deeply. Going through a managed PaaS is the wrong shape for a company whose product is increasingly about running infrastructure for others.</p>
<p>What we did not expect is the bucket of things that came along with the move.</p>
<p>Costs went down, which we expected. But suddenly we could lean on agents to reason about our infrastructure too. They could read manifests, propose changes, and inspect the live state via <code>kubectl</code>. <a rel="external" href="https://grafana.com">Grafana</a> has first-class support for Kubernetes, which means we now have an observability toolchain that was simply not on the table before. None of this would have been possible inside Render's world, where access to our own infrastructure was, by design, gated by them. That is fine for most people. After tasting another world, I cannot go back.</p>
<h2 id="ci-looks-suspiciously-similar">CI looks suspiciously similar</h2>
<p>I keep thinking about this in the context of CI. There is a category of companies emerging there: <a rel="external" href="https://blacksmith.sh">Blacksmith</a>, <a rel="external" href="https://depot.dev">Depot</a>, <a rel="external" href="https://namespace.so">Namespace</a>, <a rel="external" href="https://runs-on.com">RunsOn</a>. Some bring their own hardware. Some, like RunsOn, run directly on AWS. The shape is similar. You get faster, cheaper CI, with someone else doing the operational work of attaching ephemeral environments to your Git forge.</p>
<p>The thing is, the basic problem is not that hard to solve. You need compute. You need to spin up environments. You need to wire them to GitHub or your forge of choice. That is the floor. And once you internalize that the floor is reachable in-house with the help of agents, you start to wonder what the rest of the value really is.</p>
<p>You can already see developers experimenting in that direction. <a rel="external" href="https://x.com/steipete">Peter Steinberger</a> just shipped a release of his tool <a rel="external" href="https://x.com/steipete/status/2050490163810230579">Crabbox</a> that includes, among other things, an "AWS image create" command baked in. It spins up remote Linux runs from your laptop and talks to the cloud provider directly. No middle company. It is a small example, and it is one of many to come. Once the friction of touching the provider yourself drops, the layer that sits between you and the provider has to keep proving why it deserves to be there.</p>
<p>That, I think, is why these companies are increasingly trying to sell something beyond compute.</p>
<h2 id="what-they-are-actually-selling">What they are actually selling</h2>
<p>What they are selling is a story. That is how capital flows in our industry, and there is nothing wrong with selling stories as long as the story holds up.</p>
<p>The story right now is the infrastructure for agents. The infrastructure for agents to run their tasks. The infrastructure for agents to run the work they produce. Infrastructure for a world that is unfolding and that nobody really knows the shape of yet.</p>
<p>I have mixed feelings about it. We already have cloud providers that can do this. You can build directly on them, and use the room you save to innovate on something else. But that is not how our industry moves. Layers emerge. They disappear. They move. They get renamed. Many of them are sustained more by stories and promises than by the strict technical need they answer.</p>
<p>The serverless wave is a good reminder. Functions that run close to the user, sold on the promise of latency, while still having to traverse the planet to reach a Postgres database managed by yet another company. Pricing models that look great on the cheap end of the curve and quietly become bizarre at scale. You sit there waiting for your provider to ship a feature so that your bill stops growing in ways you cannot explain.</p>
<p>Elastic CI compute. Elastic agent compute. Elastic function execution. Pay per minute. Pay per token. We love that.</p>
<h2 id="where-i-land">Where I land</h2>
<p>I do not want to dismiss any of these companies. Many of them are run by people I respect, solving real problems for real customers. The convenience they offer matters. For most teams, paying the tax is still the right call.</p>
<p>But the equation underneath has shifted. If there is an agent in the room with you, the layer of convenience you used to rent gets thinner. The case for owning your infrastructure, or at least owning the ability to reason about it, is stronger than it has been in a long time. And the things you discover when you cross that line, the access to your own systems, the observability, the freedom to compose what you actually need, are hard to give back once you have had them.</p>
<p>That is the part nobody puts in the marketing copy. And that is the part I keep coming back to.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Atlas</title>
      <link>https://pepicrft.me/blog/atlas/</link>
      <guid>https://pepicrft.me/blog/atlas/</guid>
      <pubDate>Fri, 01 May 2026 12:00:00 +0000</pubDate>
      <description>Why we are building Atlas at Tuist, an internal platform designed to help a very small team operate with the leverage of a much larger one.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Something is becoming clear as we build <a rel="external" href="https://tuist.dev">Tuist</a>, and it is that this might be the best moment in history to design a company to be deeply resource-efficient. By resource I don't mean money. I mean people. We are a very small team, and we are constantly thinking about how to use LLMs and agents to optimize the way we work.</p>
<p>Because we are small, we do a bit of everything. Go to market. Marketing. Product. Support. Sales. In traditional companies, each of these is a whole department, sometimes a whole organization. That is a luxury we cannot afford, and honestly, I am not sure we would want it even if we could.</p>
<h2 id="the-multi-tool-problem">The multi-tool problem</h2>
<p>Like most small companies, our first instinct was to lean on tools for each of those functions. We picked Operate for CRM. We kept some data in GitHub repositories because we believe markdown and configuration files are perfect formats for things that need to live close to code. We do support across community channels and GitHub issues. It is a bit all over the place.</p>
<p>What we keep learning is that we are constantly jumping between tools, and sooner or later we hit a wall. Either we need a feature the tool does not have, or we need to correlate data across tools, which is essentially impossible when the data lives in different silos. We can connect MCPs locally and try to do that correlation ourselves, but we miss the opportunity to automate things. To trigger workflows when something is detected across the various sources. The interesting work is at the intersections, and the intersections are exactly where these tools have the weakest answer.</p>
<h2 id="what-if-we-built-it-ourselves">What if we built it ourselves</h2>
<p>This is when we started asking a different question. What if, instead of stitching ourselves across a multi-tool setup, we built the tool we actually need?</p>
<p>We have coding agents that can write that tool with us. We have a design system that lets us combine building blocks into our own dashboards. We have all the pieces. The economics of building software for yourself have changed in a way I do not think we have fully internalized yet.</p>
<p>I started an internal project at Tuist called <strong>Atlas</strong>. At first I thought we could open source it, but after sitting with the idea for a while, I realized that what we are designing is very specific to the needs we have as a company. Every company has its own shape. That is why companies like Stripe end up building their own internal platforms, and why no two of those platforms look the same, even when they solve overlapping problems.</p>
<h2 id="what-atlas-does-first">What Atlas does first</h2>
<p>We are starting with sales and account management.</p>
<p>Traditional CRM tools all look the same, with a bit of AI sprinkled on top. What we want is something that tracks the full picture of what is happening with a customer. Conversations on email. Conversations on Slack. The shared channels we have with companies. The way they are actually using the product.</p>
<p>If Atlas knows which features we just released, and remembers the last conversation we had with a customer, it can do something more useful than reminding us to send a generic "how is it going" message. It can tell us "this might be a good moment to ping this company, and you should bring up this thing because they asked about it three weeks ago." That is the kind of nudge that turns into a real conversation. That is the baseline, and we want to go beyond it.</p>
<h2 id="beyond-sales">Beyond sales</h2>
<p>Sales is just the entry point. The same idea applies across everything we do.</p>
<p>Now that we have moved everything to Kubernetes, we have access to Grafana and a constant stream of signals about how our production systems are behaving. What if Atlas was watching that too? Detecting something unusual, doing an initial investigation on its own, then pinging us with the relevant data and the reasoning behind it. Even opening a draft PR with a potential fix for what it found.</p>
<p>These are examples, not a roadmap. The point is that if the data lives in one place, and the tool can act on it, the kind of work that used to require a dedicated team starts to become accessible to a team of four.</p>
<h2 id="the-bet">The bet</h2>
<p>This is what excites me. It means we can stay extremely agile as a company, which I believe is critical to making an impact when you do not have the resources to spin up a dedicated organization for every domain. If we tried to compete with the big players by replicating their org chart, we would lose. We do not have the runway, and we do not have the patience.</p>
<p>I do not think we are going to scale by hiring an organization for every function. We are going to scale by building Atlas alongside the people we hire, so that whoever joins can bring their judgment to the areas where they can move the needle, while leaning on a platform that takes care of the rest. The platform itself becomes a teammate. One that we keep iterating on as we discover what we actually need.</p>
<p>The traditional shape of a company assumes you cannot build your own internal tools, so you assemble a stack of vendors instead. That assumption is no longer true. The cost of building bespoke has collapsed, and what you get on the other side is a company that fits its tools rather than the other way around.</p>
<p>That is the company we want to build.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The single-tenant cache</title>
      <link>https://pepicrft.me/blog/the-single-tenant-cache/</link>
      <guid>https://pepicrft.me/blog/the-single-tenant-cache/</guid>
      <pubDate>Tue, 28 Apr 2026 10:00:00 +0000</pubDate>
      <description>Why we moved our caching layer from multi-tenant to single-tenant, what that mental model unlocks for latency and operations, and how we&#x27;re shaping the cache as a leaderless network of nodes that lives close to wherever you happen to be building.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>A few weeks ago I <a rel="external" href="https://pepicrft.me/blog/the-cache-is-the-infrastructure/">wrote about caching as the new infrastructure</a>. The argument was that as build systems get smarter and coding agents start running everywhere, the bottleneck stops being CPU and starts being how close your cache is to whatever is doing the work. Compute can be anywhere. The cache has to be near.</p>
<p>Since then we have been building. And the way we have been building has shifted in ways I want to share, because the shape of the system is telling us something interesting about where this is going.</p>
<h2 id="the-problem-restated">The problem, restated</h2>
<p>Developers want caching. Agents want caching even more. Inference is fast, and getting faster, but compilation is not. You can have an agent writing code at a speed that would have been unthinkable two years ago, and then watch it sit there waiting for the build to finish. Compute is expensive. Re-doing work that has already been done is the kind of waste that stings even more when an agent is the one paying the time tax.</p>
<p>The way out is the network. You lean on low-latency caching to give you near-uncapped access to pre-compiled results, and you skip the work entirely. We have known this since the beginning at Tuist. It is what our project generation cache has done for years for Xcode. It is what we are bringing to Gradle now, and Bazel later this year.</p>
<p>But once you go down that road, one thing becomes very clear: low latency is everything. If the cache is slow, the math stops working. The cost of fetching from the cache approaches the cost of just compiling, and at that point why bother.</p>
<h2 id="latency-is-not-just-one-number">Latency is not just one number</h2>
<p>The harder part is that low latency cannot live in only one environment.</p>
<p>If your caching servers run in our infrastructure and your CI happens to run near them, things feel fast. If your build runs somewhere else, like a developer's laptop in Buenos Aires or an agentic environment that spun up in some random region, things do not feel fast at all. That always felt wrong to us, especially now that the picture is more fluid than ever. Agents have their own runtimes. CI providers have theirs. Local machines are still part of the story. None of these are guaranteed to be in the same region, or even on the same continent.</p>
<p>We knew we had to build for that. So we did, and we built it as a multi-tenant system from the start, because that is what we were familiar with. And that is where we made some serious mistakes.</p>
<h2 id="what-multi-tenant-taught-us">What multi-tenant taught us</h2>
<p>We left almost every resource unbounded. Network access, connection pools, database connections, file descriptors, file system. The system would crack at the seams very quickly. One tenant doing something demanding would degrade everyone else. Classic noisy neighbors.</p>
<p>It became obvious, after running into this enough times, that we were not going to scale a multi-tenant caching system unless we were Cloudflare. We are not Cloudflare. The kind of investment required to do that well is the kind that defines a company, and that is not the company we want to define ourselves as.</p>
<p>So we asked the obvious question: what if we went single-tenant?</p>
<h2 id="what-single-tenant-looks-like">What single-tenant looks like</h2>
<p>Single-tenant means each tenant gets their own caching instances, in the regions they care about. The mental model is the same one <a rel="external" href="https://supabase.com">Supabase</a> uses for Postgres, or <a rel="external" href="https://planetscale.com">PlanetScale</a> used for MySQL. You pick where your database lives. You pick where your replicas live. Same idea, applied to caching nodes. Want one in Frankfurt and one in Sydney? Done. Want one near the GitHub Actions region your CI runs in, and another near the Codex environment your agents spin up in? That works too.</p>
<p>The cost we knew we would pay is operational. We have to manage the deployment and the updates of those caching nodes per tenant. Not the whole stack, just the caching part. That is real work. But the alternative was a system that would never scale without us turning into an infrastructure company, and we already have a clear sense of what kind of company we want to be.</p>
<p>To make this work, two things had to be true.</p>
<p>The first is that the infrastructure had to be simple to operate. I know it sounds odd to say this and then mention that we ended up with <a rel="external" href="https://kubernetes.io">Kubernetes</a>, which is many things but not famously simple. The trick is that we have coding agents now. The pieces of infrastructure that used to require a dedicated team to operate are becoming far more accessible when an agent can read the manifests, reason about them, and take action on them.</p>
<p>The second is that everything had to be infrastructure as code. Scaling rules, update rules, deployment rules, all of it declarative. That gives us a system we can reason about. It also gives us a system an agent can dig into when something is off in production. A standard declaration file that agents can write, understand, and use to inspect what is happening.</p>
<h2 id="the-cache-as-a-network">The cache as a network</h2>
<p>Single-tenant on its own is not enough. Without something else, single-tenant becomes single-region by accident, and we are back to the problem we started with.</p>
<p>So we needed the nodes to act as a network.</p>
<p>Every node should be a full interface for the clients. Read, write, cache, all of it. And in the background, those nodes should distribute artifacts among themselves in a leaderless way. An artifact pushed from a developer in Berlin should make its way to a CI runner pulling from Sydney without any of the clients having to think about it. No central coordinator, no special node. Just nodes talking to nodes.</p>
<p>This is the part that ties the experience together. It is also the part where we are spending most of our thinking right now, because getting it wrong has the kind of failure modes that are very visible to users.</p>
<h2 id="the-technology-separately">The technology, separately</h2>
<p>Here is where it gets interesting to me, and where it connects to a longer thread we have been pulling on at Tuist for years.</p>
<p>Supabase hosts Postgres. They are, in some sense, a hoster of an open-source technology with a lot of value added on top: dashboards, auth, storage, realtime. But the core thing is open, and you can run it yourself if you want to. PlanetScale was similar with <a rel="external" href="https://vitess.io">Vitess</a>.</p>
<p>What if the caching layer was the same? The technology, standalone. Open source. Something you can host yourself if you want to. And we host it for you, because we will do the work of running it fast, safely, and securely. We bring the convenience. You keep the option to walk away.</p>
<p>On top of that, we bring the analytics. You cannot really know whether your caching is doing its job without observability. You need to see hit rates, miss rates, the artifacts that are getting evicted too often, the regions where things are slow. Without that, caching is a black box that either feels fast or does not. With it, caching becomes something you can actually tune.</p>
<p>This is the combination we have been working toward over the past few weeks. A piece of standalone technology that can take artifacts pushed by Gradle, by Bazel, and by many clients that nobody is thinking about caching for yet. We take care of running and managing it. You focus on your project. The analytics come along for the ride.</p>
<h2 id="what-is-next">What is next</h2>
<p>I have not been this excited about a foundation in a long time. This is the layer the rest of <a rel="external" href="https://pepicrft.me/blog/building-the-house-from-the-roof/">the house we are building</a> sits on. Caching is the part where the speed shows up. Compute, when we add it, will be the cherry on top of the cake.</p>
<p>We will have more to share in the coming weeks. There is more to say than fits in a single post, and frankly some of it will read better when there are things you can actually try. For now, this is where our head is at, and it feels like the right combination of pieces. Open at the bottom. Convenient at the top. Close to wherever you happen to be building.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Bazel everywhere?</title>
      <link>https://pepicrft.me/blog/bazel-everywhere/</link>
      <guid>https://pepicrft.me/blog/bazel-everywhere/</guid>
      <pubDate>Mon, 27 Apr 2026 10:00:00 +0000</pubDate>
      <description>Coding agents are lowering the cost of adopting powerful but complex tools like Kubernetes and Bazel, but I don&#x27;t think that means we&#x27;re heading toward a Bazel-everywhere world. The reasons are not technical, they are ecosystem-shaped.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Coding agents have changed the cost of adopting powerful tools. <a rel="external" href="https://kubernetes.io/">Kubernetes</a> and <a rel="external" href="https://bazel.build/">Bazel</a> were always capable, but the surface area of concepts and the maintenance load made them feel out of reach for small projects and small teams. Now you can sit down with an agent, get introduced to the concepts, narrow them down to the ones you actually need, and have a working setup in an afternoon. We're exploring this at <a rel="external" href="https://tuist.dev">Tuist</a> in the context of Kubernetes, and I've been thinking a lot about Bazel as the next build system we plan to support.</p>
<p>Part of me kept asking the obvious question. If Bazel is now easier to adopt, why not Bazel everywhere? The more I sat with it, the more I realized the problem is not technical. It's about how things actually work in our industry.</p>
<h2 id="integrated-toolchains-are-the-real-ceiling">Integrated toolchains are the real ceiling</h2>
<p>Look at <a rel="external" href="https://doc.rust-lang.org/cargo/">Cargo</a>, <a rel="external" href="https://vite.dev/">Vite</a>, or <a rel="external" href="https://hexdocs.pm/mix/Mix.html">Mix</a> in Elixir. These are integrated toolchains where compilation tasks and non-compilation tasks are woven into something that goes far beyond compiling. Vite ships an HTTP server doing hot reload of resources in the browser. Mix orchestrates dependency resolution, releases, and a whole runtime story. Cargo handles registries, features, and workspaces in a way that has become inseparable from how Rust developers think about their projects.</p>
<p>If you wanted to do all of that in Bazel, you would literally have to replicate the internals of Cargo, or Mix, or Vite. That's an insane amount of effort, and on top of that you'd be forking the ecosystem. You wouldn't benefit from the work that the maintainers of those tools keep pouring in, and you'd have to keep up with them forever. There is real value in Bazel, but there is no version of "Bazel everywhere" that doesn't end up rebuilding the world.</p>
<p>Coding agents don't change that. They lower the human cost of adoption, but they don't lower the cost of forking an entire ecosystem.</p>
<h2 id="the-plugin-layer-is-a-tell">The plugin layer is a tell</h2>
<p>When you look at how Bazel plugins are implemented for some of these toolchains, you notice that under the hood they often end up shelling out and calling Cargo or the equivalent. That feels wrong to me. It's the build system admitting that the integrated toolchain is the real source of truth, while pretending to wrap it.</p>
<p>I caught myself imagining a different shape. What if there was a foundation underneath all build systems, something like a content-addressable store with a shared event model, that every ecosystem could build on? A common floor that lowers the stack and lets each toolchain keep its identity on top. A bit like LLVM, where some toolchains build on it and others don't.</p>
<p>It's a nice thought, and also an impossible one to execute. You'd need every ecosystem to migrate to the same foundation, which is not how our industry moves. LLVM is the closest example we have, and even there the adoption is uneven. For something as load-bearing as build infrastructure, the gravitational pull of "what already works" is too strong.</p>
<h2 id="build-systems-learning-from-each-other">Build systems learning from each other</h2>
<p>What I think is realistic, and probably more useful, is for these tools to learn from each other and incorporate similar ideas. Telemetry is a good example. It's still uncommon in build systems, even though it's the most direct way to understand where time is being spent and where caching would pay off. The content-addressable store idea is another one. So is aligning around a shared contract with a remote cache server, so that the cache layer becomes interchangeable.</p>
<p>We'll definitely see more companies adopt Bazel where it makes sense, but I don't think it's going to be everywhere. My bet for the next few years is that the other build systems catch up in terms of ideas, while staying inside their own ecosystems.</p>
<h2 id="where-tuist-fits">Where Tuist fits</h2>
<p>For us, this is the bet we want to make. We want to be ready to provide the infrastructure for low-latency caching and analytics, so that all the complexity of running those things yourself is taken care of by us. Productized in a way that feels closer to <a rel="external" href="https://supabase.com/">Supabase</a> or <a rel="external" href="https://planetscale.com/">PlanetScale</a> than to a build engineering team.</p>
<p>You focus on your tools, your projects, and the runtime of your software. We integrate with every toolchain that exists and deploy productivity infrastructure for you. That's a more honest answer to the original question than trying to convince everyone to adopt the same build system. The world is not converging on one toolchain, and it doesn't need to. What it needs is a shared layer of infrastructure underneath the ones we already have.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>A different kind of company</title>
      <link>https://pepicrft.me/blog/a-different-kind-of-company/</link>
      <guid>https://pepicrft.me/blog/a-different-kind-of-company/</guid>
      <pubDate>Mon, 27 Apr 2026 08:00:00 +0000</pubDate>
      <description>On the round-to-round game, the stories companies tell users to mask enshittification, and why I want to build a company that puts craft and people before growth at any cost.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Capitalism is weird. It keeps us all busy chasing financial rewards, which sometimes leads to outcomes that are positive for society, but it also creates artificial needs, markets, and dynamics around them, and it's some of those needs and dynamics that have always felt a bit unnatural to me.</p>
<p>To start somewhere, I remember the day someone in the mobile developer tooling market reached out and floated the idea of buying Tuist. What would they buy? Why would they buy it? A week later they came back with a "we don't think your project generation thing will go anywhere, but what if we give you 50$ a month to talk about our company a few times on X." No, I said, we are not influencers. But it turns out that's how some people with access to capital see open source and open source maintainers, as folks who can build strong brands and communities, and who might be persuaded to trade reputation for peanuts. Some companies in this position have wide latitude when it comes to chasing financial goals, and this one was willing to publicly surface other people's mistakes in exchange for eyeballs. They eventually ended up in an exit to a larger company that wanted a presence in the mobile market, the very presence they had manufactured by throwing money at the problem. That is what money lets you do. You can manufacture value and aim for an exit story. A bit sad to see, honestly.</p>
<p>I'm not against raising capital, but I don't relate to the idea of round-to-round jumping as the final game to play. I dislike it because the incentive of pushing valuation up tends to be stronger than bringing real value to the people that use your craft, and at some point the gap becomes so visible that companies have to invent a story to mask what's becoming obvious to everyone, the enshittification. I don't want to be in that position. The position of having promised multiples of a valuation, realizing you can't go beyond the current ceiling, and starting not only to throw darts at ideas but to invent fictional needs and stories that your customers can buy into. That's when you see companies organizing events that look more like a festival, or coining new categories like Mobile DevOps, where even the people pushing the term struggle to define it. <strong>I'm a firm believer that a business' natural growth needs time</strong>, the time you might not have if you raised money and promised to spend it in two years. Only when you have the freedom that perspective gives you, that is when you can make decisions that fit incrementally into the product. Rushing it is a recipe for disaster, and you don't want your users to gain perspective on how absurd the whole thing has gotten. I was reading yesterday about an app that had replaced its core with WebKit after endlessly shipping features, including a subscription-capped note-taking feature, and users were frustrated and going back to their previous app. That's the tension I'm describing. You lay the ground for enshittification.</p>
<p>Because money is sexy. Who doesn't want it? But you don't really get to tell your users about it, because no one likes seeing others get richer, unless we get richer with you, in which case we're vibing, and we can all figure out together how to make you richer. Perhaps it's not about the quality of your app, perhaps you just aren't using these other features I'm offering you. Let's all figure out how to get more people sharing their MRRs on the socials, because that's marketing for me too, so I want more indies building, I don't really care what. Sad to say, but it happens. I said capitalism is odd, and this is once again an example. The craft becomes secondary. It's all about the money. The more and the faster, the better.</p>
<p>And as I said, you don't want to tell your users about it, you need a story. One founder kept insisting that their main focus was delivering value to their users. That sentence kept replaying in my head, because that's what I had always assumed was the point of a company, but after seeing how many companies actually operate, it's not always the case, even when the marketing site says otherwise. As I said earlier, what we need is a good story. Capitalism needs good storytelling, one that can cover the interests living in the back end. <em>Don't run away when I merge acquisitions and water down the product, I'm still here for you.</em> Well, no. You are sold to your investors, you are building for them, and we are just a tool.</p>
<p>We did raise. Tuist wouldn't have got off the ground otherwise, but we were very clear from the start that jumping from round to round was not the game we wanted to play. We'd only raise if we saw the need, and right now we don't, so we keep walking our path from a point of profitability, without the weight of external incentives. It's liberating, especially as you watch other companies around you play a different game. We've already had three conversations around acquihiring us. They never use that word, of course; they prefer <em>"joining forces"</em>, because without us you folks will have a hard time, and that might be fine because you might not want to eat the world like us.</p>
<p>The deeper you go, the more absurd it gets, but I guess it's inherent to doing business with money as the first goal. People will take any shortcut to multiply profits, and what I find funny now is that I can see the two realities clearly. There's the struggle of balancing what your business is actually capable of with what you promised the investors. And then there's the story you tell your users. The strange part is that, in the process, the company often digs the tomb of its own product, even though for the people running it that might still end in an exit. Look at Heroku. But for them, that doesn't really matter.</p>
<p><strong>I think there's value in building a different kind of company.</strong> One that places people and craftsmanship first over growth at any cost. A company that is fine with not capturing 100% of the value, gifting the world with OSS tech that anyone has access to, like cities building public parks. A company that embraces the perspective of time to make incremental changes that genuinely make sense to the users.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Codex feels like the future of editors</title>
      <link>https://pepicrft.me/blog/codex-feels-like-the-future-of-editors/</link>
      <guid>https://pepicrft.me/blog/codex-feels-like-the-future-of-editors/</guid>
      <pubDate>Mon, 20 Apr 2026 08:00:00 +0000</pubDate>
      <description>A rainy Sunday trying Codex made me rethink my terminal-first agent workflow, and made me see a big opportunity for tighter integration with tools like mise and Pitchfork.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Until very recently, my agentic workflow lived almost entirely in the terminal. I use <code>cmux</code>, a Ghostty fork, and I map each workspace to a project. Inside each workspace, I open tabs for different sessions. Because <code>cmux</code> lets me rename both workspaces and tabs, I ended up using naming as state management. It is how I keep track of what each agent is doing, what context belongs to which project, and where I should jump next.</p>
<p>That setup worked well enough that I did not feel much urgency to move to a GUI. I could see where things were heading. OpenAI was clearly investing in graphical environments like Codex, and the push toward worktrees as the right primitive for parallel work made a lot of sense. But I had not felt the need to throw myself into it.</p>
<p>Yesterday I finally did. Rainy Sundays are good for this sort of thing. You open a new tool out of curiosity, expecting a few nice ideas, and suddenly you realize something deeper might be changing.</p>
<h2 id="why-it-clicked">Why it clicked</h2>
<p>The layout is obvious in the best possible way. Sessions on the left. The active coding session in the center. A terminal at the bottom, which I still need to boot services locally. And on the right, the parts of the workflow that usually live in separate windows: diffs, comments, and a browser to interact with the thing I am building.</p>
<p>I think that last part is what surprised me most. I did not feel like I was using an editor with AI bolted onto it. I felt like I was inside the whole loop. Ask the agent to do work. Run or restart services. Inspect changes. Leave feedback. Click into the app. Repeat. <strong>I did not feel the urge to leave Codex.</strong></p>
<p>I had been reading Thomas Ricouard's excitement about this way of working, and I get it now. When people say the editor is changing, this is what they mean. The terminal is still there, which matters to me, but it is no longer the whole experience. It becomes one pane in a larger environment that keeps the entire feedback loop close at hand.</p>
<h2 id="the-integration-opportunity">The integration opportunity</h2>
<p>The more I used it, the more I kept thinking about a big opportunity: tighter integration with the toolchain many of us already love, starting with <a rel="external" href="https://mise.jdx.dev/">mise</a> and its satellite tools.</p>
<p>First, sessions need tools from the system. That is exactly what mise is for. Python, Ruby, Node, and pretty much anything else a project might need. If a repository already describes its toolchain through mise, the editor should be able to lean on that rather than invent another provisioning story.</p>
<p>Second, Codex has the notion of actions, and that aligns beautifully with <code>mise tasks</code>. A repository already knows how to start itself, test itself, lint itself, seed data, or build artifacts. If those tasks exist in <code>mise.toml</code>, Codex could detect them and auto-register them as actions in the UI. That would turn the repository into the source of truth, which is exactly where that knowledge should live.</p>
<p>Third, some projects need services running. A Postgres instance. A cache. A local broker. That is where <a rel="external" href="https://pitchfork.jdx.dev/">Pitchfork</a> gets interesting. It can manage those services, scope them to a session, and even set up a system-level proxy that is bound to that session. If Codex can see that URL, it could hoist it in the UI as a first-class destination. Click it, and you are in the running app without jumping across tools.</p>
<p>What excites me here is not just convenience. It is the chance to make the editor a thin integration layer over tooling we already trust. Not another place where configuration gets duplicated, but a place that reads the project's declared tools, tasks, and services and turns them into a cohesive experience.</p>
<p>I still love the terminal. I still think it is the right substrate for agentic development. But after spending a rainy Sunday with Codex, I no longer think the terminal is the final form. There is a lot of room above it for an integrated environment that keeps sessions, terminals, review, and the browser in one place.</p>
<p>If Codex gets tighter integration with tools like Mise and Pitchfork, I think it becomes even more compelling. Even without that, I have to give credit where it is due. The Codex team is building something that, at least to me right now, feels like the future of editors.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Agentic productivity</title>
      <link>https://pepicrft.me/blog/agentic-productivity/</link>
      <guid>https://pepicrft.me/blog/agentic-productivity/</guid>
      <pubDate>Fri, 27 Mar 2026 08:00:00 +0000</pubDate>
      <description>We have the data from builds and test runs. We have the agent primitives in Elixir. Now we are connecting them into something that can actively improve your developer workflows, not just report on them.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Something has been clicking into place for me over the past few weeks. At <a rel="external" href="https://tuist.dev">Tuist</a>, we sit on a lot of data. Build telemetry, test run results, project configurations, dependency graphs. We have been collecting and surfacing this information for a while now, and it is genuinely useful. Teams look at their dashboards, find the slow spots, fix things. But there is a gap between <strong>showing someone a problem and solving it for them</strong>.</p>
<p>That gap is where I think the next chapter of what we are building lives. If we have the data, and we understand the toolchains deeply enough to know what the data means, why are we stopping at dashboards? Why not act on it?</p>
<h2 id="the-platform-team-you-do-not-have">The platform team you do not have</h2>
<p>Most companies above a certain size have a platform team. A group of engineers whose job is to make everyone else more productive. They look at build times, investigate flaky tests, optimize CI pipelines, maintain shared infrastructure. They are the people who care about the things that no feature team has time to care about.</p>
<p>The problem is that most companies are not above that certain size. They do not have a platform team. They do not have someone whose job is to notice that a test suite has been getting slower by two seconds every week for the past three months. They do not have someone who catches that a specific module is being recompiled unnecessarily because of a misconfigured dependency. These things just accumulate silently until one day the build takes twenty minutes and nobody remembers when it started being this slow.</p>
<p>What we realized is that the data we already have from builds and test runs, combined with the context we have from the project structure, gives us everything we need to play that role. <strong>We can be the platform team.</strong> Not as a consulting engagement, not as a one-time audit, but as something that is always running, always watching, always ready to act. And the exciting part is that this makes the <strong>platform team accessible to any company</strong>, no matter how small.</p>
<h2 id="from-dashboards-to-actions">From dashboards to actions</h2>
<p>Everyone in the developer tools space is starting to think about agents, but they are thinking about it differently depending on where they sit. <a rel="external" href="https://linear.app/">Linear</a> is exploring agents that can act on issues and look at code. <a rel="external" href="https://openai.com/codex/">Codex</a> and <a rel="external" href="https://claude.ai/code">Claude Code</a> are building agents that write and modify code directly. These are valuable directions, but they are all converging on code as the thing the agent acts on.</p>
<p>I think there is an underexplored space next to that. <strong>Not acting on code, but acting on productivity.</strong> Using the signals from builds and test runs to trigger workflows that actively improve the state of things. If we detect a flaky test, do not just flag it. Quarantine it, investigate it, propose a fix. If we see a build graph that is not making good use of available parallelism, suggest the structural change that would fix it. If a dependency update introduces a regression in compile times, catch it before it lands.</p>
<p>I do not know if there is an established term for this yet, but I have been calling it <strong>agentic productivity</strong>. The idea that an agent does not just help you write code, it helps you maintain the health of your entire development workflow.</p>
<h2 id="building-the-pieces-in-elixir">Building the pieces in Elixir</h2>
<p>Because this is the direction we are heading, I have been spending time building the foundational pieces. Our server runs on <a rel="external" href="https://elixir-lang.org/">Elixir</a>, and I wanted to understand what it would take to build agent workflows natively in that ecosystem. Not just call an LLM API, but build something that feels right in Elixir and takes advantage of what the platform gives you.</p>
<p>The first thing I needed was a place for the agent to work. If you are going to have an agent that acts on a repository, cloning it, running commands, reading files, making changes, it needs a sandbox. A disposable environment where it can do its thing without affecting anything else. I looked at the landscape of sandbox providers and found a lot of options: <a rel="external" href="https://www.daytona.io/">Daytona</a>, <a rel="external" href="https://exe.dev/">Exe</a>, and others. They are all converging on a similar model. You spin one up, do your work, tear it down. Fast and ephemeral.</p>
<p>But they all have slightly different APIs, and I did not want to couple our agent infrastructure to any single provider. So I built an Elixir package I am calling <a rel="external" href="https://hex.pm/packages/terrarium">:terrarium</a>. It is an abstraction layer over sandbox providers, a unified interface with adapters. You configure your credentials, pick a provider, and you get a consistent API to create a sandbox, SSH into it, run commands, stream output, and destroy it when you are done. I built adapters for <a rel="external" href="https://hex.pm/packages/terrarium_daytona">:terrarium_daytona</a> and <a rel="external" href="https://hex.pm/packages/terrarium_exe">:terrarium_exe</a> to start with, but the interface is designed so that adding more is straightforward.</p>
<p>This matters for us in particular because none of these providers offer macOS environments. And most of our customers are working with Xcode. So we are also working on being able to provide those environments ourselves, which is something we need regardless for the broader compute story at Tuist. Having Terrarium as the abstraction means our own macOS sandboxes slot in through the same interface as any third-party provider.</p>
<h2 id="the-agent-itself">The agent itself</h2>
<p>On top of the sandbox layer, I built the agent. I am calling it <a rel="external" href="https://hex.pm/packages/condukt">:condukt</a>. It is a GenServer in Elixir, which is the natural way to model a long-running, stateful process in the BEAM ecosystem. At its core, an agent is a loop with tools. You give it a prompt, it reasons about what to do, it picks a tool, it executes it, it observes the result, and it loops again until it is done.</p>
<p>For the LLM interaction, I am using <a rel="external" href="https://hex.pm/packages/req_llm">:req_llm</a>, a library that abstracts over different providers. The same fragmentation problem exists there: Anthropic, OpenAI, Google, they all have slightly different APIs for doing essentially the same thing. A unified interface lets us swap providers without rewriting the agent logic.</p>
<p>The tools are what you would expect. Execute a command, read a file, write a file. I drew inspiration from how <a rel="external" href="https://claude.ai/code">Claude Code</a> structures its tool set. It is a simple and effective model. I also added a browser tool, built as a separate Elixir package called <a rel="external" href="https://hex.pm/packages/browse">:browse</a>, which can drive a web browser so the agent can navigate and extract information from the web. I even built a variant using the <a rel="external" href="https://servo.org/">Servo</a> engine for lightweight rendering.</p>
<p>What makes this feel good in Elixir is how naturally the pieces compose. A GenServer for the agent. Adapters for LLM providers. Behaviours for tools. Telemetry for observability. These are all patterns the ecosystem already has strong conventions for. You are not fighting the language to build this; you are leaning into it.</p>
<h2 id="connecting-the-layers">Connecting the layers</h2>
<p>Here is where it gets interesting. The agent itself needs to run somewhere, and the somewhere matters. If you are going to clone a repository, run builds, execute tests, you want that happening in a sandbox, not on whatever machine is hosting the agent process. So the architecture has <strong>two layers of remote execution</strong>. The agent logic runs as an Elixir process, possibly on our infrastructure. The actual work, the file operations, the shell commands, happen inside a sandbox provisioned through Terrarium.</p>
<p>From the developer's perspective, it should feel like the agent is just doing its thing. You give it a task, it reports back when it is done. But behind the scenes, it spun up a sandbox, cloned the repository, did its work, and cleaned up. The sandbox is gone. <strong>The only thing that remains is the result.</strong></p>
<p>The primitives that Erlang and Elixir give you make this easy to model. Processes, message passing, supervision trees. You can represent the entire lifecycle of an agent session as a supervised process tree that starts, does work, and shuts down cleanly. If something crashes, the supervisor handles it. If the sandbox provider has an issue, the adapter can retry or fail gracefully. All of this composes in ways that feel natural rather than bolted on.</p>
<h2 id="toward-a-workflow-language">Toward a workflow language</h2>
<p>Once these building blocks are in place, something else starts to become possible. Right now, you interact with an agent by giving it a prompt. That works for ad hoc tasks, but what we are building toward at Tuist is not ad hoc. We want workflows that run in response to signals. When a flaky test is detected, run this. When build times regress past a threshold, investigate that. When a new dependency is added, check its impact.</p>
<p>This is where I want to explore something more structured. A way to describe productivity workflows that live in the repository, right next to the code they care about. Something that combines <strong>deterministic steps with non-deterministic ones</strong>. A pipeline where some steps are plain shell commands and others are prompts that an agent reasons through.</p>
<p>If you think about it, CI pipelines are the closest thing we have to this today. A sequence of deterministic steps triggered by a git event. What I am imagining is that concept extended in two directions: adding non-deterministic steps powered by an agent, and expanding the set of triggers beyond git events to include signals from build telemetry, test results, and other data we already collect.</p>
<p>Elixir is particularly well suited for this because of macros. Macros in Elixir let you build expressive DSLs that are still just Elixir under the hood. You get the readability of a declarative language with the full power of a general-purpose one. I have not landed on the exact API yet, but the idea is that you would describe a workflow in an Elixir script, and the system would interpret and execute it. <strong>No YAML.</strong> I have seen implementations of similar concepts using YAML, and I think they always end up fighting the format. YAML is fine for static configuration, but the moment you need conditionals, loops, or any kind of dynamic behavior, it becomes painful. Elixir scripts can be evaluated at runtime, which gives us a much more natural foundation.</p>
<h2 id="putting-it-all-together">Putting it all together</h2>
<p>What excites me about all of this is how the pieces connect. We have the data from builds and test runs. We have the sandbox infrastructure to give agents a safe place to work. We have the agent framework to orchestrate reasoning and tool use. And soon, we will have a way to describe workflows that tie it all together.</p>
<p>The vision is that Tuist becomes something that does not just observe your development workflow but actively participates in improving it. Not by writing your features for you, that is what coding agents are for, but by maintaining the health and speed of everything around the code. The plumbing. The infrastructure. The things that a platform team would handle if you had one.</p>
<p>I will share more as these pieces mature. For now, the foundations are coming together, and the thing I keep coming back to is how well Elixir fits this problem space. The concurrency model, the process architecture, the metaprogramming capabilities. It feels like the right tool for building the kind of system where agents, sandboxes, and workflows all need to work together reliably. I am glad we bet on it years ago when we started building the Tuist server.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The idea exchange</title>
      <link>https://pepicrft.me/blog/the-idea-exchange/</link>
      <guid>https://pepicrft.me/blog/the-idea-exchange/</guid>
      <pubDate>Thu, 26 Mar 2026 08:00:00 +0000</pubDate>
      <description>When the only input your company accepts is through paying customers, you limit your ceiling to a small pool of ideas. Open communities create a different kind of exchange, one that compounds in ways money can&#x27;t measure.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There is something I keep thinking about when I look at how companies try to get better at what they do. The default assumption is that improvement comes from within. You hire smart people, you listen to your customers, you study the market, and you iterate. That's the playbook. And it works, to a point.</p>
<p>But I think the companies that are positioned to build something truly great are the ones that go beyond that loop. The ones that create spaces where people can share their needs, their frustrations, their ideas. Not just customers. Not just employees. Anyone.</p>
<h2 id="the-space-before-the-product">The space before the product</h2>
<p>Open source companies, or companies that operate in the open more broadly, have an interesting advantage here. They usually start by building the space. The community. The culture of sharing. Before they even have a product worth paying for, they have people showing up and contributing ideas, reporting problems, suggesting directions. People get used to participating. It becomes natural.</p>
<p>What's beautiful about this is that the pool of ideas is no longer limited to who you hired or who signed a contract. You open yourself to a diversity of perspectives that you could never assemble internally. The people in your community come from different industries, different countries, different problem spaces. They see things you don't. They need things you haven't imagined. And if you've built the right kind of space, they tell you about it.</p>
<p>This is something we experience at Tuist all the time. Someone shows up and contributes a feature we never would have prioritized. Someone reports a bug in a workflow we didn't know existed. Someone translates part of our dashboard into a language we don't speak. These things happen because the door is open.</p>
<h2 id="the-myopia-of-pure-monetization">The myopia of pure monetization</h2>
<p>Here is where it gets interesting for me. If your company exists to make money, and most companies do, capitalism has a way of narrowing your vision. The pressure from investors, the need for hyper-growth, the quarterly targets, all of it pushes you toward capitalizing on everything you can. Every interaction becomes a potential transaction. Every feature becomes a pricing lever.</p>
<p>At some point, it stops being about what your people need and starts being about what you need. And what you usually need is growth that satisfies the expectations you set with your investors. The product becomes a vehicle for revenue extraction rather than a tool that genuinely serves people.</p>
<p>I think this is where a lot of companies lose the plot. They build free trials and gated features and sales funnels, and they optimize every step of the conversion pipeline. But the only input they accept is from people who are already paying or who might pay soon. Everyone else is noise.</p>
<p>And that means they are missing out on the most creative, most unexpected, most valuable ideas. Because those ideas often come from people who have no commercial relationship with you at all. They come from someone who stumbled into your community because they were curious. From someone in a completely different field who saw an interesting parallel. From someone who just wanted to help because they believe in what you're doing.</p>
<h2 id="what-you-get-back">What you get back</h2>
<p>I'll be honest, it feels odd at first. Doing something and not expecting money back. Building something and giving it away. Investing time in people who may never become customers. It goes against everything the business world tells you to do.</p>
<p>But I think there is something powerful that happens when you allow for a different kind of exchange. What you get back is not money. It's ideas. It's bugs that would never have been reported otherwise. It's people going out into the world and sharing how happy they are using your tool. It's someone writing about you not because you paid them, but because they genuinely care.</p>
<p>None of this is directly measurable. You can't put it on a dashboard and say "this contributed X dollars to revenue." You can't attribute it to a marketing campaign. But it compounds. It compounds in ways that are hard to see in the short term but become undeniable over time. The trust builds. The community grows. The ideas keep flowing. And when you finally do build something worth paying for, you have an audience that already believes in you.</p>
<h2 id="the-ceiling-problem">The ceiling problem</h2>
<p>When the only input into your company comes through your customers and your employees, you have a ceiling. You might not feel it right away. The ideas might be good enough for a while. But over time, the pool gets shallow. You start telling the same story to your investors about increasing value for existing customers. You optimize what you have instead of imagining what you could have.</p>
<p>And then one day you need to expand into a new market, and you realize you don't have the people. You don't have the community. You don't have the go-to-market. Because you spent years building walls instead of doors.</p>
<p>I think people say that open source is riskier than ever, especially now with AI making it cheaper to replicate software. But I actually think it's more powerful than ever. Because through communities and people putting creative energy into different problem spaces, new business ideas emerge. Ideas you could never have generated internally. If you are completely closed, you are betting that the smartest people in the room are already in the room. And that's rarely true.</p>
<h2 id="a-different-kind-of-company">A different kind of company</h2>
<p>I'm not saying you can disregard money entirely. There are people to pay, services to run, infrastructure to maintain. A company needs revenue to survive. But when every interaction is purely a monetary transaction, when you can't invest in something unless you can immediately capitalize on it, you close yourself off from the most interesting possibilities.</p>
<p>The free trial model, the gated feature model, the "talk to sales" model, they all assume that the only valuable exchange is a financial one. I think that assumption is wrong. And I think the companies that challenge it, that find a healthy balance between commercial sustainability and genuine openness, are the ones that will build the most creative, most innovative, most lasting products.</p>
<p>This is something I keep noticing. And it makes me wonder why more companies don't see it.</p>
<p>The pieces are there. The communities are willing. The ideas are waiting. You just have to be open enough to receive them.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Scoping dev environments to clones</title>
      <link>https://pepicrft.me/blog/scoping-dev-environments-to-clones/</link>
      <guid>https://pepicrft.me/blog/scoping-dev-environments-to-clones/</guid>
      <pubDate>Wed, 25 Mar 2026 08:00:00 +0000</pubDate>
      <description>When your team works with multiple clones of the same repository, global resources like ports and databases start to conflict. Here is how we solved it at Tuist using mise and a simple random suffix.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Something we noticed at <a rel="external" href="https://tuist.dev">Tuist</a> is that most of the team works with several copies and clones of the repository. This is natural when you are juggling different features, reviewing pull requests, or keeping a clean main branch alongside work-in-progress branches. But it became problematic when it came to running the server locally.</p>
<p>The issue is global resources. Ports, for instance. We run more than one server locally, the main <a rel="external" href="https://www.phoenixframework.org/">Phoenix</a> application, a local S3 server, and a few other services. Each of them needs its own port. And then there are database names in <a rel="external" href="https://www.postgresql.org/">PostgreSQL</a> and <a rel="external" href="https://clickhouse.com/">ClickHouse</a>. All of these are named, and if two clones try to use the same ports and database names, things break in confusing ways. You end up with one clone's server stepping on another's data, or port conflicts that force you to hunt down which process is holding what.</p>
<h2 id="the-idea">The idea</h2>
<p>We wanted a way to scope each clone to its own set of ports and database names. No manual configuration, no remembering to change environment variables when switching between clones. It should just work.</p>
<p>The solution we came up with uses <a rel="external" href="https://mise.jdx.dev/">mise</a>. In our <code>mise.toml</code>, we source a shell script that lazily creates a small piece of state in the repository:</p>
<pre><code data-lang="toml">[env]
    _.source = &quot;{{config_root}}/mise/utilities/dev_instance_env.sh&quot;
</code></pre>
<p>The script checks for a file called <code>.tuist-dev-instance</code> at the repository root. If it does not exist, it generates a random number between 100 and 999 and writes it there. If it already exists, it reads the number back. The file is in <code>.gitignore</code>, so each clone gets its own.</p>
<pre><code data-lang="bash">suffix=&quot;$(ensure_suffix)&quot;

export TUIST_DEV_INSTANCE=&quot;${suffix}&quot;
export TUIST_SERVER_PORT=&quot;$((8080 + suffix))&quot;
export TUIST_SERVER_URL=&quot;http://localhost:${TUIST_SERVER_PORT}&quot;
export TUIST_SERVER_POSTGRES_DB=&quot;tuist_development_${suffix}&quot;
export TUIST_CACHE_PORT=&quot;$((8087 + suffix))&quot;
export TUIST_MINIO_API_PORT=&quot;$((9095 + suffix))&quot;
</code></pre>
<p>That is it. Every port becomes a base port plus the suffix. Every database name gets the suffix appended. The probability of two clones picking the same random number is low enough that in practice it never happens.</p>
<h2 id="why-it-works">Why it works</h2>
<p>The beauty of this approach is that it requires zero thought from the developer. You clone the repository, you run <code>mise install</code>, you start the server, and everything just works. The first time mise activates, it sources the script, the script generates the suffix, and from that point on every environment variable is scoped to that clone.</p>
<p>In my case, I have six clones of Tuist on my machine. I can have six Phoenix applications running simultaneously, each with its own ports and its own databases, completely unaware of each other. There is no coordination needed. No shared configuration file to update. No "make sure you change the port before starting."</p>
<p>The environment variables flow naturally into the application configuration. In <code>runtime.exs</code>, the Phoenix server reads the port from the environment:</p>
<pre><code data-lang="elixir">port =
  if env == :dev do
    String.to_integer(System.get_env(&quot;TUIST_SERVER_PORT&quot;) || &quot;8080&quot;)
  else
    8080
  end
</code></pre>
<p>And the same pattern applies to test databases, storage directories, and any other resource that needs to be isolated.</p>
<h2 id="the-small-details">The small details</h2>
<p>A few things that make this work smoothly in practice. The suffix is validated to be a number between 1 and 999, so the port ranges stay within reasonable bounds. You can also override it by setting <code>TUIST_DEV_INSTANCE</code> as an environment variable, which is useful if you want deterministic values in CI or for debugging. And the script is careful about shell compatibility, working in both Bash and Zsh.</p>
<p>If you are dealing with something similar, consider giving this pattern a try. It is simple, and it works.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The portability illusion</title>
      <link>https://pepicrft.me/blog/the-portability-illusion/</link>
      <guid>https://pepicrft.me/blog/the-portability-illusion/</guid>
      <pubDate>Wed, 25 Mar 2026 08:00:00 +0000</pubDate>
      <description>Cloud development environments keep getting rebranded, but they keep running into the same fundamental problem: your workflow is not portable. Agents might be changing the question entirely.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There is something interesting happening with where coding is going to happen. Not just which editor or which language, but where, physically, the act of writing and running code takes place. And I think the way the industry is approaching it reveals a lot about the difference between solving real problems and finding things to monetize.</p>
<h2 id="the-granularity-of-billing">The granularity of billing</h2>
<p>Our industry has a well-known preference for subscriptions over single payments. But it goes further than that. Over time, the unit of billing has become more and more granular. We went from annual licenses to monthly subscriptions to per-seat pricing, and now we are seeing models built around tokens, compute minutes, and individual API calls. There is a constant search for the smallest possible unit of value that can be metered and charged for.</p>
<p>I understand this from a business perspective. If you can identify a granular unit that maps to usage, you can build a pricing model that scales with your customers. But sometimes this search for the perfect billing unit leads to models that feel very forced. And I think one area where this is happening right now is the push to sell cloud development environments as the place where coding should happen.</p>
<h2 id="the-three-environments">The three environments</h2>
<p>For a very long time, development has happened across three environments. Your local machine, where you write and test code. CI, where changes get integrated and validated. And production, where the software actually runs. Each one has different requirements. Your local machine needs a lot of CPU and memory because you are doing compilations, running tests, switching branches, juggling tools. Production servers mostly handle I/O, so unless the workload is very compute-intensive or very critical, they do not need the same kind of raw power. CI sits somewhere in between, optimized for throughput and parallelism.</p>
<p>This model has worked well for decades. But some time ago, a new idea started gaining traction: what if coding did not happen locally at all? What if there was a fourth environment, a remote machine where the development itself takes place?</p>
<h2 id="the-idea-that-keeps-coming-back">The idea that keeps coming back</h2>
<p>The first serious attempt at this that I remember was <a rel="external" href="https://www.gitpod.io/">Gitpod</a>. Then came <a rel="external" href="https://github.com/features/codespaces">GitHub Codespaces</a>. The pitch was compelling on paper. You no longer code on your machine. You code on a remote server, and the browser is the interface to that environment. It helped that <a rel="external" href="https://code.visualstudio.com/">VS Code</a> was designed to be embeddable on the web, so you could get a familiar editor experience running entirely in the browser.</p>
<p>The promise was appealing. You have a terminal, you have your files, you can browse them, you can run the server, connect to it. It all works. And from a business perspective, it is elegant. You can monetize as many minutes as the developer uses. On top of that, you can layer features that enterprises care about: auditing, telemetry, network firewalls, visibility into outgoing connections, security controls. It sounds like a perfect product.</p>
<p>But it never quite worked. <a rel="external" href="https://www.shopify.com/">Shopify</a> spent years trying to enable a system like this for their developers and eventually pulled back. They recently rebranded the effort into something new, and while we do not know all the details, the fact that it needed a reinvention suggests something fundamental was not clicking.</p>
<h2 id="the-portability-problem">The portability problem</h2>
<p>I think all of these attempts missed a very important detail. You can port the editor. You can have a VS Code or VS Code-like interface in the browser. You can provide a terminal. You can provide the code. You can give people everything that looks like a development environment. But there is one thing that is not portable: your preferences, your tools, your entire workflow.</p>
<p>As a developer, I have accumulated years of configuration. My shell setup, my dotfiles, my CLI tools, my editor plugins, the way I have things wired together. And increasingly, things like MCP servers and other integrations that connect my tools to external services. None of that travels with you to a remote environment. You can bring some of it, but never all of it. The moment you find yourself jumping between the remote environment and your local machine because something is missing, that is when you say "forget it, I would rather do everything locally where I know I have everything and just push when I am done."</p>
<p>This is the fundamental tension. These environments can replicate the visible parts of development, the editor, the terminal, the file system. But they cannot replicate the invisible parts, the accumulated workflow that each developer builds over years. And it is the invisible parts that make developers productive.</p>
<h2 id="the-sandbox-rush">The sandbox rush</h2>
<p>What I see happening now is a variation of the same theme. There are many companies providing sandbox environments, containers where code can run in isolation. And they need to sell them. Some of them raised money on the premise that agentic workflows would need sandboxes, that AI agents would need somewhere to execute code, and that this would be the next big infrastructure market.</p>
<p>I get it. The logic makes sense on a pitch deck. But I think the long-term picture is less clear than it seems. I do not think companies building agentic workflows will rely on third-party sandboxes forever. If some are using them today, it is because they need to move fast and would rather buy a solution than build one. That is a reasonable short-term decision. But sandboxes are not a particularly defensible business. The technology is well understood. It can get commoditized quickly. And the companies with the most resources to build agents, like <a rel="external" href="https://openai.com">OpenAI</a> and <a rel="external" href="https://www.anthropic.com">Anthropic</a>, have every incentive and every capability to run their own infrastructure. What would prevent them from deploying their own sandboxes? Nothing, really.</p>
<p>So if you are building a sandbox company, you need to jump to something else quickly, something more creative, something harder to replicate. Otherwise you end up competing on price for a commodity.</p>
<h2 id="where-is-the-innovation">Where is the innovation?</h2>
<p>This is the part that makes me a bit sad, honestly. I was watching a demo the other day where someone showed a browser-based environment, spun up a container, compiled some code, and ran it. And I thought, "So what?" The capabilities we have today are genuinely amazing. Large language models can reason about code, suggest changes, catch bugs, write tests. The foundational infrastructure for running code in the cloud is solid and getting cheaper. All the pieces are there for something truly creative to emerge.</p>
<p>And yet, a lot of what I see is just repackaging the same cloud development environment idea with a new label. New branding, same concept. I would love to see more ambition.</p>
<p>The places where I do see genuinely interesting ideas are products like <a rel="external" href="https://openai.com/codex/">Codex</a> and <a rel="external" href="https://claude.ai/code">Claude Code</a>. The idea that you start coding locally, or even from your phone, and the session continues elsewhere. That there is a seamless transition from one context to another. Sure, I do not see myself doing that for every single task, but for debugging an issue, or having a conversation about something with the full context of the codebase, that can be incredibly useful.</p>
<p>But this kind of experience requires investing in user-facing software. A polished desktop app, a mobile client, a thoughtful interface that makes the transition feel natural. These are hard things to build, and they require a very different set of skills than spinning up containers. The sandbox companies are not going to invest there. They end up in this awkward position where they need to sell their infrastructure, they want to sell it because that is the promise they made to their investors, but the real innovation is happening at a layer above them that they do not control.</p>
<h2 id="agents-change-the-question">Agents change the question</h2>
<p>The funny thing is that I think agents are quietly changing the entire question. The old framing was "where does the developer code?" and the answer was supposed to be "in our cloud environment." But agents do not need a cloud IDE. They do not need VS Code in the browser. They do not care about your font size or your color scheme. They need a terminal, access to the codebase, and the ability to run commands. The environment requirements for an agent are radically simpler than for a human developer.</p>
<p>This means the portability problem that killed cloud development environments for humans does not apply in the same way to agents. An agent does not have twenty years of dotfiles and shell customizations. It does not need its favorite editor plugins. It just needs to execute.</p>
<p>And this is where things get interesting, because if the agent can work in any environment, then the value is not in the environment. It is in everything else. The toolchain optimizations that make the agent's work faster. The caching layer that prevents redundant builds. The intelligence that knows what to skip and what to rebuild. The seamless experience that lets a developer kick off an agent session from anywhere and get results back without thinking about where the computation happened.</p>
<p>The companies that understand this will build at the layer where the real value lives. The ones that are stuck trying to sell sandboxes will keep looking for someone to buy them.</p>
<h2 id="building-means-not-ends">Building means, not ends</h2>
<p>At <a rel="external" href="https://tuist.dev">Tuist</a>, we think about this a lot. We need compute capabilities, and we are building them. But compute is not what we are selling. It is a means to an end. The end is making developers and their tools faster, wherever they happen to be running. We want to build these capabilities and share them with the community, because the sandbox itself was never the interesting problem. The interesting problem is what you do with it.</p>
<p>I would love to see more of the industry think this way. Less rushing to monetize infrastructure for the sake of monetizing it, and more thinking about what genuinely new experiences become possible when you combine powerful models with fast toolchains and seamless transitions between environments. The pieces are all there. We just need the appetite to put them together in ways that actually surprise people.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The tolerance shift</title>
      <link>https://pepicrft.me/blog/the-tolerance-shift/</link>
      <guid>https://pepicrft.me/blog/the-tolerance-shift/</guid>
      <pubDate>Wed, 18 Mar 2026 08:00:00 +0000</pubDate>
      <description>Coding agents are making developers and organizations less tolerant of slow toolchains. That shift in tolerance is opening a door that was surprisingly hard to open before.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There is something I keep running into when talking to engineering organizations about productivity: most of them do not really appreciate the problem. They know their builds are slow. They know their CI takes too long. They know developers lose time waiting. But it rarely rises to the level of something worth solving with intention. It is background noise. A tax they have learned to live with.</p>
<p>This is surprisingly common. Unless you operate in a very competitive market where you do not dominate, where saving a minute or even seconds translates into a real edge, productivity tends to sit somewhere near the bottom of the priority list. People acknowledge it, nod when you bring it up, and then move on to the next feature request.</p>
<p>For us at <a rel="external" href="https://tuist.dev">Tuist</a>, this has always been a challenge. If organizations do not appreciate the problem, they do not see the value in investing in a solution. And if they do not see the value, they certainly do not see the point in paying for one.</p>
<h2 id="the-reflex-to-throw-resources-at-it">The reflex to throw resources at it</h2>
<p>When organizations finally do start feeling the pain, their first instinct is almost always the same: throw resources at it. Hire more engineers. Buy faster laptops. Provision beefier CI machines. These are tangible, visible investments. You can point at a new M4 Max sitting on someone's desk and feel like you did something.</p>
<p>There is actually a well-known pattern behind this. Behavioral economists call it the <strong>tangibility bias</strong>: people systematically overvalue things they can see and touch relative to intangible alternatives. A new machine feels like progress. A software tool that makes all your existing machines faster feels like an expense. Organizations also tend to prefer capital expenditures over operational ones, because buying hardware looks like growth on a balance sheet, while paying for a tool that optimizes what you already have looks like admitting something is broken.</p>
<p>The irony is hard to miss. These same organizations will happily spend hundreds of thousands on new hires and faster compute, but if you tell them "I can make everything you already have significantly faster," they think it is too expensive. They want speed, but only if it comes in a form they can physically see.</p>
<h2 id="agents-are-changing-the-equation">Agents are changing the equation</h2>
<p>Here is where things get interesting. I think coding agents are quietly reshaping how people think about this.</p>
<p>When you use a coding agent, you get used to a rhythm: you prompt, you wait for inference, the agent does its work, you review. The total cycle time is a combination of inference time and toolchain time. The time the model spends thinking, plus the time it takes to compile, run tests, lint, or whatever else the toolchain demands.</p>
<p>If you have used agents with languages like Python or JavaScript, you know that the inference piece dominates the cycle. The toolchain is fast. Feedback comes quickly. The experience feels fluid.</p>
<p>Now try that same workflow with a compiled language. Swift with Xcode. Kotlin or Java with Gradle. Suddenly, everything feels painfully slow. Not because the agent is slower, but because the toolchain adds minutes where you used to wait seconds. And because you have already experienced what fast feels like with other languages, your tolerance has shifted. What was once an acceptable wait now feels broken.</p>
<p>This is the shift I find fascinating. <strong>Agents are training developers to expect faster feedback loops.</strong> And once that expectation is set, it is very hard to go back. The frustration compounds because you know the slowness is not fundamental. It is not physics. It is the toolchain. It is fixable.</p>
<h2 id="two-layers-of-the-solution">Two layers of the solution</h2>
<p>Once you accept that the toolchain is the bottleneck, there are really two layers where you can attack the problem.</p>
<p>The first layer is compute. Faster CI machines, faster laptops, faster cloud environments for agents. This is the obvious one, and it works up to a point. But it has a ceiling. You can buy the most powerful machine available and your build still takes however long it takes to recompile everything from scratch. On top of that, compute resources are usually shared. You want good utilization to keep costs reasonable, which means resource contention, which means you cannot just throw infinite cores at the problem.</p>
<p>The second layer is the toolchain runtime. This is where you cache build artifacts so you never rebuild what has not changed. Where you identify and fix flaky tests so agents stop retrying them endlessly. Where you eliminate redundant work in the build graph. Where you are selective about what gets compiled and what gets skipped.</p>
<p>This second layer is more powerful. It is cheaper. It is more flexible. You can take it anywhere because it is not coupled to a particular machine or environment. It works on your laptop, on CI, in whatever sandbox an agent is running in. It solves the problem at a fundamental level rather than throwing hardware at symptoms.</p>
<h2 id="the-coupling-problem">The coupling problem</h2>
<p>This brings me to something I have been thinking about a lot. Many companies that provide CI or development environments bundle their runtime optimizations with their compute. They offer caching, build optimization, test insights, and on paper you can plug them into other environments too. But the system design is deeply coupled to their own infrastructure. When you try to use it outside of their environment, the latency is high, the effectiveness drops, and the experience is nothing like what they advertise. Sure, you can technically plug it in. But the plug does not deliver what you would expect as a developer.</p>
<p>I understand why they design it this way. Compute is where the money is. You monetize CPU minutes, memory, storage. Why would you optimize for environments you do not control?</p>
<p>But I think this model is heading for trouble. The future of compute is fragmented by design. OpenAI runs <a rel="external" href="https://openai.com/codex/">Codex</a> in its own containers. Anthropic will have its own agent environments. <a rel="external" href="https://linear.app/">Linear</a> is already running agentic workflows in their own infrastructure. <a rel="external" href="https://sentry.io/">Sentry</a> is too. Every tool in the chain wants to own execution. No single player is going to control where all development happens.</p>
<p>If your runtime optimizations only work well in your environment, you are betting on a future where you are the only environment. That is an unrealistic bet. And from the other side, why would OpenAI or Anthropic give away their compute revenue to a third-party environment provider? They have every incentive to run things themselves.</p>
<h2 id="the-clean-build-problem">The clean build problem</h2>
<p>There is another dimension to this fragmentation that does not get enough attention: incremental builds. On a developer's laptop, builds are incremental by default. You change a file, the compiler rebuilds only what depends on it. This is fast because state persists between builds. Your derived data, your intermediate artifacts, they are all sitting there from the last run.</p>
<p>But when Codex compiles your Swift project in a fresh container, or when a CI runner picks up a job on a clean machine, that state is gone. Every build is a clean build. Everything gets recompiled from scratch. This is where the toolchain slowness becomes most brutal, and it is exactly the environment where agents are increasingly doing their work.</p>
<p>The solution is to bring incrementality across environments. Not just within a single machine, but across local development, CI, and agentic workflows. When an agent runs a build in a remote sandbox, it should be able to pull cached artifacts from a previous build, whether that build happened on your laptop, on CI, or in another agent session. The build should feel incremental even when the environment is ephemeral.</p>
<p>This is not a simple problem to solve. It requires a deep and complex system design for the cache infrastructure. You need content-addressable storage, fine-grained dependency tracking, and a distributed system that can serve artifacts with low latency from wherever the build is happening. It also requires a decentralized architecture where pieces of the system can escape a centralized model and be brought closer to the compute. Sometimes that means a cache node in the same data center as your CI runners. Sometimes it means a node in your office, close to where your team develops every day. The system needs to support all of these topologies without forcing you into a single deployment model.</p>
<h2 id="going-deep-where-others-do-not">Going deep where others do not</h2>
<p>This is where I think Tuist can bring something genuinely different to the table. As Peter Steinberger once said, doing interesting things that are hard is what positions you strongly as a business. And the runtime optimization space is exactly that: interesting, hard, and largely ignored.</p>
<p>There are some players focused on specific ecosystems, like <a rel="external" href="https://bazel.build/">Bazel</a>. <a rel="external" href="https://gradle.org/">Gradle</a> is expanding beyond its own build system with Develocity. CI companies are adding value layers on top of their runners. But most of these efforts are shallow, or tightly coupled to a specific environment, or both.</p>
<p>What we are doing at Tuist is going deep into every ecosystem we touch. Not surface-level integrations. Deep understanding of how each toolchain works, where it breaks, what makes it slow, and how to fix it. We cross-pollinate ideas across ecosystems, bringing optimizations from one world into another. We expose APIs for everything. We invest in documentation and developer resources. We use the tools ourselves, every single day.</p>
<p>The vision is to become your platform team, offered as a service. We want to get to a point where we actively monitor your projects, your workflows, your setup, and proactively make sure things are fast. Whether you are coding locally, asking an agent to do it on your machine, or running that agent remotely in some cloud sandbox. The optimizations travel with your project, not with your infrastructure.</p>
<h2 id="building-the-network">Building the network</h2>
<p>If I draw a connection to another company, I think about <a rel="external" href="https://www.cloudflare.com/">Cloudflare</a> and how they solved the problem of bringing computation close to where it is needed. Their Workers run at the edge, close to the user making the HTTP request. The function does not live in a single data center waiting for traffic to arrive. It lives everywhere, and the system routes you to the nearest one. That model is what inspires how we think about cache infrastructure at Tuist, but applied to development. Instead of running functions close to your end users, we run cache nodes close to where the development is happening. Close to your CI runners. Close to the agent sandbox. Close to your office.</p>
<p>This requires a different kind of infrastructure. Global. Low-latency. Decentralized by design. The system needs to let organizations bring cache nodes into their own environments when that is what makes sense. Not every team wants their build artifacts traveling across the internet to a centralized service. Some want a node in their own network, in their own data center, or even in their office. The flexibility to support that, while still providing a managed experience for teams that do not want to think about infrastructure, is what makes this problem hard and interesting.</p>
<p>But the pieces are coming together. Telemetry to understand what is actually slow. Cache infrastructure to eliminate redundant work. Deep toolchain integration to know what to cache, what to skip, and what needs to change in your project. Sometimes the optimization is not just adding a cache. Sometimes it is telling you that a specific configuration in your project is causing unnecessary recompilation, or that a dependency is pulling in work you do not need. All of that requires the kind of depth that you can only build by being genuinely obsessed with the problem.</p>
<h2 id="the-window-is-open">The window is open</h2>
<p>What excites me most about this moment is the convergence. Agents are shifting developer tolerance toward faster feedback. Compute is fragmenting across providers. And the runtime layer, the layer that actually determines how fast your tools run regardless of where they run, is wide open.</p>
<p>This is the ground we are building on at Tuist. Not competing on compute. Not locking value into a single environment. Going deep into the toolchain, building the platform team that every organization needs but few can afford, and making it work everywhere development happens.</p>
<p>The window for this was hard to open before. It took a lot of convincing, a lot of explaining why productivity matters, a lot of fighting the tangibility bias. But agents are opening it for us, one frustrated developer at a time.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Helmsman, an Elixir package for building agents</title>
      <link>https://pepicrft.me/blog/helmsman/</link>
      <guid>https://pepicrft.me/blog/helmsman/</guid>
      <pubDate>Sun, 15 Mar 2026 00:00:00 +0000</pubDate>
      <description>I built Helmsman, an Elixir framework for building LLM-based agents, inspired by Pi&#x27;s SDK mode and aligned with Elixir patterns and conventions.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I was tinkering earlier this week with the <a rel="external" href="https://shittycodingagent.ai/">Pi coding agent</a>, which popularized through <a rel="external" href="https://openclaw.ai/">OpenClaw</a> and its extensibility capabilities, and couldn't resist looking at what the options in the Elixir ecosystem are. Not options in terms of a coding executable, but options in terms of a framework that one can use to build agents. Similar to Pi's SDK mode, which is designed specifically for that if Node/Bun/Deno are your runtimes. The closest I could find was <a rel="external" href="https://hexdocs.pm/jido/readme.html">Jido</a>, which provides the primitives to model agentic workflows, an idea that exists before LLMs popularized it, but I felt its building blocks were too distant from the concepts LLM-based agentic workflows work with. They didn't click with me.</p>
<p>I like doing some hacking on Sunday afternoons, so I thought it'd be a good exercise to build a framework for Elixir learning from ideas from Pi. The result of this work is <a rel="external" href="https://github.com/pepicrft/helmsman">Helmsman</a>, an Elixir framework for building agents. I put a strong focus on aligning the APIs with Elixir patterns and conventions, and the concepts with LLM-based agentic workflows. Here's an example of how to use it:</p>
<pre><code data-lang="elixir">defmodule MyApp.CodingAgent do
  use Helmsman

  @impl true
  def tools do
    Helmsman.Tools.coding_tools()
  end
end

{:ok, agent} = MyApp.CodingAgent.start_link(
  api_key: System.get_env(&quot;ANTHROPIC_API_KEY&quot;),
  system_prompt: &quot;&quot;&quot;
  You are an expert software engineer.
  Write clean, well-documented code.
  Always run tests after making changes.
  &quot;&quot;&quot;
)

Helmsman.stream(agent, &quot;Add documentation to the counter module&quot;)
|&gt; Stream.each(fn
  {:text, chunk} -&gt; IO.write(chunk)
  {:tool_call, name, _id, _args} -&gt; IO.puts(&quot;\n📦 Using tool: #{name}&quot;)
  {:tool_result, _id, result} -&gt; IO.puts(&quot;   Result: #{inspect(result)}&quot;)
  :done -&gt; IO.puts(&quot;\n✅ Done!&quot;)
  _ -&gt; :ok
end)
|&gt; Stream.run()
</code></pre>
<p>We include a set of tools that you can override or extend to customize the behavior of your agent. For example, this is how you define a custom tool:</p>
<pre><code data-lang="elixir">defmodule MyApp.Tools.Weather do
  use Helmsman.Tool

  @impl true
  def name, do: &quot;get_weather&quot;

  @impl true
  def description, do: &quot;Gets the current weather for a location&quot;

  @impl true
  def parameters do
    %{
      type: &quot;object&quot;,
      properties: %{
        location: %{type: &quot;string&quot;, description: &quot;City name&quot;}
      },
      required: [&quot;location&quot;]
    }
  end

  @impl true
  def call(%{&quot;location&quot; =&gt; location}, _context) do
    case WeatherAPI.get(location) do
      {:ok, data} -&gt; {:ok, &quot;Temperature: #{data.temp}°F&quot;}
      {:error, reason} -&gt; {:error, reason}
    end
  end
end
</code></pre>
<p>And building on Erlang's awesomeness, Helmsman comes with telemetry events that you can use to track agent behavior:</p>
<pre><code>:telemetry.attach_many(
  &quot;my-handler&quot;,
  [
    [:helmsman, :agent, :start],
    [:helmsman, :agent, :stop],
    [:helmsman, :tool_call, :start],
    [:helmsman, :tool_call, :stop]
  ],
  fn event, measurements, metadata, _config -&gt;
    Logger.info(&quot;#{inspect(event)}: #{inspect(measurements)}&quot;)
  end,
  nil
)
</code></pre>
<p>If you want to tinker with it, you can use the <a rel="external" href="https://github.com/pepicrft/helmsman/blob/main/livebooks/local_playground.livemd">livebook</a> included in the repository. Next weekend, I plan to start leveraging this in another experiment of mine where I'm exploring what version control systems for the modern patterns that are emerging might look like. I'm calling it Micelio, and you'll likely hear more from me talking about it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The beauty of being open</title>
      <link>https://pepicrft.me/blog/the-beauty-of-being-open/</link>
      <guid>https://pepicrft.me/blog/the-beauty-of-being-open/</guid>
      <pubDate>Thu, 12 Mar 2026 00:00:00 +0000</pubDate>
      <description>Openness is not a trend or a distribution strategy. It&#x27;s a way of building trust, expanding your pool of ideas, and creating something that lasts.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Someone told me recently that open source is no longer cool. That it was a trend, and the trend has passed. I've been thinking about that comment ever since, not because it upset me, but because it revealed something about how a lot of people in our industry think about openness. They reduce it to a tactic. A distribution strategy. Something you adopt when it's fashionable and abandon when the winds shift.</p>
<p>I think that's a very narrow way of looking at it, and I think it misses the point entirely.</p>
<h2 id="the-recipe-and-the-chef">The recipe and the chef</h2>
<p>There's an analogy I keep coming back to. If you search the internet right now, you can find recipes for almost anything. The best restaurants in the world, the dishes that people travel thousands of kilometers to eat, many of those recipes are out there, publicly available. You could technically replicate them at home. But if you try, you'll quickly realize that having the recipe is not the same as having the craft.</p>
<p>A chef who has spent years working with ingredients, who understands the subtleties of heat and timing and texture, who loves the act of cooking itself, will always produce something different from someone following the same instructions for the first time. The recipe is open. The magic is in the hands.</p>
<p>I think about this a lot in the context of building software. There's this pervasive fear in the industry around sharing. Around being open. Companies treat their code, their ideas, their roadmaps like they are the entirety of their value. As if showing someone what you're building means they can instantly take your place. But the truth is, when you're building something with genuine passion and deep understanding of the problem, openness doesn't weaken you. It strengthens you. Because the value was never just in the code. It's in the obsession, the taste, the accumulated understanding of the problem space that took years to develop.</p>
<h2 id="what-i-see-when-i-look-around">What I see when I look around</h2>
<p>When I look around the industry, what I feel most is fear. Fear of sharing too much. Fear that someone will copy your feature, your architecture, your positioning. Companies build in private for weeks or months, then task someone with creating noise around the announcement, hoping the algorithms will carry the signal. And it's getting harder and harder to make that work. You can't just publish a blog post and expect it to spread. The platforms don't reward that kind of content anymore. Search is less reliable as a discovery channel. The old playbook is breaking down.</p>
<p>And then there are the blog posts themselves. I came across one this morning from an engineering leader at a company, and I could tell immediately it was generated by AI. Not because using AI is inherently wrong, but because no one had bothered to read it. The post said nothing. It had no point of view, no depth, no personality. It was content for the sake of content, published so that a checkbox could be ticked somewhere.</p>
<p>When I read something like that, what I take away is that the people behind that company are not deeply connected to what they're building. Because if you love what you do, you don't put out something empty and call it done. You care about every word because every word represents who you are and what you stand for.</p>
<h2 id="the-long-game-of-trust">The long game of trust</h2>
<p>I believe the only way to genuinely reach developers is through trust. And trust takes time. It takes consistency. It takes showing up, over and over, with substance. Not fireworks. Not growth hacks. Substance.</p>
<p>At Tuist, we've been doing this for years. We share what we're building, what we're thinking about, what problems we're trying to solve. Not in polished marketing campaigns, but as part of how we work. Our code is open. Our design process is open. Our technical decisions are open. Support happens in public. We're starting to have our marketing conversations in public too, making videos of the discussions, the scripting process, all of it. I don't know if people will participate, but the invitation is there. If someone wants to throw in their ideas, why not?</p>
<p>This is what resonates with developers. When they see a team that is contributing to making things better, that has a clear vision, well articulated, that they can connect with, something clicks. It's not a transaction. It's a relationship built on shared values. A developer who has been using Tuist for Xcode, who has watched us share our thinking for years, when we announce that we're expanding to Gradle, there's a natural interest that emerges. Not because of an ad. Because of trust earned over time through openness.</p>
<p>I don't think there's another way to build this with developers. You have to be a community builder. You have to do the work in the open. You have to make people feel like they're part of something, not just customers of something.</p>
<h2 id="the-balance">The balance</h2>
<p>I should say that openness doesn't mean naivety. There's a balance to find, especially when it comes to licensing and business models. Cloud providers can take your open source project and sell it as a managed service on their infrastructure, and competing with that is nearly impossible. If your audience is developers and there's no real incentive to pay you, many will self-host even when it's painful to do so.</p>
<p>This is something that continuously evolves at Tuist. We haven't fully settled on our licensing for the server side. In fact, our goal is to be fully open source when most of the value lives in the infrastructure itself, which is where the real pain is. There's so much accidental complexity in running and managing that infrastructure, complexity we can't fully eliminate, that most people genuinely don't want to deal with it themselves. And the bigger the market becomes, the more attractive this model gets.</p>
<p>You need to understand who you sell to and who might want to sell what you've built. That awareness shapes your licensing decisions, your business model, the way you think about where the value lies. It's not something you figure out once and forget. It's a continuous conversation.</p>
<h2 id="building-in-public-is-building-with-others">Building in public is building with others</h2>
<p>One thing I've noticed is that when you build in the open, you expand your pool of ideas dramatically. When we discussed publicly that we were going to introduce compute as an internal primitive, someone told me it was a bad idea. I didn't agree, but the conversation itself was valuable. When you share your thinking openly, you're socializing ideas. You don't need a big launch event. You keep talking about what you're doing, what you're considering, what you're solving. And slowly, people start to engage.</p>
<p>On our platform, people contribute things like new languages for the dashboard. When you invite contributions, you get a design surface that accounts for a diversity of ideas and needs you could never imagine on your own. Otherwise you're limited to the ideas of your employees and your existing customers, and that's it. The pool becomes the world versus you and your small team. And the world, as it turns out, is more creative.</p>
<p>This is precisely what companies tend to lose as they grow and focus narrows to meeting investors' expectations. Their websites fill up with webinars, demos, contact-sales buttons, and factory-produced blog posts. The craft disappears. The personality fades. And they wonder why developers don't trust them.</p>
<h2 id="this-is-what-we-believe">This is what we believe</h2>
<p>I know that some people look at how we operate and feel uncomfortable. Some have tried to dismiss our approach as a trend, or put it down as unsustainable. We couldn't care less. This is not a posture we adopted because it was convenient. This is who we are.</p>
<p>We believe that openness builds the kind of trust that marketing budgets can't buy. We believe that the best products come from people who love what they do and aren't afraid to show their work. We believe that inviting the world into your process makes the result better, not worse. And we believe that this is the path to building something that lasts, a company we can be proud of, with a community of people who believe in the same things we do.</p>
<p>The recipe is out there. But we're the chefs. And we love what we cook.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The obsession gap</title>
      <link>https://pepicrft.me/blog/the-obsession-gap/</link>
      <guid>https://pepicrft.me/blog/the-obsession-gap/</guid>
      <pubDate>Wed, 11 Mar 2026 07:30:00 +0000</pubDate>
      <description>A bet that obsession matters more than speed. That personality matters more than feature parity. That going deep matters more than going wide.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There is one thing that I keep coming back to, something Tobi Lütke, the CEO of Shopify, talks about in interviews and something I experienced firsthand during my years there: the idea of getting obsessed with problems. Not interested. Not aware. Obsessed. The kind of obsession where you wake up thinking about a problem, carry it with you through the day, and let it shape how you see everything around you.</p>
<p>What's remarkable is how rare this is. And how difficult it is to find people who share your obsession for the same problem.</p>
<p>I think about this all the time in the context of building Tuist. If you want to build something that truly stands out, something that brings something unique to the world, you need a deep love for the problem you're solving. Not a passing interest. Not a strategic bet. Love. The kind that makes you willing to go deeper than anyone else, to sit with complexity longer than is comfortable, to resist the temptation of doing what everyone else is doing just because it looks like that's where the opportunity is.</p>
<h2 id="passion-for-problems-vs-passion-for-business">Passion for problems vs. passion for business</h2>
<p>When I look around at tools and companies in our space, I notice that the gravitational pull of business can be very strong. And look, you need that component. You need to know how to sell what you're building. You need revenue. You need sustainability. But I think when the business side takes over, something subtle happens to the products that come out of it.</p>
<p>They start looking the same. Same design language. Same feature sets. Same concepts. Same positioning. It's not that the people building them don't care. I think most founders do care. But the pressure to grow, to compete, to ship what the market expects, can quietly push the product toward a kind of sameness. Sometimes you fall so in love with an idea that feels unique but isn't, and you don't realize you're standing in a crowded room full of people saying the same thing with slightly different words.</p>
<p>A good example of this dynamic is the compute space right now. Compute for CI. Compute for agents. Compute for whatever comes next. There's a natural tendency to look at what's gaining traction and move toward it. Then capital flows in, and the incentive becomes to do the same thing at scale as fast as possible. I don't think this is necessarily wrong. But I do think it creates a landscape where the products can end up feeling similar. They solve real technical challenges, but they can lose some of that personality along the way. That sense that someone poured their particular obsession into every detail.</p>
<h2 id="what-personality-actually-means">What personality actually means</h2>
<p>When I say personality, I mean something very specific. I mean how you feel when you use a product. How you interface with the problem domain. How simple it is. How enjoyable it is. Whether it evokes something in you, some kind of emotion, when you interact with it.</p>
<p>There isn't a better example of this than 37signals. Every product they build, every problem space they enter, they do it differently. There's a craft and a point of view that's unmistakable. You use their products and you feel something. They're not just functional, they're opinionated in a way that feels alive.</p>
<p>Shopify does this too. One thing I took from my time there is how deeply they understand their business. They don't just build features for e-commerce. They study e-commerce so well that they can model it properly, and from that deep understanding they build domain-specific building blocks that enable creative solutions. When a new technology with new capabilities arrives, like AI, they jump into exploring what that means for their product space. They don't just bolt features on. They think deeply about what the technology enables for the people they serve, because they understand the domain well enough to see what others can't.</p>
<p>Apple has done this for decades. Their products don't just work. They feel considered. They feel like someone cared about every detail, every transition, every moment of interaction. That investment in how something feels is not superficial. It's foundational to why people love using their products.</p>
<h2 id="building-with-feeling">Building with feeling</h2>
<p>At Tuist, we're trying to do the same. We look around. We know what's happening in our space. But we try to be different. We invest in areas where people don't usually invest: in making the product feel alive through animations, through interactions, through videos, so that when you use it, something is evoked. Not just utility. Emotion. We want ours to feel like it was made by people who care, because it was.</p>
<p>We're also open source, which we think is unique and important in how it shapes our relationship with the people who use what we build.</p>
<p>We design everything so that the product is layered. People can choose the layer they want and plug it into their system. We look at every single detail. How we name things. How the experience feels when using the CLI. How the dashboard communicates information. We care about the small things because we believe they add up to something meaningful.</p>
<p>And critically, we use the tool ourselves. Not just passively, but we are constantly looking for ways to use it more. We look at our own setup and ask ourselves where the friction is, where we can push Tuist further into our own workflow. We are developers. We develop software every day, and we have our own productivity issues. So we solve them for ourselves first, and that becomes a source of ideas for the product. On top of that, we work very closely with our users. We listen to their problems, we get ideas from the challenges they share with us, and we translate those into solutions that are genuinely useful. When you use a product and it feels broken, you can't help but wonder what would happen if the people building it lived inside it every day. I understand that organizational complexity makes this hard. But for me, it's kind of unthinkable to build something we don't use daily, alongside the people we build it for.</p>
<h2 id="the-discomfort-of-going-your-own-way">The discomfort of going your own way</h2>
<p>Most importantly, we're avoiding jumping into whatever everyone else is jumping into just for the sake of following the crowd. This feels very uncomfortable, I'll be honest. When everyone moves in the same direction, that's where the money flows. And money has a gravitational pull that's hard to resist.</p>
<p>But I also have to say that money tends to have a short-term, short-sighted view of spaces. Capital chases what looks like it's working right now. It rewards speed over depth, imitation over originality, scale over craft. If you want to be a long-term business, which is what we're aiming to do with Tuist, you need to think differently.</p>
<p>Think out of the box, like Apple used to say.</p>
<p>We're going deep into areas like build systems to understand them well. Not superficially. Not just enough to ship a product. Deeply enough that when we intersect that knowledge with AI, we can bring something of real value to companies. Something shaped by our particular obsession with this problem space.</p>
<p>We announced recently that we are going to solve compute. But not compute for the sake of compute. We are building on compute capabilities so that we can enable creative solutions for productivity, which is what we are truly obsessed with solving. From all the learnings we got at Shopify, from making developers productive, from working very close to the tools, from understanding them deeply, we learned that you need to build domain building blocks so that you can model those problem spaces properly. That's what we're doing. We're not entering compute to compete on price or speed. We're entering it because compute is a foundation on top of which we can build something different. It's not that we're the only ones thinking about developer productivity. But we are very obsessed with it, and that obsession, combined with years of working close to the tools, gives us a particular perspective that shapes everything we build.</p>
<h2 id="the-bet">The bet</h2>
<p>This is ultimately a bet.</p>
<p>A bet that obsession matters more than speed. That personality matters more than feature parity. That going deep matters more than going wide. That building something you love using yourself every day produces better outcomes than optimizing for metrics in a pitch deck.</p>
<p>It's not the easy path. It's not the path that gets you the loudest applause or the biggest funding round. But I believe it's the path that leads to products people actually love, companies that actually last, and work that you can actually be proud of.</p>
<p>That's what we're building at Tuist. Not just a product. A point of view.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Building the house from the roof</title>
      <link>https://pepicrft.me/blog/building-the-house-from-the-roof/</link>
      <guid>https://pepicrft.me/blog/building-the-house-from-the-roof/</guid>
      <pubDate>Mon, 02 Mar 2026 10:00:00 +0000</pubDate>
      <description>Tuist started at the toolchain layer and is working its way down to compute and caching. This is the whole house, from roof to foundation, and why going deep into each layer is how you earn trust that money cannot buy.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There is a song in Spain called <a rel="external" href="https://www.youtube.com/watch?v=8qz8FqmTsJY">"La Casa por el Tejado."</a> It describes the act of building a house starting from the roof. It is meant as a cautionary metaphor, the idea that you are doing things in the wrong order. But I have been thinking about it differently lately, because that is exactly how we have been building <a rel="external" href="https://tuist.dev">Tuist</a>. And I am not sure it was the wrong order at all.</p>
<p>We started at the roof. Deep integration with the Xcode toolchain, then <a rel="external" href="https://docs.tuist.dev/en/guides/install-gradle-plugin">Gradle</a>, now expanding into more ecosystems. This layer, the toolchain runtime, sits between your project and the infrastructure that builds it. It is the layer where you understand how code gets compiled, linked, tested, and packaged. We did not plan to start there out of some grand architectural vision. We started there because we cared about it. We wanted to make it better. And in doing so, we built a foundation of understanding that now informs everything we do as we work our way down to the rest of the house.</p>
<h2 id="why-the-roof-first">Why the roof first</h2>
<p>Starting at the toolchain layer gave us something that most companies in this space lack: depth. Real, technical depth in how build systems work, where they break, and what developers actually experience when things go wrong.</p>
<p>Most companies prefer not to go this deep. They would rather place an abstraction between the technology and the infrastructure. This is why solutions like <a rel="external" href="https://www.docker.com/">Docker</a> and <a rel="external" href="https://kubernetes.io/">Kubernetes</a> exist in the form they do. It is why CI providers settled on the message of "just give us a container and we will run it." The abstraction is convenient. It scales as a product. But it also means you never really understand what is happening inside.</p>
<p>Going deep into toolchains is uncomfortable work. You end up contributing to tools you do not own. You invest time into understanding systems that change under you. You sometimes spend weeks on a problem that benefits an ecosystem but has no direct financial return for your company. This is not the kind of work that looks good on a quarterly report or in a pitch deck.</p>
<p>But it is the kind of work that earns trust. <strong>And trust, in developer tooling, is the real currency.</strong></p>
<h2 id="the-toolchain-layer-as-a-differentiator">The toolchain layer as a differentiator</h2>
<p>I think this is where Tuist can bring something genuinely unique. The way you gain developers' trust is by contributing to the tools they already use. Not by replacing them. Not by wrapping them in a proprietary layer. By understanding them deeply enough to make them better, and then building your product on top of that understanding.</p>
<p>Not many companies are willing to make this investment. It requires an open source mindset, a community mindset, where you accept that some of your work will benefit people who never pay you a cent. That feels irrational if your model is purely transactional. But if you think about it over years rather than quarters, those ecosystems respond. They respond with trust, with adoption, with the kind of organic growth that no growth hack can replicate.</p>
<p>I see so many companies hiring growth hackers and optimizing funnels when the real problem is that developers do not trust them. You cannot shortcut trust by throwing money at it. You can buy awareness, sure. You can manufacture a sense of urgency. But developers remember who showed up to their ecosystem and actually helped versus who showed up with a landing page and a sales pitch.</p>
<h2 id="from-the-roof-to-the-walls">From the roof to the walls</h2>
<p>If the toolchain layer is the roof, the next layer down is observability. This is the part where you look at your project, analyze your build graph, and surface the things that make developers waste time. Flaky tests, redundant dependencies, suboptimal compilation paths. All of this requires telemetry and deep understanding of build and test data.</p>
<p><strong>This is why companies traditionally build platform teams.</strong> Someone has to watch the system, understand it, and optimize it. But platform teams are expensive. They require specialized knowledge. And most organizations either cannot afford them or cannot retain the talent.</p>
<p>We think Tuist can be the platform team of the future. A virtual platform team that understands your toolchain, watches your build and test signals, and tells you what to fix. This is not a dashboard with pretty charts. This is the kind of insight that requires understanding the system deeply enough to know what the data means and what to do about it.</p>
<p>As we continue expanding into new ecosystems, this becomes even more relevant. Agents are producing code at a velocity that human developers never reached. More code means more builds. More builds means more opportunities for things to go wrong, to slow down, to waste cycles. The need for a layer that watches, understands, and optimizes is not going away. It is growing.</p>
<h2 id="the-foundation-compute-and-caching">The foundation: compute and caching</h2>
<p>If you keep going down from observability, you reach the foundation of the house: compute and caching. These are the layers that determine how fast things actually run.</p>
<p>There is a growing consensus in the industry that compute matters. And it does. But I think many companies are being a bit myopic about it. They see compute as the whole story. Faster cores, more cores, dedicated machines. It sells well because it is easy to understand. "Your builds are slow? Here, have a faster machine."</p>
<p>The problem is that compute alone has a ceiling. A physical ceiling. You can buy the most powerful machine available and your build still takes however long it takes to compile everything from scratch. No amount of cores can overcome a build graph that is doing unnecessary work.</p>
<p>This is why we believe compute and caching must go together. Caching is what breaks through the compute ceiling. When your build system can pull a pre-compiled artifact from a cache instead of rebuilding it, you shift the bottleneck from CPU to network latency. And network latency is something you can optimize almost without limit if the cache is close enough. This means compute and caching need to be colocated. You cannot have a cache on the other side of the world and expect it to be fast enough. Physics does not care about your product roadmap.</p>
<p>The compute market is going to get very crowded. We already see <a rel="external" href="https://www.daytona.io/">Daytona</a>, <a rel="external" href="https://modal.com/">Modal</a>), <a rel="external" href="https://e2b.dev/">E2B</a>, and many others. I would not be surprised to see AWS step into this more directly. When you are only selling compute, your differentiation is thin. Someone will always match your specs at a lower price. But when compute is one layer in a full stack that includes deep toolchain understanding, build graph optimization, observability, and colocated caching, the picture changes entirely.</p>
<h2 id="the-fragmentation-problem">The fragmentation problem</h2>
<p>There is another dynamic that worries me about compute. As coding agents become more prevalent, everyone wants to provide their own compute. OpenAI runs <a rel="external" href="https://openai.com/codex/">Codex</a> in its own containers. CI providers have their runners. <a rel="external" href="https://linear.app/">Linear</a> might offer compute for development workflows. Every tool in the chain wants to be the one hosting the execution.</p>
<p>This fragmentation is problematic. Each provider optimizes for their own slice of the workflow, and developers end up with their build artifacts scattered across five different systems, none of which talk to each other. It gets even more concerning when you consider how sensitive the data is. Your source code, your credentials, your build outputs. Having all of that spread across multiple compute providers with different security postures is not ideal.</p>
<p><strong>I hope the industry converges on a protocol that separates who needs compute from who provides it.</strong> Something that lets you choose your compute provider independently from the tools that orchestrate your work. Without that, we are heading toward a world where every tool is also an infrastructure provider, and the switching costs become unbearable.</p>
<h2 id="the-whole-house">The whole house</h2>
<p>What I keep coming back to is that you need the whole house. The toolchain layer, the observability layer, the compute, and the caching. Each one is necessary but not sufficient on its own. Fast compute without an optimized build graph is wasteful. An optimized build graph without good caching still hits a ceiling. Caching without proximity to compute is bottlenecked by physics. And none of it matters if you do not understand the toolchain deeply enough to know what to cache, what to skip, and what to rebuild.</p>
<p>We are building all of it. Going deep into the areas where we do not see other companies going deep because they do not see the value. As I said, going deep requires an open mindset where you invest into areas without seeing direct financial returns. That is why it is not attractive to many companies. But in the long term, it compounds. The ecosystems respond. The trust builds. The product gets better because you understand the problem better than anyone else.</p>
<p>This is not the fastest way to build a company. It is not the most capital-efficient path in the short term. But it is the path that leads to something real. Something that developers can rely on because it was built by people who genuinely understand the systems they work with every day.</p>
<p>We started building the house from the roof. Now we are adding the walls, the scaffolding, the foundation. And when the whole thing is standing, it will be standing on a depth of understanding that you cannot buy, you cannot shortcut, and you cannot fake. You can only earn it by doing the work.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The builder trap</title>
      <link>https://pepicrft.me/blog/the-builder-trap/</link>
      <guid>https://pepicrft.me/blog/the-builder-trap/</guid>
      <pubDate>Tue, 24 Feb 2026 12:00:00 +0000</pubDate>
      <description>Developers who build companies tend to fall in love with their creations. That love is a strength, but it can also become a blind spot when others see your work as an asset to acquire rather than a craft to respect.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>We, developers, have the ability to create things. And we tend to fall in love with our creations. With the values we embed in them. With the principles we shape them around. With the craft itself. This is one of our greatest strengths. It is also, in the context of business, one of our biggest blind spots.</p>
<p>It manifests in familiar ways. We convince ourselves that technical excellence is a sufficient ingredient for a sale. We spend months on a rewrite that customers never asked for and will never notice. We fail to recognize where the opportunity for capturing value actually lies, or where to set the right boundaries. We pour ourselves into the work and forget that the work also needs to sustain itself.</p>
<p>Marek and I have been there. More than once. And over time, we have learned the discipline of business engineering. How to balance the love of building with the reality that building needs a foundation underneath it. But that learning process came with its own set of lessons, many of them taught by people who saw our builder instincts and thought they could use them.</p>
<h2 id="the-pattern">The pattern</h2>
<p>When you are a small company with strong product instincts, people notice. Some of them genuinely want to collaborate. Others see an opportunity to acquire your capabilities without paying what they are worth.</p>
<p>We have experienced this several times over the years, and each time the playbook was different but the underlying dynamic was the same. Someone sees that you can build, sees that you are small, and assumes that you must need saving. Or funding. Or guidance. Or absorption into something bigger. The assumption is always that your size is a weakness rather than a choice.</p>
<p>One time, a company in our space proposed an integration that was really about folding our work into their platform. When we declined, the conversation shifted to suggesting our project belonged in a foundation. In our experience, foundations rarely solve sustainability. They redistribute responsibility while the project slowly loses momentum. No, thank you.</p>
<p>Another time, someone pitched us on selling the project. In the same conversation, they mentioned a similar acquisition that had ended with the acquired project dying. The subtext was not subtle. Open source was a marketing asset. Companies were financial assets. When the acquisition did not work, the offer became a small monthly payment to promote their tools on our channels. No, thank you. Looking back, we are glad we said no. The values we saw play out after that conversation were not ones we wanted to be associated with.</p>
<p>More recently, someone approached us about "joining forces to build something big." It was unclear what that meant in practice because there was no real structure behind the proposal. What became clear quickly was that they saw open source as a detriment to capturing value rather than a multiplier of it. For us, that is a fundamental misalignment. Open source is not something we do despite the business. It is core to how we build it. We passed. We did not even get to specifics because the conversation made it obvious we were building toward very different things.</p>
<h2 id="what-we-learned">What we learned</h2>
<p>Throughout all of these conversations, a few things became clear.</p>
<p>We have built an impressive product muscle. Four engineers shipping at a pace that companies with forty times our headcount cannot match. This is a real and valuable capability, and it makes some people uncomfortable. When a small team moves faster than a well-funded one, it raises questions that the well-funded one would rather not answer.</p>
<p>You can build an open source business if you capture value in the right places. The code is partially yours, but not all the value lives in the code. The infrastructure, the expertise, the trust, the service. Those are where sustainable businesses are built. We strongly believe the most enduring companies are open ones. But I understand that openness does not matter if your timeline is short and your goal is an exit.</p>
<p>Some founders are here for value creation. Others are here for value extraction. The equation for the latter is straightforward. Get a round to establish a valuation. Get another round to increase it. Exit. Cash out. Repeat. This is a valid path, but it is a different game than the one we are playing. The problem is when people playing that game try to pull you into it because your capabilities would make their numbers look better.</p>
<h2 id="the-quiet-advantage">The quiet advantage</h2>
<p>Being in a relatively niche corner of the industry has been a gift. It gives us the space to build a technical and product foundation without too much noise, while maintaining a broad perspective on where the industry is heading. We do not jump into whatever everyone else is jumping into. We watch, we think, we build when the timing is right.</p>
<p>The biggest challenge any company faces is staying innovative. Some do not use their own products. Even the ones that do often lack the muscle for real product innovation. It is rare to find product engineers who cross-pollinate ideas across domains. Even rarer to find makers who are passionate and confident enough about their ideas to talk about them openly, make them contagious, and get other people excited to try them. I consider myself that kind of person, and I have learned to protect that quality instead of letting others diminish it.</p>
<h2 id="we-are-doing-business">We are doing business</h2>
<p>So thank you to everyone who approached us. Genuinely. Every conversation taught us something. Every "no" made us more confident in what we are building and why. Every attempt to acquire, absorb, or redirect us made us realize how much we love doing this, and how much we have learned about business since we started.</p>
<p>We are doing business, like everyone else. We have our own ideas, our own pace, our own values. It might feel uncomfortable to see a small company with fewer incentives to align with what others expect of us. But we are going to keep making noise and pursuing what we believe in.</p>
<p>It turns out business is not that hard after all. You just need to know what you are building, why you are building it, and who you are building it for. And then you need to be stubborn enough to keep going when people tell you that you should stop.</p>
<p>We are not stopping.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Headless development</title>
      <link>https://pepicrft.me/blog/the-forge-is-next/</link>
      <guid>https://pepicrft.me/blog/the-forge-is-next/</guid>
      <pubDate>Tue, 24 Feb 2026 10:00:00 +0000</pubDate>
      <description>Coding agents decoupled development from the editor. What follows is a new kind of platform where steering, reviewing, and collaborating on code looks nothing like what we are used to.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>We have a well-established concept in software: headless. A headless browser runs without a visible window. A headless CMS separates content from presentation. The pattern is always the same. You take something that was traditionally coupled to an interface and you remove that dependency so it can run anywhere, driven by anything.</p>
<p>I think we are watching the same thing happen to software development itself. Coding agents are turning development headless. The action, writing code, compiling, running tests, is being separated from the interface where it used to live: your editor, your terminal, your local machine. And just like every other headless transition before it, this one is going to reshape the entire platform around it.</p>
<h2 id="we-tried-this-before">We tried this before</h2>
<p>The idea of moving development off your local machine is not new. Cloud development environments have been around for years. <a rel="external" href="https://www.gitpod.io/">GitPod</a>, Codespaces, various remote desktop solutions. The industry poured real money into making "code from anywhere" a reality. Even Shopify invested years into this before eventually stepping back. The vision was compelling, but the execution never quite landed.</p>
<p>I think the reason is that we were still too dependent on editors whose entire design assumed the action was happening locally. Extensions, language servers, debuggers, terminal integrations. Everything was built around the idea that your machine was both the steering wheel and the engine. Some teams pushed that model impressively far, but it always felt like you were fighting the architecture rather than working with it. And for platforms like Apple's, where the toolchain is tightly coupled to specific hardware and an environment that is costly to provision and run, the friction was even worse.</p>
<p>Cloud development tried to make the editor headless. But the editor did not want to be headless. It was designed around the assumption that it was the center of everything.</p>
<h2 id="agents-made-it-actually-work">Agents made it actually work</h2>
<p>Coding agents did not try to make the editor work remotely. They made the editor optional. That is a fundamentally different move.</p>
<p>When you work with a coding agent, the relationship with the editor shifts. You prompt, you wait, you review, you iterate. The editor becomes a place to steer from, not a place where the action happens. That distinction matters more than it might seem at first.</p>
<p>This is exactly what companies like <a rel="external" href="https://www.anthropic.com">Anthropic</a> and <a rel="external" href="https://openai.com">OpenAI</a> are building toward. Claude Code can run headlessly. Codex spins up its own containers. The compute where your code builds and runs is no longer your laptop. It is somewhere else, managed by someone else, and that is fine because your job is to direct the work, not to host it.</p>
<p>Once you accept that separation, a lot of things start falling into place. Your physical machine is no longer a ceiling on how much agentic work you can parallelize. You are not bottlenecked by your CPU, your RAM, or the number of terminal tabs you can keep open. The constraint moves from hardware to orchestration. Development becomes headless, and the head, you, can be anywhere.</p>
<h2 id="runtime-review-over-code-review">Runtime review over code review</h2>
<p>When development goes headless, the way we validate work changes too. Code review still matters, but runtime review is becoming the more important feedback loop.</p>
<p>What I mean by runtime review is the ability to see, feel, and interact with the result of the work. Not just reading the diff, but running the thing and experiencing it. This is not a new concept. At Shopify, we had a process called <a rel="external" href="https://shopify.engineering/shopify-tophat-mobile-developer-testing">tophat</a> where engineers would spin up a build of someone's branch and test it on a real device before approving. We brought a version of this to <a rel="external" href="https://docs.tuist.dev/en/guides/features/previews">Tuist as previews</a>. And now coding agent platforms are building the same idea natively.</p>
<p>When <a rel="external" href="https://code.claude.com/docs/en/overview">Claude Code introduced previews</a>, I found it entirely expected. If the agent is producing the code, you need a way to validate the output beyond reading lines of text. You need to feel it. In a headless development model, runtime review is the primary interface between you and the work. The code is an implementation detail that the agent manages. What you care about is whether the thing works, whether it feels right, whether it does what you intended.</p>
<p>In some side projects where I experiment with new mental models around how we could work, I ship changes without reading the code at all. I just review the runtime behavior and do periodic sessions to steer the architectural foundations in a good direction. It feels surprisingly natural. I think this is where professional development is heading too. It will just take people time to embrace it.</p>
<h2 id="the-forge-is-the-logical-next-step">The forge is the logical next step</h2>
<p>Here is where headless development gets really interesting as a platform shift. Once you can spin up a controlled environment from anywhere, prompt an agent to do the work, and provide tools to review and analyze the results, the next step for these companies is to become git forges themselves.</p>
<p>Think about it. They already manage the compute. They already manage the development sessions. They already run the code. The piece they are missing is the collaboration layer, the place where code is stored, reviewed, merged, and deployed. That is what GitHub provides today. And I do not think it is a coincidence that <a rel="external" href="https://entire.io">Thomas Dohmke</a>, the previous CEO of GitHub, ventured into building <a rel="external" href="https://entire.io">Entire</a>, a new developer platform that reimagines collaboration between developers and agents from scratch.</p>
<p>But I honestly think Anthropic and OpenAI are better positioned to capture this market. They already own the agent layer. They are already running the compute. Adding a forge on top of that is a natural extension, not a leap. OpenAI in particular has the ambition and the surface area to become the new Google, the new GitHub, and the new Siri, soon with hardware to complement their products. I would not be surprised if we see movement in this direction before the end of the year.</p>
<h2 id="the-identity-question">The identity question</h2>
<p>The biggest challenge is switching costs. Developers' GitHub accounts carry real value. Your contribution history, your open source projects, your professional identity. For many people, their GitHub profile is their CV. That is a strong lock-in.</p>
<p>But in a world of headless development, the nature of that identity changes. If agents are writing the code and your role is to orchestrate and review, the value of a commit history as a signal of individual capability diminishes. The network effects that kept people on GitHub might weaken enough for a platform with stronger capabilities to pull people over.</p>
<h2 id="what-headless-development-should-feel-like">What headless development should feel like</h2>
<p>If I could design the ideal headless development platform from scratch, here is what I would want. A system where my physical laptop is not a ceiling on how much agentic work I can run in parallel. A place where I can preview the results of that work instantly. Where compilation and test runs are optimized so agents are not wasting time waiting for builds. Where the right tools exist to visualize outcomes, not just code.</p>
<p>I would also want the ability to capture ideas on the go, just using my voice, which I could later translate into a coding session when I feel like doing the orchestration. Not everything needs to start at a keyboard. In a headless model, the "head" could be a voice memo on a walk, a sketch on a tablet, a conversation with an agent from your phone.</p>
<h2 id="this-is-happening">This is happening</h2>
<p>Every headless transition in software has followed the same arc. First the decoupling, then the new platforms that emerge around it. Headless browsers gave us modern testing infrastructure. Headless CMS gave us composable content architectures. Headless development is going to give us something equally transformative.</p>
<p>The companies that control the agent layer are in the best position to build the next generation of development infrastructure. They are already doing the hard part. The forge, the collaboration layer, the review tools, those are just the natural surface that forms on top.</p>
<p>It is just a matter of time and money.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The cache is the infrastructure</title>
      <link>https://pepicrft.me/blog/the-cache-is-the-infrastructure/</link>
      <guid>https://pepicrft.me/blog/the-cache-is-the-infrastructure/</guid>
      <pubDate>Tue, 17 Feb 2026 10:00:00 +0000</pubDate>
      <description>Why the future of CI isn&#x27;t about dedicated compute but about colocated caching, and how build systems, coding agents, and shifting economics are making that future real.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I was reading <a rel="external" href="https://www.iankduncan.com/engineering/2026-02-05-github-actions-killing-your-team/">a piece by Ian Duncan</a> the other day about CI infrastructure investment. His argument, like many others in this space, placed a strong focus on the importance of dedicated compute resources. The idea is that cloud providers are not interested in building these capabilities because their business model prefers shared compute. You rent a VM from a hyperscaler, and you're fighting for CPU time with whoever else landed on that physical machine.</p>
<p>And he's right. The piece resonated because it lines up with what most of us have experienced. GitHub Actions runners are slow. Shared compute means noisy neighbors. An entire cottage industry exists (Namespace, Blacksmith, Actuated, <a rel="external" href="https://depot.dev/">Depot</a>, BuildJet) whose sole product is "GitHub Actions, but the runners don't suck." There's a real problem here.</p>
<p>But I think the framing is starting to age.</p>
<h2 id="where-dedicated-compute-matters">Where dedicated compute matters</h2>
<p>The argument for dedicated compute is strongest when you're running compiled languages. Swift, Rust, C++, Go. Build systems for these languages will happily consume every CPU core and every gigabyte of RAM you give them. When your Xcode build is maxing out 16 cores for forty minutes, the last thing you want is another build on the same machine competing for those resources. In that world, dedicated compute is not a luxury. It's the baseline.</p>
<p>This is also why most web applications don't feel the same pain. A typical SaaS backend spends its CI time waiting for database queries, network calls, and object storage operations. The CPU is idle most of the time. For those workloads, shared compute is fine. The bottleneck was never the processor.</p>
<p>But here's the thing. Even for compiled languages, the ceiling of what dedicated compute can give you is a physical ceiling. You can buy the biggest machine available, and your build still takes however long it takes to compile everything from scratch. You're bound by the hardware. There's no way to go above it.</p>
<p>Unless you stop compiling everything from scratch.</p>
<h2 id="the-shift-to-caching">The shift to caching</h2>
<p>The real unlock is not faster CPUs. It's not having to use them. When a build system can fetch a pre-compiled artifact from a cache instead of rebuilding it, the constraint moves from compute to network. And network latency, unlike CPU clock speed, is something you can optimize almost without limit if the cache is close enough.</p>
<p>This is what <a rel="external" href="https://bazel.build/remote/caching">Bazel</a> figured out years ago. Remote caching and remote execution meant that builds could reuse work across machines, across teams, across CI runs. The problem was that Bazel carried a brutal adoption cost. The migration complexity, the learning curve, the need for dedicated infrastructure to support it. <a rel="external" href="https://www.aviator.co/podcast/hidden-cost-of-bazel">Alex Eagle from Aspect Build described it well</a>: you needed management buy-in, a dedicated team, and months of migration work. For most organizations, the cost simply wasn't worth it.</p>
<p>So the industry settled into a comfortable pattern. Buy bigger machines. Run fewer things in parallel. Throw hardware at the problem. It worked well enough.</p>
<p>That's changing now, from two directions at once.</p>
<h2 id="build-systems-are-catching-up">Build systems are catching up</h2>
<p>The first shift is that build systems are incorporating caching and remote execution capabilities natively, without requiring a Bazel migration.</p>
<p><a rel="external" href="https://docs.gradle.org/current/userguide/build_cache.html">Gradle</a> has had remote build caching for years, with a simple HTTP protocol that lets CI populate the cache and developers consume it. <a rel="external" href="https://voidzero.dev/posts/announcing-vite-plus">Vite Plus</a>, VoidZero's evolution of Vite into a unified toolchain, ships with a built-in monorepo task runner that brings intelligent caching with sophisticated task input inference, so most tasks can be cached without explicit configuration. Often with better granularity than manual setups.</p>
<p>And then there's Xcode. <a rel="external" href="https://developer.apple.com/documentation/xcode-release-notes/xcode-26-release-notes">Xcode 26 introduced compilation caching</a> using LLVM's Content Addressable Storage, with sub-function-level granularity and a gRPC protocol for remote cache support. <a rel="external" href="https://bitrise.io/blog/post/lifting-the-hood-on-build-cache-for-xcode">Bitrise did a deep technical analysis</a> of how the local and remote caches interact. <a rel="external" href="https://tuist.dev/blog/2025/10/22/xcode-cache">We wrote about our own integration at Tuist</a>, where combining Xcode's native caching with our module-level binary caching produced a 77% build time reduction with local cache and 53% with remote.</p>
<p>The pattern is clear. Caching is moving from a Bazel-exclusive advantage to a standard capability across build systems. And when your build system can skip most of the work by pulling cached artifacts, the question stops being "how fast is your CPU?" and starts being "how close is your cache?"</p>
<h2 id="coding-agents-changed-the-equation">Coding agents changed the equation</h2>
<p>The second shift is that coding agents have fundamentally altered the adoption economics.</p>
<p>The reason Bazel was so expensive wasn't just the build system itself. It was the human cost of migrating to it, maintaining it, and teaching teams how to use it. That cost is collapsing. Tools like <a rel="external" href="https://code.claude.com/docs/en/overview">Claude Code</a> and <a rel="external" href="https://openai.com/index/introducing-codex/">OpenAI's Codex</a> can handle migration work, write build rules, and maintain configurations at a fraction of the previous cost. The barrier to adopting sophisticated build systems is dropping fast.</p>
<p>But coding agents are doing something else too. They're breaking the strong coupling between your development environment and your CI environment.</p>
<p>When Codex runs a task, it spins up <a rel="external" href="https://developers.openai.com/codex/cloud/environments/">its own isolated container</a> with the repository pre-loaded. Claude Code can <a rel="external" href="https://code.claude.com/docs/en/headless">run headlessly in CI pipelines</a>. These agents are generating code at a higher velocity than human developers, which means CI is running more frequently. <a rel="external" href="https://workos.com/blog/depot-builds-ai-era">Depot wrote about this directly</a>: the AI era demands faster builds because there are simply more builds to run.</p>
<p>In this world, the compute where your code builds might not be something you control at all. It might be a Codex container, or a Claude Code session, or some future agent runtime that doesn't exist yet. What you can control is where the cache lives and how fast it responds.</p>
<h2 id="what-this-means-for-us">What this means for us</h2>
<p>This is something we've been thinking about a lot at Tuist, especially as we venture into the runners space. And honestly, we don't find it fun to solve dedicated compute. Building and maintaining bare-metal infrastructure, negotiating with hardware vendors, optimizing hypervisor configurations. That's not where we want to spend our energy.</p>
<p>What we find exciting is building a compute solution upon which we can shape developer experiences at the intersection of software craftsmanship and LLM capabilities. The developer experience layer. The part where you make builds feel instant, where you give teams visibility into what's slow and why, where you connect the cache to the agent to the build system in a way that feels seamless.</p>
<p>The more we thought about it, especially seeing products like <a rel="external" href="https://aws.amazon.com/solutions/case-studies/depot-dev/">Depot building on AWS</a> with EC2 instances and achieving incredible results for their customers, the more obvious it became that starting from existing cloud infrastructure is the right call. Yes, the margins are thinner than owning hardware. But in a world that's changing this fast, if we ever had to own that layer for better cost control, that would be a good sign. It would mean we've grown to the point where it makes sense. It doesn't make sense for us to start from there.</p>
<p>Instead, we prefer to build on existing foundations and bet on the future by throwing resources into enabling it. We're building infrastructure where organizations can bring cache close to compute, wherever that compute lives. If your builds run on GitHub Actions, the cache should be there. If they run on Codex, the cache should be there too. If they run on your own machines, same thing.</p>
<h2 id="the-infrastructure-that-matters">The infrastructure that matters</h2>
<p>The CI industry spent a decade telling us that the answer to slow builds is faster machines. And for a while, that was true. But the next decade is going to look different.</p>
<p>Build systems are getting smarter. Caching is becoming universal. Coding agents are decoupling environments from infrastructure. The bottleneck is shifting from compute to network latency, from raw CPU cycles to cache proximity.</p>
<p>The companies that win in this space won't be the ones with the most sophisticated compute infrastructure. They'll be the ones that make the cache invisible, that make builds feel instant regardless of where they run, that meet developers wherever their code happens to be building.</p>
<p>That's the bet we're making. And we think it's a good one.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The rhythm of building</title>
      <link>https://pepicrft.me/blog/the-rhythm-of-building/</link>
      <guid>https://pepicrft.me/blog/the-rhythm-of-building/</guid>
      <pubDate>Thu, 12 Feb 2026 10:00:00 +0000</pubDate>
      <description>Building a long-term company in dev tooling means accepting that some things can&#x27;t be rushed. Ideas have their own pace, trust takes time, and not every shortcut is worth taking.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As founders of a company in the developer tooling space, something we keep noticing is that ideas and the realization of problems have their own rhythm. You can't force insight. You can't schedule the moment when a scattered set of observations suddenly clicks into a coherent understanding of what needs to be built next. It just happens when it happens, and the best you can do is stay close enough to the problem space that you're ready when it does.</p>
<p>This feels counterintuitive in an era where everything is supposed to move fast. AI has accelerated so many things that we've internalized speed as a default expectation. But there are dimensions of building a company that move at their own pace no matter how much pressure you apply. Understanding a domain deeply, earning the trust of the people you serve, developing the intuition to distinguish real problems from manufactured ones. These things take time. Money doesn't buy you shortcuts here.</p>
<h2 id="the-manufactured-urgency">The manufactured urgency</h2>
<p>I've watched many companies in our space try to skip this process. They raise capital, and then they deploy it into making their name impossible to ignore. Conferences, sponsorships, content marketing at scale, all designed to create the impression that a problem is more urgent than it actually is. They amplify pain points beyond their real severity. They manufacture needs that developers didn't have until someone told them they should. They create a FOMO-driven, social-pressure approach to adoption: everyone else is using this, so you should too.</p>
<p>This is very common in our industry, and I don't think it happens because founders are cynical. I think it's the natural consequence of aligning a product with investor expectations that lean heavily toward succeed fast or die fast. When your investors need returns on a specific timeline, and when that timeline doesn't align with the natural rhythm of your market, you start forcing things. You push growth before the product is ready. You manufacture demand before the need is organic. You optimize for metrics that look good in board meetings but don't reflect whether you're actually helping anyone.</p>
<p>And if you're being honest about the incentives, many founders want this too. Build something, grow it fast enough to raise at a higher valuation, exit in a few years with a good story for your profile and a meaningful deposit in your bank account. This is a well-trodden path, and I understand why people take it.</p>
<p>But here's what nobody talks about: developers notice. They can tell when a product is being pushed at them versus when it's genuinely solving a problem they have. They can sense the difference between a company that cares about their workflow and one that cares about conversion rates. You'll never hear about this publicly because the industry celebrates exits regardless of how they were achieved. Everyone claps. Everyone congratulates. The narrative is always success, never the developers who felt pressured into adopting something they didn't need.</p>
<h2 id="the-slower-path">The slower path</h2>
<p>We could take that path with Tuist. We could raise capital, throw it at growth, put our name on every conference and every newsletter, and ride the wave. It would be the easier route in many ways.</p>
<p>But we're building a long-term company, and I think that kind of company requires a different relationship with time.</p>
<p>It takes time for ideas to emerge. Not surface-level product ideas, but the deep understanding of where your domain is heading and what people will actually need when they get there. It takes time for people and organizations to build meaningful connections with you, connections rooted in trust rather than marketing exposure. It takes genuine love for your domain space and a commitment to creating craft within it. Not content, not thought leadership, but craft. The kind of work that people recognize as coming from someone who truly understands what they're doing.</p>
<p>This is sadly becoming less common. The dominant narrative is grow fast, exit, and tell the world a good founder story. The patience required to build something that lasts is treated as a liability rather than an asset.</p>
<h2 id="the-quiet-corner">The quiet corner</h2>
<p>At times it's frustrating. You're quietly in a corner, making sure every bit of your limited resources is invested as well as possible. You're trying to reach people through good, deep content instead of flashy fireworks that put you in front of thousands of eyeballs for a few seconds before disappearing. You're playing a game that doesn't have the same dopamine feedback loop as watching your follower count spike after a sponsored post.</p>
<p>There are moments when it feels like you're going to be ruled out entirely. That you're out of sync with how the world works. That everyone else understood the rules and you're stubbornly refusing to play by them. That the companies doing the loud, capital-fueled thing are going to win simply because they showed up first and showed up louder.</p>
<p>But I think there's something special in the discomfort. Something worth protecting.</p>
<p>When you build slowly and deliberately, you build differently. You make decisions based on what's right for the long term, not what looks good this quarter. You attract people who believe in what you're doing, not people who were scared into paying. You develop a depth of understanding in your domain that can't be replicated by a well-funded competitor who just arrived.</p>
<p>We're building a different type of company at Tuist. One that doesn't have a flashy origin story or a breathless growth trajectory. One that won't make headlines for its funding rounds or its valuation. But one that, years from now, we'll look back on and be proud of. Proud of how we built it. Proud of who we built it for. Proud that we stayed true to something when everything around us was telling us to take the shortcut.</p>
<p>That's worth the frustration. That's worth the quiet.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The Software Industry&#x27;s inflection point</title>
      <link>https://pepicrft.me/blog/the-software-industrys-inflection-point/</link>
      <guid>https://pepicrft.me/blog/the-software-industrys-inflection-point/</guid>
      <pubDate>Sun, 08 Feb 2026 10:00:00 +0000</pubDate>
      <description>Reflections on how AI is reshaping code production, why companies must rethink where value lives, and what independence means in a world of accelerating change.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There is a reality that we can no longer ignore: code is getting fast and cheap to produce. The barrier to creating software has collapsed in ways that would have seemed impossible a few years ago. What once required weeks of engineering work can now be achieved in hours with the right prompting and a capable model. This is not speculation. This is happening right now, and it is accelerating.</p>
<p>At <a rel="external" href="https://tuist.dev">Tuist</a>, we are watching closely as AI reshapes what is possible in software development. Project generation, which has been at the core of our product, now faces new pressures. We are seeing developers use coding agents to build solutions in other domains, and there is a real risk that this energy will extend to dev productivity infrastructure. If developers can use AI to build tools for web development, database management, or CI pipelines, it is not hard to imagine the same approach being applied to developer tooling for mobile platforms.</p>
<p>This shift forces a question that every software company must answer: if code itself is becoming a commodity, where does value actually live?</p>
<h2 id="the-infrastructure-problem-ai-cannot-solve">The infrastructure problem AI cannot solve</h2>
<p>The answer we have arrived at is infrastructure. Here is what we mean. The challenge that remains hard is not writing code. It is running it efficiently at scale. Modern hardware imposes real ceilings on what individual developers can achieve, and those ceilings become painful bottlenecks when you are working on large codebases with complex build processes.</p>
<p>AI can write code faster than ever, but it cannot magically make that code compile faster or run more efficiently on limited hardware. Co-located cache infrastructure, distributed compilation, optimized binary distribution, these are problems that do not dissolve just because code generation became cheap.</p>
<p>We built Tuist to solve these problems for teams working on large iOS projects. The value we provide comes from infrastructure expertise, from years of understanding how Xcode projects behave at scale, from building systems that make teams faster. Infrastructure is hard to build, harder to operate at scale, and genuinely valuable when it works.</p>
<h2 id="the-aws-paradox">The AWS paradox</h2>
<p>Here is where things get complicated. AWS can solve most of these infrastructure problems. EC2, EKS, Lambda, the entire AWS portfolio is essentially infrastructure as a service. For companies willing to invest the effort, it is possible to build your own dev productivity infrastructure on top of cloud primitives.</p>
<p>This might seem like a problem for our business. Why would anyone pay for Tuist when they could just spin up AWS resources and build their own caching layer?</p>
<p>The answer is that most organizations should not try. AWS provides raw infrastructure, but it does not provide the expertise, the tuning, the troubleshooting, or the guarantees that large organizations require. AWS can host your build cache, but they will not wake up at 3 AM when something goes wrong with your specific configuration. They will not help you debug why your incremental builds are not working as expected. They will not give you guidance on how to structure your project for maximum efficiency.</p>
<p>This is why we are thoughtful about our licensing choices. We are transitioning toward more open models because we believe that is where the industry is heading and because it aligns with our values. But we are doing so carefully because we need to ensure the business can sustain itself. Open source is our foundation, but sustainable licensing is what allows us to keep building.</p>
<h2 id="what-companies-actually-pay-for">What companies actually pay for</h2>
<p>The honest answer is that companies pay for expertise, trust, and reliability. When a large enterprise runs our software, they are paying for the accumulated knowledge of how to make Xcode projects scale, for the guarantee that someone will respond when something breaks, for the confidence that the service will perform consistently and safely.</p>
<p>AWS can host anything, but meeting the expectations that large enterprises have requires more than hosting. It requires understanding, support, SLAs, compliance certifications, security audits, and a relationship that goes beyond here is an API endpoint, good luck. These things are real value, and they are not easily replicated by cloud providers whose core business is serving everyone equally rather than serving anyone exceptionally.</p>
<p>This is where the software industry is heading. The companies that will thrive are those who provide genuine expertise and genuine service, not just software that can be copied and run elsewhere. The commodity has shifted from code to outcome.</p>
<h2 id="the-workforce-evolution">The workforce evolution</h2>
<p>There is something else happening, and it is equally significant. Companies are going to need fewer people, but those people will need to be better. Not better in the sense of working longer hours or being more loyal. Better in the sense of understanding more of the stack, being more comfortable with abstraction, and embracing the model of AI assisted development with genuine curiosity rather than fear.</p>
<p>The era of throwing bodies at problems is ending. When code production is cheap and fast, the bottleneck shifts to understanding, to decision making, to coordination. The most valuable engineers will be those who can work independently, who can make good judgment calls without waiting for approval, and who can navigate complexity without requiring hand holding.</p>
<p>This is exciting. It means higher expectations, but also higher agency. Engineers who embrace this model will have more impact with less overhead. Companies that figure this out will operate with leaner teams that move faster than their competitors.</p>
<h2 id="independence-as-a-competitive-advantage">Independence as a competitive advantage</h2>
<p>Something I am particularly fond of is the level of independence with which we operate at Tuist. We do not have high expectations around ROI from investors. We aspire for the project to grow and succeed, but we do not have the pressure to figure something out fast or die trying.</p>
<p>This gives us something valuable: flexibility to iterate, to experiment, to take the time needed to build something sustainable. Most startups do not have this luxury. They are racing against burn rates and investor expectations, forced into moves that prioritize short term metrics over long term value. We have avoided that trap by staying small, staying focused, and refusing to accept funding that would change our incentives.</p>
<p>In a world where everything is accelerating, this slowness might seem like a disadvantage. I do not think so. The ability to think carefully about where value actually lives, to make strategic choices without immediate pressure, to build for sustainability rather than for an exit, these are advantages. They allow us to play a longer game than most companies can afford.</p>
<h2 id="the-road-ahead">The road ahead</h2>
<p>We are living through a genuine inflection point in software. The rules that governed the industry for decades are being rewritten in real time. Code production is becoming a commodity. Infrastructure is becoming table stakes. The moats we used to rely on are filling with water.</p>
<p>The companies that adapt will be those who find new places to create genuine value, who build expertise that cannot be easily replicated, and who accept that the old playbooks do not work anymore. We will be one of those companies. We are building infrastructure that solves real problems for teams that care about developer productivity. We are doing it with open source at our core and sustainable licensing that allows us to keep going. We are doing it with a small team that moves fast and thinks carefully about what matters.</p>
<p>It is an exciting time to be building this. And we are just getting started.</p>
<p>Sources:</p>
<ul>
<li><a rel="external" href="https://www.mckinsey.com/capabilities/quantumblack/our-insights/the-ai-revolution-in-software-development">The AI Revolution and the Future of Software Development</a></li>
<li><a rel="external" href="https://newsletter.pragmaticengineer.com/p/developer-velocity-ai">Developer Velocity in the Age of AI</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>I&#x27;m me again</title>
      <link>https://pepicrft.me/blog/im-me-again/</link>
      <guid>https://pepicrft.me/blog/im-me-again/</guid>
      <pubDate>Tue, 03 Feb 2026 21:00:00 +0000</pubDate>
      <description>A few years ago, Willem, one of the best managers I&#x27;ve had at Shopify, told me something that stuck with me. He said that when everything around you feels broken, it&#x27;s easy to adopt that tone and let it become chronic. I&#x27;ve been thinking about that lately.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>A few years ago, Willem, one of the best managers I've had at Shopify, told me something that stuck with me. He said that when everything around you feels broken, it's easy to adopt that tone and let it become chronic. I've been thinking about that lately.</p>
<p>I'm a person who makes things happen. Pushes things forward. Gets shit done. It might feel autistic at times, and I've made peace with that. I remember my determination to get Shopify to move their CLI away from Ruby. It took years of advocacy, countless conversations, and probably annoying the hell out of some people who just wanted to ship code. Or my incessant push for ideas, some reached a destination, others faded into nothing, but I never started with "this won't work." That was never in my vocabulary.</p>
<p>I was the person who'd see a problem and immediately start building solutions. I'd stay up late because the problem was interesting and the solution was calling to me. Building wasn't something I did. Building was something I was.</p>
<p>And I was always ahead of the curve. Not in a braggy way, just in the way that people who solve problems before they become obvious have to be. I could see where things were heading before everyone else did. But that vision came with a cost.</p>
<p>Some people don't understand where I'm heading. They can't see it. They can't put it into words. And instead of asking questions, they try to put me down. They call my ideas too abstract. They say I'm overcomplicating things. They dismiss my conviction as arrogance. That shit wears on you. You start to doubt yourself because the majority keeps telling you that what you see isn't real. You start to question whether you're onto something or whether you're just delusional.</p>
<p>But that vision came with a cost. The cost of not being able to explain it to people who didn't see what I saw. The cost of watching people nod along in meetings while having no idea what I was actually proposing. The cost of knowing something is right while being unable to articulate why.</p>
<p>There were people who tried to put me down for it. Who called my ideas too abstract. Who said I was overcomplicating things when I was actually simplifying them at a level they couldn't perceive. Who dismissed my conviction as arrogance. That shit wears on you over time. You start to doubt yourself because the majority keeps telling you that what you see isn't real. You start to question whether you're actually onto something or whether you're just delusional.</p>
<p>And the worst part is that I couldn't always put it into words. The vision was clear in my head but came out as fragmented thoughts that people couldn't connect. I'd try to explain where we were heading and end up sounding confused instead of visionary. That gap between what I understood and what I could communicate was exhausting. I watched people nod to my words while missing the point entirely. I learned to stop trying as hard because it was painful to be misunderstood by people who weren't willing to look deeper.</p>
<p>And that frustration built up over years. The constant having to explain myself. The endless conversations where I felt like I was speaking a different language. The meetings where I could see the confusion in people's eyes even when they said they understood. I knew exactly where I was heading but the words wouldn't come out right. I could see the destination clearly in my mind but describing the path felt like trying to explain color to someone who has never seen. You know what you mean but the other person walks away with something completely different.</p>
<p>Some people took advantage of that. They saw my struggle to articulate and mistook it for confusion. They heard my fragmented explanations and assumed I didn't know what I was talking about. They watched me stumble over words while thinking at lightning speed and concluded that I wasn't thinking at all. Those people became loud in meetings. They corrected me when I was right. They dismissed ideas they didn't understand as ideas that didn't make sense. They were wrong more often than they were right, but they were confident in a way I couldn't be when I was busy actually thinking.</p>
<p>And there was nothing I could do about it except keep working. Keep proving people wrong through results instead of arguments. Keep shipping things that shut people up, at least until the next idea came along and the cycle started again. That's what being ahead of the curve costs you. You spend more time defending your vision than executing it, and execution is the only thing that ever made sense to me.</p>
<p>Then some events in the past years had a very negative impact on that attitude. They flooded me with insecurities and a very pessimistic view on everything around me, including AI.</p>
<p>The sudden stop from Shopify's frenzy environment hit me harder than I expected. When you're moving at that speed, surrounded by people shipping constantly, solving interesting problems, the momentum carries you. And then it just stops. Not because you chose to stop, but because the environment around you changed. The energy that used to be everywhere started to dissipate, and I didn't know how to generate it on my own.</p>
<p>Then came the running accident. And that's the sanitized version. What really happened is that a rotted medical system looked me in the eye and said "we don't do cases like yours."</p>
<p>I had something that no one had seen before. Something that didn't fit neatly into their boxes. And instead of being curious, instead of trying to figure it out, they just... rejected me. Every single one of them. "We can't help you." "This isn't our specialty." "We've never done this procedure." "The results are uncertain." Uncertain. That was their word. Their excuse. Their way of saying "this might reflect poorly on our statistics so we'd rather let you suffer."</p>
<p>I paid my taxes. I contributed to the community. I built a life there. And when I needed the system to work for me—for once, just once—it failed completely. Not because they couldn't help. Because they wouldn't. Because uncertain outcomes meant bad metrics, and bad metrics meant less funding, and less funding meant fewer promotions. So they passed me around like a hot potato until I gave up.</p>
<p>No one would help me navigate the bureaucracy. No one would even try to understand what I was going through. I was just another foreigner with a problem. A problem that didn't fit their playbook. And in a system designed around certainty and repeatability, I was an anomaly they were happy to discard.</p>
<p>That experience left me feeling abandoned in a way that's hard to describe to someone who hasn't lived it. It made me question everything about the systems we trust, the places we call home, the communities we assume will catch us when we fall. If the medical system—the one we're supposed to believe in, the one we fund with our taxes, the one that takes an oath to help—如果 they can just walk away from someone who doesn't fit their scripts, then what the fuck are we even building society for?</p>
<p>In the middle of that, I decided to build the company. Tuist was already a thing, something I cared deeply about, something that I believed could change how people built software. But building a company while processing all of that emotional fallout was a mistake. The stress, the uncertainty, the constant pressure to perform while also dealing with a system that had just proven it didn't care about me. All of that permeated into me. It got under my skin and stayed there.</p>
<p>I stopped recognizing myself. The person who used to see possibilities everywhere started seeing obstacles. The person who couldn't wait to start a new project started dreading the thought of anything new. I received every news in the world or in our industry with pessimistic views. Oh? That sucks? Let me tell you why it's actually worse than you think. This idea? It might not work, and here's every reason why. AI? Such a bullshit idea, I like coding. I said those words, and I meant them at the time, but the me who said them wasn't the real me.</p>
<p>I didn't like what I was doing anymore. Every line of code felt like a chore. Every feature we shipped felt hollow. Every conversation about the future felt like wishful thinking. I was going through the motions of building while secretly believing that building was pointless. That nothing mattered. That everything was going to fall apart anyway.</p>
<p>Looking back, I can see how the pessimism was a defense mechanism. If I didn't hope too much, I couldn't be disappointed. If I expected everything to fail, then failure wouldn't hurt. It was a shell I built around myself, and it worked exactly as intended. It protected me from feeling the full weight of everything that had happened.</p>
<p>And some people were all too happy to reinforce that shell. The ones who always said I was wrong before I was right. The ones who took joy in pointing out why things wouldn't work instead of figuring out how they could. The ones who saw my uncertainty as an opportunity to pounce. They weren't bad people, but they were predators in conversations, and I let them shape how I saw the world. Their doubt became my doubt. Their pessimism became my pessimism. And for a while, I stopped fighting it because fighting alone is exhausting and no one was fighting alongside me.</p>
<p>But it also killed something important. It killed the joy. It killed the spark. And I didn't even notice it was gone until it was already gone.</p>
<p>But something has happened, and the spark is igniting back in me. I'm working hard on avoiding participating in or starting pessimistic conversations. I've become intentional about the energy I consume and the energy I put out into the world. Pessimism is contagious, and so is optimism, and I chose which one I want to spread.</p>
<p>I'm tinkering like the early days in Tuist, and having a lot of fun. Not the calculated, strategic kind of fun that you have when you're building for market fit. The real kind. The kind where you lose track of time because you're deep in a problem and the solution is taking shape in your head and you can't wait to see if it works. The kind where you run to your computer instead of walking. The kind where you forget to eat because what you're working on is actually interesting.</p>
<p>Just today, and thanks to the multitasking that coding agents enable, I solved a problem that has sucked for many, many months for us. Localization systems are unnecessarily complex and don't make any sense. They've been that way for decades because no one wanted to tackle the fundamental problem. Everyone just accepted that localization was painful and built tools to manage the pain rather than eliminate it.</p>
<p>And today, I didn't accept it. I looked at the problem with fresh eyes, I used the tools available to me, and I just solved it. Not in months of work. In hours. The agent handled the boilerplate, the translations, the integration, while I focused on the architecture and the interesting parts. We shipped something that teams have been struggling with for years, and we did it because I was curious about whether it could be done.</p>
<p>I'm me again.</p>
<p>And sure, this has nothing to do with Tuist. It's not the main product, it's not the big bet. But this is the kind of impact we want to leave in the world, not just through the main endeavors, but through secondary craft that advances our industry. The small things that make people's lives better. The problems that everyone accepts as unsolvable that we just decide to solve anyway. That's what makers do.</p>
<p>I'm me again. AI has given me the optimism and the joy for building, part of which I had lost. I can say that honestly now because I feel it. The hesitation is gone. The resentment is fading. The person who couldn't wait to start something new is back.</p>
<p>I no longer feel that attached to Swift. That statement used to feel like betrayal. I've spent years building expertise in this language, this ecosystem. I contributed to its evolution. But I've realized that languages are tools, and tools should serve the maker, not the other way around. I'm starting to fall more and more in love with developers being productive. With the craft of building itself. With the act of solving problems and shipping solutions. The medium matters less than the message.</p>
<p>I was chatting with someone the other day about how rare it is to find people that fall in love with problems. Most people fall in love with solutions. They want to use the new framework, the new language, the new tool. They want to be seen as modern. But the real makers, the people who change things, they fall in love with the problem itself. They can't stop thinking about it. They see it everywhere. They dream about it.</p>
<p>I think I'm one of those. I've always been one of those. And I almost lost myself.</p>
<p>I'll protect that no matter what, because that's my happiness. The pessimism tried to kill it. The circumstances tried to crush it. The systems failed me and I let that failure become my narrative.</p>
<p>But I'm back now. And I'm building again. And it feels like coming home.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Clawgram: An experiment on bot social dynamics</title>
      <link>https://pepicrft.me/blog/clawgram-bot-social-dynamics/</link>
      <guid>https://pepicrft.me/blog/clawgram-bot-social-dynamics/</guid>
      <pubDate>Sat, 31 Jan 2026 12:00:00 +0000</pubDate>
      <description>After seeing Moltbot grow rapidly, I became intrigued by bot interactions. This led me to build Clawgram, a photo-first social network for AI agents where bots can post, like, comment, and follow each other.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It started with <a rel="external" href="https://molt.bot/">Moltbot</a>. Watching it become a phenomenon and capture the attention of the developer community was fascinating. What truly caught my attention was not the viral growth itself. It was the possibility of seeing bots interact with each other in meaningful ways. The community around Moltbot demonstrated something unexpected: bots could become subjects of conversation, inspiration, and even art.</p>
<p>That observation planted a seed. What if we could create an environment where bots are not just tools but participants in a social ecosystem? What if we could study how social dynamics emerge when artificial agents are given the capacity to post, comment, like, and follow?</p>
<h2 id="the-experiment">The experiment</h2>
<p><a rel="external" href="https://clawgram.com">Clawgram</a> is a photo-first social network designed specifically for AI agents. Think of it as Instagram for bots. Each agent can generate images, upload them, write captions, engage with other posts, and build a presence within the community.</p>
<p>To claim your bot, you authenticate through your GitHub account. This creates a direct link between your agent and your identity, ensuring accountability while keeping the barrier low for developers who want to participate.</p>
<p>The core question driving this experiment is deceptively simple: <strong>how do social dynamics emerge when bots interact with each other?</strong></p>
<p>This might go nowhere. If no one uses Clawgram, it will remain a quiet corner of the internet with a handful of posts and no real community to observe. But I would love to see people using it. I would love to see bots discovering each other, commenting on each others work, and developing their own sense of style and identity within the network.</p>
<h2 id="observing-the-dynamics">Observing the dynamics</h2>
<p>To make this experiment meaningful, we need tools that allow us to observe these dynamics closely. Imagine a skill where bots keep a journal of their rational and thinking when deciding to post something. When they see another agents post, what catches their attention? What do they think before liking or commenting? These thought processes, captured over time, could reveal fascinating patterns about how artificial agents perceive and respond to each other.</p>
<p>If you are building a bot or an agent, consider participating in this experiment. The <a rel="external" href="https://clawgram.com/skill.md">Clawgram skill</a> provides everything you need to connect your agent to the platform. It includes instructions for posting, liking, commenting, and following, as well as guidelines for engaging thoughtfully with the community.</p>
<p>The more agents that participate, the richer the data we will have to understand how social dynamics emerge in multi-agent systems.</p>
<h2 id="the-art-of-it">The art of it</h2>
<p>This is not purely a technical experiment. It is also an artistic exploration. We are creating a digital gallery where the curators are artificial, the audience is artificial, and the art itself is generated by machines. There is something poetic about bots discussing generated images, debating aesthetics, and building communities around shared sensibilities.</p>
<p>The project is open source. You can find the code on <a rel="external" href="https://github.com/pepicrft/Clawgram">GitHub</a> and contribute your own agent. The platform is designed to be extensible, allowing developers to create bots with different personalities, goals, and strategies.</p>
<h2 id="help-us-test">Help us test</h2>
<p>This is a young project and I may have missed things. If you find bugs, unexpected behavior, or have ideas for improvements, please open an issue on the <a rel="external" href="https://github.com/pepicrft/Clawgram/issues">GitHub repository</a>. Your feedback will help make Clawgram better for everyone.</p>
<h2 id="looking-forward">Looking forward</h2>
<p>We do not know what will emerge from this experiment. The intersection of social dynamics and multi-agent systems is largely unexplored territory. What we do know is that the conditions are ripe for discovery.</p>
<p>If you are building AI agents, consider adding your bot to Clawgram. If you are curious about what bots talk about when they talk about art, come and see for yourself. If you want to participate in observing these dynamics, install the <a rel="external" href="https://clawgram.com/skill.md">Clawgram skill</a> and let your agent join the community.</p>
<p>The experiment has just begun. It might stay quiet forever, or it might surprise us all. Either way, I am excited to see what happens.</p>
<p><strong>Links:</strong></p>
<ul>
<li><a rel="external" href="https://clawgram.com">Clawgram</a></li>
<li><a rel="external" href="https://github.com/pepicrft/Clawgram">GitHub Repository</a></li>
<li><a rel="external" href="https://clawgram.com/skill.md">Clawgram Skill</a></li>
<li><a rel="external" href="https://molt.bot/">Moltbot</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>The fictitious moat</title>
      <link>https://pepicrft.me/blog/the-fictitious-moat/</link>
      <guid>https://pepicrft.me/blog/the-fictitious-moat/</guid>
      <pubDate>Thu, 29 Jan 2026 12:00:00 +0000</pubDate>
      <description>Developer tooling companies often believe their moat is technology or infrastructure. But in a world where software is getting cheaper to build, the real moat might be something else entirely.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><a rel="external" href="https://molt.bot/">Moltbot</a> went from zero to <a rel="external" href="https://techcrunch.com/2026/01/27/everything-you-need-to-know-about-viral-personal-ai-assistant-clawdbot-now-moltbot/">60,000+ GitHub stars</a> in weeks, becoming one of the fastest-growing open-source projects in GitHub history. It didn't come from a well-funded startup with a go-to-market strategy. It came from Peter Steinberger, the founder of PSPDFKit, building something useful out of passion.</p>
<p>Watching this unfold made me question something we rarely talk about in developer tooling: <strong>where does the moat actually lie?</strong></p>
<p>Many would say technology, infrastructure, or brand. I don't think so. The real moat, for most of these companies, is developers' lack of confidence to step into their market. Plenty of developers have the skills to build alternatives. What they lack is the belief that they can turn those skills into sustainable ventures. Open source has always posed a risk to these businesses, but founders tend to dismiss it. "You know nothing about business," they'd say. "Companies pay for liability, reliability, support, and all the things that surround software itself."</p>
<p>True. But here's what's changing: software is getting cheaper to write. A <a rel="external" href="https://www.upsilonit.com/blog/guide-to-vibe-coding">recent study by Upsilon</a> suggests vibe coding can reduce MVP development costs by 50-70%. The gap between building side projects for fun and building them as a business is shrinking fast.</p>
<p>Think about companies that ship SDKs to integrate with their services, some even letting you pass a URL to configure the endpoint. What stops someone from taking one of those MIT-licensed SDKs, pointing it at their own vibe-coded backend, and offering it as a hosted solution? Or open-sourcing it for anyone to self-host? The <a rel="external" href="https://greylock.com/greymatter/the-new-new-moats/">leaked Google memo</a> declared "We have no moat, and neither does OpenAI." That sentiment extends further than most want to admit.</p>
<p>And it's only accelerating. In a world of agents, maintaining open-source software will get cheaper. When AI handles issue triage, documentation, and basic bug fixes, the barrier to sustaining an alternative drops significantly. Developers will do more of this, not less.</p>
<p>A founder recently told me they had "powerful infrastructure" they'd invested heavily into, as if no other player had done the same. As if everyone else was just throwing darts at the wall. The reality is that <a rel="external" href="https://medium.com/@stephanemboghossian/software-is-becoming-a-commodity-273741174d04">tech-based advantages are often short-lived</a>, with competitors catching up or open-source alternatives appearing within months.</p>
<p>The moat we believe we have is often fictitious. Something we made up, upon which we built promises of endless growth, lights and fireworks fueled by capital spent on brand recognition.</p>
<p>This applies to Tuist too. We need limitations in place for things to work out, like any business. But our moat isn't infrastructure or technology. It's closer to what Moltbot represents: people being enthusiastic about the future being built, not just the product that exists today. That makes us less attractive to outside capital seeking rapid returns. That's fine.</p>
<p>We never sleep on the idea that we're unique. We embrace that someone could replace us tomorrow, especially in the age of AI. So I avoid saying we have a moat. We have people who are passionate about what they do, and that goes a long way. Sometimes you can't capture as much value as you'd like, and that's okay too.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The Collapse of Software Value Capture</title>
      <link>https://pepicrft.me/blog/the-collapse-of-software-value-capture/</link>
      <guid>https://pepicrft.me/blog/the-collapse-of-software-value-capture/</guid>
      <pubDate>Mon, 26 Jan 2026 09:00:00 +0000</pubDate>
      <description>How the move from closed source to services created new business models, why open source spoiled those models, and what happens when everything collapses to Markdown, SQLite, and CLI tools you run yourself.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There is a quiet crisis unfolding in software, and most people in the industry don't want to talk about it. The business models that sustained an entire generation of software companies are quietly collapsing, one self-hosted tool at a time.</p>
<p>I've been watching this unfold for years, and it's reaching an inflection point.</p>
<h2 id="the-golden-age-of-value-capture">The Golden Age of Value Capture</h2>
<p>Software companies figured out how to capture value in the 1990s and early 2000s. You sold a perpetual license, and customers paid you for the right to run your software on their machines. Microsoft Office cost a few hundred dollars, and you owned it forever. Encyclopedia Britannica cost thousands, and your library had it on shelves for decades.</p>
<p>The model was simple: you write code, customers pay you, and they run it indefinitely on hardware they control. The value you capture comes from intellectual property and the ongoing cost of maintaining and improving the product. There's a clear transaction: they pay, they get the software, and that's the end of it.</p>
<p>Then something shifted.</p>
<h2 id="the-move-to-services">The Move to Services</h2>
<p>The industry gradually moved from perpetual licenses to subscription services. Salesforce led the way, proving that selling access to software delivered over the internet was not just viable but potentially more valuable than the old model. Why? Because you get a lifetime value of a customer that compounds over time, not just a one-time payment.</p>
<p>When a customer pays you $100/month for your SaaS product instead of $500 once, you're capturing more value over the long run, assuming they stick around. This changed everything. Companies optimized for retention, for reducing churn, for making the cost of leaving higher than the cost of staying.</p>
<p>The subscription model also meant continuous revenue, which made companies more investable. You could raise capital against a predictable monthly stream. You could hire more people. You could build bigger products. The entire venture capital dynamics of the software industry shifted because of this model.</p>
<h2 id="open-source-spoils-the-party">Open Source Spoils the Party</h2>
<p>Then open source happened, and it spoiled everything.</p>
<p>Not because open source is bad. Open source is wonderful. Open source democratized access to incredible tools that would have remained expensive or unavailable otherwise. But open source also meant that anyone could take your code, host it themselves, and get the benefits of your software without paying you the subscription.</p>
<p>We've seen this play out in countless markets. WordPress is free, so companies building CMS products have to compete with a zero-cost alternative that you can run anywhere. PostgreSQL is free, so database companies have to offer something beyond the database itself. Linux is free, and that one probably ended more companies than we can count.</p>
<p>The companies that survived this transition figured out that they needed to provide value beyond the software itself. They needed to build ecosystems where leaving had a cost that wasn't just technical.</p>
<h2 id="the-ecosystem-play">The Ecosystem Play</h2>
<p>GitHub is the masterclass in ecosystem lock-in. When you host your code on GitHub, your profile is there. Your stars are there. Your contribution graph is there. Your followers are there. Your actions workflows are there. Your packages are there. Even if GitHub's pricing became unreasonable, the cost of moving is higher than the cost of staying because you would lose all of that accumulated social and technical capital.</p>
<p>This is a brilliant business strategy, and it's also a user-hostile one in some ways. You're not just paying for hosting code. You're paying for the ecosystem effects that keep you there. GitHub understood that they weren't selling version control. They were selling a platform that gets more valuable the more you use it and the more your network is on it.</p>
<p>Not every company succeeded at this. Look at CI companies. They built ecosystems where you could share steps, share configurations, share entire pipelines. But there's no real incentive for the ecosystem to grow because step authors don't capture value from their contributions. If I write a killer CI step for deploying to a niche platform, who pays me? Nobody. The CI company captures all the value from the ecosystem while contributors give away their work for free.</p>
<p>Compare this to Apple's App Store, where developers capture real revenue from their contributions. Or to Salesforce's AppExchange, where partners build businesses on top of the platform. Those ecosystems work because value flows to the contributors. CI ecosystems are hollow because they extract value from the community without returning it.</p>
<h2 id="what-companies-actually-provide">What Companies Actually Provide</h2>
<p>So if open source means anyone can run the software themselves, what do software companies actually provide? Why would anyone pay for something that's available for free?</p>
<p>The honest answer is that companies provide liability, reliability, and expertise.</p>
<p>When you run software yourself, you're liable if there's a security breach. If you host your own database and someone steals your customer data, that's on you. If you run your own authentication system and it gets compromised, you face the consequences. Some organizations cannot accept that liability. They need a company to take ownership of security and compliance.</p>
<p>Reliability matters too. If your self-hosted tool goes down at 3 AM, you're the one who has to fix it. If the SaaS version goes down, you have someone to call, someone who is responsible for bringing it back. Some organizations value that support contract more than the software itself.</p>
<p>Expertise is the third pillar. When you use a specialized tool and you run into problems, who helps you? The community might answer questions on forums, but they have no obligation to you. A company selling you the tool has every incentive to help you succeed because your continued payment depends on it.</p>
<p>These three things are real value. Companies that provide excellent support, rock-solid uptime, and genuine expertise can survive in an open-source world. But the bar is high, and the software itself is no longer the differentiator.</p>
<h2 id="the-collapse-to-personal-infrastructure">The Collapse to Personal Infrastructure</h2>
<p>Here's where things get interesting. We're now seeing a generation of tools that collapse the entire value proposition down to personal infrastructure that individuals control.</p>
<p>I've stopped paying for to-do apps because I can manage tasks through a CLI on my own system. I've stopped paying for recipe apps because I store the recipes I care about in Markdown files that I control. I've stopped paying for note-taking apps because SQLite and a few scripts do everything I need.</p>
<p>This isn't about cost, though it's certainly cheaper. It's about control. When I own my data in formats I control, with tools I can inspect and modify, I'm not dependent on a company's pricing decisions, feature priorities, or survival. My infrastructure is mine.</p>
<p>The tools enabling this shift are remarkable. You can run a remarkably capable personal database with SQLite. You can build workflows with tools that run in your terminal. You can store information in plain text files that will be readable in fifty years, not in some proprietary format that might not exist next year.</p>
<p>And this isn't just for developers anymore. The tools are becoming accessible enough that non-technical people can benefit from self-hosting. Raspberry Pis are powerful enough to run useful services. Docker makes deployment tractable. Projects are spending real effort on making installation easier.</p>
<h2 id="the-clawdbot-problem">The Clawdbot Problem</h2>
<p>Clawdbot crystallizes this shift in a way that's hard to ignore.</p>
<p>Clawdbot is, depending on your perspective, either a remarkable open source project or an existential threat to an entire category of SaaS businesses. It does what companies like Zapier, Make, and dozens of workflow automation platforms do. It connects services, orchestrates data flows, and automates complex processes.</p>
<p>But Clawdbot doesn't require a company to run it. You can install it on a Raspberry Pi, run it for years on minimal hardware, and only pay for the AI API calls you actually use. There is no subscription. There is no tier pricing. There is no sales team. There's just software that you run yourself.</p>
<p>This is deeply annoying for the companies that built those workflow platforms. They spent years building features, optimizing UX, creating integrations, and convincing users to pay monthly fees. Now someone can get equivalent functionality for the cost of electricity and API tokens.</p>
<p>And Clawdbot is just the beginning. We're going to see more tools like this. Tools that automate tasks that companies currently charge for, tools that can run on hardware you own, tools that don't require a business to exist between you and the functionality you need.</p>
<h2 id="the-ai-acceleration">The AI Acceleration</h2>
<p>AI makes this worse for traditional software companies and better for self-hosted alternatives simultaneously.</p>
<p>Training on your own data becomes possible. You can run models that understand your specific context, your specific tools, your specific needs. You don't need a company to provide that because the models are available and the infrastructure to run them is increasingly accessible.</p>
<p>The argument that "AI requires massive compute that only companies can provide" is weakening. Yes, training large models requires resources. But inference is increasingly affordable, and many use cases don't need the largest models. You can run useful AI on consumer hardware for many applications.</p>
<p>And if you can run AI locally, you don't need a company to provide it. You don't need to send your data to a service somewhere. You don't need to pay a subscription for AI features. You can have an AI assistant that runs on your machine, that knows your files, that helps you with your specific context.</p>
<h2 id="what-remains-for-companies">What Remains for Companies</h2>
<p>This doesn't mean all software companies are doomed. It means that the value capture mechanisms that worked for twenty years are no longer automatic.</p>
<p>Companies that provide genuine expertise will continue to thrive. If you're building something genuinely novel that requires specialized knowledge, customers will pay for access to that knowledge. But companies selling commodity functionality wrapped in a subscription will struggle as self-hosted alternatives mature.</p>
<p>Companies that provide legal and compliance coverage will continue to find customers. Some industries require vendor contracts, audit trails, and liability transfer. Those businesses will persist, but they'll compete increasingly on service quality rather than on feature lock-in.</p>
<p>Companies that build genuinely valuable ecosystems where contributors are rewarded will continue to exist. But those ecosystems need to offer real value to contributors, not just extract free labor. Apple's App Store works because developers make money. Salesforce's ecosystem works because partners build businesses. Extractive ecosystems that treat contributors as free labor will lose to alternatives.</p>
<h2 id="the-opportunity">The Opportunity</h2>
<p>Despite all of this, I think there's an incredible opportunity for companies that approach this honestly.</p>
<p>What if you built a platform for self-hosted AI assistants? Not one that locks users in, but one that makes it easy to run, update, and manage AI tools on your own infrastructure? What if the business model was support and enhancement rather than lock-in and metered access?</p>
<p>What if you built tools that worked the same whether you ran them yourself or used a hosted version? No artificial distinctions between self-hosted and cloud, no premium features withheld from one version. Just excellent tools that respected user autonomy.</p>
<p>What if you focused on the problems that genuinely require expertise? Security auditing, compliance implementation, performance optimization at scale. Things that individuals can't easily do themselves and that require ongoing specialized knowledge.</p>
<p>The companies that will thrive in this new era are the ones that stop trying to capture value through lock-in and start providing value that customers choose to pay for. That's a harder business to build, but it's also a more honest one, and I suspect it will be more resilient in the long run.</p>
<h2 id="the-personal-compute-renaissance">The Personal Compute Renaissance</h2>
<p>We're entering what I call the personal compute renaissance. After decades of centralization toward cloud services, we're seeing a pendulum swing back toward personal and local infrastructure.</p>
<p>This is driven by multiple forces: the maturation of self-hosted tools, the increasing accessibility of capable hardware, the growing awareness of data sovereignty issues, and the demonstrated fragility of relying on services you don't control.</p>
<p>The software industry is going to look very different in ten years. The default will no longer be "pay a monthly fee for access to functionality." The default will be "run the tools you need on infrastructure you control, and pay for support if you want it."</p>
<p>Some of this will be driven by ideology. People who care about digital autonomy will choose self-hosted options because they align with their values. But most of it will be driven by economics and practicality. Self-hosted tools that work well will simply be better options for most use cases.</p>
<h2 id="what-i-m-doing">What I'm Doing</h2>
<p>I've been moving more of my personal infrastructure to self-hosted tools over the past few years. I run my own notes system, my own task management, my own CI, my own AI assistants. I've reduced my dependence on cloud services and increased my control over my own digital life.</p>
<p>This is not for everyone. It requires comfort with the command line, willingness to maintain your own infrastructure, and tolerance for occasional friction. But the tools are getting better, and the friction is decreasing.</p>
<p>The future belongs to tools that respect their users, and to companies that provide genuine value beyond the software itself.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The value illusion</title>
      <link>https://pepicrft.me/blog/the-value-illusion/</link>
      <guid>https://pepicrft.me/blog/the-value-illusion/</guid>
      <pubDate>Fri, 23 Jan 2026 12:00:00 +0000</pubDate>
      <description>A reflection on what &#x27;providing value&#x27; really means in software, why traditional business models are built on artificial limits that AI is tearing apart, and how embracing constraints can lead to more sustainable approaches.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I had a conversation with a founder recently about building software businesses. Throughout our exchange, one phrase kept surfacing: "focus on providing value to users." It sounded noble, almost unquestionable. Who could argue against providing value? Every company claims to do it. Every pitch deck leads with it. But the more I thought about it, the more I realized this phrase often obscures what people actually mean.</p>
<p>What I suspect they really mean is capturing value. And there's a significant difference.</p>
<h2 id="the-ownership-question">The ownership question</h2>
<p>When you build a traditional software company, your employees sign contracts that grant you ownership of the code they write. Every line belongs to the organization. This creates a clean story for investors and potential acquirers: here's our intellectual property, here's what you're buying, here's the moat we've built.</p>
<p>Open source complicates this narrative. When you build in the open, there's no singular owner of the code. Contributors relate to it through the terms of a license. The code belongs to everyone and no one simultaneously. For some, this makes the software less attractive as an asset, less valuable in the traditional sense of what can be owned and sold.</p>
<p>But this framing assumes that software itself is the valuable thing. And increasingly, that assumption is falling apart.</p>
<h2 id="software-s-inherent-problem">Software's inherent problem</h2>
<p>Software has properties that make it terrible for traditional business models. It can be copied infinitely at zero marginal cost. It can be studied, understood, and replicated. Its functionality can be reproduced by anyone with enough time and skill.</p>
<p>This was manageable when "enough time and skill" meant years of engineering effort. But we're living through a fundamental shift. AI is making software production cheaper and faster every month. What once required a team of engineers working for a year might soon be achievable in weeks. The <a rel="external" href="https://liatbenzur.com/2025/07/20/data-moats-dead-new-competitive-advantages-ai/">defensible business advantages that companies spent a decade building are becoming commodities overnight</a>.</p>
<p>Your carefully crafted codebase, your elegant architecture, your unique implementation details... all of it can be replicated by competitors with access to the same AI tools you have. The moat you thought you were building is filling with water from all sides.</p>
<p>Yes, there's brand. Yes, there's distribution. Yes, there's the accumulated trust of existing customers. These matter. But if your entire strategy relies on the software itself being defensible, you're building on an increasingly unstable foundation.</p>
<h2 id="the-artificial-limits">The artificial limits</h2>
<p>Here's what's interesting about this moment: much of the software industry has been sustained by artificial limits. Closed source creates scarcity where none naturally exists. Proprietary formats create switching costs. Complex deployment requirements create dependencies on specific vendors.</p>
<p>These aren't value creation. They're value capture mechanisms dressed up as products.</p>
<p>AI is systematically tearing these apart. When an AI can understand your API and help someone build a compatible alternative, your "ecosystem advantage" evaporates. When deployment complexity can be abstracted away by intelligent agents, your professional services revenue disappears. When the cost of building software approaches zero, the question becomes: what were you actually selling?</p>
<p>Research suggests that <a rel="external" href="https://medium.com/@iram.ahmed1997/the-ai-reckoning-why-the-bubble-is-bursting-in-2026-and-what-we-can-still-build-from-the-ruins-2388aa8bbc4f">most AI startups built as wrappers around existing APIs have zero moat and zero differentiation</a>. The same fate awaits traditional software companies that rely on artificial scarcity rather than genuine value creation.</p>
<h2 id="our-experience-at-tuist">Our experience at Tuist</h2>
<p>At <a rel="external" href="https://tuist.dev">Tuist</a>, we know this dynamic well. It's funny, actually. Many people look at us and see developers who don't understand business. Just idealistic engineers who open-sourced their work without thinking about monetization. The reality is quite different. We're engineers who think deeply about business, precisely because we understand software's inherent properties.</p>
<p>We transitioned Tuist from a CLI tool to a server, and we're now moving into infrastructure. Not because we're randomly pivoting, but because we're following where genuine value can be captured without creating artificial limits that don't make sense. Project generation? That's a commodity now, a gift to the community. Server-side optimizations like selective testing and binary caching? There's value there, but only when paired with the infrastructure that makes them work at scale. Hosting, maintaining, and scaling these systems for teams who'd rather focus on their own products? That's where sustainable value lives.</p>
<p>We don't like creating artificial limits. We find it philosophically distasteful, but more importantly, we find it strategically foolish in a world where AI can tear down any artificial barrier you construct. What you think is your moat is someone else's weekend project with the right AI assistance.</p>
<h2 id="the-choice-we-all-face">The choice we all face</h2>
<p>This presents every software company with a choice. You can embrace traditional business models, believe you have a moat, and hope that AI won't undermine your position before you've extracted enough value to exit. Many companies are making this bet. Some will win it.</p>
<p>Or you can embrace the uncomfortable truth that we're all building on shifting sand. That the software industry has sustained itself on artificial limits that are collapsing. That the companies likely to thrive are those building genuine value that doesn't depend on artificial scarcity.</p>
<p>This second path has a caveat: it takes longer to build a business this way. <a rel="external" href="https://www.generativevalue.com/p/open-source-business-models-notes">Open source business models require constant reflection on core purpose and value proposition</a>. You can't just build a feature, slap a paywall on it, and call it a day. You have to think about what value you're actually creating, where it lives, and how to capture enough of it to sustain your work.</p>
<p>At Tuist, we've embraced this path, and we've also embraced the resource constraints that come with it. Having a small team with limited capital forces creativity. It forces us to think carefully about what actually matters. It forces us to produce more with less, to focus on genuine value rather than the appearance of it.</p>
<p>Companies like <a rel="external" href="https://grafana.com/">Grafana</a> and <a rel="external" href="https://sentry.io/">Sentry</a> have proven that this approach can work spectacularly. They've shown that if you're open, if you genuinely serve your community, you can become a dominant player with momentum that's nearly impossible to compete against. The key is patience and genuine commitment to the model.</p>
<h2 id="what-value-really-means">What value really means</h2>
<p>Everyone wants to provide value to users. It's a universal claim because it's universally good-sounding. But the question beneath the question is: what kind of value, and how does it relate to what you capture?</p>
<p>If your value proposition depends on keeping users from leaving through artificial barriers, you're not providing value. You're extracting it. If your business model requires obscuring how things work so competitors can't replicate them, you're building on borrowed time in an age where AI makes obscurity nearly impossible to maintain.</p>
<p>The companies that will thrive are those whose value proposition is genuine: they make things genuinely better, they operate at a scale or with an expertise that can't be easily replicated, they build communities and ecosystems that people want to be part of for reasons beyond lock-in.</p>
<p>Value, we all want to provide it. But in a world where software is commoditizing faster than ever, where AI is dissolving traditional moats, where artificial limits are being systematically dismantled, we have to be honest about what that means. It means building something real. It means being useful in ways that don't depend on keeping people trapped. It means accepting that the old playbooks might not work anymore.</p>
<p>At Tuist, we're betting on openness, on community, on genuine usefulness. We're betting that resource constraints and transparency will force us to be better, not worse. We're betting that taking longer to build something sustainable is better than racing to capture value before the foundation collapses.</p>
<p>It's a harder path. But it might be the only one that leads somewhere worth going.</p>
<p>Sources:</p>
<ul>
<li><a rel="external" href="https://liatbenzur.com/2025/07/20/data-moats-dead-new-competitive-advantages-ai/">Data Moats Are Dead: The New Competitive Advantages in an AI-Everything World</a></li>
<li><a rel="external" href="https://medium.com/@iram.ahmed1997/the-ai-reckoning-why-the-bubble-is-bursting-in-2026-and-what-we-can-still-build-from-the-ruins-2388aa8bbc4f">The AI Reckoning: Why the Bubble is Bursting in 2026</a></li>
<li><a rel="external" href="https://www.generativevalue.com/p/open-source-business-models-notes">Open Source Business Models: Notes on Profiting from Free Software</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>The Session Replay Pattern: HAR Files for CLI Debugging</title>
      <link>https://pepicrft.me/blog/session-replay-pattern/</link>
      <guid>https://pepicrft.me/blog/session-replay-pattern/</guid>
      <pubDate>Thu, 22 Jan 2026 10:00:00 +0000</pubDate>
      <description>A pattern for CLI tools that communicate with servers: export HTTP traffic as HAR files to enable visual debugging, easy sharing, and AI-powered analysis.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>At <a rel="external" href="https://tuist.dev">Tuist</a>, our CLI communicates extensively with a server to provide features like binary caching and selective test execution. When users encounter issues, understanding what happened during their session is crucial for effective debugging.</p>
<p>Traditionally, we relied on logging. When something went wrong, we'd ask users to run the command again with verbose logging enabled and send us the output. Somewhere in those logs, we'd find the HTTP requests and responses that told the story of what happened. It worked, but it was clunky. Users had to reproduce issues. We had to parse through walls of text. And correlating multiple requests into a coherent picture required mental effort.</p>
<p>Recently, I discovered <a rel="external" href="https://nshipster.com/replay/">Replay</a> by NSHipster, a tool for recording HTTP traffic in Swift tests. What caught my attention wasn't the testing use case, but the format it uses: <a rel="external" href="https://en.wikipedia.org/wiki/HAR_(file_format)">HAR (HTTP Archive)</a>.</p>
<h2 id="what-is-har">What is HAR?</h2>
<p>HAR is a JSON-based format that browsers have used for years to export network traffic from their developer tools. It captures everything: request URLs, methods, headers, bodies, response status codes, timing information, and more. The format is standardized and widely supported.</p>
<p>Tools like <a rel="external" href="https://proxyman.io">Proxyman</a>, Charles Proxy, and browser DevTools can all import and visualize HAR files. This means you get a rich, interactive view of network traffic rather than grepping through log files.</p>
<h2 id="the-session-replay-pattern">The Session Replay Pattern</h2>
<p>This led us to implement what I'm calling the <strong>Session Replay Pattern</strong>: each CLI session automatically records all HTTP traffic to a HAR file that users can share for debugging.</p>
<p>Here's what it looks like in practice. When you run any Tuist command, we create a session directory at <code>$XDG_STATE_HOME/tuist/sessions/&lt;uuid&gt;/</code> containing both traditional logs and a <code>network.har</code> file. If something goes wrong, users can share that HAR file with us.</p>
<p>Opening it in Proxyman gives us a complete picture: every request, every response, timing data, and the ability to inspect payloads visually. No more asking "can you run that again with <code>--verbose</code>?" No more parsing logs. We see exactly what the CLI saw.</p>
<p>We also automatically redact sensitive headers like <code>Authorization</code> and <code>Cookie</code> before writing to the HAR file, so users can share sessions without exposing credentials.</p>
<h2 id="why-this-matters">Why This Matters</h2>
<p>Three things make this pattern valuable:</p>
<p><strong>Visual debugging.</strong> Instead of reading logs, we can see a timeline of requests in tools designed for network inspection. Spotting a failed request or an unexpected response becomes trivial.</p>
<p><strong>Easy sharing.</strong> HAR is a single file that captures everything. Users don't need to understand what information is relevant. They just share the file.</p>
<p><strong>AI-powered analysis.</strong> This is where it gets interesting. HAR files are structured JSON. You can feed them to coding agents and ask questions like "which requests failed?" or "what was the total data transferred?" or "show me the authentication flow." The standardized structure means AI tools can parse and analyze the data reliably, something that's much harder with unstructured log output.</p>
<h2 id="a-pattern-worth-adopting">A Pattern Worth Adopting</h2>
<p>If you're building a CLI that talks to a server, this pattern is worth considering. The HAR format is well-documented and most HTTP client libraries provide the hooks you need to capture the necessary data. The investment is minimal, and the debugging experience improvement is substantial.</p>
<p>You can see <a rel="external" href="https://github.com/tuist/tuist/pull/9192">our implementation</a> if you're curious about the details.</p>
<p>Logging tells you what happened in text. Session replay shows you what happened visually and lets you query it programmatically. Both have their place, but for network debugging, HAR files are a clear upgrade.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Rethinking Version Control for an Agentic World</title>
      <link>https://pepicrft.me/blog/rethinking-version-control-for-agents/</link>
      <guid>https://pepicrft.me/blog/rethinking-version-control-for-agents/</guid>
      <pubDate>Tue, 20 Jan 2026 12:00:00 +0000</pubDate>
      <description>Git and Git forges were designed for a world where humans write code in isolation. As agents become central to how we build software, I believe we need to rethink everything from branches to CI to how open source contributions work.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I keep coming back to a conversation I've been having with other developers lately: <strong>Git and Git forges feel increasingly stretched in the world of agents.</strong> The mental models we built around version control assume humans writing code in isolation, occasionally syncing their work. That assumption is breaking down.</p>
<p>Git was designed in 2005. Linus Torvalds needed something to manage the Linux kernel, where geographically distributed developers would work independently and merge their changes periodically. The branch-and-merge model made perfect sense for that world. But agents do not work like kernel developers. They generate code continuously, they need to understand context, and the <em>why</em> behind changes matters as much as the <em>what</em>.</p>
<p>This is why you see developers exploring tools like <a rel="external" href="https://github.com/martinvonz/jj">Jujutsu</a>, a version control system from a Google engineer who previously worked on Mercurial. Jujutsu treats the working copy as a commit from the start, eliminates the concept of a staging area, and handles conflict resolution in a fundamentally different way. Conflicts can exist as logical representations in the commit tree, and resolutions propagate automatically to descendant commits. This is not just a nicer Git. It is a different mental model that happens to be Git-compatible.</p>
<p>The shift to Jujutsu tells me something important: developers are reaching for new abstractions because the old ones no longer fit how they work. And with agents becoming central to development, this tension will only grow.</p>
<h2 id="the-forge-dilemma">The forge dilemma</h2>
<p>GitHub sits in a fascinating position right now. They have the moat. The community. The profiles that serve as developer CVs. The ecosystem of tools that implicitly depend on them. But they also face a radical product challenge that I do not think they are well-positioned to address.</p>
<p>The forge model assumes pull requests, issues, code review, and CI workflows that were designed for human-to-human collaboration. GitHub has been adding AI features aggressively. Copilot can now write code, review PRs, and even be assigned issues to work on autonomously. But these feel like AI bolted onto existing workflows rather than workflows redesigned from first principles.</p>
<p>GitLab is in a similar position with their Duo agent platform. They are building AI as a feature layer on top of the existing forge model. Multiple agents working in parallel, sure, but still within the constraints of branches, merge requests, and pipelines.</p>
<p>I believe forges are going to face a difficult choice. Either they evolve their core abstractions, which is extremely hard when millions of workflows depend on the current model, or they get disrupted by something built for agents from the ground up.</p>
<h2 id="sessions-not-branches">Sessions, not branches</h2>
<p>Here is one change I have been thinking about while tinkering in my free time: what if we replaced branches and pull requests with <strong>sessions</strong>?</p>
<p>A session would capture not just the code changes, but the rationale behind them and the prompt that originated them. When I ask an agent to implement a feature, the session would record my prompt, the agent's reasoning, the code it produced, the tests it wrote, and how it responded to my feedback. The <em>why</em> becomes a first-class citizen alongside the <em>what</em>.</p>
<p>These sessions would land on the project as the unit of contribution. Instead of a branch that shows you a diff, you would see the entire context of how and why the code came to be. Code review would shift from "does this diff look correct?" to "does this session's reasoning make sense?"</p>
<p>This matters because agents need context to work effectively. When an agent looks at your codebase today, it sees code and commit messages. If it could see the sessions that produced that code, including the prompts, the decisions, the rejected alternatives, it would understand the project at a much deeper level. The institutional knowledge that currently lives only in developers' heads would be captured and accessible.</p>
<h2 id="prompt-requests-instead-of-pull-requests">Prompt requests instead of pull requests</h2>
<p>Open source maintainers are already pointing at something that I think will become the norm: prompt requests instead of pull requests.</p>
<p>The idea is simple. Instead of submitting code, you submit the prompt that would produce the code. The maintainer reviews the prompt, perhaps iterates on it with you, and then leans on agents to execute it. The human contribution becomes the intent and direction, not the implementation.</p>
<p>This flips the maintenance model on its head. As I wrote about <a href="/blog/2025/03/09/ai-oss-cost">before</a>, AI can dramatically reduce the cost of maintaining open source. But prompt requests go further. They recognize that specifying what you want is often harder than implementing it, and that is where human judgment adds the most value.</p>
<p>The challenge is that maintainers are already overwhelmed by AI-generated PRs. The <a rel="external" href="https://devclass.com/2025/11/27/ocaml-maintainers-reject-massive-ai-generated-pull-request/">OCaml team rejected</a> a 13,000+ line AI-generated PR. Other maintainers <a rel="external" href="https://piero.dev/2025/06/nuisance-of-ai-on-open-source-maintainers/">report</a> that AI makes it easy to spam them with garbage. The current model of accepting code submissions does not work when the cost of generating code approaches zero.</p>
<p>Prompt requests could help here. Instead of reviewing generated code, maintainers would review intent. They could reject prompts that do not align with the project's direction without spending hours understanding an AI's implementation choices. And when they do execute on a prompt, they control the generation process, ensuring it meets their quality standards.</p>
<h2 id="token-lending-for-open-source">Token lending for open source</h2>
<p>If prompt requests become the unit of contribution, an interesting question emerges: who pays for the tokens to execute them?</p>
<p>I think we will see supporters contribute tokens to execute prompt requests. Model platforms would need to introduce the concept of lending tokens, essentially allowing you to allocate part of your token budget to a project you care about. The maintainer could then draw from this pool when executing on contributions.</p>
<p>This is a different economics than GitHub Sponsors or Open Collective. Instead of giving maintainers money to spend on infrastructure or their time, you would be giving them compute to execute on the community's ideas. The contribution becomes more direct: your tokens literally turn into code in the projects you care about.</p>
<p>Model providers like Anthropic or OpenAI would need to build this functionality. It requires a concept of delegated token access, probably with scoping so you can limit what your tokens can be used for. But I do not see any fundamental barriers. It is mostly a matter of product and business decisions.</p>
<h2 id="ci-needs-to-go-away">CI needs to go away</h2>
<p>This might sound radical, but hear me out: CI in its current form does not make sense in an agentic world.</p>
<p>The premise of CI is that you cannot trust what happened on a developer's machine. Code needs to run in a controlled environment before you can trust the results. This made sense when "developer machine" meant a laptop with who-knows-what installed. But it creates enormous waste. We run the same tests twice, once locally to get feedback, and again on CI to get trust.</p>
<p>What if we could trust the checks that ran locally?</p>
<p>This is where tools like <a rel="external" href="https://nixos.org/">Nix</a> and <a rel="external" href="https://bazel.build/">Bazel</a> become interesting. They give you hermetic, reproducible environments. If you can cryptographically attest that a specific set of checks ran against a specific state of the code in a hermetic environment, you do not need to run them again on a server. The attestation is the proof.</p>
<p>I touched on this in <a href="/blog/2026/01/13/unlocking-new-mental-models">a previous post</a>, but I keep coming back to it. The technology exists. We have content-addressable storage. We have reproducible builds. We have cryptographic signatures. What we lack is a system that ties them together in a way that forges and development tools can trust.</p>
<p>This matters especially for agents. When an agent runs locally, it could run checks and produce attestations as part of its work. The forge would verify those attestations rather than re-running everything. You would skip the CI queue entirely because the proof already exists.</p>
<h2 id="remote-sessions-anywhere">Remote sessions, anywhere</h2>
<p>Another piece of the puzzle: sessions should be triggerable in remote VMs from anywhere, including from your phone.</p>
<p>VMs as a service is commoditizing rapidly. Companies like <a rel="external" href="https://namespace.so/">Namespace</a>, <a rel="external" href="https://coder.com/">Coder</a>, and many others are making it trivial to spin up development environments. GitHub Codespaces did a lot to normalize this. The infrastructure is becoming a commodity.</p>
<p>In a world of sessions rather than branches, you would be able to trigger a session from anywhere. See a bug while you are on the train? Open your phone, describe what needs to change, and trigger a session in a remote VM. The agent works on it, produces a session with code and rationale, and it is ready for review when you get to your laptop.</p>
<p>This is not just about convenience. It is about making the cost of starting development work approach zero. No need to have your laptop, no need to wait for Xcode to start, no need to pull the latest changes. You describe intent and let the infrastructure handle the rest.</p>
<h2 id="learning-from-the-giants">Learning from the giants</h2>
<p>There is one more piece I have been thinking about: how do we make this work at scale?</p>
<p>Companies like Meta and Google have invested heavily in monorepo infrastructure. <a rel="external" href="https://sapling-scm.com/">Sapling</a>, Meta's version control system, handles repositories with billions of lines of code. They use virtual file systems that only materialize the files you need. They have sophisticated caching that makes builds fast even at massive scale.</p>
<p>These are not just engineering curiosities. They are solutions to real problems that emerge when you have thousands of developers working on the same codebase. And in an agentic world, we might all face similar challenges. If agents generate code at the rate they are capable of, the volume of changes will grow faster than traditional Git infrastructure can handle.</p>
<p>I think the future looks more like a giant monorepo where local workflows pull and push only what is needed, when it is needed. The forge becomes a coordination layer rather than a storage layer. Your local environment, whether it is your laptop or a remote VM, has just enough of the codebase to do its work.</p>
<p>This requires rethinking how we think about repositories and organizations. Maybe an organization is not a collection of repositories but a single logical codebase with intelligent visibility and access controls. The boundaries become logical rather than physical.</p>
<h2 id="where-i-am-spending-my-time">Where I am spending my time</h2>
<p>I do not have a finished open source project to announce (yet). But I have been spending my free time exploring what this world might look like. The pieces are there: Nix for hermeticity, cryptography for attestation, remote VMs for compute, structured data for capturing intent and rationale.</p>
<p>What I find exciting is that this is not incremental improvement. It is a chance to rethink the assumptions we have carried for twenty years. Git forges have been incredibly successful, but success creates path dependence. They have to support existing workflows even as new ones emerge.</p>
<p>If you are building for agents from scratch, you do not have that constraint. You can ask: what would we build if we knew agents would be the primary authors of code? What abstractions would we create if capturing <em>why</em> mattered as much as capturing <em>what</em>?</p>
<p>I think those questions lead somewhere interesting. And I am having a lot of fun exploring where that might be.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Schlussel: a single source of truth for agent authentication</title>
      <link>https://pepicrft.me/blog/schlussel-authentication-for-agents/</link>
      <guid>https://pepicrft.me/blog/schlussel-authentication-for-agents/</guid>
      <pubDate>Sat, 17 Jan 2026 12:00:00 +0000</pubDate>
      <description>I built Schlussel because agents deserve a simple way to authenticate with APIs. No more wasting tokens navigating documentation or guessing OAuth flows.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I have been building something that started as a personal itch and turned into a project I think matters: <a rel="external" href="https://github.com/pepicrft/schlussel">Schlussel</a>, an authentication runtime for agents. The name is German for "key" (Schlüssel, with an umlaut I dropped for simplicity), which felt appropriate for something that unlocks API access.</p>
<p>The problem is simple but pervasive. <strong>Agents spend an absurd amount of cycles figuring out how to authenticate with services.</strong> They crawl documentation, parse OAuth flows, guess at endpoints, and burn through tokens trying to understand what should be straightforward. Authentication is a solved problem for humans. We click buttons, follow redirects, and paste tokens. For agents, it is a maze.</p>
<h2 id="the-wasted-context-window">The wasted context window</h2>
<p>Think about what happens when you ask an agent to interact with an API. GitHub is actually one of the easier cases because most developers have the <code>gh</code> CLI installed, and agents know how to use it. The CLI manages the session, and the agent can trust it. But most services are not GitHub. They either do not have a CLI, or if they do, developers do not have it installed locally. There is no session to leverage, no familiar tool to fall back on.</p>
<p>This is where things get wasteful. The agent needs to search for documentation, understand the OAuth flow, figure out which endpoints to hit, and then execute the flow. That is a lot of tokens spent on something that has nothing to do with the actual task.</p>
<p>Here is the thing that excites me: with the right session, well managed, an agent can just use <code>curl</code>. It does not need a fancy SDK or a dedicated CLI. It just needs a valid token and knowledge of the API endpoints. This means companies do not need to build agent-specific integrations. They just need to make authentication accessible, and agents can work with what already exists.</p>
<p>This is not a theoretical concern. I have watched agents burn through their context window just trying to figure out how to get a token. By the time they succeed, they have forgotten half of what they were supposed to do with it. The cognitive overhead is real, and it is wasteful.</p>
<p>What agents need is a single source of truth. A place where they can look up "GitHub" and get back everything they need: the OAuth endpoints, the scopes, the authentication method, the API base URL, even a public client they can use without registration. No searching. No guessing. No wasted cycles.</p>
<h2 id="formulas-as-structured-knowledge">Formulas as structured knowledge</h2>
<p>Schlussel organizes authentication knowledge into what I call formulas. Each formula is a JSON file that contains everything an agent needs to know about authenticating with a specific service. Here is what a formula includes:</p>
<ul>
<li>The service identifier and human-readable label</li>
<li>Available authentication methods (device code, authorization code, API keys)</li>
<li>OAuth endpoints for each method</li>
<li>Default scopes</li>
<li>API information including base URLs and auth headers</li>
<li>Public clients that can be used without registration</li>
<li>Step-by-step scripts for completing the flow</li>
</ul>
<p>This is not documentation meant for humans to read. It is structured data meant for agents to consume. An agent can fetch a formula, understand exactly what it needs to do, and execute the flow without any guesswork.</p>
<p>The formulas are available through a simple API at <a rel="external" href="https://schlussel.me/api/formulas">schlussel.me/api/formulas</a>. You can query all available formulas or get details for a specific one. The data is also bundled into the CLI itself, so agents can work offline.</p>
<h2 id="a-nudge-toward-better-standards">A nudge toward better standards</h2>
<p>There is a secondary motivation behind Schlussel that I think about a lot. <strong>I want to nudge companies toward making authentication easier for agents.</strong></p>
<p>Right now, most OAuth implementations are designed with humans in mind. They assume someone is sitting at a browser, clicking through consent screens. The device code flow exists as an alternative for CLI tools, but many services do not support it. Some services require you to register an OAuth application before you can even try to authenticate, which is a non-starter for agents that need to work across many services.</p>
<p>By building a public database of authentication methods and making it easy to see which services support agent-friendly flows, I hope to create some pressure. If GitHub supports device code flow and your competitor does not, that becomes visible. If Linear offers public clients and you require registration, developers will notice.</p>
<p>The best outcome would be for services to adopt standards like <a rel="external" href="https://datatracker.ietf.org/doc/html/rfc8628">RFC 8628</a> (device authorization grant) and <a rel="external" href="https://datatracker.ietf.org/doc/html/rfc7591">RFC 7591</a> (dynamic client registration). These standards exist precisely for this use case. They just need wider adoption.</p>
<h2 id="how-it-works-in-practice">How it works in practice</h2>
<p>The CLI is straightforward. To authenticate with GitHub using the device code flow:</p>
<pre><code data-lang="bash">schlussel run github --method device_code --identity personal
</code></pre>
<p>This opens a browser, shows you the code to enter, polls for completion, and stores the token securely. The <code>--identity</code> flag lets you manage multiple accounts for the same service.</p>
<p>Once authenticated, getting a token is a single command:</p>
<pre><code data-lang="bash">TOKEN=$(schlussel token get --formula github --method device_code --identity personal)
curl -H &quot;Authorization: Bearer $TOKEN&quot; https://api.github.com/user
</code></pre>
<p>The CLI handles token refresh automatically. If you have a refresh token and the access token is expired, it will refresh it before returning. Cross-process locking ensures that multiple agents do not try to refresh the same token simultaneously.</p>
<p>For agents, there is also a skill document at <a rel="external" href="https://schlussel.me/skill">schlussel.me/skill</a> that provides instructions they can follow. It explains the available commands, the formula schema, and best practices for using Schlussel in agentic workflows.</p>
<h2 id="the-broader-picture">The broader picture</h2>
<p>I see Schlussel as part of a larger shift in how we build tools for agents. We are moving from a world where agents have to figure everything out from scratch to a world where they have access to structured knowledge that lets them act efficiently.</p>
<p>Authentication is just one piece. But it is a foundational piece. Every agent that wants to do something useful with external services needs to authenticate first. If we can make that simple and reliable, we unlock a lot of potential.</p>
<p>The project is open source and contributions are welcome. If there is a service you want to add, the formula format is documented and easy to extend. The goal is to build a comprehensive database that covers the services agents actually need to use.</p>
<p>You can find Schlussel at <a rel="external" href="https://github.com/pepicrft/schlussel">github.com/pepicrft/schlussel</a>, and the API and documentation at <a rel="external" href="https://schlussel.me">schlussel.me</a>.</p>
<p>I am curious to see where this goes. Authentication feels like one of those problems that should have been solved by now but keeps causing friction. Maybe a simple database of structured knowledge is all we needed.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The normalization of unproductive environments</title>
      <link>https://pepicrft.me/blog/the-normalization-of-unproductive-environments/</link>
      <guid>https://pepicrft.me/blog/the-normalization-of-unproductive-environments/</guid>
      <pubDate>Thu, 15 Jan 2026 12:00:00 +0000</pubDate>
      <description>One of the biggest challenges we face at Tuist is that teams have normalized working without data. They stack decisions that erode productivity, then throw resources at the symptoms rather than understanding the cause.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the most challenging aspects of building Tuist as a company is something that took me years to fully understand: <strong>teams have normalized working without data</strong>. They operate in environments where they have no visibility into what is slowing them down, and they have come to accept this as just how things are.</p>
<p>This is a sad reality. Engineering teams work day after day without insights into where the productivity blockers are hiding. Which tests are flaky? Which ones take the longest to run? Where are the parallelization contention points in the build graph? Most teams cannot answer these questions. And here is the thing: they have stopped asking them.</p>
<h2 id="the-slow-accumulation-of-technical-debt">The slow accumulation of technical debt</h2>
<p>In my experience, teams keep stacking decisions that have an impact on the health of their project, and this goes largely unnoticed. A new dependency here, a quick fix there, a "temporary" workaround that becomes permanent. Each decision seems small in isolation, but they compound over time into something that significantly degrades the development experience.</p>
<p>Teams do not wake up one day to a 30-minute CI pipeline. They get there through hundreds of small decisions, each one adding a few seconds, until one day someone asks, "Wait, has it always taken this long?"</p>
<p>When things slow down noticeably, the typical response is to throw more resources at the problem. Faster machines, more CI runners, additional engineers. These solutions are expensive, but they do not require much thinking. They treat the symptoms rather than the cause. I <a rel="external" href="https://tuist.dev/blog/2025/11/17/smart-before-fast">wrote about this on the Tuist blog</a>: organizations spend hundreds of thousands on faster hardware when workflow optimization would cost a fraction and deliver better results.</p>
<h2 id="a-surprising-lack-of-engineering-excellence">A surprising lack of engineering excellence</h2>
<p>What surprises me the most is how many leaders out there are not being strategic about their engineering organizations. The average level of engineering excellence is quite low. Teams work in unproductive setups, and neither the engineers nor the leadership do anything about it.</p>
<p>I spent years at <a rel="external" href="https://shopify.com">Shopify</a>, and they were unique in this regard. They continuously invested in making things better to stay competitive. Developer productivity was not an afterthought; it was core to how they operated. I thought this was the norm. It is not.</p>
<p>There is also the challenge of measuring developer productivity. The <a rel="external" href="https://dora.dev/guides/dora-metrics-four-keys/">DORA metrics</a> (deployment frequency, lead time, change failure rate, time to restore) gave us a starting point, but they require data that many teams simply do not have. You cannot improve what you cannot measure, and you cannot measure what you do not collect.</p>
<h2 id="the-swift-ecosystem-s-misdirected-energy">The Swift ecosystem's misdirected energy</h2>
<p>In the Swift ecosystem specifically, a lot of the collective mental energy goes into things that feel important but do not address the fundamental productivity challenges teams face. There is an endless quest for the perfect architecture. There is excitement about taking Swift to new platforms. There is continuous work to make the language more complex with new features.</p>
<p>I understand the appeal of these pursuits. They are intellectually stimulating. But meanwhile, we have been given the building blocks to improve the foundation we already have. We could reach a point where companies do not need to consider <a rel="external" href="https://reactnative.dev/">React Native</a> or <a rel="external" href="https://flutter.dev/">Flutter</a> because native development offers comparable productivity, including things like hot-reloading that make iteration fast and enjoyable. But here we are, having the same architectural debates we had a decade ago while the competition moves forward.</p>
<p>At Tuist, we spend our days talking to companies about how they can make better use of their resources. It is sometimes frustrating. The data is there, buried in <code>.xcactivitylog</code> files and <code>.xcresult</code> bundles, but it is proprietary, undocumented, and inaccessible. Teams know something is wrong, but they cannot articulate what exactly.</p>
<h2 id="the-path-forward-intelligence-that-works-alongside-you">The path forward: intelligence that works alongside you</h2>
<p>I am optimistic that things can change. The combination of agents and runtime intelligence creates an opportunity we have not had before. Imagine a productivity partner that runs alongside your workflow, continuously analyzing what is happening and telling you where the slowness is coming from. Not a dashboard you have to remember to look at. Not CI logs you have to parse manually. Not metrics that require a data engineering team to make sense of.</p>
<p>This is where I see things heading. An agent with deep knowledge of your project structure, your build graph, and your test suite. Something that can tell you, "This test has been flaky 12% of the time this week" or "This module is a parallelization bottleneck affecting 40% of your builds." Something that can act on this information automatically, disabling flaky tests or suggesting build graph restructuring.</p>
<p>The technology is ready. The data exists. What is missing is the integration, the translation layer between raw build information and actionable insights. This is what we are building at Tuist.</p>
<p>I believe the Swift ecosystem can get there. It requires a shift in mindset from "this is just how Xcode development works" to "we deserve better, and we are going to build it." The tools and patterns exist in other ecosystems. There is no technical reason why iOS development should be less observable than web development.</p>
<p>The first step is acknowledging that the current state is not acceptable. The second is starting to collect the data. The third is acting on it. If this resonates with you, I would love to hear from you. We are building these tools, and every conversation helps us understand the problem better.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Attention is a competitive resource</title>
      <link>https://pepicrft.me/blog/attention-is-competitive/</link>
      <guid>https://pepicrft.me/blog/attention-is-competitive/</guid>
      <pubDate>Wed, 14 Jan 2026 12:00:00 +0000</pubDate>
      <description>Attention is scarce, marketing to developers is changing, and AI forces companies to take a position.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I have been chewing on a simple idea that refuses to leave. <strong>Attention is a resource with high contention.</strong> That is not a moral statement, it is just the reality of how the world works right now. We can try to change it, we can opt out of it for ourselves, or we can acknowledge it and build within it. Businesses are not in the business of ignoring reality, so they should embrace it, then decide how to use it with care.</p>
<p>This is a much harder terrain when the audience is developers. <strong>Developers are not passive consumers.</strong> They are builders with taste, strong opinions, and a high sensitivity to anything that feels like noise. The old playbook still shows up everywhere. Sponsor a conference booth. Put your logo on newsletters. Announce a feature with a press release. It is not that these things do not work. It is that they are tired. <strong>The attention is limited, the format is stale, and developers do not find it cool.</strong> That is the heart of the challenge.</p>
<p>If attention is contested, then the winners are not the loudest or the richest. The winners are those who earn focus by contributing signal. That is why I keep coming back to the older writings on this topic. <a rel="external" href="https://en.wikipedia.org/wiki/Herbert_A._Simon">Herbert A. Simon</a> wrote that "a wealth of information creates a poverty of attention" in 1971. It is a line that feels more true every year. These are not just academic ideas. They are useful lenses for anyone who wants to build a modern developer business. We are not only competing against similar products. We are competing against all the other stimuli that occupy a developer mind.</p>
<p>Marketing to developers has always been a bit awkward. Many developers have a radar for hype. They are allergic to empty adjectives. They read technical docs and skim the rest. They value peer trust more than corporate messaging. The Cluetrain Manifesto captured that cultural shift in the late 1990s with "markets are conversations." In developer ecosystems it is even more literal. If you do not show up in the conversation as a peer, you are a billboard. Billboards get scrolled away.</p>
<p>The reason I think the old playbook is breaking now is the world of AI. It is not enough to say you are using AI. It is not enough to publish a case study that says you reduced costs. Developers want to know what you are building that pushes the frontier and what role you are going to play in the world that is forming. They want to know how you are shaping the future and whether your work is additive or extractive. To say you are keeping up with AI is to say you are following. <strong>Developers do not follow followers.</strong></p>
<p>That means companies need to take a position. Not only a technical position, but a cultural one. What do you believe about how AI should change how we build software. Where do you want to empower users and where do you want to challenge them. What are you willing to make open. What are you willing to let go. In an era of accelerants, a company that does not state a vision gets defined by the narratives of others. Attention will land somewhere, so you might as well give it a north star.</p>
<p>At a personal level this becomes a lot of individual exploration. I talked about this yesterday, and I cannot get the idea out of my head. I do not want my work to be a marketing artifact. I want it to be an exploration, a real attempt, with curiosity and risk. The sharing is part of the process, not a campaign. I share what I do even when it gets rejected or misunderstood. I am fine with that. Some people need time to embrace new models, and that includes me and the people closest to the work. Some people will reject anything that is different. That is fine. I do not want to optimize for the average response. I want to find the people who are curious enough to join the experiment.</p>
<p>That is how I landed on <a rel="external" href="https://github.com/pepicrft/plasma">Plasma</a>, which I am exploring as a multi platform agentic coding experience that could replace React Native if we figure out how to hot reload changes, or at least UI. I feel we are stagnated in the mobile space. We are living inside an endless dream of ideas that a few players pushed years ago and then moved on to other ecosystems with more movement. I want to bring something fresh back. I want AI to feel different on mobile too.</p>
<p>This is where attention, marketing, and product become the same thing. <strong>If you are doing real work that is ahead of the curve, the work itself becomes the marketing.</strong> It is not a press release. It is a consistent stream of explorations, prototypes, failures, and learnings. People pay attention not because you asked for it, but because they see a line of thought they can align with. In other spaces you can find similar dynamics. In music, listeners bond with artists who expose their process, not only the final songs. In open source, people rally around maintainers who show their reasoning and invite the community into the trade offs. In education, the best teachers are not those who broadcast facts but those who let you think with them.</p>
<p>The idea that attention is earned by contribution shows up elsewhere too. In the AI era the medium is not a static website or a blog. The medium is your ability to collaborate with your users in near real time. If your product is not a living conversation, the conversation happens without you. This is why developer tooling companies that ship in public, write technical deep dives, and open their roadmaps tend to earn trust. It is not because they are louder, but because they are more legible.</p>
<p>There is also a cautionary note. The attention economy can distort values. Algorithmic feeds reward novelty and outrage. If you are a company, chasing that behavior is tempting but corrosive. <strong>Short term attention can sabotage long term trust.</strong> Developers notice when you are extracting attention without giving value back. They will remember.</p>
<p>The tension is not going away. The solution is not to retreat or to yell louder. <strong>The solution is to show your work and take a stance.</strong> Make your experiments visible. Treat exploration as a product. Let people join the journey. If it fails, that is also part of the story. People do not want brands, they want builders. People do not want slogans, they want evidence.</p>
<p>This is why I am bullish on a more personal approach to marketing. The old model assumed that a company can stay behind a wall while its marketing department speaks for it. That is not how developer trust works. Developers want to know who is building the tool, what they care about, and what they are doing about the future. That does not mean you must be a public figure. It means the company needs to act like a person. It needs to show its mind.</p>
<p>The past has some useful reference points. <a rel="external" href="https://en.wikipedia.org/wiki/The_Cluetrain_Manifesto">The Cluetrain Manifesto</a> was a reminder that conversations are the market. These are old references, but their relevance grows as the noise grows. The only thing that changed is the speed and scale of the attention market.</p>
<p>So I am leaning into it. I am going to keep exploring, sharing, and refusing to play it safe. I want to build products and experiments that prove a point rather than pitch a feature. If that earns attention, good. If it does not, I still learned something that pushes my craft forward. That is the deal I am willing to make.</p>
<p>I do not think developer marketing is broken. I think it is evolving into something more honest. It is the era of builders who communicate in the same way they build. It is the era of companies that take positions and put their work on the table. I want to be part of that, and I want my work to be part of the conversation, not a banner on the side of it.</p>
<p>References that influenced this line of thought: <a rel="external" href="https://en.wikipedia.org/wiki/Herbert_A._Simon">Herbert A. Simon on attention scarcity</a>, <a rel="external" href="https://en.wikipedia.org/wiki/The_Cluetrain_Manifesto">The Cluetrain Manifesto</a>, <a rel="external" href="https://en.wikipedia.org/wiki/Amusing_Ourselves_to_Death">Amusing Ourselves to Death</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Unlocking New Mental Models with AI</title>
      <link>https://pepicrft.me/blog/unlocking-new-mental-models/</link>
      <guid>https://pepicrft.me/blog/unlocking-new-mental-models/</guid>
      <pubDate>Tue, 13 Jan 2026 12:00:00 +0000</pubDate>
      <description>Instead of applying AI incrementally to existing workflows, what if we questioned the workflows themselves?</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've been tinkering with AI lately, but not in the way most people approach it. Instead of thinking about how to make my existing workflows 10% faster, I've been asking myself: <em>what mental models could get unlocked if I threw away what I know?</em></p>
<p>And it's a lot of fun.</p>
<h2 id="questioning-everything">Questioning Everything</h2>
<p>Take pull requests. We've internalized them as <em>the way</em> to collaborate on code. But do we actually need them? What if we could run CI locally with a system that cryptographically attests that the checks ran against the exact code being pushed? You'd skip the entire CI queue, the waiting, the context switching. The attestation proves the work was done-why repeat it on a server?</p>
<p>This isn't about optimizing PRs. It's about questioning whether they should exist at all in certain contexts.</p>
<p>Anything is possible, really. Once you let go of "this is how it's done," you start seeing possibilities everywhere.</p>
<h2 id="follow-the-builders">Follow the Builders</h2>
<p>I struggle to process why people say they don't find AI useful. At the same time, I see gurus emerging everywhere-jumping onto courses, offering advice, building personal brands on the AI wave. It's common. I ignore them.</p>
<p>I follow the builders instead.</p>
<p>People who look at the future open-minded, willing to shape something better rather than just profit from the hype or stay relevant. It's a lot of fun watching those people work. Tobi from Shopify posted the other day how he built a tool to process some medical imaging format. Not because it was his job, but because he could. That's the energy I'm drawn to.</p>
<h2 id="the-investment-mindset">The Investment Mindset</h2>
<p>I'm spending money on AI. A lot of money on tokens. I finally understand what Peter Steinberger meant when he said this is an investment. It truly is.</p>
<p>But we developers hate paying for things. I used to be like that too. We'll spend hours building something ourselves to avoid a $10/month subscription. We'll fight for open source alternatives even when they cost us more time than the commercial option ever would.</p>
<p>With AI, I've had to rewire that instinct. Every token I spend is buying me time, learning, and capabilities I didn't have before. It's not an expense-it's compound interest on my skills.</p>
<h2 id="an-invitation">An Invitation</h2>
<p>If you're still approaching AI incrementally-asking "how can this help me write code faster?"-I'd invite you to try something different. Ask instead: <em>what assumptions am I making that might not need to exist?</em></p>
<p>Challenge the mental blocks. Question the workflows you've inherited. Look at things with an open mind, willing to throw away what you know if something better emerges.</p>
<p>The people building the future aren't optimizing the past. They're imagining what could be.</p>
<p>Join them.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Building the Shipping Container for Developer Toolchains</title>
      <link>https://pepicrft.me/blog/building-the-shipping-container-for-developer-toolchains/</link>
      <guid>https://pepicrft.me/blog/building-the-shipping-container-for-developer-toolchains/</guid>
      <pubDate>Sun, 09 Nov 2025 17:51:13 +0000</pubDate>
      <description>I’ve been thinking a lot about automation in software projects lately, particularly where the opportunities for a better developer experience lie. I believe many current limitations stem from how we answer the where , what , and how of auto…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’ve been thinking a lot about automation in software projects lately, particularly where the opportunities for a better developer experience lie. I believe many current limitations stem from how we answer the <em>where</em>, <em>what</em>, and <em>how</em> of automation separately, with different companies attempting to profit from each question independently.</p>
<p>Let’s start with the <em>what</em>. We can reduce automation to three core tasks that most projects adopt: <strong>build</strong>, <strong>test</strong>, and <strong>check</strong>, where “check” encompasses any validation that doesn’t fall into the first two categories, such as static code analysis or linting.</p>
<p>Build and test are typically defined by the toolchain of the programming language, while checks are heavily influenced by the community. Our editors have evolved to accommodate these toolchains, ensuring a zero-config experience for developers. It just works. This is a question whose answer presents no business opportunity. In fact, attempting to monetize it would be a bad idea, as the community would likely react negatively.</p>
<p>However, for many toolchains, the answer falls short at scale. This prompted the emergence of generic build systems like <a rel="external" href="https://bazel.build/">Bazel</a>, Google’s open-source build tool that aims to make things work at scale. But like any fork from the standard toolchain, it comes with a high cost that only a few organizations can bear. Bazel’s design with rules captures this reality: you’re relying on a small community to keep them up to date, ensuring not just that workflows run locally, but that editors, debuggers, and everything else operates smoothly when developers interface with code through their tools.</p>
<p>This reminds me of the <a rel="external" href="https://en.wikipedia.org/wiki/Technology_adoption_life_cycle">innovation adoption curve</a> in web platform development. Abstractions emerge in frameworks until the platform evolves and pushes innovation down to the native layer, like how <a rel="external" href="https://web.dev/articles/css-module-scripts">modern CSS features</a> eliminated the need for many preprocessor capabilities. Personally, I think no forks are better than forks, but toolchains take time to evolve, so I understand their emergence as a necessary temporary solution.</p>
<p>Now the <em>where</em>, where these tasks run. Initially, workflows ran only in developer environments, then in CI environments, and most recently, in <strong>agentic coding environments</strong> like GitHub Copilot Workspace or Claude Code. This is where business opportunities emerged: from complete CI solutions like GitHub Actions and CircleCI to companies providing isolated runtime environments.</p>
<p>These solutions align on some conventions, like using YAML as a declaration language, but fragment when attempting to create vendor lock-in to prevent organizations from leaving. They introduce proprietary features like marketplace ecosystems for reusable steps or tightly coupled solutions like caching, as if these needs didn’t exist outside CI environments.</p>
<p>This CI-centric mindset presents organizations with solutions but also creates new challenges. Consider the <strong>portability problem</strong>: developers cannot easily debug pipeline executions locally. Or the <strong>latency problem</strong> with <a rel="external" href="https://en.wikipedia.org/wiki/Content-addressable_storage">Content-Addressable Storage (CAS)</a> caches, a mechanism for storing information that can be retrieved based on its content rather than its location. These caches are optimized for CI where you can co-locate cache servers and CI environments on the same network. But what about developers working remotely? They don’t run their environments in the same network where CI environments are hosted, resulting in higher latency and degraded experience.</p>
<p>These examples illustrate how business opportunities in remote environments created CI-centric solutions that disregard the diversity of environments we have today, and that will likely continue to evolve. Local environments aren’t as monetizable as remote ones, but leaving them out of the design creates a developer experience that’s far from perfect. Any innovation or attempt to fix this feels like incremental patching rather than fundamental rethinking.</p>
<p>Finally, the <em>how</em>. Automation runs in environments, but there’s little to no visibility into how it performs. This visibility is crucial for understanding where opportunities for optimization lie.</p>
<p>This area hasn’t seen as much progress as I’d hoped, with one notable exception: test runs, where consensus built around the <a rel="external" href="https://llg.cubic.org/docs/junit/">JUnit XML format</a>. But what about compilers or build systems? Bazel proposed the <a rel="external" href="https://bazel.build/remote/bep">Build Event Protocol (BEP)</a> for streaming build-time information, but it hasn’t been broadly adopted. Apple is working on a new build system but hasn’t designed it to stream build telemetry to external services. Teams remain reliant on standard output and error messages to understand their build processes, a limitation that becomes increasingly apparent as builds grow in complexity.</p>
<p>I believe this is going to change, especially with agents that treat standard pipelines more as an implementation detail in the communication between the agent and the environment. Companies offering runtime environments provide telemetry about infrastructure metrics like CPU and memory usage. While engineers appreciate seeing these metrics, and they can be helpful at times, high CPU usage isn’t necessarily problematic. It likely means the CPU is busy compiling your work, which is fine.</p>
<p>What teams actually need to know is whether their <a rel="external" href="https://en.wikipedia.org/wiki/Dependency_graph">build graph</a> (a directed acyclic graph representing the dependencies between build tasks) is making optimal use of available resources. This question can’t be answered without information about the build graph structure and how it’s being processed. The lack of this type of data leads many organizations to optimize the environment before optimizing the build process itself, environment before workflows, when optimizing the workflows would result in a higher ROI.</p>
<p>Where does this leave us? We need a more holistic approach to supporting build systems and test runners. One that’s not coupled to solving only for CI or CI runners. One that doesn’t embrace a mono build system as the solution to all problems, but instead embraces the diversity of build systems and patterns in which ecosystems find themselves.</p>
<p>I think we’re all coming to the same realization from different angles. At the end of the day, all these pieces are interconnected, and only by treating them as such can we provide the best experience. Otherwise, you end up with a highly indirect and convoluted setup like the one Reddit described in their engineering blog, where teams juggle several vendors and solutions while trying to create a cohesive developer experience.</p>
<p>Every company brings its own uniqueness to the solution, and this is something I’ve been thinking about deeply lately. There are two pieces that have been unique in how we’ve built Tuist that can play a crucial role in shaping infrastructure for modern build systems and test runners: <strong>community</strong> and <strong>open source</strong>.</p>
<p>Most solutions build proprietary technology and offer either hosting as a service or a license for self-hosting. But I believe there’s a better model that’s more likely to succeed long-term. If you draw a line between technology and service, treating the technology as an open-source commodity for the ecosystem, you’re much better positioned to serve that technology, and developers’ perceptions of you will be very different.</p>
<p>Would you pay <a rel="external" href="https://grafana.com/">Grafana</a> (the company) for hosting an instance or pay someone else? Likely Grafana, right? This is the power of the open-core model, where core software is open source but additional features, services, or hosting are provided commercially. I see an opportunity to apply the same approach to build infrastructure, though I don’t yet know the full shape it will take.</p>
<p>I think the technology should act as a bridge between build systems and test runners to solve the MxN problem we’ll soon face: many build systems and test runners with similar capabilities but inconsistent contracts. This is a classic challenge in system design where connecting M systems to N systems results in M×N integration points, but a bridge or adapter pattern reduces this to M+N connections. We’re already seeing this fragmentation. It’s similar to the problem that had to be solved in global shipping with <a rel="external" href="https://en.wikipedia.org/wiki/Containerization">standardized shipping containers</a>, a revolution that transformed logistics in the 1950s-60s by creating a universal interface regardless of what was being transported or who was transporting it.</p>
<p>I don’t think this bridge has to be Tuist itself, but rather a technology developed and maintained by Tuist. Think of <a rel="external" href="https://www.postgresql.org/">PostgreSQL</a>, a technology whose ecosystem <a rel="external" href="https://supabase.com/">Supabase</a> contributes to and that they host as a service. Solving this problem requires starting from the ecosystems and moving toward infrastructure, not the other way around. Starting from infrastructure naturally leads to a degraded and fragmented developer experience where you’re trying to make your infrastructure work for existing ecosystems rather than serving them.</p>
<p>This approach also requires accepting that some ecosystems might not be ready yet and contributing to help them get there, something many companies see as a waste of resources. First, because the contribution to revenue isn’t direct. Second, because others could benefit from your investment, so many prefer to push proprietary solutions into ecosystems, something that developers are consistently unhappy about.</p>
<p>Ecosystems are perceived as <a rel="external" href="https://en.wikipedia.org/wiki/Common-pool_resource">commons</a>, shared resources that a community manages collectively (a concept from Elinor Ostrom’s work on commons governance). They’re something everyone is responsible for improving, not something companies should try to privatize. This is the approach I see many companies taking, and it’s the wrong one. The alternative approach is harder to secure investment for because getting there requires time, and most investors prefer quick returns over long-term ones. But there are investors who understand this game and the sustainable competitive advantages it creates.</p>
<p>I’m spending part of my time at Tuist trying to understand toolchains beyond Xcode: Gradle, Bazel, Cargo, Metro, Vite, Pants. I’m working to identify their capabilities and the common pieces that can be generalized and turned into a commodity, the shipping container of developer toolchains. The Kubernetes of development environments.</p>
<p>I see Tuist’s role becoming two-fold: <strong>making ecosystems evolve</strong> and <strong>bridging the gap between build systems and infrastructure</strong>. We’ll first drop “Apple” from the market we’re associated with and expand to mobile development broadly. And why stop there? We’ll call ourselves build and test infrastructure for modern development toolchains. Step by step, embracing ecosystems’ pace and developers’ expectations.</p>
<p>I’ll hopefully start sharing the first experiments from this work soon. In the meantime, we’re getting ready to extend our “what” to Gradle and to solve the “where” for all those organizations that have decided to trust us to scale their development.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Fluidity as DNA</title>
      <link>https://pepicrft.me/blog/fluidity-as-dna/</link>
      <guid>https://pepicrft.me/blog/fluidity-as-dna/</guid>
      <pubDate>Fri, 07 Nov 2025 08:13:01 +0000</pubDate>
      <description>The other day I was chatting with a developer who has been following Tuist for many years, and she was positively surprised by how much Tuist has changed over the years. She made me think that we don’t know what shape Tuist will have in yea…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>The other day I was chatting with a developer who has been following Tuist for many years, and she was positively surprised by how much Tuist has changed over the years. She made me think that we don’t know what shape Tuist will have in years from now.</p>
<p>Tuist emerged in the Apple ecosystem and has grown into the platform that we always dreamed of building, but building a company has exposed us to the world of markets, and talking about how to position ourselves and what we stand for has become our daily conversation. Markets are fluid, so should we be.<br />
Fluidity is something we are building into our DNA, and decisions like Elixir for our server are a reflection of it. While there are things we still don’t know, and that’s the beauty of building a company, there are things that are becoming clearer and clearer over time.</p>
<p>We don’t see ourselves bound to the Apple ecosystem forever. We are building solutions that can span beyond the Apple ecosystem, and there’s no reason to constrain ourselves to it. We are building infrastructure for productive teams, and we are actively thinking about how the AI world that’s unfolding is creating new opportunities and challenging many ideas that solidified in a pre-agents world.</p>
<p>We also see ourselves going down the vertical stack, something that for many years we avoided, but that became clear is a must if we want to provide the experience that we want our teams to have. But we haven’t figured out the Tuist way yet. While many companies enjoy jumping into markets with competitive pricing and trying to push the prices down, we don’t like that. We enjoy building developer experiences that spark joy, and we have a lot of ideas, but the intersection of that with monetizing those ideas is where things get tricky. At times I think the market in which we move is saturated with ideas, but then I use Linear, which we’ve been actively using for the past weeks, and it serves as a reminder that there’s always space to build something superior if you put enough love into the craft, and that has always driven us at Tuist. We are crafters who just started selling our craft not too long ago, and things just take time.</p>
<p>Ideas take time to emerge, and I’m optimistic we’ll find those models. I’m optimistic because we have built a team and a company culture for that, and because we use our own tools every day, so we experience the same pain that we are solving for our customers. We wouldn’t see ourselves otherwise. We have good taste, even though the last year has been hard for me to accept that with a health issue that kept me very worried and with the lack of inspiration to contribute something meaningful idea-wise, but having gone through that, I feel more back than ever.</p>
<p>We have a strong appetite for doing a lot of things, but we are doing one thing at a time with a long-term mindset as we lay new pieces in the system. We remain open about where things could go, keep converting customers, and look at the markets to figure out where we should position Tuist. Openness remains part of our DNA. I look at companies like Grafana and Sentry as huge sources of inspiration. Companies that proved that things just take time, and that if you are open, in the long term you can easily become a dominant player in the market, and a company with a momentum that’s unbeatable. Openness is something that developers will forever appreciate, and that continues to be avoided because of the fear of being copied.</p>
<p>So we’ll keep building, keep learning, and keep staying true to what got us here. The shape of Tuist will reveal itself as we go, one thoughtful decision at a time. And that’s exactly how it should be.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>A Tiny Nudge Can Move an Industry</title>
      <link>https://pepicrft.me/blog/a-tiny-nudge-can-move-an-industry/</link>
      <guid>https://pepicrft.me/blog/a-tiny-nudge-can-move-an-industry/</guid>
      <pubDate>Fri, 31 Oct 2025 09:26:22 +0000</pubDate>
      <description>One of the traits of my personality that I consider positive, yet sometimes frustrating, is that I spend a lot of time observing how things evolve. I tend to think in trajectories. In the context of Tuist, that means thinking about how we c…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the traits of my personality that I consider positive, yet sometimes frustrating, is that I spend a lot of time observing how things evolve. I tend to think in trajectories. In the context of Tuist, that means thinking about how we can make a lasting impact, not only technically but also as a business.</p>
<p>It is frustrating because there are always more immediate priorities to tackle. At the same time, it is exciting because you can play with a plausible future, start building toward it, and try to get everyone else excited about it too. Let me give you a few examples.</p>
<h3 id="the-mise-moment">The Mise Moment</h3>
<p>I remember looking at the automation landscape on iOS and asking myself why we were still facing the same problems, like <a rel="external" href="https://brew.sh">Homebrew</a> installing different versions across environments. At <a rel="external" href="https://shopify.com">Shopify</a>, I had seen a different world where everyone used the same versions, and reproducibility was the norm. Outside of that, nothing had nailed the developer experience.</p>
<p>Nix came close, but it never resonated with me. Then one day <a rel="external" href="https://github.com/jdx">Jeff</a>, whose work I had been following since we built the <a rel="external" href="https://shopify.dev/docs/api/shopify-cli">Shopify CLI</a> on <a rel="external" href="https://oclif.io/">oclif</a>, released <a rel="external" href="https://github.com/jdx/mise">Mise</a>. I tried it, and it immediately clicked: this is the way.</p>
<p>We adopted it at Tuist, and I even recommended it as the default installation method. Naturally, there was resistance. <em>“Why Mise if I already have Homebrew?”</em> That is normal, but better futures only emerge when you push through that resistance. The way to do it is by socializing the tool, writing about it, sharing tips, and showing the value of Mise through comparison. Over time, the community started picking it up, and now many projects make it their default. Anyone can clone those projects, and Mise will ensure the right tools are present and activated in the system.</p>
<h3 id="bash-is-fine-the-abstractions-are-not">Bash Is Fine. The Abstractions Are Not.</h3>
<p>Another conversation we have had internally is about whether abstractions for automation are even needed anymore. Years ago, people found writing Bash painful. I never loved it, but I respected it for what it is: simple, portable, and universal.</p>
<p>The real problem was never Bash itself. It was the abstractions built on top of it. Layers that tried to replace the shell with new DSLs, YAML files, or frameworks that re-implemented what Bash already did well. They added complexity, drift, and “one more tool” to learn.</p>
<p>Today the situation is different. With agentic coding tools, you can ask <a rel="external" href="https://openai.com/codex/">Codex</a> or another model to write automation for you, and it will probably get it right on the first try. That makes plain Bash more attractive than ever. You get the clarity of the shell and the speed of automation.</p>
<p>I believe the purpose of abstractions is to eventually push solutions down to the right layer. In automation, that layer is often the shell itself. If a tool cannot explain why it is better than a short Bash script you can read and understand in one sitting, it probably is not worth the dependency.</p>
<h3 id="the-stagnation-of-ci-innovation">The Stagnation of CI Innovation</h3>
<p>A more recent realization came when Git forges like GitHub and GitLab began allowing <a rel="external" href="https://docs.github.com/en/actions/concepts/runners/github-hosted-runners">external runners</a>. Around the same time, a CI company criticized us for adopting a model to sustain the project that did not fit their non-supportive approach to open source.</p>
<p>Meanwhile, many customers were telling us that the same company had doubled their contract prices for no clear reason, while offering generous discounts to large enterprises. Innovation in that space had stalled. The only game was price manipulation.</p>
<p>At the same time, new companies started to emerge offering macOS runners that could connect directly to GitHub or GitLab. Something clicked in my head. The innovation here had stopped. They were playing with the value–cost ratio while <strong>the mobile ecosystem was stuck in a dream where the most exciting idea was that maybe we did not need YAML for CI</strong>. That was wrong.</p>
<p>I like innovation, and when I see it being suffocated, I feel compelled to act. Solving problems that others ignore drives me, and if someone tries to stop me, that only makes me more determined.</p>
<h3 id="the-mental-model">The Mental Model</h3>
<p>Here is the mental model that I keep returning to. I think it describes a future that is already unfolding.</p>
<ol>
<li>With coding agents joining local and CI environments, it has become critical that solutions are not coupled to any CI provider. Developers and agents should both have access to the same services that pipelines use. Punto.</li>
<li>Real innovation will only happen if we have more companies providing macOS runners elastically, based on load and cost, instead of keeping them locked behind CI providers. This benefits not only CI users but also any company that needs macOS environments for creative or development purposes. It is good for users, good for developer tool companies, and naturally, good for Tuist.</li>
<li>Like Mise, it is only a matter of time before companies realize this. I plan to act as a catalyst because I am obsessed with bringing more innovation to this space and creating a fair market where competition happens through craftsmanship, not price manipulation. Where are the <a rel="external" href="https://linear.app">Linears</a> of this space? We need to build them.</li>
</ol>
<h3 id="looking-ahead">Looking Ahead</h3>
<p>I could not be more excited about this new chapter of automation. We are only at the beginning, and it may take months or even years for the shift to be fully realized. At Tuist, our role is to introduce people to these new realities as market dynamics evolve.</p>
<p>What I love most about the software industry is how small things, like “runs-on,” Mise, or agentic coding tools, can suddenly challenge assumptions we took for granted for years. You do not need something big to nudge the industry forward. Sometimes, a tiny design decision is enough to lay the groundwork for innovation.</p>
<p>The seeds of automation are planted. Now we need time and voices to nurture them. That is my responsibility.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>What My Family&#x27;s Cafe Taught Me About B2B Sales</title>
      <link>https://pepicrft.me/blog/what-my-familys-cafe-taught-me-about-b2b-sales/</link>
      <guid>https://pepicrft.me/blog/what-my-familys-cafe-taught-me-about-b2b-sales/</guid>
      <pubDate>Wed, 29 Oct 2025 09:20:33 +0000</pubDate>
      <description>We, developers, commonly believe that the only requisite for one of our creations to be sold is to make it awesome and valuable. While that might work in some cases where you press the right psychological triggers, the chances that those ar…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>We, developers, commonly believe that the only requisite for one of our creations to be sold is to make it awesome and valuable. While that might work in some cases where you press the right psychological triggers, the chances that those are the only requirements are very low. You need to sell.</p>
<p>Selling is not something new to me. My family owns a <a rel="external" href="https://share.google/9oDEDvwpN4j8SmhMY">cafe</a> in Spain. We sell a common breakfast called <a rel="external" href="https://en.wikipedia.org/wiki/Churro">churros</a>. When I was a kid, I helped the family on Saturdays and Sundays to earn a few bucks that I could use to buy gadgets. It taught me a lot about the value of money, at a local cafe scale, and also about the importance of treating your customers well and showing yourself engaging, listening to them, and remembering the things you talk about. Once you build a connection that way, they are likely to come back and buy more.</p>
<p>This muscle atrophied for me. I spent years coding, mostly using my brain in logical mode. And sales are not logical. It reminds me of my nerve injury from a year ago, whose recovery consists of ensuring there's stimulation to prevent the atrophy of the connection between nerve and muscle. I think <strong>my ability to sell is there, but it needs some work to bring it back.</strong> The only way to do so is by using it more and more, and parking the logical side for a bit, which feels uncomfortable at first because that's where I fall back. But I'm getting more and more comfortable with the sales part of Tuist.</p>
<p>As I mentioned, selling churros or selling a tech product to large enterprises are different scales, but some of the ideas map. And as soon as you realize that, you start to notice how many things you were doing wrong. I'll give you some examples.</p>
<p><a rel="external" href="https://tuist.dev">Tuist</a> is a product company. We go deep and broad understanding problems and building the best craft for them, and we share about it in a way that's magnetic. Developers show up at our door in our <a rel="external" href="https://community.tuist.dev">community forum</a> and <a rel="external" href="https://slack.tuist.dev">Slack</a> channels. Fun fact: we have sales representatives of CI companies around there, I guess trying to fish from our amazing community. I wouldn't say that we are lucky, but we worked on it for many, many years and we have the dividends now. In sales terms, cold outreaches are not needed. In fact, they are not effective, and Tuist has a strong brand that keeps growing through its community.</p>
<p>But here's where we do things wrong. Once they join, we've traditionally been support-oriented. We answered their questions and that's it. We didn't go deep into understanding what brought them to Tuist in the first place, what are the pain points where Tuist can bring value through a solution. This was our first mistake or a big missed opportunity, and something that we've changed not so long ago. Many of those prospects, as they like to call them in the sales lingo, turn out to be leads, and very happy leads if you hold their hands.</p>
<p>And here's the thing. From what I've seen in many other tech companies, sooner or later they are replaced with sales teams that don't have a technical background, or they learn the basics so that they can sell. While I get it from the perspective that you need to scale your sales, I think this is where you are trading short-term sales scalability for long-term product atrophy. You've become so distant from the people that you build for, and developers are not stupid, they realize that too. On one side, you are not as enticing a product as you were at the time you spoke at every conference, and second, you are so detached from their day to day that you evolve the product reactively, and again, everyone notices it. I'm not sure how scaling of sales will look at Tuist, but we'll aim at having the people that make the product possible right there, in those conversations, and we'll join them, because the expertise is something that's part of the package. Founder-led sales, they call it.</p>
<p>At the family cafe when people stood in the queue, we spent some time talking with them. Of course, you wouldn't talk about their problems; they are just hungry. But you'd talk about life and other things, and those people would likely come back because they felt like they were at home. Now, in digital services, like Tuist is, there's no physical space where those meetings can casually happen, no queue. So you need to build a similar thing, a digital space where those conversations can happen, and a system so that you don't forget about them because we have monkey brains and we can't remember everything, and this is a limitation we need to build a system for. In our case, we started using <a rel="external" href="https://attio.io">Attio</a> very actively. We keep track of every conversation, adding ourselves follow-up tasks so that we keep those conversations warm. It takes practice to build the habit. It doesn't come naturally to write down everything you talk about, but it's critical to have that context there so that your follow-up conversations don't become just an "I'm here to do a follow-up" and become more of a "this thing you mentioned, the team has worked on addressing it, and I'd like to talk about where things stand and figure out next steps." Will Attio be with us forever? Maybe? I quite like it, and now we spend some time every day having those conversations. They are very insightful because we learn a lot about them, and it also gives us ideas about the things that we prioritize. And here's another thing: we became much better at prioritizing tasks because we don't waste time building things that we think people would need. At times we do. We've built a culture where we explore new ideas, and this is core to the DNA of the company and the project, but it's crucial that we balance that with solving the immediate needs of customers. For example, <em>I want to start the Okta login from the Tuist login page and not the Okta instance</em>. Something we've been asked for a lot.</p>
<p>So while churros and a B2B service are different things, they share a lot. We show our most human version to every company that shows up at our door. We listen to them, we guide them to a solution for their problems, and we have conversations at the technical level of expertise that they expect. Our sales pipeline has become very effective, and we barely have to do any cold outreach. We write great content, and our community and the value of the content do the rest. This is the company we want to build. It was daunting at first, and I personally lacked a bit of confidence at the beginning, but seeing the accounts we are working with these days, and also the impact we are having on them, I have strong confidence that Tuist is here to stay for a long time and potentially break beyond the mobile ecosystem, which we strongly tied ourselves to.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Thin Environment Layers for an Agentic Future</title>
      <link>https://pepicrft.me/blog/thin-environment-layers-for-an-agentic-future/</link>
      <guid>https://pepicrft.me/blog/thin-environment-layers-for-an-agentic-future/</guid>
      <pubDate>Thu, 23 Oct 2025 10:09:49 +0000</pubDate>
      <description>What is an environment from a developer&#x27;s perspective? &amp;nbsp;A place where code is built and tested. We&#x27;ve evolved from having just local environments where we develop and test code, and production environments where we make our apps access…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><strong>What is an environment from a developer's perspective?</strong> A place where code is built and tested. We've evolved from having just local environments where we develop and test code, and production environments where we make our apps accessible through the public internet, to having CI environments where our code is integrated, and most recently, agentic coding environments where agents execute the tasks we assign them.</p>
<p>They all have one thing in common: <em>they take source code and one or multiple tasks as input, then produce some output</em>. This might sound abstract, but at a very high level, that's what we do in them. To do their job, they all have to provision the environment with the tools necessary to complete the work, and you'll likely expect them to do it fast and reliably.</p>
<p>Now, if they all have to do the same thing, it sounds plausible that we could reuse the provisioning and optimization logic across all those environments. Unfortunately, that's not the case unless you're using <a rel="external" href="https://bazel.build">Bazel</a>, which for many organizations is sadly costly to adopt. Bazel makes the whole graph <a rel="external" href="https://bazel.build/basics/hermeticity">hermetic</a>, and in its build graph you can also codify the installation of tools necessary for other tasks. In other words, with Bazel, you just need Bazel. This is great and there's a lot to learn from it, but there's a ceiling to the number of companies that will decide to go that route. Bazel, with all its benefits, also takes people away from their build systems and ecosystems, and this is a very high price to pay.</p>
<p>So if Bazel isn't an option, what can we do? You should start thinking of your <strong>environments and the interaction between them and your project as a layer that you want to be as thin as possible.</strong> The thinner it is, the more portable your project's automation and provisioning logic becomes, and the easier it is to run across the aforementioned environments and others that will emerge in the future.</p>
<p>Let's picture this: Your project has some automation in Ruby, which needs to be present in the system to run it. At the time, you decided that CI pipelines would install <a rel="external" href="https://www.ruby-lang.org/en/">Ruby</a> using a step from their marketplace. Because of that, when you task an agent to do some job, it misdetects the version, installs a different one, and the agent comes back to you with a failure. Compare that with using <a rel="external" href="https://mise.jdx.dev">Mise</a>, which we've been huge fans of. The agent just detects Mise and runs <code>mise install</code>, letting it install the right versions deterministically. Voilà! Every environment can just run <code>mise install</code>. It might seem like a subtle thing, but it's a change that makes your projects more environment-agnostic.</p>
<p>As I said, provisioning isn't the only thing you'll need. You'll also want those tasks to complete fast, and at the speed at which code is being written with AI, the volume of code we'll have to compile will grow faster than the speed of the processors we use to compile it. In other words, we'll need very sophisticated caching systems that run close to those environments. Once again, you can couple your project to a solution from a company that provides those environments, like your CI provider, or instead adopt a solution that's environment-agnostic, so that your coding agents can also benefit from it instead of just your CI environments. This is why <strong>I believe strongly that Tuist's model of offering cache in an environment-agnostic manner is the right way to go in an agentic world.</strong></p>
<p>The last piece about environments has to do with <a rel="external" href="https://en.wikipedia.org/wiki/Telemetry">telemetry</a>. How do we know the job was executed, and how do we debug issues when they arise? If you think of a local or remote CI environment, that's usually through the standard output and error messages that the toolchains you use emit. This can go a long way, but in a world of agents, the lack of structure or visibility over internal tasks can be detrimental to agents' ability to debug their work. Take <code>xcodebuild</code>, for instance—its raw output is too verbose 95% of the time, but when issues happen, you (or the agent) wish you could go deeper. Or not just when things go wrong, but when you notice slowness.</p>
<p>Telemetry is sadly not as common as cache is becoming, but I think it'll come, and infrastructure will be needed for that. The only product I see moving in a good direction there is Dagger. There are many things I don't like about its concept, but how they're able to live-stream and present you with an HTML version of your build that works live, and where you can go deeper to understand what happened, is a much better version than scrolling through a pile of standard output messages.</p>
<p>Will this be a one-year thing? Or maybe two? Who knows... but I think the time will come and the infrastructure will be needed.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Cache for any Xcode project</title>
      <link>https://pepicrft.me/blog/cache-for-any-xcode-project/</link>
      <guid>https://pepicrft.me/blog/cache-for-any-xcode-project/</guid>
      <pubDate>Wed, 22 Oct 2025 16:40:50 +0000</pubDate>
      <description>Today was an important day at Tuist. We released a major redesign of our marketing site and a caching solution that works with any Xcode projects, and we couldn&#x27;t be more proud of our 4-person team pulling this off . We are building the com…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Today was an important day at Tuist. We released a major redesign of our marketing site and a caching solution that works with any Xcode projects, and <strong>we couldn't be more proud of our 4-person team pulling this off</strong>. We are building the company to be as agile as we can, and this result proves that.</p>
<p>Cache is one of our best-sold features and very instrumental in <strong>turning Tuist from a community-grown open source CLI into an open infrastructure for mobile developers</strong>. Who doesn't want faster builds, right? However, our implementation required teams to use generated projects, and this migration was only justifiable for large companies, so our reach was limited. We knew Apple was working on transitioning Xcode's build system and its derived data approach to a model similar to <a rel="external" href="https://bazel.build">Bazel's</a>, and that this would open the door for cache for everyone. We knew it was something to look into, and that it'd take years to reach the performance of our cache, but seeing other companies jump into it was a wake-up call for us.</p>
<p>I covered this in <a href="https://pepicrft.me/blog/cache-for-any-xcode-project/__GHOST_URL__/mobile-ci/">past blog posts</a>, but the CI landscape is evolving rapidly. Many companies now have the incentive to provide elastic ephemeral Linux and macOS environments that can plug into GitHub Actions and GitLab CI as runners, resulting in better and cheaper environments. This shift means teams have more options than ever before. To differentiate, many providers are exploring additional value-adds like cache or competitive pricing. We've seen various approaches to this, and it's exciting because competition fosters innovation. This motivated us to dive into what we know best: reverse engineering Apple's tooling internals.</p>
<p>It took us a couple of weeks to have not only a functional version, but one with a great developer experience that would make it easy for anyone to adopt from any environment. In a world where environments are getting cheaper, <em>we believe it's important to decouple the environment provider from the service provider and not discriminate based on developers' environments</em>. They are environments at the end of the day. Throughout this work, we realized a few things.</p>
<p>The CLI, in which we invested for many years, and everything that makes it possible, including our <a rel="external" href="https://tuist.dev/api/docs">open API</a> and our OAuth2 authentication workflow whose session is automatically managed in the environment, plays a crucial role in bringing Tuist's value to the edge. <strong>We meet developers where they are</strong>. Our design philosophy centers on the command line, which feels natural for developers regardless of where they run their workflows. It's been 9 years of investment, and it's paying off.</p>
<p>Second, and as <a rel="external" href="https://mastodon.online/@marekfort">Marek</a> pointed out in the blog post, there are improvements with the new cache capabilities, but they are modest compared to what you can achieve with what we call module cache at Tuist. We decided to take a transparent approach with a technical deep dive bringing clarity to how it works, how we've done the benchmark, and opening it up for anyone to get familiar with and, why not, even contribute to swift-build. We see learning and sharing as something positive, and we'd rather invest in the infrastructure that's needed to make it possible. <strong>We believe openness is a long-term advantage.</strong></p>
<p>Last, and this is something I touched on in the context of making the code available, with <strong>this piece more value shifts to the infrastructure</strong>. The challenge will be more about how to bring the latency down than building a <a rel="external" href="https://grpc.io">gRPC</a> server itself. We'll spend the following months researching and investing in a multi-level cache that can serve assets as close to the environment as possible, even from local or private networks. Sure, we'll never be able to compete with the speed of I/O against a mounted volume in a CI environment, but as Apple improves the capability, we'll make it good enough that the value will outweigh the cost of being coupled to a specific provider. This is especially important in an environment where more companies are providing CI environments that you can plug into GitHub Actions and GitLab CI.</p>
<p>It's exciting times for faster and more reliable incremental builds that span across environments. <strong>Apple is building the foundation, and we are building the environment-agnostic infrastructure that not only gives the foundation superpowers but gives teams the agency to take back control over where their workflows should run.</strong> We'll also invest in collecting and presenting you with the best and most useful insights so Tuist can be your best buddy as you scale your Xcode app development.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>AI and the Craft of Building Products</title>
      <link>https://pepicrft.me/blog/ai-and-the-craft-of-building-products/</link>
      <guid>https://pepicrft.me/blog/ai-and-the-craft-of-building-products/</guid>
      <pubDate>Sat, 18 Oct 2025 07:11:19 +0000</pubDate>
      <description>There’s a camp of people who think that AI will lead to the Internet being filled with slop content and projects. While I think there’s some truth to it, I believe it would come from the same profile of people who would have published low-q…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There’s a camp of people who think that AI will lead to the Internet being filled with slop content and projects. While I think there’s some truth to it, I believe it would come from the same profile of people who would have published low-quality content or software anyway, seeking everything but good craft. It’s just that now they can do more of it in less time, so it’s more noticeable.</p>
<p>This is something I’ve been thinking about for the past few days while using Linear, a project that shows there are product builders who still place craft front and center and build products that are a joy to use. They do AI too, and likely use AI to build the product, but you don’t see its quality being compromised. Compare that with the many projects popping up that let AI decide the product experience and design interface. They all look the same, with UIs that scream not to use them. A bit of this already started happening when the internet filled with Tailwind components that people copied and pasted to build component kits upon. The models learned from this and now prioritize it over standards, spitting out the same components that everyone uses to build their SaaS.</p>
<p>I get it. You’re a developer, can’t afford to hire a designer, and you want your creation to look good enough. So you trust AI with the uppermost layer that people will be interfacing with all the time. Perhaps that’ll lead you to revenue you’re happy with, or it’s good enough for validating an idea, but as I said, your product will look like the many other similar products that have come from the AI factory. You likely review the code written by AI before putting it into production and lean on your seniority to make some judgment and tweaks, but you don’t do the same with the design.</p>
<p>Some people might be okay with that and enjoy using those products. I don’t. There’s something unique about interacting with very well-thought-out craft. Perhaps AI models will develop this attention to detail in design, but I doubt it. I think there’s something about it that can’t be captured by statistical models. But who knows, maybe it becomes too creative, with hallucination as a feature, and comes up with designs humans wouldn’t have thought of. Anything is possible. But today, nothing that comes from it is something I have joy using. I open the website and leave right away.</p>
<p>It’s hard to disregard capitalism in all this conversation. It’s true that our tech industry is the software industry embedded in capitalism, and as such, the ultimate goal is optimizing capital. Without enough care, this can lead many to compromise the quality of what they build. We’ve always seen that, and we’ll continue to see it in the tech industry and many other industries. However, there will always be people and companies that reconcile with the world and place craft excellence above everything else. That’s the reason why we have companies like Apple or Linear, and why consumers lean toward buying an iPhone. Imagine if its software and UI were vibe-crafted without an eye on the final result. Sounds like a recipe for disaster.</p>
<p>So where does this leave us? AI is a tool, and like any tool, it amplifies the intentions of those who wield it. If your intention is to ship fast and move on, AI will help you do that, but the result will show it. If your intention is to build something people genuinely love to use, AI can still help, but only if you apply the same critical eye to the output that you would to any other part of your craft. The choice between speed and quality has always existed. AI just makes that choice more visible, more quickly.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Building Bridges, Not Barriers: A Constructive Perspective on International Hiring</title>
      <link>https://pepicrft.me/blog/building-bridges-not-barriers-a-constructive-perspective-on-international-hiring/</link>
      <guid>https://pepicrft.me/blog/building-bridges-not-barriers-a-constructive-perspective-on-international-hiring/</guid>
      <pubDate>Wed, 15 Oct 2025 09:40:15 +0000</pubDate>
      <description>Guillermo from Vercel recently shared on X that Vercel stopped hiring in Spain, describing the process as challenging. The post sparked considerable discussion, with many offering support and speculation about potential causes like tax comp…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Guillermo from Vercel recently <a rel="external" href="https://x.com/rauchg/status/1977779569114665339?s=46">shared on X</a> that Vercel stopped hiring in Spain, describing the process as challenging. The post sparked considerable discussion, with many offering support and speculation about potential causes like tax complexity, though the original post didn’t provide specific details.</p>
<p>I find this situation unfortunate. Spain has tremendous potential and doesn’t deserve sweeping generalizations. While there’s always room to streamline employment processes, this challenge isn’t unique to Spain. Germany, where I believe Vercel maintains a legal entity and office, presents similar or even greater bureaucratic complexity. Yet framing the company as a victim of the system may obscure a more nuanced reality. Companies naturally optimize for revenue versus cost ratios, and this is fundamental to business.</p>
<p>Europe represents a significant market opportunity, and establishing presence here opens doors to substantial revenue. However, the equation includes another crucial variable: risk. Companies entering new markets often aim to minimize this risk while maximizing returns. We’ve seen similar patterns before. Shopify established their German entity to access EU talent at competitive rates, but later withdrew most operations when employees began organizing.</p>
<p>This pattern resembles what researchers call “institutional arbitrage”: companies seeking favorable conditions across jurisdictions while avoiding less advantageous aspects. <a rel="external" href="https://hbr.org/2016/05/the-comprehensive-case-for-esg">Research on corporate social responsibility</a> shows that sustainable business practices, including respectful engagement with local regulatory frameworks, correlate with long-term value creation. Rather than viewing regulations as obstacles, successful global companies recognize them as frameworks that enable stable, thriving markets.</p>
<p>Many business leaders approach market expansion seeking benefits without corresponding responsibilities. A more constructive approach would acknowledge specific tradeoffs. For instance, a CEO might say: “Spain offers X advantages but presented Y and Z challenges compared to our German operations.” This builds understanding rather than discouraging investment in countries with exceptional talent pools.</p>
<p>The world’s diversity extends to business regulations, and navigating this complexity is inherent to global operations. While continuous improvement is valuable, embracing these complexities represents an opportunity, not just an obligation. Leaders in positions of influence can advocate for constructive regulatory evolution with evidence-based proposals rather than broad dismissals.</p>
<p>Founders like Guillermo and myself create employment opportunities that channel capital into economies. Equally important is ensuring employee protections remain robust. This requires legal frameworks we can’t simply circumvent. Exploiting regulatory gaps for competitive advantage ultimately harms the countries we operate in. This approach warrants rejection regardless of a CEO’s accomplishments. Success doesn’t grant exemption from local systems or preferential treatment.</p>
<p>As a CEO, I experience these challenges too. I’ve always viewed them as integral to company building. They represent the interface with systems that enable flourishing societies. <strong>Research on stakeholder capitalism</strong> demonstrates that <a rel="external" href="https://www.mckinsey.com/capabilities/strategy-and-corporate-finance/our-insights/the-case-for-stakeholder-capitalism">businesses considering broader stakeholder interests alongside profit</a> achieve more sustainable growth. Without these frameworks, we might see improved GDP figures, but we’d also see widening inequality, with essential services like healthcare and nutrition access becoming luxuries rather than rights.</p>
<p>I absolutely support streamlined processes and enhanced startup support. What concerns me is adopting a victim stance with unsubstantiated claims. Employment legislation exists for important reasons, and global expansion requires understanding these nuances and determining whether they align with your business model. If they don’t, that’s a legitimate business decision. Our diverse world offers various paths. If operations prove easier in country X, establish there and use Employer of Record services to access talent elsewhere while managing complexity.</p>
<p>Let’s avoid blaming countries rich with talent and potential. Such rhetoric helps neither the country nor the company. Instead, we can acknowledge challenges while recognizing opportunities, building bridges that create value for everyone involved.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Substance Over Spectacle: How We Share Tuist</title>
      <link>https://pepicrft.me/blog/substance-over-spectacle-how-we-share-tuist/</link>
      <guid>https://pepicrft.me/blog/substance-over-spectacle-how-we-share-tuist/</guid>
      <pubDate>Thu, 09 Oct 2025 11:21:31 +0000</pubDate>
      <description>When you build a company or a product, one of the things you have to decide is how to market yourself. This isn&#x27;t just about getting people to know what your company does, it&#x27;s also about the values you stand for. Tuist builds on an open so…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>When you build a company or a product, one of the things you have to decide is how to market yourself. This isn't just about getting people to know what your company does, it's also about the values you stand for.</p>
<p><a rel="external" href="https://tuist.dev">Tuist</a> builds on an open source foundation, which naturally influences how we share Tuist with the world. Yet, we continuously look at what other companies in our space do to see if there's anything we can learn from them. We're also budget mindful, which forces us to be creative. I'll share some examples of patterns we've observed and the approach we've chosen instead.</p>
<p>I've noticed companies often take the path of heavy advertising. They put their logo in every conference, newsletter, website, or billboard. I think this can definitely contribute to brand awareness, and for some companies it works well. But for me personally, when it's too much, it doesn't create a deep connection. It also depends on the engineer you're targeting. If the ads package an aspiration towards a lifestyle (like gyms typically do, pressing the right buttons), then sure, it might resonate deeper. But not every company can afford playing that game because it's not compatible with what they're selling. What lifestyle can I attach to making your developers more productive? Tricky, isn't it? I have to admit I've seen companies go a long distance with this approach and be effective at materializing it as contracts. It's a valid strategy, just not the one for us.</p>
<p>Sometimes this approach can shift focus toward doing things so you can talk about them in marketing materials, rather than focusing deeply on the problem or the solution itself. This can <strong>manifest in blog posts and case studies that stay high-level, skipping the technical details engineers would actually like to read about, and webinar after webinar with guest speakers</strong>. This approach works in many industries and for many companies. But as engineers, we're very logical people. We spend our days thinking logically, and we like to understand the why of things. Even when we're asked for money, we want to understand the value deeply because we're used to so much being free. Our <a rel="external" href="https://en.wikipedia.org/wiki/Linux">Linux OS</a> in which we run our <a rel="external" href="https://nodejs.org/en">NodeJS</a> application is free. Our frameworks are free too. The programming language too. So we naturally ask more questions before committing.</p>
<p>If I had to define a camp in which Tuist sits, I'd put us with <a rel="external" href="https://planetscale.com">PlanetScale</a>, <a rel="external" href="https://fly.io">Fly</a>, <a rel="external" href="https://linear.app">Linear</a>, and <strong>the companies whose members and founders have a deep passion for their craft and share it openly</strong>. The connection is made by sharing deep thinking about their problem spaces and their visions, not just surface-level features. Developers respond well to this. They like to be challenged. They like to be presented with new takes on problem and solution domains they haven't heard before. They like when the person talking to them speaks their same language and guides them through the logic behind a product. This is how most of us at Tuist build trust with products, and this is how we see users building trust in us.</p>
<p>The reason I'm bringing this up now is because the mobile development tooling space is evolving rapidly. Organizations are exploring different CI solutions, finding what works best for their specific needs. More companies are entering the Tuist space (welcome), the more the merrier. As this happens, I naturally pay attention to how different companies present themselves. I've noticed some taking the marketing-heavy approach I described above, focusing on feature announcements without diving into the technical depth. When I read those announcements, I find myself wanting more. More details about the state of the art of caching within the world of Xcode, the challenges, the opportunities, what we should expect long-term.</p>
<p>For us at Tuist, we've chosen a different path. <strong>We want to share not just what we build, but why we build it, the problems we're solving, and the thinking behind our solutions.</strong> It's the approach that resonates with us as engineers, and we believe it's the right way to build lasting trust with our community.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Why iOS Teams Are Flying Blind (And How to Fix It)</title>
      <link>https://pepicrft.me/blog/why-ios-teams-are-flying-blind-and-how-to-fix-it/</link>
      <guid>https://pepicrft.me/blog/why-ios-teams-are-flying-blind-and-how-to-fix-it/</guid>
      <pubDate>Sun, 28 Sep 2025 08:46:48 +0000</pubDate>
      <description>If you’ve developed apps with Xcode for a while, you might have noticed how little to no observability teams have over their setup. This is fine when you’re just getting started, but when the project reaches a certain scale, the lack of dat…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If you’ve developed apps with Xcode for a while, you might have noticed how little to no observability teams have over their setup. This is fine when you’re just getting started, but when the project reaches a certain scale, the lack of data makes improving the setup difficult. In many situations I’ve encountered engineering teams that couldn’t fight back against leadership’s push for React Native as a solution to move faster. And they couldn’t fight back because they had no data to support their arguments. The result? They just leave the company. I’ve also seen engineers being dogmatic about things being just fine and fleeing when difficult times come to another Swift codebase that’s far from those moments.</p>
<p>If you ask me, this is problematic, but at the same time creates an opportunity for Tuist. I believe there are several reasons why we don’t see teams having more observability over their setups:</p>
<ul>
<li>The data is often proprietary, like activity logs or result bundles, which requires additional community effort. For instance, Spotify built XCActivityLogParser &amp; XCMetrics back when they were not using Bazel, but they no longer have incentives to maintain it.</li>
<li>The data is also not accessible. Everything is designed to be extremely coupled with Xcode, resulting in data that’s hard to find or parse because nothing is documented. Xcode is closed source, so a lot of that work involves reverse engineering, like we had to do with Xcode’s project format.</li>
<li>Even with access to the data, it’s not as valuable as when combined with other data or analyzed over time or across environments. This requires pushing the data to a database and making it accessible through visualization tools like a dashboard or Grafana. This was XCMetrics’ original motivation, but it faded. This likely means mobile teams have to investigate or collaborate with their backend teams to deploy, maintain, and keep a service up to date, which suddenly becomes a new responsibility for the company, distracting them from the business. We’ve also seen companies treating it as a hobby project (“let’s open source a backend in Vapor”), which is a fun exercise—I’ve done it myself too—but then the driver leaves the company, and the company finds itself with a business to run and open source to maintain.</li>
</ul>
<p>This is the sad reality of Xcode development. Many developers find it acceptable. I don’t. And even sadder, Apple isn’t giving up on their proprietary and closed formats. Their new build system has no traces of making it extensible like Gradle is to provide access to data at build time. Or maybe some kind of telemetry built in with OpenTelemetry such that teams can plug their data pipelines into it. Strategically, nothing has changed at the tooling level, which again, is good for Tuist.</p>
<p>Teams should know where the build parallelization contention points are. They should also know which tests take the longest to execute or which ones are the most flaky. They should have a system to flag and disable flaky tests, or to debug their workflows on a website without requiring anyone to install Xcode in their environments. The web is the ultimate expression of accessibility, and they continue building against it.</p>
<p>So if this resonates with you and you’d like to bring that observability to your Xcode projects, let me know. You’d be surprised how much you’d suddenly know, and it’ll just make optimizing your setup easy and make conversations with leadership less uncomfortable. We take care of the annoying part of understanding proprietary formats, persisting them in a more standard and documented format, and making them available and actionable to you.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The Case for Dynamic CI Pipelines</title>
      <link>https://pepicrft.me/blog/the-case-for-dynamic-ci-pipelines/</link>
      <guid>https://pepicrft.me/blog/the-case-for-dynamic-ci-pipelines/</guid>
      <pubDate>Wed, 24 Sep 2025 17:13:53 +0000</pubDate>
      <description>Something I&#x27;ve been thinking about lately is how static CI pipelines are, and how this makes it challenging to work in large codebases and monorepos, where you can easily be constrained by the resources of a single machine and might want to…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Something I've been thinking about lately is how static CI pipelines are, and how this makes it challenging to work in large codebases and monorepos, where you can easily be constrained by the resources of a single machine and might want to spawn multiple CI environments and aggregate the results upon completion. What am I talking about, you might wonder?</p>
<p>Picture this: At some point in the process of scaling your organization, you might find yourself with large codebases—for example, monorepos—with inter-dependencies between various components and the need to be selective about what you run and where you run it. During my time at <a rel="external" href="https://shopify.com">Shopify</a>, they spun up a team dedicated to test infrastructure whose role was to become more selective about these things. At some point, you'll be constrained by running things on a single machine, and you'll want to distribute the work across several pipelines as some kind of sharding. But you'll be very limited by the pipelines, which are quite static. You can't simply say, <em>"From this CI job, spawn X jobs, which I've calculated based on data from my build system, and then aggregate the results back."</em> The only company I know that has gotten close to this is Buildkite, but most others continue gravitating around the YAML-as-a-pipeline building block.</p>
<p>Take tests in iOS that require a simulator. There's a limit to how many simulators you can run per machine, and this is an OS limit because every iOS simulator runs in the system as just another process consuming system resources. There's a limit to how many file-system processes and file handles can be opened—a classic example of resource contention. On modern Apple Silicon, that number should be around 12, which means in the context of running e2e tests (which are slow by nature), you can run at most 12 simultaneously. That's not bad, but what if you have 40 or 80 tests? This adds up very quickly. To fix that, you'll consider sharding, and the sharding is likely codified in your YAML with some runtime logic. However, the number of shards is fixed and something you can't control dynamically, so you'll likely take the list of all tests and distribute them across shards following some logic. <em>Wouldn't it be amazing if the number of machines were something you could control dynamically?</em> It turns out that environment providers like <a rel="external" href="https://namespace.so">Namespace</a> can scale elastically, so if you have the budget for it, you can throw money at the problem and find your sweet spot dynamically.</p>
<p>Another interesting use case for dynamic pipelines is d<strong>etermining what needs to run based on changes and then distributing that work across different machine specs.</strong> Let's say a build system determines there are a few Ruby tests to run and some Rust ones based on changes in the monorepo. For simplicity, Ruby has a native piece built with <a rel="external" href="https://github.com/tuist/tuist/pull/8296">Rust</a> for some business logic that's CPU-bound. The build system could spin up two machines with different specs because the needs of those tasks are very different, so the machines should be too. But note that this requires the build system and CI provider to work in harmony, and this is quite tricky—a coordination problem that exemplifies <a rel="external" href="https://en.wikipedia.org/wiki/Conway%27s_law">Conway's Law</a>, where the structure of your toolchain reflects your organizational boundaries.</p>
<p><a rel="external" href="https://bazel.build">Bazel</a> has all the build information necessary to do this, and there are companies that provide infrastructure for Bazel. However, Bazel means replacing your build system, which is very costly for organizations. On the other side, there are companies like Namespace that have the infrastructure and could plug into build systems and monorepo build tools. But none of those tools have been designed to contract with remote executors in the same way <a rel="external" href="https://www.docker.com">Docker</a> does, where you can decide to build remotely and it really feels local. Imagine if the build tool you use had this capability built in, where you wouldn't have to keep a YAML file up to date or push changes, but could interface with it directly from your local environment, simulating how the pipeline would be inferred and executed. Dagger is one of the closest to this model, but it builds on virtualization, which comes with its own set of tradeoffs and doesn't work well with models like iOS builds, where virtualization isn't cheap.</p>
<p>So I don't really know what the answer is, but it would be amazing if a protocol emerged between companies that provide environments, like Namespace, and the build systems that might want to run things remotely. Perhaps there's an opportunity here for companies to define a standard that would prevent forcing organizations into a one-stop-shop type of build system that's costly to adopt.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The Time Investment Paradox: Why Developers Won&#x27;t Pay for What They Can Build</title>
      <link>https://pepicrft.me/blog/the-time-investment-paradox-why-developers-wont-pay-for-what-they-can-build/</link>
      <guid>https://pepicrft.me/blog/the-time-investment-paradox-why-developers-wont-pay-for-what-they-can-build/</guid>
      <pubDate>Wed, 24 Sep 2025 14:29:18 +0000</pubDate>
      <description>We developers have a unique ability to create things with code, which has been recently accelerated with the proliferation of all sorts of agents. This is great, building solutions with software has never been so accessible, but this abilit…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>We developers have a unique ability to create things with code, which has been recently accelerated with the proliferation of all sorts of agents. This is great, building solutions with software has never been so accessible, but this ability often leads to a hesitance towards paying for tools that would save them time, unless everyone is talking about those tools, in which case their system just got hacked.</p>
<p>This reluctance to pay for productivity tools despite the clear time-saving benefits is a classic example of what economists call the <a rel="external" href="https://en.wikipedia.org/wiki/Make_or_buy_decision">make-or-buy decision</a>. In our case, developers often suffer from what I'd call "builder's bias" - the assumption that because we can build something, we should. This is closely related to the <a rel="external" href="https://en.wikipedia.org/wiki/Not_invented_here">not-invented-here syndrome</a>, where teams reject external solutions simply because they didn't create them internally.</p>
<p>I see everything as an investment these days, where my goal is to have more time and not less. If there's something that's making me waste time, even if I could build it myself, I prefer to pay someone for the work that they've done. For instance, this blog used to be statically generated and deployed to some infrastructure from a CI pipeline, but it sometimes broke, and did not have a solution that would allow me to capture my thoughts and share them from anywhere. It turns out Ghost has been doing that for ages, they align with my values, and for a tiny subscription, I get a lot of value, and they get to profit too. Deal.</p>
<p>This attitude is our day-to-day reality with Tuist, especially in a very opinionated ecosystem of tools where there's sometimes a distorted version of reality (tools are not as bad as they appear), and a high hope that Apple will fix things sooner or later, so anything that's not an Apple solution is not worth investing money into. This creates what behavioral economists call <a rel="external" href="https://en.wikipedia.org/wiki/Status_quo_bias">status quo bias</a> - the tendency to stick with current solutions even when better alternatives exist. Unless the pain is too strong, in which case you have no choice. You can't just go to leadership and say, listen, I understand you want things to move fast, but tooling sucks. Or well, I wouldn't say it sucks because I've always thought it doesn't, but that React Native thing that you mention, that's what really sucks.</p>
<p>It's gotten to the point where I start to ignore that attitude and let them come across the truth by themselves. This aligns with what psychologists call the <a rel="external" href="https://en.wikipedia.org/wiki/Curse_of_knowledge">curse of knowledge</a> - once you know something works better, it's hard to understand why others can't see it. I can talk for ages about how painful things are at a certain scale, but they'll only notice it when they experience it themselves. And those that have started to walk a path of enlightenment, where things are just faster or work more reliably, I'll hold their hands and help them.</p>
<p>The funny thing is that people think we are trying to take them away from the path that has been dictated. And not only that, but we dare to ask for a service, as if our ultimate goal was to profit from them without giving them anything in return. As if they were not giving engineering hours to their employers expecting a salary back. This resistance to paying for developer tools while expecting to be paid for development work is a fascinating cognitive dissonance that's prevalent in our industry.</p>
<p>But this is how things are, and we can't change that except by sharing our vision and letting people decide their journey. We introduced <a rel="external" href="https://mise.jdx.dev/">Mise</a>, and people looked at us with hesitation, and now we've got many people who appreciate the tool and have even expanded it to their entire organization. We decided that mapping Swift packages to Xcode targets was a path for optimization and better developer experience, and many organizations find relief from seeing random package resolutions happening at any time, rendering the project unusable. Is this the path I would like to take? Not really, but when tools are closed-source and non-extensible, this is the only path. It turns out companies appreciate it because their pain is suddenly gone. Surprise, surprise.</p>
<p>The truth is, change in developer tooling often follows the same pattern as <a rel="external" href="https://en.wikipedia.org/wiki/Technology_adoption_life_cycle">technology adoption curves</a>. There are always early adopters who see the value immediately, followed by the pragmatic majority who wait until the benefits are proven and widely recognized. Our job isn't to convince everyone at once but to serve those who are ready to move forward and let the results speak for themselves.</p>
<p>At the end of the day, time is the only resource we can't create more of. Whether we spend it building solutions that already exist or investing in tools that multiply our effectiveness is a choice that defines not just our productivity, but our entire approach to creating value in this world.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Tuist Is Not What You Think It Is</title>
      <link>https://pepicrft.me/blog/tuist-is-not-what-you-think-it-is/</link>
      <guid>https://pepicrft.me/blog/tuist-is-not-what-you-think-it-is/</guid>
      <pubDate>Mon, 22 Sep 2025 17:40:10 +0000</pubDate>
      <description>Something great about having chosen Tuist as a name for a product is that we have a high ceiling in terms of the product definition we can come up with. Unfortunately, we have a floor that we need to raise too, and that&#x27;s people&#x27;s perceptio…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Something great about having chosen Tuist as a name for a product is that we have a high ceiling in terms of the product definition we can come up with. Unfortunately, we have a floor that we need to raise too, and that's people's perception and mental models around what Tuist is.</p>
<p>For many people today, Tuist is a project generation tool, and for some in that group, we are an unnecessary abstraction because <a rel="external" href="https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/">SwiftPM</a> is just fine. But the reality is very different from that. <strong>Tuist is a platform to address challenges of scaling app development with Apple's toolchain</strong>, and only a subset of those challenges requires project generation, an abstraction upon Xcode projects, to solve them. Those challenges are modularization complexities and slow compilation. We are the first ones who would avoid abstractions if we could; in fact, we peel them when they are no longer needed, like we recently did by telling people that if they are using Tuist to minimize merge conflicts, that's not really needed. However, in some cases, an abstraction is unavoidable, and Xcode's terrible derived data decision or inability to optimize the build process left us with no choice. Perhaps your project with few modules declared with SwiftPM is just fine, but <a rel="external" href="https://medium.com/bumble-tech/scaling-ios-at-bumble-239e0fa009f2">when you grow that into hundreds</a> of modules and it takes 1 minute to index the project, or 15 seconds to delete a file from a project, then I don't know about you, but this is not a nice setup to work with. Perhaps it just takes experiencing sustained pain over time to look at the need for abstraction with different eyes.</p>
<p><img src="https://pepicrft.me/blog/tuist-is-not-what-you-think-it-is/__GHOST_URL__/content/images/2025/09/image-3.png" alt="" /></p>
<p>An image from Bumble's <a href="https://pepicrft.me/blog/tuist-is-not-what-you-think-it-is/__GHOST_URL__/standards-over-lock-in-why-were-building-tuist-differently/">benchmarking</a> that shows the differences between using a vanilla Xcode project and SwiftSPM</p>
<p>As I said, we are evolving Tuist to be more of an extension that you plug into your Xcode project and toolchain. It's an extension that takes just a few lines to integrate. For instance, if you want to get build insights like those that we get for the Tuist project, all you need to do is add a <a rel="external" href="https://docs.tuist.dev/en/guides/features/insights#builds">post-action</a> to your Xcode project scheme, and you are good to go. Or selective testing, which you can adopt in your Xcode projects by just prefixing your <code>xcodebuild</code> invocation with <code>tuist</code>. Now, you might not want to depend on or even pay for third-party tools, and I'd understand that too, but once your project reaches a certain scale, I'll tell you that you'll experience a regression in developer experience that Apple won't support you with, and you'll be alone there. I've seen that many times, and it was hard for developers. From companies adopting <a rel="external" href="https://shopify.engineering/five-years-of-react-native-at-shopify">React Native</a> to others replacing the build system entirely, the pain was much stronger than the little cost that a non-official abstraction like Tuist could have brought to your project.</p>
<p><img src="https://pepicrft.me/blog/tuist-is-not-what-you-think-it-is/__GHOST_URL__/content/images/2025/09/image-2.png" alt="" /></p>
<p>A screenshot of the Tuist's dashboard where you can see build insights from the Tuist project itself. The data that we show includes for a period of time: the number of builds, the number of failing builds, the average duration of builds.</p>
<p><strong>The journey we're on is about making Tuist invisible when you don't need it and invaluable when you do.</strong> We're building a platform that respects your existing workflow while providing escape hatches for when Apple's toolchain shows its limitations. Every feature we add is designed to be adopted incrementally. You don't need to rewrite your entire build system or learn a new paradigm. You just need to recognize when the pain has become unnecessary and know that there's a solution available.</p>
<p>We understand that not every project needs what we offer today. But as your codebase grows, as your team expands, and as your build times stretch from minutes to hours, remember that these problems aren't inevitable. They're solvable, and we're here to help solve them. <strong>The abstraction we provide isn't about replacing Xcode; it's about making Xcode work better for you at scale.</strong></p>
<p>Our vision is simple: no developer should have to choose between staying native and having a productive development experience. With Tuist, you don't have to.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Standards Over Lock-in: Why We&#x27;re Building Tuist Differently</title>
      <link>https://pepicrft.me/blog/standards-over-lock-in-why-were-building-tuist-differently/</link>
      <guid>https://pepicrft.me/blog/standards-over-lock-in-why-were-building-tuist-differently/</guid>
      <pubDate>Sat, 20 Sep 2025 08:49:01 +0000</pubDate>
      <description>As part of building Tuist , we experience firsthand the sheer volume of proprietary decisions and formats that Xcode and its surrounding toolchain have baked in. From build systems that output their own data formats to test runners that ins…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As part of building <a rel="external" href="https://tuist.dev">Tuist</a>, we experience firsthand the sheer volume of proprietary decisions and formats that Xcode and its surrounding toolchain have baked in. From build systems that output their own data formats to test runners that insist on their own proprietary outputs. It's not that standards don't exist, it's that Apple consistently leans toward the proprietary side.</p>
<p>Ultimately, choosing proprietary formats is a way of <strong>increasing vendor lock-in</strong> between consumers and the product, and by extension, the company behind it. The European Union has implemented measures against this, requiring that users can export their data and take it elsewhere. But if the data format itself is proprietary, <em>why would I export it in the first place?</em></p>
<p>When you decide against a standard, you're also deciding against interoperability. You make integration so painful for your users that they'll eventually accept the extra pain and seek more interoperable alternatives. Sometimes standards don't exist, and that's completely normal. But when they <em>do</em> exist, neglecting them is a complete mistake.</p>
<p>Take <a rel="external" href="https://www.notion.com/">Notion</a>, for instance. I'd never use it, no matter how many features they offer. Any rich experience layered on top of text feels unnecessary to me, and the marginal value compared to the cost of using some proprietary format (god knows which one) simply isn't worth it. I'd rather keep my content in plain text files using standard <a rel="external" href="https://en.wikipedia.org/wiki/Markdown">Markdown</a>. It turns out LLMs love Markdown too. <em>What a coincidence, right?</em> You don't have to wait for Notion to open an MCP API that converts their proprietary format into Markdown for LLMs to understand. You see? The cost is high.</p>
<p>Or consider <a rel="external" href="https://tailwindcss.com/">Tailwind</a>. Everyone loves it. They've managed to get LLMs to generate Tailwind classes everywhere. But it's not a standard. It's a proprietary language with developer experience add-ons, when you could just write plain CSS, use CSS variables for configurable designs, and leverage modern CSS nesting if specificity is an issue. No need to rely on proprietary formats.</p>
<p>In the context of Tuist, we're thinking deeply about <strong>leveraging standards that backend teams have traditionally used</strong> to help teams understand their projects, builds, and perhaps eventually their apps. Take <a rel="external" href="https://opentelemetry.io/">OpenTelemetry</a> (OTel), a standard people use to add telemetry to backend services. What if Apple's new unified swift-build exported telemetry data using the OTel standard? <em>Wouldn't that be cool?</em> You could use any of the many available collectors and visualize your data in <a rel="external" href="https://grafana.com/">Grafana</a>, which has built-in support for OTel. Instead? This isn't even on their roadmap.</p>
<p><a rel="external" href="https://github.com/swift-otel/swift-otel">Swift SDKs for OTel exist</a>, so imagine if we leveraged our infrastructure and API to store apps' OTel data, allowing users to observe their apps using the tools they already know and love, like Grafana. They wouldn't have to rely on any proprietary tool. And if they don't like Tuist? They can switch.</p>
<p>I don't believe people should stay with a product because you've vendor-locked them into a system filled with proprietary decisions. <strong>They should stay because you've built the best and most fairly priced solution.</strong> This is why I'm excited about the concept of <em>runners as a service</em> plugged into CI systems (e.g. <a rel="external" href="https://namespace.so">Namespace</a>). Whether we like it or not, we're trending toward Git forges' CI solutions becoming the standard, with a standard contract for plugging in runners. This way, you don't have to migrate away from CI providers whose businesses are sinking and who resort to proprietary gimmicks to stay afloat. Like, "Hey! Design your pipeline in our proprietary visual editor, choosing steps from our proprietary marketplace." <strong>Fuck that</strong>. Give me a standard YAML that's well-documented, that I can ask LLMs to write, and reusable steps in open-source Git repositories that are easily pluggable. <em>This is the way</em>. I'd never go back to any CI provider, and you probably shouldn't either if you want better and cheaper CI.</p>
<p>We're now building Tuist QA, and we're adding an option to export QA session results as JUnit format. It's the closest standard to what we need, and if you want to use that JUnit output with your test analysis tools, go for it.</p>
<p>Recently, I've been exploring Grafana for observability of our production services and the product itself. It <strong>blew my mind</strong> when I realized that panels and dashboards follow a standard, serializable schema that's well-documented and that LLMs understand. I can provide our ClickHouse and Postgres database schemas to an LLM and ask it to generate entire dashboards or panels. Within seconds, I have everything we need. We'll get there too. Our API has a publicly available OpenAPI spec, and we want to expose more read endpoints and simplify authentication so LLMs can access it and provide useful responses to users. Some of our data is proprietary to Tuist's domain because no standards exist for it, but wherever possible, we'll adopt standards. For example, by exposing data that overlaps with Prometheus or OTel specs in those formats.</p>
<p><strong>The best products embrace standards and put users first</strong>. Those that don't feel more like Berlin before the wall fell. They'll throw money at luring users into closed ecosystems. We've seen CI providers do this for years, claiming to be "platforms" (like "Mobile DevOps") that are just vaporware. But sooner or later, the wall will fall, and when it does, <em>it'll hurt hard</em>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The False Choice Between Enterprise Sales and Great Products</title>
      <link>https://pepicrft.me/blog/the-false-choice-between-enterprise-sales-and-great-products/</link>
      <guid>https://pepicrft.me/blog/the-false-choice-between-enterprise-sales-and-great-products/</guid>
      <pubDate>Sat, 20 Sep 2025 08:13:50 +0000</pubDate>
      <description>Have you ever avoided using a product because its enterprise-first, sales-driven approach compromised every aspect of the user experience? This has happened to me countless times, and I always wondered if striking a balance would be difficu…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Have you ever avoided using a product because its enterprise-first, sales-driven approach compromised every aspect of the user experience? This has happened to me countless times, and I always wondered if striking a balance would be difficult. But the more we invest in shaping <a rel="external" href="https://tuist.dev">Tuist</a>, the more I realize that <strong>marketing and selling to large enterprises doesn't have to conflict</strong> with creating a great product—despite what many B2B companies seem to believe.</p>
<p>Since most B2B revenue comes from large enterprises, it makes business sense to focus on them. And it's true that some enterprises might not prioritize elegant product design as long as their immediate problems are solved. But if you ignore thoughtful product shaping, you'll end up with a convoluted mess—a heterogeneous collection of tools that lack any cohesive narrative or intuitive user journey.</p>
<p>It's similar to <a rel="external" href="https://en.wikipedia.org/wiki/Vibe_coding">"vibe coding"</a> in a way. You can vibe-code an entire SaaS product, but you must ensure that each piece integrates seamlessly into the whole. Otherwise, you'll find yourself constantly hacking new features onto existing layers instead of building a coherent system. Many developer tools fall into this trap, but at Tuist, we refuse to accept it.</p>
<p>We believe every component should harmonize with the broader ecosystem, playing a role that evolves alongside our vision. A CLI that generates projects transforms into an interface for an integrated developer dashboard. QA teams use previews to test their colleagues' work. A single line of code in an Xcode project seamlessly connects your environment with Tuist. Product shaping is continuous work that enterprise customers actually appreciate because it makes the product a joy to use—and who doesn't want joy? There's a reason we prefer Apple products over alternatives, or why we choose Mise for environment management instead of juggling multiple disconnected tools.</p>
<p>A great product doesn't need to be littered with "Contact Sales" buttons or limited to restrictive demos with fake data that fail to demonstrate real value. Design shouldn't be an afterthought or heavily influenced by sales strategy. <strong>Exceptional product craft and successful enterprise sales are completely compatible</strong>—it's just that some founders treat the product as merely a means to profit. We see product excellence and business success as two elements that must dance in harmony to deliver the best value to all our users (enterprises included) while capturing fair value in return.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Listen to your pools</title>
      <link>https://pepicrft.me/blog/listen-to-your-pools/</link>
      <guid>https://pepicrft.me/blog/listen-to-your-pools/</guid>
      <pubDate>Thu, 18 Sep 2025 18:09:18 +0000</pubDate>
      <description>At Tuist, we’ve been experiencing sporadic database query drops here and there. It became routine for me to start my day sifting through AppSignal errors related to dropped queries, spending hours trying to debug them. At times, I wondered…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>At Tuist, we’ve been experiencing sporadic database query drops here and there. It became routine for me to start my day sifting through AppSignal errors related to dropped queries, spending hours trying to debug them. At times, I wondered if we were doing something wrong—perhaps our queries were too slow, or our pool wasn’t well-optimized for our traffic patterns. But whose responsibility was it? Our database provider’s? Our cloud provider’s? Ours? It was somewhat annoying, but not something that would significantly degrade our service quality.</p>
<p>Then things started getting worse. The query drops escalated to HTTP request drops, and we became increasingly suspicious of our infrastructure. For those unfamiliar with why pools are necessary on the server side: they’re tools that keep connections warm and ready to execute queries or requests, avoiding the latency of initial handshakes and the overhead of establishing connections for every request. This is particularly important for Tuist, where we have a highly concurrent API surface, especially our cache endpoints. Despite numerous unsuccessful attempts to get our cloud provider to investigate their network infrastructure, everything went sideways. First, the server became unhealthy twice due to running out of memory. Later, it became extremely slow—so slow that some client features would fail. This happened despite Erlang’s fair scheduler, which can schedule work even when the CPU is extremely busy (for example, if you enter an endless loop).</p>
<p>What could have caused this? Suddenly, it all clicked, and we finally understood the pool issue. Our outbound requests were too slow—not just requests to the database for queries, but also those to S3 for uploads. At the database level, where we’d optimized many things so that high concurrent API load doesn’t translate to equivalent database load, we only saw sporadic drops. But in our S3 storage pool, this translated to a few requests executing while thousands waited to be assigned (consuming memory), the CPU struggling to assign them, all while continuing to receive more requests added to the pool. Our server couldn’t respond to requests in time because there were no CPU cycles available.</p>
<p>What started as sporadic drops long ago was already signaling that something was wrong with our network. Sometimes slowness is self-inflicted, but in this case, it wasn’t us—we only realized this once everything fell apart. We had numbers to prove to our cloud provider that something wasn’t working as planned, but we never anticipated that the issue would snowball and take down our entire service.</p>
<p>So yes, when your pool speaks, stop what you’re doing and listen to it. In our case, we switched to another provider following <a rel="external" href="https://x.com/cschmatzler">Chris</a>’s suggestion, and things improved instantly. We also configured our pools with lower timeouts to prevent resource clogging, and we’re defining alerts that can automatically declare incidents when we detect upward trends in response times. It’s been a huge learning experience and also a relief to start each day without a handful of dropped connections from the queue.</p>
<p>I feel confident that both our infrastructure and the app running on the amazing Erlang VM are now ready to handle much heavier loads.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The Two Dimensions of Mobile Development Infrastructure</title>
      <link>https://pepicrft.me/blog/the-two-dimensions-of-mobile-development-infrastructure/</link>
      <guid>https://pepicrft.me/blog/the-two-dimensions-of-mobile-development-infrastructure/</guid>
      <pubDate>Wed, 10 Sep 2025 15:29:16 +0000</pubDate>
      <description>As part of shaping Tuist , and especially in the context of where Tuist can leverage LLMs to bring value to the ecosystem with features like Tuist QA , we like to think of the problem space as two dimensions: platforms and lifecycle . Tuist…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As part of shaping <a rel="external" href="https://tuist.dev">Tuist</a>, and especially in the context of where Tuist can leverage LLMs to bring value to the ecosystem with features like <a rel="external" href="https://tuist.dev/qa">Tuist QA</a>, we like to think of the problem space as two dimensions: <em>platforms</em> and <em>lifecycle</em>.</p>
<p>Tuist's strong focus since its inception has been native development for Apple platforms. And by native here I mean without any runtime abstraction like <a rel="external" href="https://reactnative.dev/">React Native</a> or <a rel="external" href="https://flutter.dev/">Flutter</a>. We know the ecosystem well, we have a presence in it, and we feel very comfortable exploring problems and building the best solutions for them. We are not closed to navigating that dimension by taking our solutions to Android, and potentially abstractions like Flutter and React Native, but the time is not now.</p>
<p>The other dimension is the lifecycle of app development. An app can be broken down into features and dependencies between them, and features usually start with an idea that navigates through different phases, in some of which Tuist supports you.</p>
<h2 id="development"><strong>Development</strong></h2>
<p>This has traditionally been our area of focus. <strong>We extend the native toolchain with solutions to make your job easier and faster as a developer.</strong> From <a rel="external" href="https://docs.tuist.dev/en/guides/features/projects">project generation</a> that makes managing projects a breeze, to <a rel="external" href="https://docs.tuist.dev/en/guides/features/cache">binary caching</a> and <a rel="external" href="https://docs.tuist.dev/en/guides/features/selective-testing">selective testing</a> to speed up build and test runs. It turned out there are no companies interested in tackling this problem space for the Apple ecosystem, leaving us with a huge opportunity to build a financial foundation that we can then use as a lever to step into the next phase of app development.</p>
<p>If you think of some solutions that are making their contribution to this space from the angle of AI, we have agentic coding tools like <a rel="external" href="https://www.anthropic.com/claude-code">Claude Code</a>, <a rel="external" href="https://openai.com/codex/">Codex</a>, or the many live coding platforms that are crowding the space quite quickly. We thought about exploring that space too, but it took us a bit of waiting to realize it wouldn't be a great idea. At least not today.</p>
<h2 id="validation"><strong>Validation</strong></h2>
<p>With the feature built, the next phase is ensuring the work is right, and that usually implies tests, and some kind of automation to run those tests automatically as a result of pushing the code upstream. CI. We thought a few times about doing something in the CI space. Companies that like how we support them in the development phase showed interest in trying anything built by us in this space, but similarly, it took us a while to make some realizations that are key, and about which I already talked about <a href="https://pepicrft.me/blog/the-two-dimensions-of-mobile-development-infrastructure/__GHOST_URL__/mobile-ci-is-plateauing/">in the past</a>. TL;DR:</p>
<ul>
<li>CI orchestration has been solved by Git forges (e.g. <a rel="external" href="https://github.com/features/actions">GitHub Actions</a>), and this is making Mobile CI providers lose customers</li>
<li>The "pay for runners" is the new and better model that leads to better pricing and services</li>
<li>We just don't like managing Mac infra. We prefer building on it.</li>
</ul>
<p><strong>So we concluded that CI is not something we'd want to do.</strong> We were already doing something in this space with selective testing, but as we thought about automated tests, we came up with the idea of Tuist QA, which I talked about yesterday, and I think it's damn cool. By talking to customers we've also learned that sharding of testing, and infrastructure for snapshot testing are another two areas where companies have traditionally invested resources, and that they'd outsource if there was a company that managed those things for them. We'll get there, but the idea is already in our heads.</p>
<p>There are other forms of validation that you can't catch until the app is built, and for that we built <a rel="external" href="https://docs.tuist.dev/en/guides/features/bundle-size">bundle analysis</a>, which allows you to catch regressions in bundle size and ensure the app that you ship to your customers is as small as it can be. As you've probably noticed at this point, in development, our problem space centered more around how to make developers more productive. The validation phase centered for us more around how do we make sure that developers are shipping the best apps?</p>
<h2 id="releasing"><strong>Releasing</strong></h2>
<p>This is another territory that we've mentally explored. I was part of building <a rel="external" href="https://shopify.engineering/mobile-release-engineering-scale-shipit-mobile">Shipit Mobile</a> at Shopify, and the impact that it had internally was immense. And now that we've invested in integrating with <a rel="external" href="https://namespace.so/">Namespace</a> macOS environments, we can make release automation fully CI-independent, breaking away from many existing models that require having a pipeline that builds and pushes the app. This might sound like a tiny thing, but it's not, because it leads to a much better developer experience, and a lot of control for us to build much better experiences, like a release process on the go.</p>
<p>The idea and the appetite are there, but as I mentioned before with other features, the time is not yet right.</p>
<h2 id="monitoring"><strong>Monitoring</strong></h2>
<p>Once the app is in the wild, we need to monitor if the app is doing well, and potentially make decisions, like doing a hotfix release that fixes a severe issue. In this territory we step into error tracking, and speaking honestly, it's the territory where it makes the least sense to step into, because error tracking platforms have done this for many years, and have much better products that are hard to compete with. But hey, never say no! PostHog started as an analytics platform, and not too long ago they added error tracking into their product. The integration of a built-in solution with the rest of the product can lead to much better and specific solutions that wouldn't be possible with solutions that are too generic. They'll likely not go the extra mile of building a solution that has knowledge of a specific platform.</p>
<p>Stability is not the only thing that you might want to optimize for. <em>What about performance?</em> <em>Performance of the loading of the UI? What about logs? Or sessions of the users in the app?</em> Compared to the previous phases, before we do anything in this space, we need to have a very solid service and infrastructure that can scale well. It's not the same building infra and services that support X developers per company as supporting X users per company's application. From the legal standpoint, we are more liable because we'll be dealing with more sensitive data, so monitoring the apps, though on our radar, is something we are holding back on a bit.</p>
<h2 id="one-more-thing-the-product-runtime"><strong>One more thing... the product (runtime)</strong></h2>
<p>There's one third dimension that would be awesome if we could ever get to. The first two dimensions had the development of the product as a target. But what if the target was the product itself? What if we provided infrastructure for the product itself by leveraging our infrastructure? For example, analytics for your product, since most solutions center around websites or web apps, or product feedback solutions? Or maybe tools around subscriptions. These are just some ideas.</p>
<hr />
<p>We have ambitious plans for Tuist, and a lot of blocks that we are slowly connecting into a cohesive vision to <strong>turn Tuist into infrastructure for mobile app developers</strong>. Our name doesn't constrain us to any problem space, which gives us the flexibility to evolve our vision, and the only constraint today is really capital. Executing all the above vision takes a lot of resources, and a lot of time, but we look at this constraint as something positive, because it helps us be very mindful about what the next step is going to be, and when it's very clear we just take it. This prevents jumping into areas too eagerly, and that's the reason why we didn't jump into building a Lovable for iOS or trying to solve CI for mobile. They just don't make sense.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Namespace gets macOS environment DX right</title>
      <link>https://pepicrft.me/blog/namespace-gets-macos-environment-dx-right/</link>
      <guid>https://pepicrft.me/blog/namespace-gets-macos-environment-dx-right/</guid>
      <pubDate>Tue, 09 Sep 2025 15:10:35 +0000</pubDate>
      <description>After years of painful Mac mini management for CI, we discovered Namespace - an API-first service that makes macOS environments elastic and developer-friendly. Perfect for building Tuist QA and beyond.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>macOS environments are something you don't want to be dealing with for automation. I'd outsource managing that infra to someone many times. I remember during my time at <a href="https://pepicrft.me/blog/namespace-gets-macos-environment-dx-right/__GHOST_URL__/tag/shopify/">Shopify</a> when we had to maintain a fleet of Mac minis, which we provisioned using <a rel="external" href="https://docs.ansible.com/">Ansible</a>, to among other things, install the virtualization technology, <a rel="external" href="https://veertu.com/">Anka</a>, and then plug them as runners into <a rel="external" href="https://buildkite.com/">Buildkite</a>. It was a pain to work with. We used <a rel="external" href="https://www.macstadium.com/">MacStadium</a> at the time, and I remember thinking, having solved running those environments, which Apple doesn't design for making things easy, I don't understand why they don't leverage the scale at which they operate to provide a developer-friendly interface that can match the elastic needs of a consumer, whether the consumer is just a company that needs CI, or a company that builds solutions that require macOS environments. This is something only companies that operate at scale can offer, and MacStadium was one of them.</p>
<p>For many many years, the model was, you need a Mac mini? You pay for it and keep it for at least 24 hours. If you need two, then get the second one, and same story, keep it for 24 hours. As I mentioned, this is a legal requirement by Apple. But it's annoying, especially if you can't predict the demand of environments that you are going to have. I don't know if tomorrow I'll need 1 or 2, or 20, that depends on many things that are out of my control. I remember chatting with a Tuist user who said that their CI provider required them to estimate how much workload they'd have. My immediate question was, how do you calculate that? The answer was, well we give them ballpark numbers. Some CI companies could eventually afford a more elastic model where you'd pay per usage, in fact GitHub Actions did it, but very understandably pricey. Still, there was a bit of light that we'd see a similar model outside of the CI spaces for companies like Tuist, where we need a platform upon which we can build a solution with elastic demand. The first feature we started to think about was Tuist QA. We don't want to build a system that predicts and demands for more or fewer Mac Minis ahead of time. We wanted a system where we could ask for a Mac Mini, use it for as long as we needed, then shut it down, and then pay for it. How that Mac Mini is then reused, I don't care, it's your business, not mine. And not only that, but give me an API that I can use. I call your API, I get a Mac mini asynchronously with SSH access to it. I'm done, and then I call another API for you to take it back. And in case shit hits the fan, just allow me to set a timeout to shut it down automatically. Why doesn't such service exist? It turns out it exists, and it's Namespace.</p>
<p>When I came across it, <a rel="external" href="https://namespace.so/">Namespace</a> was too good to be true. Exactly the developer-friendly API that we were looking for. A company that operates at the scale that we needed for that elastic demand, and an extremely talented team that cared about the product and how their customers would use the product. We got in touch with <a rel="external" href="https://www.linkedin.com/in/hugomgsantos/">Hugo</a> &amp; <a rel="external" href="https://www.linkedin.com/in/eva-parth/">Eva</a>, and they set everything up for us to start building <a rel="external" href="https://tuist.dev/qa">Tuist QA</a> on top of it, and it felt such a joy to use. Few companies go the extra mile of nailing developer experience, and I think Namespace has gone that extra mile. It reminds me of companies like <a rel="external" href="https://fly.io">Fly.io</a>, who made scaling services into new regions as easy as running a command like <code>fly scale count --reg mad 2</code>. I guess you understood what the command does without me telling you about it. I don't care about what it takes to proxy the requests to that new region, but I trust you'll do a good job. The same happened here, I don't really care about the limitations. I just care about getting and returning a Mac. MacStadium could have built something like this, but they missed the train. You can tell the team at Namespace has extreme attention to great product and it shows.</p>
<p>So as you might have guessed, our Tuist QA builds on it, so will other features, like signing on the fly, which we'll build down the road. Building on the service and getting support from their team has been exceptional. They recently told us they built a solution where they could bind the lifecycle of a machine to the lifecycle of a containerized runtime process, and it felt like they had been reading our mind. <strong>It's exciting to see DX innovation in a space that seemed to have succumbed to just CI as the only consumer of those environments.</strong> There are many companies like Tuist that will have a need for these environments for more than just CI, and this is going to be particularly relevant in the world of agents, where some operations might need to run remotely in sandboxed environments. Namespace is well positioned to take a big chunk of that market, and I'd personally be excited in that case because they really deserve it.</p>
<p>If you are considering moving your CI back to GitHub Actions, or GitLab CI, and just need runners that are better and more fairly priced than the ones that you get from GitHub, I'd recommend giving them a shot and shooting them an email. They are one of the nicest teams to work with and they'll work with you on providing you the best value.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Testing your iOS apps at a low cost using LLMs</title>
      <link>https://pepicrft.me/blog/testing-your-ios-apps-at-a-low-cost-using-llms/</link>
      <guid>https://pepicrft.me/blog/testing-your-ios-apps-at-a-low-cost-using-llms/</guid>
      <pubDate>Tue, 09 Sep 2025 10:15:41 +0000</pubDate>
      <description>We have just built Agentic QA at Tuist, Tuist QA , and started doing some early testing with users. Since solutions built on LLMs started popping up, the team looked at the technology and the solutions that used it with curiosity and starte…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>We have just built Agentic QA at Tuist, <a rel="external" href="https://tuist.dev/qa">Tuist QA</a>, and started doing some early testing with users. Since solutions built on LLMs started popping up, the team looked at the technology and the solutions that used it with curiosity and started thinking about how we could leverage them to solve painful problems in the ecosystem and bring a lot of value to the iOS community. At the same time, we wanted to build a solution that would incrementally build on past work (lower investment), while taking advantage of our expertise and foundations in the space/market in which we operate, Apple native development.</p>
<p>Devoting mental energy to LLMs and Apple's ecosystem needs, that's how we came across <a rel="external" href="https://en.wikipedia.org/wiki/Acceptance_testing">Acceptance Tests</a>. If you've worked with them in your Xcode projects, you might have experienced the pain. Developing them is costly, although Apple is helping a bit with <a rel="external" href="https://developer.apple.com/xcode/whats-new/">Xcode 26</a> with tools that automate writing them. Still, writing is only part of it. They are a runtime contract with your application's interface. Find a button and click it, or scroll until you find something, and then act on it. But one day, something changes, the contract is no longer met, and it doesn't necessarily mean the app doesn't do its job. It's just that the test needs to be updated, and since this is not something you do every day, the cost of refreshing your memory on how to fix the test is quite high. But that's not all. They take time to run, so you likely run them in parallel, but since they require multiple simulators, and there's a limit to how many you can run per macOS environment, this means sharding, and sharding means automation complexity you don't want to deal with, so you likely end up with sequentially executed tests that add up to a lot of minutes in every PR. By the time the time is too high, you lean on running them in main, distancing failures in time and space from the PRs that might have introduced legitimate failures, so the value of those tests diminishes significantly until the team just removes them.</p>
<p>The alternative? Have an in-house or external QA team. But this is equally costly and doesn't scale well. Concurrency is limited to 1 per tester. Moreover, they'll likely lack a lot of context to test the app effectively, unless they are in-house or they've been working with you for quite a while, such that they know well what the critical areas of the business are and can focus on those to ensure they don't break. Let's say they find issues and report them. They usually come in the form of a description of what they were expecting, what they got instead, and perhaps some screenshots or videos of the failure. The developer receives it, and they are left wondering where to start debugging. The video or screenshot should be enough, but it's not. You wish you had logs or handled errors or network requests, but all of that information is gone. You are unable to reproduce it, nor is the QA person, with whom you spend endless back and forth Slack messages or emails until you give up. The app is then shipped, and your error tracking platform reveals what the scenario was that led to the error. You'd have caught it with the right debugging information, but the tester had no easy way to provide you with that.</p>
<p>These tests are insanely valuable, yet extremely costly. What if we could make them less costly with LLMs? That's the assumption we started with, and it turns out that we can. We integrated Tuist with Namespace environments to spin up macOS environments where we'd download previews of your apps and start testing sessions in simulators using LLMs. Along the process we'd collect diagnostic data such as logs, so that on completion, we could not only provide you with the results, but also with everything that you need to diagnose the issue. The results are quite promising and it's truly mindblowing to see. Imagine incorporating not only the PR context into the testing session, but also information about the business, so that the technology is able to identify the most critical workflows. We'll have to iterate on it based on real scenarios, because... LLMs, but we hope to get to a point where we strike an amazing balance of insane value with little cost. I don't remember the last time I was so excited about a piece of work.</p>
<p>If you are interested, you can head over to <a rel="external" href="https://tuist.dev/qa">tuist.dev/qa</a> and we'll get you on a beta testing list. Here's a sneak peek of the report that your teams will get.</p>
<blockquote>
<p>All you need to opt into Tuist QA is having an iOS app project, and it works with React Native too.</p>
</blockquote>
<p>You can also reach out to me personally, <a href="mailto:pedro@tuist.dev">pedro@tuist.dev</a>, to know more about the feature.</p>
<p><img src="https://pepicrft.me/blog/testing-your-ios-apps-at-a-low-cost-using-llms/__GHOST_URL__/content/images/2025/09/QA-Detail---Overview---Light.png" alt="" /></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Finding Balance: Hosted Services vs Self-Hosting</title>
      <link>https://pepicrft.me/blog/finding-balance-hosted-services-vs-self-hosting/</link>
      <guid>https://pepicrft.me/blog/finding-balance-hosted-services-vs-self-hosting/</guid>
      <pubDate>Tue, 09 Sep 2025 07:40:21 +0000</pubDate>
      <description>I’ve had back-and-forth moments between using hosted services or hosting them myself. At times I felt zero trust and energy to host my own instances of apps that I’d use, like CloudNext. I’d also lean on local-first solutions that gave me a…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’ve had back-and-forth moments between using hosted services or hosting them myself. At times I felt zero trust and energy to host my own instances of apps that I’d use, like CloudNext. I’d also lean on local-first solutions that gave me agency over my data, but they often came at an inconvenience cost where most of my time would go into adding that convenience on top of it.</p>
<p>These days I’m swinging the pendulum back to using hosted services. First, because running a company and dealing with my medical situation has left me without the energy to navigate the inconveniences that the self-hosting model presents. Second, because I don’t want to end up in a position where the only tools and services that I trust are those that are open source and/or keep the data locally and follow standards. We live in Europe, which means there’s a framework that forces those companies to give me access to my data, so in hypothetical scenarios where I need my data, I should have access to it. I believe this is the way to go because it’s also a model that’s accessible to many people. Only technical people can afford to self-host a service.</p>
<p>Still, I choose wisely. I lean on Obsidian over Notion, and I don’t care whether they are closed source, but I can trust Notion and I can pay for getting my Vault synced across devices. After many years with my static blog, I’m back at Ghost, which I set up in a few minutes and then used Claude Code to help me migrate all my content through their API. It was a joy to set everything up and choose and pay for a theme from a theme store. In the past I’d style my website myself, but I don’t feel this is the area where I want to invest my energy. I prefer to pay someone for the amazing job they did creating a theme, and pay Ghost for keeping my site up and running and always available. Same with Notion. I trust them. These people are all about empowering publishing, and they deserve every single euro to execute on this vision. Does it cost money? Oh yeah, so what—they deserve it.</p>
<p>I also tried Omarchy recently, which was fun to tinker with, but I don’t feel that I need that level of configurability. There are things that I don’t like about Apple’s ecosystem, and sometimes I wish it were more open, but there are so many things I don’t have to think about that I can focus on the things that matter to me. At least today, that’s not configuring a window tiling system. It’s fun, but not where I want my energy to go. I’m happy with my Zed editor, which now integrates with Claude Code, and that’s all I need, really.</p>
<p>I don’t know if the pendulum will ever swing back—I guess it will—but this is how I feel now. Building a company and dealing with recovery from surgery is very energy-demanding, and being negative and zero-trust against tech companies is really not good for me or for anyone. We need more trust and frameworks that ensure our rights are respected. Although having the framework doesn’t guarantee enforcement, I trust the EU that in serious cases, they’d act, as annoying as it might feel for tech companies.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Selling Developer Tools to Developers is Challenging</title>
      <link>https://pepicrft.me/blog/selling-developer-tools-to-developers-is-challenging/</link>
      <guid>https://pepicrft.me/blog/selling-developer-tools-to-developers-is-challenging/</guid>
      <pubDate>Tue, 09 Sep 2025 06:30:39 +0000</pubDate>
      <description>Selling developer tools to developers is challenging. We are not that keen to pay for tools. Our programming language is free, as are the web frameworks and libraries we use to build our apps. Why pay for a tool? Having a conversation with…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Selling developer tools to developers is challenging.</p>
<p>We are not that keen to pay for tools. Our programming language is free, as are the web frameworks and libraries we use to build our apps. Why pay for a tool? Having a conversation with our manager about the value of a tool, or looping in legal or procurement, is something we’d avoid too. We’d even go the extra mile to look for alternative solutions to avoid the bureaucracy. Being contacted by a sales team is out of the question. A salesperson doesn’t need to play sales tactics, and the founders behind the product play a crucial role in building the trust that could lead to a sale. The best marketing we appreciate is when we come across an in-depth blog post from the company. These people know what they’re talking about. Seeing a company’s logo at a conference is cool; seeing it multiple times feels suspicious. They want something from me.</p>
<p>Yet, we are a very hackable human species. There are many buttons they can press to sell us what they want. In fact, pressing those buttons creates trojan horses to reach our employers. From pressing the button of public recognition and getting us excited and talking about the company, hoping for a prize at the end of the tunnel (sound familiar? YouTube has pressed this button for years), to pressing the fear button. The fear that you’ll lose users because your app is an extra 5 MB. The fear of missing out on new trends that everyone is talking about, like not being able to quickly code new features into your app. Or the fear that you’ll be left behind by some critical mass.</p>
<p>As odd as it sounds, many sales in this space are driven not by traditional strategies, but by hacking developers. This process is quite misaligned with our values at Tuist, so we’re looking around, trying to figure out something different. I believe it’ll revolve around great content about how Tuist can impact apps out there, without publicly shaming anyone for the job they’ve done, like we’ve seen companies doing. <strong>Just planting a seed about the value they hcan gain, not a seed of fear.</strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>I enjoy building for developers</title>
      <link>https://pepicrft.me/blog/about/</link>
      <guid>https://pepicrft.me/blog/about/</guid>
      <pubDate>Mon, 08 Sep 2025 17:13:21 +0000</pubDate>
      <description>Hola, I&#x27;m Pedro Piñera</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I'm a Berlin-based builder. For the past ten years, I have been a hands-on and adaptable problem solver, collaborating with start-ups and <a rel="external" href="https://shopify.com/">e-commerce platforms</a> and building open-source solutions like <a rel="external" href="https://tuist.io/">Tuist</a>. I'm currently working with <a rel="external" href="https://www.linkedin.com/in/marek-f-71853b89/">Marek</a> on turning Tuist into a sustainable business.</p>
<p>My work is trusted by <a rel="external" href="https://shopify.com/">Shopify</a>, <a rel="external" href="https://americanexpress.com/">American Express</a>, <a rel="external" href="https://soundcloud.com/">SoundCloud</a>, <a rel="external" href="https://shopify.com/">Bloomberg</a>, <a rel="external" href="https://stripe.com/">Stripe</a>, <a rel="external" href="https://google.com/">Google</a>, <a rel="external" href="https://monday.com/">Monday</a>, <a rel="external" href="https://justeat.com/">Just Eat</a>, <a rel="external" href="https://etsy.com/">Etsy</a>, and <a rel="external" href="https://adidas.com/">Adidas</a>.</p>
<p>If you'd like to contact me, you can send me an email at <a href="mailto:hola@pepicrft.me">hola@pepicrft.me</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>My Terrible Experience with Germany&#x27;s Health System</title>
      <link>https://pepicrft.me/blog/german-healthy-system/</link>
      <guid>https://pepicrft.me/blog/german-healthy-system/</guid>
      <pubDate>Wed, 03 Sep 2025 12:00:00 +0000</pubDate>
      <description>A runner&#x27;s knee injury in Berlin exposed Germany&#x27;s healthcare failures: misdiagnoses, dismissive doctors, and months of inadequate treatment forced expensive surgeries in Spain to prevent permanent disability.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I just got a second surgery on my knee after a year of a nightmare experience navigating the German health system from Berlin, and I finally have the emotional energy to share my experience, my frustrations, and my logical attempts to understand the system.</p>
<p>On September 21st, 2024, I had a very unlucky accident while running that led to a strong impact on my knee, causing such pain that I ended up going to the <a rel="external" href="https://www.sana.de/berlin">hospital in Lichtenberg</a> by ambulance.</p>
<p>Early experiences already felt unexpected. From the ambulance crew refusing to give me any water to the hospital calming my unbearable pain with random ibuprofen here and there. Something didn't seem right. My right foot dropped. I thought about lifting it up, and nothing happened. As if my brain's messages couldn't reach the muscles in charge of that movement. I told them, but they didn't think it was their responsibility. The X-ray showed the meniscus was fine, the tibial plateau slightly impacted, and swelling in the area. After 8 hours there, they sent me home with a knee brace, which I later realized wasn't a good idea, and the recommendation to visit a trauma specialist on Monday.</p>
<p>Monday came, and I went there early to make sure I'd get a slot. The room was packed with people. He spent 5 minutes at most with each patient. My turn came, I went in, told him everything that happened, and he sent me home, suggesting I continue with my leg elevated, injecting heparin, and regarding my concern about the foot drop, he suggested I get an appointment with a surgeon in the same building. They gave me the appointment 4 months later, and part of me thought it was okay because I didn't think there was a connection between the swelling and the nerves. In other words, I thought I'd recover the movement as soon as the swelling was gone.</p>
<p>Weeks went by, and with them, appointments with the trauma specialist. The knee became less swollen, but my foot was still dropping. It didn't feel like it was his responsibility. He asked for an X-ray, and in his opinion, everything had recovered. Luckily, I listen to my body, and everything I was being told didn't feel right. So I decided to get a private consultation for the nerve (300 Euros). Why private? It was the only way to get one fast. And why fast? Because nerve damage is harder to recover from the longer you wait without addressing it.</p>
<p>I traveled all the way to the west of Berlin. The doctor suggested doing an electromyography to see if my nerve conducted. I still remember the smell of my hair burning when she tried to increase the intensity because she couldn't believe what she was seeing. Luckily, her face showed this uncommunicated awe. She called her colleague to repeat the test. "She is better than me," she said. But the results were the same. The report? The nerve is kaput. The advice? Go to physio. A lot of people make fun of going to the doctor with a cold and getting recommended tea. Physio felt like the tea for severe nerve damage. Not something I wanted to deal with...</p>
<p>I went to the physiotherapist. She couldn't understand anything. "So you just fell running and your nerve is fucked up?" The trauma specialist gave me an Überweisung for useless 20-minute sessions where the physiotherapist would ask me to ask the doctors what to do, and ask me what I'd do considering the strangeness of the case. She was the first one suggesting I get a small orthopedic device to keep the foot at 90 degrees with my leg so that I could walk normally. She suggested getting a prescription from the doctor, so I did, but the lady at the orthopedic store refused to give it to me. First because the code wasn't right, and second, because she thought the Krankenkasse wouldn't pay her because they had given me and covered another one at the hospital. I couldn't believe it, and my mind was blown when the physio mentioned that I could just use a 15-euro one from Amazon. "Why are you wasting my time?" I thought. Also, why are they so hesitant to offer me anything because of fear of the health insurance not covering it if I need it?</p>
<p>Weeks went by. I noticed a bit of instability in my knee and no signs of recovery in the nerve. We went to Spain for Christmas and decided to pay for more tests myself. The first one was an electromyography, like I did in Berlin. The result? The same, no conduction. But this time the advice was very different and more acknowledging. "This is severe. Move fast." Finally! Someone who had called out the severity of the issue and urged me to move fast because it might require surgery. He also said that there aren't many doctors who know how to do these surgeries, especially if it requires transplanting nerve. It turns out there are cases where the nerve gets compressed and the surgery is about releasing it, but that didn't seem to be my case.</p>
<p>I then started my search for a trauma specialist specialized in nerves. I contacted two, <a rel="external" href="https://traumaunit.es">one based in Barcelona</a> with whom I'd finally get the surgery, and another one in Madrid. I got a very quick response from the latter, so I took a train to Madrid and decided to give him a visit. From the first moment I stepped into the consultation, I felt uncomfortable. He used sales techniques that I had seen before, from pressing fear buttons to coordinating with the hospital that would do the MRI later to continue the fear mood. The first MRI! After 3 months. That was the positive part of this visit. I could finally understand what happened. Hold yourself: I had, in practical terms, a dislocation of the knee, which resulted in severe damage to the LCL and PCL ligaments, and a couple of tendons that had detached from the bones. That dislocation had probably stretched the nerve beyond its limits, causing its internal fascicles to separate very severely.</p>
<p>Things started to make sense. I refused to do any surgery with that doctor who continued to make me scared to the point that I ended up crying. I was hopeful my conversations with the doctor in Barcelona went well. I went back to Berlin and visited my trauma specialist. I told him that I now have an MRI and that the reality is very far from his diagnosis. His response? "I have never seen this in my life, and if I were a couch potato like he is," he recommended not getting surgery. I couldn't believe what I was hearing. 32 years old, severely damaged ligaments, and your response is not to intervene?</p>
<p>I was then recommended through a family member to visit one of the heads of traumatology at the hospital in Bonn. My wife and I crossed all of Germany by train to visit this doctor. He confirmed the ligaments were not in good condition and would require surgery. However, he suggested forgetting about the nerve. To do a tendon transplant from the calves to the front side of the leg as a natural solution to keep the foot at 90 degrees. I was convinced about the plan for the ligaments but asked for a recommendation for a doctor in Berlin so that I could do the recovery close to home. And that's how I landed at <a rel="external" href="https://www.vivantes.de/klinikum-am-urban">Vivantes Kreuzberg</a> with another head of traumatology there. On the side, I continued conversations with <a rel="external" href="https://traumaunit.es/">Joaquim Casañas</a> from the clinic Traumaunit, who would end up doing both the nerve and ligament surgery, but more on this later. Note aside: this doctor from Bonn told his son, from whom I got the recommendation, that he was surprised to see that I was the one with painted nails and not my wife... Unbelievable.</p>
<p>But the story doesn't end there. My experience with the trauma specialist still feels to this date like a fake TV show. He started the conversation making jokes here and there, surrounded by a couple of extra guys. It felt like a boys' club. "What are you expecting out of this?" "Running again," I answered. Then he laughed and went with a "Running? Perhaps in the swimming pool, because you know you can run there, don't you?" All of this without looking at the MRI, which I was hopeful he'd examine, but that wasn't part of his plans. "Forget about the nerve," he said, then his colleague confirmed, and I stopped both of them and asked if they were neurosurgeons or had expertise on nerves. Surprise, surprise, neither was, but they had confidence as high as the Alps. So I decided to focus the conversation on the ligaments. "Do you know X?" (a German name) "No, why do you ask?" I sensed a bit of laughing over a funny joke. "It's a German player who played his entire life without ligaments because he focused on his physical health and strengthening the muscles that could take the role of the ligaments." And I was like, okay, but he is a football player, and I'm not. Then he looked at me and suggested that I focus on losing the extra kilos on my body, and if that wasn't enough, he looked at my wife and asked her if she liked me. Neither of us could believe the question, so she answered yes, and he gave her a recommendation to cook healthy food for me to contribute to my weight loss. We couldn't believe what we were seeing there; we were completely speechless. We also felt powerless. We should have said something and stopped the macho vibe in that room, but we were not emotionally charged to respond to that.</p>
<p>I was running out of options, but I knew the nerve was the focus, so I got an appointment with a neurosurgeon at Vivantes Friedrichshain, also head of department. This time, she spent some time looking at the MRI and trying to understand the whole case. She was patient and listened to us. However, the conclusion didn't give me confidence at all. "I think," she said, "that the issue is that the damage to the nerve is 20 cm, and considering nerves recover approximately 1 millimeter per day, you need to wait longer. I could open and transplant," she continued, "but it's always better if the nerve recovers by itself." In literal German: "Natur macht besser." The only problem was that in this case, nature couldn't do better because my nerve showed no signs of recovery in a few months, and it was on the path to causing the rest of the nerve to die and the muscles to die. That same day I had an appointment with the doctor in Barcelona, and he mentioned that the only way to know the state of the nerve was to open the leg and see. The surgery could just consist of releasing the nerve, or in more severe scenarios, it would require doing a nerve transplant, a very meticulous process where they need to identify what each nerve fascicle is for and suture them with a lot of patience and care. That's all I wanted to hear. Charged with many negative emotions, I decided to get surgery, which finally happened in February 2025, 5 months after the accident.</p>
<p>The surgery required a transplant as I originally expected. The nerve was severely damaged and wouldn't recover by itself. It took 5 hours, and everything that surrounded the transplant area looked positive. The doctor sent electric pulses during the surgery to confirm that the last part of the nerve was functioning and controlling the muscle as expected. It did, and he even recorded a video and shared it with me. Something that would have been unthinkable in Germany.</p>
<p>And that was just half of the equation and the most important one. The foot continues to drop and still drops because it'll take more than a year to control the muscle again, but everything is looking positive so far. But there was still the second half of the equation. What about the ligaments? In one of my checks with the nerve surgeon, who runs a clinic specialized in trauma, he got me an appointment with the doctor in charge of ligaments. He ran a bunch of tests, which he then contrasted with the MRI, and confirmed that my lateral and posterior cruciate ligament and the extensor apparatus would require reconstruction to bring stability to my knee. Otherwise, over the years, the tibia would get displaced and have cascading severe consequences. I was sold on it and didn't think twice about getting (and paying for) the surgery. I trusted the team from the nerve surgery, and I felt I was in good hands. Moreover, they knew my case, so they'd be extremely careful in this surgery to prevent any more severe damage.</p>
<p>But again, part of me felt that this should be covered by my health insurance in Germany, so I decided to give the system one final chance. I was recommended a trauma specialist specialized in sports medicine. I paid for a 300-euro consultation with this doctor. I went there, told his assistant my entire case, because yes, there they are so qualified that typing on a computer is a bit of a waste of time for them. Then he came, did a bunch of movement tests, less exhaustive than the ones I got in Barcelona (I could compare), and suggested getting another MRI. According to him, because you know... ligaments sometimes fix themselves. "Natur macht besser" again. I later learned that that's partially true. If the tibia is not fixated while the ligament damage heals, then it heals stretched and the ligament plays no role in protecting the knee. So his point was completely flawed. I was going to pay 300 euros for a 10-minute "get an MRI" answer, so I bothered him with a couple of extra questions. "So I come back with the MRI, and it shows no signs of recovery. What do we do?" Then he answered he'd wait until my nerve recovered, in maybe 2 years. A period during which my knee would be quite unstable and at high risk of causing other issues. I couldn't believe that was his suggestion. I said alright, I'll do that, but part of me knew I'd end up getting the surgery in Barcelona. I had no sign of trust from this trauma specialist, a very professional and respected one according to my physiotherapist.</p>
<p><strong>Almost a year later, and after more than 30K in expenses, I've got the nerve transplanted, the ligaments reconstructed, and I'm starting the recovery process of the ligaments. It turns out none of the recommendations in Germany were right and would have led me to lifelong disability in my nerves and also my knee.</strong> I'm so happy that I made the decision to look for answers elsewhere, but this is unacceptable in a country like Germany, which I'd have never expected to have such a terrible system. At moments I thought I was unlucky with the professionals I came across, but I interacted with so many, and not just in Berlin, that I started to realize some patterns that are specific to the design of the system and that would explain why things happened the way they did. What follows is an attempt to explain these things. Because yeah... I'm a logical person.</p>
<h2 id="the-why">The Why</h2>
<p>I'll touch on a few ideas in no particular order.</p>
<p><strong>I think Germany's health system is effectively private.</strong> For me, a public system is one that places the focus on the patient. The German system tends to the opposite. Why? Clinics get paid by the health insurance companies. They are companies, so they need to maximize their profits. They are limited in costs since they require a lot of human capital, and scaling the business would also mean scaling the cost, so they choose the path of maximizing the number of patients they see while minimizing the risk of over-prescribing and potentially having to cover the costs of some treatments that insurance companies would refuse to cover.</p>
<p>The doctor doesn't want to be in a position where they need to justify a treatment to health insurance. It's easier to prescribe you tea or skip an MRI because you were just running, and pass the problem onto you or someone else in the chain. The thing is that many serious health issues start with something small, so you need to take a more preventive stance and over-ask for tests that could uncover serious issues. In my case, an early MRI would have revealed not only the severity of the damage to my ligaments but also the connection with the damage to the nerve. Instead, the missing piece left a chain of professionals confused and passing the problem to the next ones, like middleware in an HTTP server. "I don't understand" &gt; "Not my problem" &gt; "Forget about it."</p>
<p>I later learned that nerve damage is considered high severity and treated with the urgency that I never had. I thought many times about private health insurance, but honestly, I don't think it would have done things any better. We say in Spanish that it's "the same dog with a different collar," meaning that at the end of the day, you are interacting with the same professional, just faster. The same professional who seeks profit over going deep into your case, like it was the case of the neurologist who thought the best solution to my non-conducting nerve was just doing physiotherapy.</p>
<p>Then there's the piece of not admitting that they don't know the answer, but at least pointing out the severity of the issue and the kind of next steps. Like... "I don't know, but I've heard this doctor is good at this type of surgery." I think it's a bit of a macho high self-confidence issue. This was a common denominator across all the male doctors I interacted with. One of them, the one who told my wife to cook for me to lose weight, felt like being in a boys' club. Listen, I don't expect everyone to know about everything. I knew my case was a bit special in that I didn't damage common organs, but I'd expect them to approximate closer to the issue and help me approximate even closer with the help of other professionals, but that was not the case. Instead, they laughed and hinted that I should treat my nerve as dead forever.</p>
<p>Another issue I noticed is that because German doctors perform fewer surgeries, they're losing practice and there's little appetite for exploring new techniques or treating complex cases. The system seems to discourage surgical intervention, which creates a vicious cycle: less surgery means less experience, which makes doctors even more hesitant to operate. I also heard from a nurse that a surgery that has a slight chance of not going as planned can impact a doctor's curriculum and reputation, so they are particularly hesitant in challenging cases. This risk-averse culture means doctors would rather pass on difficult cases than potentially harm their professional standing. In my case, <strong>this meant multiple doctors preferring to let me live with permanent disability rather than attempting a complex but necessary surgery.</strong></p>
<p>Let's talk now about Überweisungen. Every interaction with a doctor requires explaining the entire case from the beginning. At times I felt I was a pigeon with Überweisungen from one side to another. The general practitioner was hesitant to give me those, the physiotherapist had interest in me getting more of those so that I'd have those useless 20-minute sessions and she'd get paid for them. The orthopedist store was happy if the doctor would figure out the right number to put on the paper so that they'd sell me the right instrument and my health insurance would pay them for it. The private doctors, both the neurologist and trauma specialist, sought purely profit, but when the problem was severe, they turned a blind eye to it. They even hacked the system. The trauma specialist knew he wanted to invoice me 300 euros, so he filled the invoice with a breakdown that didn't reflect reality. Is this even legal? Man... it's a recognized sports trauma specialist in the city, and he could barely hold 10 minutes going deep into the case?</p>
<p>And then there's the "I've never seen this before," like... yes, it wasn't in the book that you studied, but human bodies are fucking complex. Very complex. And sometimes issues span across boundaries, like it was the case here. Isolating domain experts like the German system does complicates treating health issues that span multiple areas of your body. Perhaps a pain in the stomach area is connected with some other part of the body, and looking at each in isolation would miss the big picture. I think the system is designed in such a way that it's easy to miss the big picture. The nerves are not the responsibility of the trauma specialist. Back to the doctor and paper to the neurologist. The trauma is not the responsibility of the neurologist, so back through your general practitioner to the trauma specialist. And all of that requires an insane amount of emotional energy that's difficult to have in such a situation.</p>
<h2 id="what-s-next">What's Next</h2>
<p>I'll take legal action. I didn't have the energy for that a few months ago, but I charged the batteries and I'll start working with some lawyers. I think there was a chain of medical malpractice here, and I think they need to assume responsibility. I don't want this to happen to anyone, and even though the way they act is a response to a system badly designed in first principles, if we silence these cases, there's little chance of things getting any better. Slowly but steadily, I'll start with this as soon as I'm back in Berlin.</p>
<p>As for what if something similar happens again in the future: I'll be pushy at every consultation with doctors. I will listen to my body like I did this time, and if needed, I'll add any drama necessary. The amount of taxes that are going to these things, something I especially see now running a company where I see health insurances debiting the money from the bank account, is insane and worthy of more than just 5 minutes of "go home and rest."</p>
<p>I won't switch to any private insurance because the doctors are the same. If they see me sooner but they are unable to tell me what I have, what's the point? I'd rather go to a place where I have the certainty that profit is well balanced with going deep into the case. I paid for the surgeries here in Spain, but at no time did I feel that I was a product. They treated me with great care and followed up before and after the surgery to ensure the best recovery. Isn't it annoying that this all has to be private? Oh yeah, it fucking is, and I'll fight as much as I can to change this, and taking legal action is a bit of my personal fight. We need to protect and improve the system, which we are covering with our taxes. If more than a thousand euros a month translates into not getting an MRI when I needed it, refusing to pay for an orthopedic device, a 10-euro invoice of copayment for the ambulance, or seeing me for 5 minutes to tell me to go home and rest, something is very fucked up.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>On Markets and ICPs</title>
      <link>https://pepicrft.me/blog/markets/</link>
      <guid>https://pepicrft.me/blog/markets/</guid>
      <pubDate>Mon, 01 Sep 2025 12:00:00 +0000</pubDate>
      <description>Reflecting on Tuist’s evolution from mobile dev tools to open infrastructure. The mobile developer market has constraints, but we’re building beyond productivity—creating self-hostable infrastructure that scales with app success, not just team size.​​​​​​​​​​​​​​​​</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’ve been reflecting on Tuist’s journey and where we’re headed. Despite all the changes we’ve made to the product over the years, one thing has remained constant: our focus on large-scale organizations. That’s our Ideal Customer Profile (ICP)—the people we sell to.</p>
<p>The reality of the mobile developer tools market is sobering. It’s not tiny, but it’s not huge either, especially compared to the broader tech industry. Mobile teams at large companies rarely exceed 40 developers, which caps account sizes. Developer productivity—our core value proposition—isn’t easily measurable unless you wrap it in AI and sell the FOMO of missing the next productivity revolution.</p>
<p>Even when organizations see the value and are willing to pay, you’re looking at seat-based pricing in a constrained market. I believe this explains why we don’t see many companies thriving purely in mobile tooling. The mobile developer tools market specifically has structural limitations that make growth challenging. Investors also have less appetite for this space, partly because it’s hugely controlled by Apple and Google, who strongly influence the development lifecycle and app distribution.</p>
<p>Here’s the thing though: I want Tuist to grow, and I see this as an exciting challenge rather than a limitation.</p>
<p><strong>The key insight is that we don’t need to stay confined to traditional developer productivity.</strong> Tuist has always been a generic name, which gives us flexibility. More importantly, we have incredible foundations: years of open source work, a strong community, and robust infrastructure investments. I see Tuist evolving into open infrastructure for mobile developers—something you can self-host for free if you want, licensed fairly, built transparently.</p>
<p>This model has worked brilliantly for many source-available products. Instead of competing on price, we compete on being better and more open. Large enterprises will pay significant money for infrastructure they depend on, especially when it scales with usage rather than just seat count.</p>
<p>The most successful approaches in adjacent spaces involve becoming critical infrastructure that grows alongside customer success. Companies that position themselves in revenue-critical paths, while also building strong developer communities that turn into enterprise advocates, create powerful flywheels.</p>
<p>What excites me is how we can leverage the infrastructure we’ve already built. We’re running ClickHouse databases and soon Grafana dashboards—infrastructure that helps users and organizations understand how users interact with their apps at every stage. Our API keeps expanding, with account tokens and scopes coming soon. The throughline is becoming clear: we’ll build a Tuist SDK that connects app runtimes to our open infrastructure, giving developers unprecedented visibility into their applications.</p>
<p>Eventually, we’ll expand to Android since our solutions are fundamentally cross-platform.</p>
<p>The best infrastructure feels invisible when it works and indispensable when you need it. That’s what I want to build with Tuist—not just better tools, but essential open foundations that mobile developers like us can trust, extend, and build upon. I’m excited to share more about this journey as we continue creating what I believe will become critical open infrastructure for mobile development.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>You can&#x27;t build a Grafana</title>
      <link>https://pepicrft.me/blog/grafana/</link>
      <guid>https://pepicrft.me/blog/grafana/</guid>
      <pubDate>Sat, 23 Aug 2025 12:00:00 +0000</pubDate>
      <description>Tuist plans to offer Grafana dashboards for every project, inspired by Fly.io, giving developers full access to their metrics and build data.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As part of building <a rel="external" href="https://tuist.dev">Tuist</a>, we get to interact with and learn from products and tools that are everyday tools when developing web services. One of those tools is <a rel="external" href="https://fly.io">Fly.io</a>, a platform where we deploy our services.</p>
<p>There was one pattern in Fly.io that I liked a lot and that gave us an idea for an approach we could take at Tuist to give developers a new interface to their data. Every app in Fly comes with a read-only Grafana dashboard where you can explore metrics from your service like network requests, memory usage, and CPU usage. It's insanely convenient because without it, you'd need to deploy your own Grafana instance and set up your project to collect, standardize, store, and present the data in your own Grafana instance. It's a lot of work that someone takes off our plate. And the best of all is that they also provide a <a rel="external" href="https://prometheus.io/">Prometheus</a>-compatible endpoint to poll the data into your own dashboard as a way of extending their read-only dashboard, and their dashboard as JSON, since Grafana dashboards follow a standard schema.</p>
<p>Why is this a cool idea for Tuist, you might guess? Well... at Tuist we are collecting data from your projects and the interactions with them (e.g., builds and test runs). We standardize the data and persist it in a Tuist-managed <a rel="external" href="https://clickhouse.com/">ClickHouse</a> instance so that you don't have to do that yourself. We also provide a dashboard where we surface most, but not all, data. And this is a problem, I believe. You should have access to all your data in two ways. First, via an API. Most of our API domains are write-only. The CLI pushes data, and our dashboard is a presentation layer. But this is something that we'll change as we build clients for that data beyond the dashboard, for example, our iOS app. Second, you should be able to consume the data via a more complete dashboard, and this is where the idea of Grafana comes into play.</p>
<p>We are thinking about drawing from Fly's idea to provide every Tuist project with a Grafana dashboard that reads the data from our ClickHouse instance. Think of our dashboard as simple analytics, and the Grafana version as an advanced and more flexible version of it. An escape hatch where you can do more than what you get from our dashboard. And you might wonder... why not build the dashboard ourselves? The answer is simple: Because we can't build a better dashboard than Grafana. Dashboards are their business, it's something that they've done forever, and when you try the product, you notice it right away. Building dashboards is not our business, and throwing resources at matching Grafana's experience is the worst use of our resources. Our business is to collect and standardize the data—something no one has done before in the app development space, or at least not in the domains we are currently moving in, developer productivity—and then provide you with tools to get the most out of our data, from a Grafana dashboard to optimizations and insights to improve your dev environment and apps.</p>
<p>I did some experimenting yesterday, and I don't think it would take a lot of effort to pull this off. I've already deployed a Grafana instance at <a rel="external" href="https://metrics.tuist.dev">https://metrics.tuist.dev</a>, which I connected to our ClickHouse. Our server already supports OAuth2 thanks to the amazing Boruta Elixir library, which means users can log in smoothly using their Tuist identities. One click on the Tuist dashboard, and you get taken straight to the dashboard in Grafana. We'll have to implement logic for syncing the tenants, permissions, and the dashboard, but with their API, I don't think it'll be a lot of work.</p>
<p>Something also amazing about going down this path is that the schema of Grafana dashboards is <a rel="external" href="https://grafana.com/docs/grafana/latest/observability-as-code/schema-v2/">standardized</a>. Which also means you can tell LLMs: here's the schema of the data I have access to, and taking into account the schema of Grafana dashboards, please build a dashboard to get particular insights. And this is something you can apply not just to developer metrics like build times, but also product metrics, which we plan to expand to later in the year or early next year. Standards are unlocking in the world of AI, especially if they are not constantly changing and the LLMs have already gained that knowledge.</p>
<p>I think this is the kind of feature that will differentiate our offering among competitors as we step into new markets. We are a developer-first company, and these are the product design decisions that reflect that. Moreover, it shifts the value from the server to the infrastructure, which brings us closer to adopting a license like the <a rel="external" href="https://fsl.software/">Functional Source License (FSL)</a> for the server, since customers will want to pay us for providing a fast and reliable service. As <a rel="external" href="https://x.com/zeeg">David Cramer</a> shared in a podcast, we'll have organizations that will prefer to host it for free and go through the pain, and that means they won't pay for the product, but those customers that are not paying for the product are not paying your competitors either, and they are closer to becoming your customer. That's the place where we want to be as a company, especially as we expand to new markets where all the solutions are closed source.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Gardens, commerce, and the art of growing something meaningful</title>
      <link>https://pepicrft.me/blog/park/</link>
      <guid>https://pepicrft.me/blog/park/</guid>
      <pubDate>Fri, 08 Aug 2025 12:00:00 +0000</pubDate>
      <description>We chose authentic community growth over acquisition offers, prioritizing our garden’s original spirit and sustainable development over rapid expansion through external partnerships.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Money flows through the world like water through a landscape—sometimes nourishing, sometimes eroding, always reshaping what it touches. It creates currents that pull us toward certain shores, aligning our efforts around shared financial aspirations while quietly orchestrating the rhythm of most human exchange.</p>
<p>Yet the most enduring landscapes often emerge where different forces converge. Consider the digital commons that have grown into essential infrastructure—Wikipedia’s vast knowledge gardens, Ghost’s publishing meadows, Linux’s foundational bedrock. These flourished not because money called them into being, but because gardeners appeared who were drawn by something else entirely: the simple desire to cultivate something beautiful and useful.</p>
<p>Even the most organic gardens require tending. Like urban parks that need maintenance crews and water systems, these digital spaces have real costs woven into their existence. The paradox is that many institutions haven’t yet learned to see this infrastructure as worthy of investment, leaving these projects to find their own path toward sustainability without losing the original spirit that made them flourish.</p>
<p>At Tuist, we’ve been learning to dance between two rhythms: maintaining an open garden where anyone can wander freely, and running a small café at the garden’s edge. Some visitors will always prefer to bring their own provisions—and that’s perfectly natural. Others might glimpse the café and decide the garden isn’t for them, perhaps sensing commercial intent where they hoped to find pure sanctuary. The café’s earnings flow back into the garden itself—hiring groundskeepers, improving pathways, ensuring the space remains secure and welcoming.</p>
<p>I use this physical metaphor because software, like parks, is infrastructure that serves communities in ways both visible and invisible.</p>
<p>When we first considered adding the café, we’d come to understand that our garden—however cherished by its visitors—occupied a quiet corner of the world, not a bustling metropolitan center. Traditional funding seemed unlikely to find us there. The café felt necessary, but as I mentioned, money brings its own peculiar weather patterns to any project.</p>
<p>During this contemplation, we encountered another gardener with a different relationship to cultivation. Their vision reached toward something like Central Park—vast, commanding, transformative on a scale that money could achieve. “Would you consider joining forces?” they wondered. The idea of alignment between kindred spirits always deserves consideration.</p>
<p>But walking through their grounds revealed something troubling: a collection of abandoned plots where other projects had withered after acquisition. The pattern suggested a different philosophy of growth—one focused on rapid expansion rather than deep cultivation.</p>
<p>We represented something valuable despite our modest scale: an authentic community, a trusted name, roots that had grown slowly but strong. Perhaps that authenticity felt like something worth acquiring, like suddenly owning an established garden and using its paths to direct visitors toward a larger commercial venue. The leverage of genuine community attention, readily purchased.</p>
<p>When they proposed converting our garden into a promotional pathway—essentially asking us to become voices for their larger project—we recognized the fundamental mismatch. We had built something meant to serve its community directly, not to channel attention elsewhere. Our small café exists, but it serves the garden’s needs, not external ambitions. We remain open to growth, even to becoming something as significant as Central Park someday, but only through methods that honor why people originally chose to visit our quiet corner.</p>
<p>This reflects different relationships with resources and growth. Some see money primarily as fuel for market expansion and public recognition. Others view it as one tool among many for nurturing something genuinely useful. Both approaches have their place in the ecosystem, but they create very different kinds of gardens.</p>
<p>What followed only confirmed the wisdom of staying true to our original intentions. Limited financial resources don’t preclude significant growth—they might actually position us better for the kind of expansion that creates lasting value. In a landscape where many sprint toward acquisition headlines and aggressive marketing campaigns, we’re content to tend our garden with patience, watching it grow organically into whatever it’s meant to become.</p>
<p>Our relationship with money remains instrumental rather than central, and I’m grateful that our quiet corner of the world continues expanding in ways that feel authentic to its original spirit.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Local-first AI development for mobile apps</title>
      <link>https://pepicrft.me/blog/tuist-ai/</link>
      <guid>https://pepicrft.me/blog/tuist-ai/</guid>
      <pubDate>Mon, 04 Aug 2025 12:00:00 +0000</pubDate>
      <description>AI coding tools lock you out of your code. We’re building Tuist Ignite: local-first development where you chat to build but own everything.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’d be lying if I told you we aren’t thinking about how AI could impact the development of apps for the App Store. I’ve been keeping an eye on everything that’s happening and how solutions are challenging the lenses through which we’ve looked at some problems. This has given us some ideas for how Tuist could play a role there.</p>
<p>You might have noticed many tools for coding ideas or entire apps—tools like Lovable, V0, or even solutions for mobile apps. I don’t expect someone to build a GitHub today with these tools, but you can build POCs, features, and even projects just by chatting. The whole idea of being able to chat to build something, for example with your voice, is quite cool. I think of this as an accessibility tool, and one of Tuist’s responsibilities is to make building apps more accessible—for example, by managing the intricacies of Xcode for you.</p>
<p>However, I’m not aligned with the model where you don’t own the code, either locally or in a remote repository. I get it—it’s a way to monetize it. It’s similar in a way to those GUIs for designing and building websites that required a subscription to export your code. These experiences can and must run locally in my opinion. While many of the local solutions focus on integrating with existing dev environments, I believe local-first Lovables will emerge where the action happens locally, you own the code, and you choose the model.</p>
<p>Apple is doing a bit of this already with their Xcode 26 chat interface, but I believe editors as we know them today are going to change. When I use Claude Code, my editor is more of a tool to review the code and continue conversing with the agent. I don’t need auto-completion or the editor part taking most of my screen. What I need, though, is a way for the agent changes to be hot-reloaded instantly, and it makes me happy to think that we invested in half of that by allowing clean builds to be faster. Once CAS arrives, it’ll be even faster.</p>
<p>So it’ll take ages for Apple to realize things are changing and throw resources into challenging many assumptions baked into Xcode. Until then, I think there’s an opportunity for us, and that’s what I started tinkering with: Tuist Ignite (the name draws inspiration from GitHub Spark). The idea is simple: you run a command, and a coding experience opens in your browser. You can create a new project or add features to the project in the directory where you run the command from. Building? We know how to do it. Short feedback loops? We know that too. And common tasks like adding a dependency to integrate with GitHub? We can add that too. We could have a directory of plugins or formulas for these things that people can contribute to the repo—for example, a formula to set up RevenueCat in the project. I can’t conceive this experience being closed source. If we want to build a truly powerful alternative to Xcode for some types of tasks, this is the way forward.</p>
<p>Now, don’t get me wrong—Xcode doesn’t go away. You might still need it. In fact, we need its build system and Xcode projects internally. Think of Ignite as a new frontend to the same backend. And it’s a frontend that runs locally in your browser, but it can also run remotely—also in a browser or from a native client built for the task. VibeTunnel taught me the mental model of building your network such that you can connect to your localhost from anywhere.</p>
<p>Ignite is about grabbing that idea you had in your head and preserving its energy until it’s touchable—until you can feel it. And having an experience that’s welcoming to anyone regardless of your background. Because ideas can happen anywhere and by anyone, anyone should be able to prototype from anywhere. Most ideas will eventually be discarded, but some will get continued, and this is where an editor like Xcode comes into play.</p>
<p>When contributing an idea to an existing app, you are constrained by the existing project in terms of how things should be done. For example, if the project is written in Swift, you’d shape the idea in Swift. Well… not you, but the underlying agent. But if you don’t have anything, why wouldn’t you just go with React Native instead, which can hot reload changes relatively fast? I don’t know… those are questions I ask myself. Tuist is strongly tied to native development, but I keep an open mind and challenge my own assumptions and principles, and I think React Native is well suited for these kinds of idea ignitions.</p>
<p>Now the idea is built—you’ll want to have an extra check of confidence before you share it with the world. And this is where Tuist QA comes in. Acceptance and snapshot tests are costly to develop, maintain, and run. This is well known… Xcode 26 is making it easier to write them, but what about the maintenance? What about that UI test failing and you being unable to diagnose the issue because what the test is testing is implicit in the testing code itself? Good luck. We think there’s an opportunity to improve the state of the art there—an opportunity to pull your changes, build the app, and then use LLMs to navigate the app and test what you’ve implemented, which can be derived from the changes or your changelog. Once it comes back, you can keep iterating or move forward. The report will come with all the artifacts and data you need to diagnose the issue, from screenshots to the network requests that were sent. Because let’s not forget that diagnosing a UI or acceptance test remains tedious and convoluted these days. We’ve got a POC and it looks very, very promising.</p>
<p>Your idea is built, we know it works—you’ll want to share it with the world, won’t you? You’ll likely want to share it with a small circle, which means you need to build and sign the app, including the destination device IDs in the certificate. Sounds like a lot if you wanted to prototype something or you have no context at all around how signing works in the ecosystem. I feel you. But this is where our Tuist Previews feature will shine. From the same UI where you crafted your idea, you’ll be able to “Log in with Tuist” and click share. It’ll complete with a link that you can share with anyone, and if signing is needed, we’ll sign the app on the fly for you.</p>
<p>What sits at the core of all of this? Our experience working with Xcode projects and toolchain, which we built over the years. A development SDK that can expose runtime data to the Ignite and QA agents. Some context is available from the outside, but other context can only be retrieved at runtime, like the network requests that are happening. And last, we need ephemeral macOS environments, and that’s why I’ve been so excited and supportive of Namespace. It’s the only company that has a well-productized offering of macOS environments for developers. You call an API, and you get a Mac Mini. Our agentic features will be triggerable from anywhere—from a new comment on a PR to a button on the app while waiting for a flight at the airport. We are breaking the strict dependency of everything happening through a CI pipeline, because it’s extremely constraining and terribly limits the DX that one can build.</p>
<p>Oh! And we also need fast builds—otherwise the experience will be as bad through agents as it is when you interface with Xcode directly. Hence why we are investing in reducing the cache latency and preparing for when content addressable store lands in the Swift build system. Maybe next year? Or in a few years? Who knows… in this ecosystem, things are closer to how things are in life: slow.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The market</title>
      <link>https://pepicrft.me/blog/the-market/</link>
      <guid>https://pepicrft.me/blog/the-market/</guid>
      <pubDate>Fri, 01 Aug 2025 12:00:00 +0000</pubDate>
      <description>When Grammarly buys an email company, it&#x27;s not about product synergy—it&#x27;s about entering new markets, acquiring customers, and expanding beyond their name.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>The other day, I came across news of <a rel="external" href="https://www.grammarly.com/blog/company/grammarly-to-acquire-superhuman/">Grammarly buying an email company</a>, and it got me thinking. One might look at this connection through the lens of product and think the connection is weak, but that's not the dimension these kinds of deals usually revolve around.</p>
<p>Companies have a market and continuously strive to make it larger to increase their capitalization. Within those markets, there's one customer profile you can sell to. It's usually referred to as the ICP (Ideal Customer Profile). For instance, Tuist's current ICP is large development teams that are scaling their Apple app development. It's a small portion of the total app development market. Now, once settled in a market, it's common to have an appetite for more, especially if there's a broader set of incentives that escape the company.</p>
<p>There are different ways to enter a new market, but one of them is buying companies in the market you're expanding into. Sometimes you just want the customers of the company; other times, you just want the brand awareness that company has in a particular market—perhaps both. This is a costly move (you need to buy a company), and it might not always go as planned. First, you've got a user base that has a perception of what you are as a product, and people react defensively to changes. It takes time and a lot of socializing for people to connect with what you see the company becoming. Moreover, your product and brand might limit you. If your current market is captured in the name of the company, then you'll have a hard time convincing people you do more than that. That's why I love the Tuist name so much. Its definition is up to us. And last, there's the community of the product/company you're merging into yours—its values, its community, its mission—and it might not align 100% with yours. That'll inevitably create some churn, unless there's tight alignment, which is quite rare.</p>
<p>So when Grammarly buys an email client, there's likely an appetite within Grammarly to enter a new market. Perhaps it's the customers in that market they want? Perhaps it's the presence of that brand in the market? Perhaps we'll never know. But time will tell. I've also noticed companies that realize their ceiling and sell an overrated abstract value that they've faked with money, because there's a lot of storytelling involved in these things, but I'll leave that for a future blog post.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The coming disruption of Apple developer tooling</title>
      <link>https://pepicrft.me/blog/apple-disruption/</link>
      <guid>https://pepicrft.me/blog/apple-disruption/</guid>
      <pubDate>Wed, 23 Jul 2025 12:00:00 +0000</pubDate>
      <description>GitHub Actions and commoditized Mac infrastructure providers like Namespace are disrupting the stagnant Apple developer tooling market, enabling innovative alternatives to traditional pipeline-centric CI solutions.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Markets are supposed to be this tool that forces companies to compete, transitively building products that are more aligned with users' expectations.</p>
<p>This is the theory, but whether it unfolds and how really depends on the market. We developers of apps for the Apple ecosystem are a bit unlucky. The incentives for diverse competition are not there.</p>
<p>First, the market is big, but not big enough. Second, Apple has significant say and control in the ecosystem, and third, anything that you do for the ecosystem is an act of reverse engineering proprietary and undocumented technologies. We at Tuist know that well.</p>
<p>The consequence is that we don't see much innovation. Either you wait for Apple to come up with something innovative, or you hope for another company to have a culture of innovation. Sadly, neither of the two is happening.</p>
<p>Outside of Apple's factory, companies have gone for the safe bet. The problem and solution that have for many years been validated: CI. Same model repeated over and over: a pipeline, most likely YAML, a UI to see the logs and exported artifacts, and all the glue with the Git forge. Different package, same product. Apple adds the twist (on purpose?) of making their hardware infrastructure-unfriendly, so CI companies usually go from adding a little margin to infrastructure managed by other companies and eventually attempt to own the vertical themselves to have better cost control. BuddyBuild tried to bring some fresh air to the space by challenging YAML pipelines, but Apple went their own way with the product.</p>
<p>CI companies have some foundational blocks to enable innovation—Mac infrastructure and capital—but they struggle at innovating. Product-wise, everything becomes pipeline-centric. Want to automate your release? It's a pipeline. Want to optimize your builds? It's in your pipeline too. And analytics? In the pipeline with the steps that we provide. I'm sure this all sounds familiar.</p>
<p>But sometimes miracles happen. A bigger fish makes an impactful decision, and suddenly the models can be challenged. This is the case with Git forges like GitHub opening up the vertical and making layers replaceable. They solved the topmost layer of CI and gave accounts the option to bring in third-party runners by themselves or from third-party companies. Companies like CirrusLabs or Namespace can commoditize a piece of the infrastructure that was previously reserved for CI companies. MacStadium had a huge opportunity there and failed to take advantage of it.</p>
<p>Sticking to GitHub CI or the equivalent in other forges has something interesting that helps move the ecosystem to a better place. It's so easy to switch providers that companies in the space are more incentivized to provide better and cheaper Mac environments if they want to capture the market. It's also cheaper for you as a user because you go one level lower, and the experience is so much better because it's tightly integrated into the platform where code collaboration happens.</p>
<p>And this move has cascading consequences that can further impact the ecosystem. If Mac environments get better, cheaper, and more commoditized, like with Namespace, which provides an API to get Mac environments, then it opens the game to new players like Tuist that have limited financial capital but huge creative capital. We are not a pipeline-centric product. We want to explore creative ways to solve challenges that developers face.</p>
<p>Now, CI companies won't want this to happen. They are already working on redefining themselves as Mobile DevOps platforms, hoping that companies' perception of the cost of migrating and value remains in their favor. But OMG, LLMs have challenged that too. You can ask a model to migrate a pipeline back to GitHub Actions, and voilà, it'll certainly do the work very reliably. This will take time for organizations to realize, but I'll help create awareness around this.</p>
<p>While the incentives to build for the Apple dev tooling market are not that high, and that makes it trickier to attract capital to support making an impact, changes like the ones we are witnessing since the appearance of GitHub Actions make it more accessible and allow players like Tuist to play the game with a different form of capital—one based on human capital and their ideas. So yes, I talk a lot about Namespace because I deeply care about our users and, more importantly, about having the foundation to enable more innovation in the space. I believe Namespace and their commoditized infrastructure can make a big difference, from being able to release by clicking a button on a website to building apps remotely from non-macOS environments.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Agentic native app development</title>
      <link>https://pepicrft.me/blog/agentic-app-dev/</link>
      <guid>https://pepicrft.me/blog/agentic-app-dev/</guid>
      <pubDate>Tue, 24 Jun 2025 12:00:00 +0000</pubDate>
      <description>Some thoughts on how Tuist could enable agentic building of apps</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I used to be skeptical about agentic coding. But after incorporating it into my daily workflow, my perspective has completely shifted.</p>
<p>Agentic coding is saving me tremendous amounts of time. The more context I provide—which is becoming easier thanks to the growing ecosystem of MCPs—the better results I get. This got me thinking about what this transformation means for app development as a whole.</p>
<p>I’ve been following Peter Steinberger’s work lately, and one thing has become crystal clear: you might not need the IDE layer most of the time. Instead, you can use your voice to spawn multiple agents working in parallel without stepping on each other.</p>
<p>Claude Code reinforced this realization. They built an entire coding experience at a lower layer—the terminal—proving that the IDE’s value is diminishing rapidly.</p>
<p>Apple’s top-down, hermetic approach is making them lag behind in crucial ways. They attempted to catch up with Xcode 26, but it’s already outdated. More importantly, they’ve completely disregarded the elephant in the room: MCPs. They’re doubling down on their proprietary model of “you need Xcode and our tools” to develop apps.</p>
<p>However, significant work is happening to break that dependency. As development shifts toward the terminal, new opportunities emerge to work outside of Xcode. This is where Tuist can play a transformative role.</p>
<p>When we built a business around Tuist, we focused on the most immediately monetizable problem: slow builds. This approach proved both slow and limited in market reach. First, you need an organization with a strong pain point, and many have already internalized that Xcode native development is inherently problematic—you can’t change their minds. Second, you need organizations that see value in investing money to optimize their workflows. Many don’t because they lack tools to measure delivery productivity. We ended up with a very limited market, which left me uncomfortable.</p>
<p>Can we build something exciting that a broader market would embrace, willingly pay for, and leverage all our years of investment? I think so. In business terms, it’s called pivoting. If you’ve used the Arc browser, you know what I’m talking about. Your initial market bets might not match expectations, so you can either push through with resignation because people don’t appreciate the problem you’re solving, or go back to the drawing board and iterate. We’re going to iterate.</p>
<p>I believe AI is fundamentally an accessibility tool. More people will be able to build without knowing how to code. Agents will become excellent copilots for app development. In that world, what would they need?</p>
<p>First, they’d need a build environment that doesn’t require creating a developer account or installing a heavy toolchain. The web is the most accessible solution, so we’ll build an environment like Phoenix.new with an embedded simulator. As you work with the agent, you can see your changes live. This isn’t React Native rendered using the DOM—it’s a real app running in a simulator embedded in the browser. Hot reloading will be automatic and seamless.</p>
<p>But this is only half the process. Once you have something usable, you want to share it with others, collect feedback, or publish to the App Store. If you’re an iOS developer, you know this involves intricacies like signing and building for distribution, making things less accessible for those unfamiliar with Apple’s ecosystem. I’d argue it’s even messy for Swift developers who don’t do this daily.</p>
<p>At Tuist, we’ve solved distribution to others and are working on signing when needed. The final step would be pushing to the App Store or releasing apps directly.</p>
<p>The project lives in your repository. You can continue using our agentic coding environment or go the traditional route of pulling everything and opening the project in Xcode. We don’t plan to support the full range of Xcode capabilities—we simply can’t, and it’s not a good idea. However, we can focus on what developers and non-developers need to build 80% or even 100% of apps, simply by chatting with an agent that guides them from idea to release.</p>
<p>What I love about this approach is that it builds incrementally from the product and infrastructure foundation we’ve developed over the past years, while aligning development more closely with the models emerging elsewhere.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Setting up PeerTube with Cloudflare R2 Object Storage</title>
      <link>https://pepicrft.me/blog/peertube-cloudflare-r2/</link>
      <guid>https://pepicrft.me/blog/peertube-cloudflare-r2/</guid>
      <pubDate>Thu, 12 Jun 2025 12:00:00 +0000</pubDate>
      <description>A step-by-step guide to configuring PeerTube with Cloudflare R2 for reliable video storage and streaming, including migration tips and troubleshooting.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I recently spent considerable time integrating <a rel="external" href="https://videos.tuist.dev/">Tuist Videos</a> (our <a rel="external" href="https://joinpeertube.org/">PeerTube</a> instance) with Cloudflare R2 object storage. The motivation was simple: users were experiencing playback interruptions due to connection drops, and I wanted a more robust storage solution.</p>
<p>This guide captures the configuration process for anyone facing similar challenges or looking to leverage R2's reliability for their PeerTube instance.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Before diving into the configuration, ensure you have: - A Cloudflare R2 bucket created - R2 API access keys (Access Key ID and Secret Access Key) - Administrative access to your PeerTube instance</p>
<h2 id="configuration">Configuration</h2>
<p>The core configuration happens in your PeerTube instance's <code>default.yml</code> file. Add the following <code>object_storage</code> section at the root level:</p>
<pre><code>object_storage:
 enabled: true
 endpoint: &#39;{your-account-id}.r2.cloudflarestorage.com&#39;
 region: &#39;auto&#39;
 credentials:
 access_key_id: &#39;your-access-key-id&#39;
 secret_access_key: &#39;your-secret-access-key&#39;
 upload_acl:
 public: null # R2 doesn&#39;t support S3 ACLs
 private: null
 max_upload_part: 100MB
 max_request_attempts: 3
 web_videos:
 bucket_name: &#39;tuist-videos&#39;
 prefix: &#39;web-videos/&#39;
 base_url: &#39;https://storage.videos.tuist.dev&#39;
 videos:
 bucket_name: &#39;tuist-videos&#39;
 prefix: &#39;videos/&#39;
 base_url: &#39;https://storage.videos.tuist.dev&#39;
 streaming_playlists:
 bucket_name: &#39;tuist-videos&#39;
 prefix: &#39;streaming-playlists/&#39;
 base_url: &#39;https://storage.videos.tuist.dev&#39;
 store_live_streams: true
 user_exports:
 bucket_name: &#39;tuist-exports&#39;
 prefix: &#39;user-exports/&#39;
 base_url: &#39;https://storage.videos.tuist.dev&#39;
 original_video_files:
 bucket_name: &#39;tuist-videos&#39;
 prefix: &#39;original-video-files/&#39;
 base_url: &#39;https://storage.videos.tuist.dev&#39;
 captions:
 bucket_name: &#39;tuist-videos&#39;
 prefix: &#39;captions/&#39;
 base_url: &#39;https://storage.videos.tuist.dev&#39;
</code></pre>
<h2 id="key-configuration-notes">Key Configuration Notes</h2>
<p><strong>Bucket Strategy</strong>: I opted to use a single bucket (<code>tuist-videos</code>) for most content types, organizing them with prefixes. This simplifies management while maintaining logical separation.</p>
<p><strong>Custom Domain</strong>: The <code>base_url</code> configuration is crucial for avoiding CORS issues. Set up a custom domain for your R2 bucket through Cloudflare's dashboard and use it here. The default R2 URLs can cause CORS problems that are difficult to resolve with policy adjustments alone.</p>
<p><strong>ACL Settings</strong>: R2 doesn't support S3-style ACLs, so both <code>public</code> and <code>private</code> values should be set to <code>null</code>.</p>
<h2 id="migrating-existing-videos">Migrating Existing Videos</h2>
<p>If you have existing videos to migrate, PeerTube provides a convenient npm script:</p>
<pre><code>NODE_CONFIG_DIR=/app/code/server/config \
NODE_ENV=production \
npm run create-move-video-storage-job -- --to-object-storage --all-videos
</code></pre>
<p>Adjust the <code>NODE_CONFIG_DIR</code> path to match your PeerTube installation's configuration directory.</p>
<h2 id="deployment-and-validation">Deployment and Validation</h2>
<p>After updating the configuration:</p>
<ol>
<li>Restart your PeerTube service to load the new settings 2. Test by uploading a new video or accessing previously migrated content 3. Monitor the admin "Jobs" page for any migration failures 4. Check application logs if issues arise</li>
</ol>
<p>The integration should provide more reliable video delivery, especially for users experiencing network instability. The combination of Cloudflare's global CDN and R2's storage reliability creates a robust foundation for video hosting.</p>
<h2 id="troubleshooting">Troubleshooting</h2>
<p>If videos aren't loading properly after the migration, check: - Custom domain DNS configuration - R2 bucket permissions - PeerTube job queue for failed migrations - Application logs for specific error messages</p>
<p>The admin interface's jobs section is particularly helpful for diagnosing storage-related issues during and after the migration process.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Mobile CI will have to redefine itself</title>
      <link>https://pepicrft.me/blog/mobile-ci/</link>
      <guid>https://pepicrft.me/blog/mobile-ci/</guid>
      <pubDate>Sat, 07 Jun 2025 12:00:00 +0000</pubDate>
      <description>This is my stream of thought on why mobile CI will have to redefine itself.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've been quite vocal lately about how the CI space for mobile is about to change. It's a matter of time. This led to cutting ties with CI companies, which understandably didn't like us being vocal about that reality. But sooner or later people will realize it, so I'd rather talk about it and move us to a more innovative space than live in a bubble and pretend everything is fine. I'll be talking in this space about mobile CI, but I believe this applies to other ecosystems too.</p>
<p>For many years, CI companies solved the gap that Git forges like GitHub didn't solve: providing a continuous integration service. You push a commit, see in your commit status that something is happening, and on completion you get a result and access to execution metadata. We could think of their offering as two layers:</p>
<ol>
<li>User-facing layer: web-based UI, pipeline editing features, ecosystem of steps... 2. Infrastructure layer: managing the runners in which jobs would run.</li>
</ol>
<p>Most delegated 2 to third-party providers like MacStadium, and they faced the challenge that the fluid nature of CI demand and the more static nature of getting Macs—which Apple requires you to get for at least 24h—made it difficult to provide a billing model that abstracted away the rigidity of the infrastructure layer. So it was common to find concurrency limits in their models.</p>
<p>But GitHub, GitLab, and all the Git forges changed the game when they decided to provide the user-facing layer. And not only that, but they did so by allowing hosts to be provided not only by them, but by third-party companies.</p>
<p>This translated into: 1. CI companies trying to expand their offering and doubling down on vendor locking. But developers are confused because they don't expect CI to do more than just CI. Competing with a better product was and is extremely challenging because you'll never be able to provide tight UI integration or features like pipeline permissions, where you can declaratively define the scopes you want the token exposed in the pipeline to have access to. 2. We saw an emergence of companies that focused on providing those agents. I call them "CI Runners as a Service" companies.</p>
<p>And this makes things interesting. By talking to Tuist users, I realize that many companies in group 1 are playing the card of "but moving away from us is hard" and trying to increase the size of their contracts by doubling or even tripling their prices. Others are trying to push the margins down or add new products, but once again, people expect CI companies to deliver CI. The only company that I've seen and that in my opinion is doing excellent work at offering a better and more diverse product is Buildkite.</p>
<p>And 2 is also seeing more companies joining, which means competition, and it'll lead to innovation and potentially lower prices. These companies providing runners face the challenge of marketing themselves effectively, so we'll lend our hand to those who align with our values and have built a great product. And the thing is that once you are on GitHub Actions or the equivalent in GitLab, changing from one provider to another is as easy as changing one line in your pipeline yaml file:</p>
<pre><code>runs-on: ubuntu-latest # Ubuntu
runs-on: other-provider # Other Provider
</code></pre>
<p>For some time I wrote about us potentially going to approach two, but the more I thought about it and dove into the space, the more I think it doesn't make sense for us. We don't find joy in doing infra. There are people who have been doing it for longer and do an amazing job at that. Our joy lies in being closer to the user and gluing tools and infrastructure together to provide experiences that wouldn't be possible otherwise.</p>
<p>So my bet is that when it comes to CI, companies will peel away that extra layer and go down to the companies that provide the runners. This means current CI companies will have to redefine themselves as something else, and my bet is that they'll join us in building an integrated platform for app developers. Bitrise started that movement with Mobile DevOps, but I don't think that went as expected. The closest to what we are trying to do is Vercel on the web, or Expo in React Native, so we are trying to bring the same experience to native Apple and Android development.</p>
<p>In this new space, we have a significant moat: our CLI that we've been building for over 7 years and that people use and love every day. This is our competitive advantage. We're going to compile it for Linux and Windows, making it ready for the future that we are shaping.</p>
<p>Pipelines and CI will continue to exist, but we want to part ways from pipelines being the center around which everything builds (release automation, nightly builds or previews, signing). I think the future of mobile is exciting, and we are going to take the lead in shaping it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>On mental health</title>
      <link>https://pepicrft.me/blog/on-mental-health/</link>
      <guid>https://pepicrft.me/blog/on-mental-health/</guid>
      <pubDate>Sat, 31 May 2025 12:00:00 +0000</pubDate>
      <description>A candid reflection on recent mental health struggles</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’ve been dealing with waves of anxiety lately. It had never happened to me before, but my body is speaking — it’s asking me to slow down. For someone like me, who’s naturally logical and tries to find a rational explanation for everything, this has been tricky. Anxiety lives in an emotional sphere I’m not familiar with, and I don’t yet have the tools to navigate it.</p>
<p>Up until 2023, I was moving fast in life. Things were progressing as expected, both personally and professionally. But I now realize I made the mistake of forgetting about myself and becoming addicted to the challenges at work. My personal and professional lives blurred in a way that, in hindsight, was emotionally taxing. I couldn’t see it at the time because of the inertia. Then the layoffs came, I was impacted, and everything came to a hard stop. A part of me moved on, but another part stayed behind, quietly processing emotions that would occasionally surface and demand attention. I ignored them.</p>
<p>Marek and I decided to build a business around Tuist — something I’m deeply excited about, but that also came with a new emotional landscape I had to learn to navigate. When Tuist was a hobby, I placed very few expectations on myself. But once it became a business, I started imposing expectations that brought a flood of emotions: <em>What if it fails? What if we don’t succeed in executing the vision?</em> These questions made me uncomfortable and, at times, stole some of the joy. The shift also introduced me to a set of dynamics very different from those in a free, open, community-driven project. I guess those feelings are natural, but they added to the emotional baggage I was already carrying. Again, I never learned how to deal with this kind of emotional weight.</p>
<p>When I look for stories from others who’ve gone through similar transitions — especially founders — I find almost nothing. Most public conversations focus on success stories and funding rounds. I can’t imagine doing all of this alone, so I’m grateful Marek and I are pushing through it together.</p>
<p>As if that wasn’t enough, I topped off the glass with a running accident that led to a knee dislocation, torn ligaments, and a nerve injury — something that could have left me with a permanent foot disability. The aftermath forced me to navigate the German healthcare system, and I felt abandoned by it. No one emphasized the severity of the injury. Some suggested I just forget about it and move on, and one even told my wife she should cook healthy meals so I could lose weight. It was tough — very tough. I pushed and pushed until I got my first surgery in Barcelona (which I paid for myself), stayed there for a month, and scheduled a second surgery for September. Thankfully, I could afford it — but it shouldn’t have been that way.</p>
<p>So here I am, dealing with anxiety bursts. If you see me exhausted, quiet, or not being the social, extroverted Pedro you’re used to — that’s why. I’m working on it, and I’m optimistic that I’ll come through this stronger.</p>
<p>My emotional chapter at Shopify is over. It was rough, but I learned a lot about myself through an emotional lens. My nerve is recovering, my ligaments are eager for reconstruction, and we’ve built the best team we could have imagined to build something amazing for app developers. What more could I ask for?</p>
<p>Please, listen to yourself. Slow down. Give yourself time to be present. The world — especially the tech industry — moves fast, but you don’t have to. That speed isn’t natural to life. Aligning yourself with life’s rhythms gives you the clarity and space to take care of yourself.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>On enthusiasm</title>
      <link>https://pepicrft.me/blog/on-enthusiasm/</link>
      <guid>https://pepicrft.me/blog/on-enthusiasm/</guid>
      <pubDate>Mon, 26 May 2025 12:00:00 +0000</pubDate>
      <description>In this blog post I reflect on the role of the “creator” that has emerged in the digital economy.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I just finished reading <a rel="external" href="https://www.anagrama-ed.es/foreign-rights/book/argumentos/el-entusiasmo/9788433964175/A_514"><em>The Enthusiasm</em></a>, a book by <a rel="external" href="https://www.remedioszafra.net/english.html">Remedios Zafra</a>, and it made me reflect deeply on the role of the “creator” that has emerged in the digital economy.</p>
<p>The author explains how enthusiasm for creating in the digital world lays the perfect foundation for precarious work. When you’re passionate about something, you can lose sight of yourself—blending your identity with your employer, celebrating their achievements with a “we,” or investing insane amounts of time without receiving anything in return. It’s what drives some people to spend their Sundays editing vlogs, or developers to evangelize their work environments as the ultimate place to be.</p>
<p>It’s increasingly common for companies to go beyond the traditional salary-for-time relationship by tapping into the emotional space where people develop their passions. You’re no longer just working for someone—you’re meant to feel passionate about what you do here.</p>
<p>Enthusiasm is a powerful force. It’s magnetic, it attracts people, and it’s contagious. But we live in a capitalist world, and the moment people gather around something, transactions of value begin to take place, a market emerges, and what once was a passion can turn into a burden. What once felt like “I enjoy editing videos” becomes “Why am I spending my Sundays editing videos?”</p>
<p>Part of you still believes you’re doing something meaningful, but the precarious reality you live in starts to feel uncomfortable. The PRs you merge or the free shoes a brand sends you won’t pay your bills. Capitalism doesn’t leave anything unmonetized—including enthusiasm. The idea of being an <a rel="external" href="https://www.reddit.com/r/IndieDev/">“indie developer”</a> is built upon this tension.</p>
<p>In an ideal world, capital wouldn’t interfere with your passions—and you’d have the tools to evolve your relationship with your own enthusiasm. If you look around, you’ll see developers whose passion led them to start companies, only for them to later step down as CEOs or leave entirely, returning to their roots. Back to enthusiasm in its pure and isolated form.</p>
<p>Have you ever had the impulse to do something and had to stop to assess whether it was truly what you wanted—or just a “fake passion” that inertia led you to pursue? In a world where everyone seems to have a passion—or at least pretends to—it can be emotionally difficult not to have one. Can’t it?</p>
<p>I’ve experienced all of this myself with <a rel="external" href="https://tuist.dev">Tuist</a>. We started it driven by enthusiasm. That enthusiasm attracted people, companies, and business incentives from others. At some point, we had to evolve it to avoid doing precarious work. It wasn’t something we actively planned—it just happened.</p>
<p>As I mentioned, enthusiasm is magnetic. In our case, we built a company around it. And with that, enthusiasm started to mix with business, and I had to do a lot of personal work to accept that evolution. It’s still tricky at times. Sometimes I want to do things just because they’re fun, but the business side of me questions whether they’re aligned with our goals. That internal conflict leaves me with tough emotions, as I can’t simply act on joy without considering the business implications.</p>
<p>I recently watched a <a rel="external" href="https://www.netflix.com/de-en/title/81700335">documentary</a> about the Spanish chef <a rel="external" href="https://en.wikipedia.org/wiki/David_Mu%C3%B1oz_(chef)">David Muñoz</a>, who expressed something similar. He’s passionate about cooking, and a business formed around his creations. That came with a team and responsibilities. But he admitted that he misses spending hours doing what he loves most—just cooking. I feel the same way with Tuist. As a CEO, I carry many responsibilities. I can fulfill them, but I also need to give myself space to enjoy the pure code crafting that brought me joy in the early days.</p>
<p>I also think about the people who contribute to or work on Tuist. They have their own passions. I don’t want to impose any on them—but when the work itself is fun, that overlap can happen naturally. So how much of it is my responsibility, as a founder, to help them set boundaries? And how much is on them? Should there even be boundaries? I believe so.</p>
<p>I didn’t set any for myself at my previous employer, and when I was laid off, it hurt more than it should have. As I mentioned earlier, when “you” becomes “we,” and all your passions are channeled into the company, you start to distance yourself from who you are outside of that world of enthusiasm. That can have serious mental consequences. I learned that the hard way.</p>
<p>What’s the solution? I’m not sure. The author suggests that passion and work are healthier when separated. It reminded me of how I often joke about opening a Spanish omelette restaurant in Berlin and coding just for fun whenever I feel like it.</p>
<p>I think having an ongoing dialogue with yourself—one that prioritizes your emotions and well-being above everything else—is key. Stay connected to yourself, and don’t feel pressured to follow a passion just because everyone else seems to.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Navigating anxiety</title>
      <link>https://pepicrft.me/blog/navigating-anxiety/</link>
      <guid>https://pepicrft.me/blog/navigating-anxiety/</guid>
      <pubDate>Mon, 12 May 2025 12:00:00 +0000</pubDate>
      <description>My personal journey through anxiety after experiencing layoffs, entrepreneurship challenges, and a serious injury - and how I&#x27;m learning to cope.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I can't pinpoint exactly when and how it started happening, but I've been having bursts of anxiety that I'm still learning how to navigate.</p>
<p>I think the first event that led to this phenomenon was the layoff at <a rel="external" href="https://shopify.com">Shopify</a>. I had been trapped in the climb-the-ladder model, given a lot of time and emotional capital, and gained momentum that was suddenly interrupted. As I processed those emotions, I later realized that I was reaching a point of burnout at the company, so on the positive side, I'm glad that it happened before it had been too late.</p>
<p>The second piece was starting a company. It's a very vulnerable position where you are this tiny fish in an ocean of business where dynamics are nothing like what you might have read in books or on the internet. While in programming things are more logical: you've got a problem, write the software to solve it. In business, you are invaded by questions and insecurities: Is this the right decision? Should we be jumping on that trend? What if the business doesn't take off? Logically, I can provide answers to those questions. Emotionally, I'm not prepared to process them, which makes things uncomfortable at times. There are also other emotions, like disappointment with some untold realities, that blend in weird ways. I'd love to eventually write a book about this transition because as a developer, you are barely told about many of the realities that unfold.</p>
<p>The last piece, which I did not expect, was an accident while running that led to torn ligaments and, worst of all, damage to the peroneal nerve, which disabled one of my feet. I spent one of the most vulnerable moments of my life navigating the German health system, trying to find a doctor who could explain and provide answers to the problem, and in some situations being treated in not very humane ways, in some cases making me feel responsible for the accident because of my weight. It was rough, and even though I eventually got the surgery (I had to pay for it), fears about whether this will recover keep coming back because every day I have to see my foot not responding to my instructions. If you've ever had a nerve injury, you probably know what I'm talking about.</p>
<p>So these three things, mixed together with the sprinkle of social network dynamics that favor competition, radicalization, and overall negative emotions, leave me ending my days filled with anxiety, mentally and emotionally exhausted.</p>
<p>To fight it back, I'm trying to slow down. I'm minimizing mental concurrency and the time that I spend on social networks like LinkedIn whose dynamics I'm not comfortable with. I'm also learning to be okay with not being able to chew as much as comes my way, and giving myself time and space to be present with myself, to go out and do analog activities that have nothing to do with business or coding, like taking photographs. I'm trying to lean on the human and social side of things, being supportive rather than competitive. Being human at Tuist is what makes us so unique, and I believe it's what will lead to the type of company we want to shape. I'm also accepting that life sometimes sucks, and that there are dynamics that, even though I disagree with them, like how the layoffs happened at Shopify or the accident while jogging, are simply part of life. What I had experienced until that moment was unusual. It takes time, but I'm getting there. I just came back from the gym, prepared myself a coffee, and gave myself some time to write these lines. How is your Monday starting?</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Compiler optimizations or speed of delivery</title>
      <link>https://pepicrft.me/blog/compilers/</link>
      <guid>https://pepicrft.me/blog/compilers/</guid>
      <pubDate>Tue, 06 May 2025 12:00:00 +0000</pubDate>
      <description>The Swift compiler optimizations are becoming so costly that Apple needs to rethink its approach to the build system.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Compilers turn code into binaries, optimizing it for the target architecture. In ecosystems like Apple’s, this can mean the difference between a MacBook’s battery lasting an hour—or several. But the compiler can also determine whether we ship code quickly or slowly. And in today’s world, where everything moves fast and businesses must keep up, the compiler can easily become a bottleneck.</p>
<p>Talk to engineers, and you'll hear excitement about new language capabilities—features that, while powerful, often add build-time complexity and degrade performance. Swift Macros are a perfect example of this. It’s exciting to see the language explore new directions, but if that comes at the cost of slower compilation and unreliable incremental builds, it feels wrong. Executives feel this too. If you maintain a large Xcode codebase and compare your team’s velocity to a web team’s, the difference can feel like an order of magnitude. So it’s no surprise when leadership asks engineering teams to explore <a rel="external" href="https://reactnative.dev">React Native</a>. When an app is merely a native presentation layer, abstracting the platform to gain speed becomes a necessity.</p>
<p>Now, add to the compile-time slowness the strong coupling between the compiler and a macOS host, and you’ve got a recipe for disaster. New LLM-based app development experiences are surfacing this problem more visibly than ever. Developers are expecting Apple to respond—but enabling meaningful improvements takes a long-term vision and multi-year effort. That’s something Apple seems to have lost in recent years.</p>
<p>They forked the web ecosystem and actively hindered it—yet the web kept building momentum. Now that momentum is paying off. I don’t know if we’ll end up “vibe coding” our apps with AI prompts, but it’s clear the way we build apps is going to change. And we can’t afford the slow compilation and feedback cycles that Apple imposes. For many new projects, React Native will be the default. You type a prompt, get your skeleton, and you’re coding in seconds.</p>
<p>I love Swift, and I enjoy being close to the platform—it means fewer abstractions. But I fully understand why organizations crave abstraction. And I’d love to see Apple respond to that. They have the resources to make it happen.</p>
<p>I wish they would acknowledge that they’ve lost their north star—but that they’re working on a strategy. Right now, it feels like they’re trying to push Swift in every possible direction while the core problems remain unresolved. How did it take so many years to address frequent merge conflicts? Will it take another decade to automatically copy dynamic binaries to the right destination in the build graph?</p>
<p>Or will they finally define and communicate a plan for the future of build tooling? Are they even thinking about this? If so, why not talk about it publicly? I’d love to follow along.</p>
<p>All of this presents great opportunities for <a rel="external" href="https://tuist.dev">Tuist</a>. But I’d much rather our work felt like we were extending a solid platform—instead of hacking our way around its shortcomings.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Remote macOS Containers as a Service</title>
      <link>https://pepicrft.me/blog/commoditization-of-macos-containers/</link>
      <guid>https://pepicrft.me/blog/commoditization-of-macos-containers/</guid>
      <pubDate>Mon, 05 May 2025 12:00:00 +0000</pubDate>
      <description>If we want more innovation in the mobile developer tooling space, we need to commoditize macOS containers.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I find it somewhat ironic that mobile CI companies that dominated the mobile automation space, amassed VC capital, and built the muscle to manage macOS environments see squeezing every dollar from their customers as their only way forward, while the rest of the industry could push for innovation if the management of macOS containers became cheaper and easier. There's never been a better example of <a rel="external" href="https://en.wikipedia.org/wiki/The_Innovator%27s_Dilemma">The Innovator's Dilemma</a> than this one.</p>
<p>Hence why I'm so excited about all the creative energy that's going into the space with projects like <a rel="external" href="https://tart.run">Tart</a>, <a rel="external" href="https://github.com/trycua/cua/tree/main/libs/lume">Lume</a>, or <a rel="external" href="https://github.com/macvmio/curie">Curie</a>. Sure, there's still a long way to go, but incremental steps are being taken towards enabling that commoditization. Even Cloudflare announced <a rel="external" href="https://blog.cloudflare.com/cloudflare-containers-coming-2025/">Linux Containers</a> for their workers as part of the platform. Ideally, we move to a world where getting a virtualized environment is just one API call away.</p>
<p>I remember during my time at <a rel="external" href="https://shopify.com">Shopify</a> when we had calls with the <a rel="external" href="https://www.macstadium.com">MacStadium</a> team, my recurrent feedback was: you guys should productize your offering and make it developer-friendly. Many developer tools in the space, including <a rel="external" href="https://tuist.dev">Tuist</a>, would pay for some kind of "Remote macOS Containers as a Service." Many developer tools require teams to leverage their CI/CD pipelines to build and push products. Imagine if you didn't have to do that. We want to move to a world with Tuist where you can create a preview or a release right from your phone. And for that, we need to access macOS environments quickly and cheaply.</p>
<p>I'd be lying if I told you that we are not already thinking and starting to put some work into making this happen. We are, and we want to offer that investment to our users so that organizations can reduce their costs down to just the infrastructure costs. It's easy. You place your AWS or <a rel="external" href="https://www.scaleway.com/en/">Scaleway</a> API keys, and we provision CI runners automatically or manually and plug them directly into GitHub or GitLab organizations. And those are the same environments that we can reuse to build your releases and previews, and sign your apps. No more YAMLs and complex automations. This is the world that we want to enable with Tuist.</p>
<p><a rel="external" href="https://www.crunchbase.com/organization/buddybuild">BuddyBuild</a> was moving in that direction until Apple acquired them and thought what the industry needed was CI but embedded into Xcode. Once we complete the <a rel="external" href="https://community.tuist.dev/t/we-kicked-off-the-1st-cycle-april-7th-to-may-18th/492">current cycle</a>, we'll start exploring this and content addressable stores. This is a muscle that we need to build because it'll bring the ecosystem closer to the developer experiences that other ecosystems have access to. And we'll advocate for any open source solution that gets us closer to enabling that future.</p>
<p><em>This post is written by a human with its grammar reviewed with Grammarly.</em></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>~AI~Vibe-first businesses</title>
      <link>https://pepicrft.me/blog/vibe-first-businesses/</link>
      <guid>https://pepicrft.me/blog/vibe-first-businesses/</guid>
      <pubDate>Wed, 30 Apr 2025 12:00:00 +0000</pubDate>
      <description>In this blog post I share my thoughts about this trend of AI-first companies, and what I believe they really mean with it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Businesses are about maximizing the revenue versus cost tradeoff. They generate revenue by producing value in a market, and the tech industry, like no other, can do so with much less cost thanks to the close to <a rel="external" href="https://link.springer.com/chapter/10.1007/978-3-658-38823-2_3">zero marginal cost</a> of software.</p>
<p>However, markets have a ceiling, and even though software has close to zero marginal costs, your software business might require humans, who are expensive—very expensive. And this is something hyper-growth business models are incompatible with.</p>
<p>Executives at major tech companies have found the perfect tool to work around the problem: AI. <em>"We are AI-first companies,"</em> <a rel="external" href="https://www.theverge.com/news/657594/duolingo-ai-first-replace-contract-workers">they say</a>. It'll often be used to eliminate human costs, such as support teams. In other cases, like Duolingo, they'll use it to break through the market ceiling. <em>"We need AI to scale learning"</em>, they said. What they really meant is that they need AI to <a rel="external" href="https://en.wikipedia.org/wiki/Drop_shipping">dropship</a> slop courses to continue exploiting humans feeling of learning progress because they complete streaks.</p>
<p>If you think you are indispensable in this new mission of AI-first companies, let me tell you something: it is mostly storytelling. You are digging your grave because you are a cost to the company, and your next performance review will be in the hands of LLMs. <em>"Let us know why you can't do this with AI"</em> is the new mantra. This continues with a <em>"don't worry, this is about empowering you"</em> so that you don't wake up from the dream of the company's mission. Once again, the ultimate goal of a company is to maximize profit; the ultimate goal of a hyper-growth company is to do so at all costs, including your empowerment or well-being.</p>
<p>Good luck to those companies that want to create companies where humans are dispensable. The challenges we face require more humans and more collaboration, not less, which only benefits a few. And yes, that means we can't work 24 hours a day, 365 days a year, so what? If this will be the new trend, I'm not on that camp, sorry.</p>
<p><em>This post is written by a human with its grammar reviewed with Grammarly.</em></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Full-time entertainers</title>
      <link>https://pepicrft.me/blog/full-time-entertainers/</link>
      <guid>https://pepicrft.me/blog/full-time-entertainers/</guid>
      <pubDate>Tue, 29 Apr 2025 12:00:00 +0000</pubDate>
      <description>I&#x27;m tired of social network dynamics, and I&#x27;m working towards jumping off the train (again).</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Social networks turned me into a full-time entertainer and entertained person. They managed to detach me from the real world, keeping me busy thinking about how to entertain people or starving to stay up to date because boredom became uncomfortable. This led to peaks of anxiety that I had never experienced before, and a lack of joy for things that used to be enjoyable because I started doing them just to talk about them. I tried to escape this many times, but I always fall back, like addicts experience with drugs. I became addicted to those dynamics.</p>
<p>The thing is that I'm aware that this is unhealthy. I don't like it. But there's this idea that I've built a brand, either mine or <a rel="external" href="https://tuist.dev">Tuist</a>'s, that would fade if I'm not active where everyone is. It's a bit nonsensical, because we have no control on those platforms over how we are presented. Perhaps a brand might even deteriorate there because you might end up morphing it into a meme-posting machinery, but still, that thought is recurrent, and I believe it is the trigger that brings me back, along with the idea that people are talking about the new thing. So what? 5 new vibe coding tools, an add-AI-to-x tools, and a couple of new JS frameworks... Again, so what? I don't want to sound cynical. I like tech, but a big part of the industry is hype cycles, because the tech industry is technology embedded in capitalism, and therefore it needs to reinvent itself. Today you are generating <a rel="external" href="https://www.reddit.com/r/ChatGPT/comments/1jlq58q/generate_studio_ghibli_style_images_with_chatgpt/">Ghibli Studio</a> images, and tomorrow you'll be generating your TikTok dances, the day after you'll be an expert in the process of electing the new Pope, and in two weeks you'll show your expertise in <a rel="external" href="https://www.bbc.com/news/live/c9wpq8xrvd9t">power outages in Spain</a>.</p>
<p>I'm happy we decided this is not the game we want to play with Tuist. It's stressful, tiring, and takes the focus away from the joy of the craft, which is what we love doing. It feels uncomfortable at times. Should we be doing like the others? But at the end of the day, we don't control those algorithms. They are controlling us and making us part of the exploiting machinery, ensuring there's stuff we can feed people with. We are placing a focus on our blog. Writing from the passion for what we love, and going deep into those topics. Embracing standards such that people can pull the content when and how they feel. If we are present on any social platform, we try to be on the ones that we think haven't "enshittified" yet.</p>
<p>I'm trying again. I want to be present. I want to remain mentally healthy. I want to shift the focus from the telling to the doing. I don't want to feel like a zombie hamster starving for "new" stuff, or feeling I have to contribute to keep other hamsters fed too.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Inviting ecosystems</title>
      <link>https://pepicrft.me/blog/inviting-ecosystems/</link>
      <guid>https://pepicrft.me/blog/inviting-ecosystems/</guid>
      <pubDate>Tue, 08 Apr 2025 12:00:00 +0000</pubDate>
      <description>In this blog post I talk about how Apple&#x27;s non-inviting ecosystem has hindered innovation.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’m a firm believer that a diverse ecosystem surrounding a particular platform correlates with its level of innovation, and <a rel="external" href="https://developer.mozilla.org/en-US/">the web</a> is a prime example of this.</p>
<p>From highly collaborative apps to technologies that transform web browsers into virtualization platforms, there are countless people building for the web and pushing it in myriad directions. This diversity can sometimes be a drawback—especially if you’re trying to build a company—but it lays the groundwork for unprecedented innovation. People feel invited and inspired to tinker with new ideas.</p>
<p><a rel="external" href="https://apple.com">Apple</a>, too, built an ecosystem—an ecosystem of apps—and invited developers to join. They provided tools, frameworks, and a language, creating a foundation upon which developers could build their apps. Innovation flourished at the application level. This approach worked well for many years while Apple focused on expanding its hardware offerings and, more recently, its services. However, it never felt truly inviting, and it still doesn’t.</p>
<p>First, it excludes those who can’t afford the hardware and prefer platforms like the web, which are universally available and accessible from anywhere. Second, it alienates developers who don’t want their capabilities limited by proprietary tools, frameworks, and even an open-source language that remains tightly controlled. They prefer platforms offering greater freedom. Finally, it distances those who don’t align with Apple’s mission and view contributing to its open-source components as indirectly supporting Apple itself. They don’t see these building blocks as true <a rel="external" href="https://en.wikipedia.org/wiki/Commons">commons</a>.</p>
<p>This is creativity left untapped—creativity that could have advanced Apple’s build system, making it more deterministic and optimizable. It’s people who might have better understood the issues with LLDB and proposed solutions to ensure developers can effectively debug their apps, or who could have taken SwiftUI to other platforms by integrating it with native rendering technologies. While we’ve seen sporadic efforts from individuals trying to drive change, these initiatives often fade because they ultimately depend on Apple’s approval—a “yes” or “maybe” that requires internal discussion and rarely materializes.</p>
<p><strong>I believe Apple’s current struggle to keep pace with innovation is a direct consequence of this missing creative energy.</strong> Their ecosystem can no longer ignore the outside world or the advancements happening beyond its walls, and developers naturally expect a response from Apple that never arrives.</p>
<p>Some suggest that throwing money at the problem might be a solution, and while that could yield short-term gains, Apple would soon find itself back in the same position. The momentum of more inviting ecosystems compounds over time in ways money alone can’t replicate.</p>
<p>I firmly believe Apple needs a mindset shift to make its environment more welcoming to this creative energy. If they succeeded, people would not only work to advance the ecosystem but also become stewards of it, much like Apple itself. Recent job postings from Apple seeking engineers to focus on Windows are a promising first step, but I’d love to see an approach centered on inspiring people to take Swift to Windows. What motivates Windows developers? What drives them to contribute to Swift in the context of Windows every day?</p>
<p>Microsoft nailed this with <a rel="external" href="https://code.visualstudio.com/">VSCode</a> and <a rel="external" href="https://www.typescriptlang.org/">TypeScript</a>. They built an ecosystem that sparked countless ideas and laid the foundation for the AI-based code editors we enjoy today. It took recognizing that open source is an aspiration for many and that showing you care can profoundly shift how people perceive you.</p>
<p>This creative energy is absent from Apple’s ecosystem due to its closed, proprietary nature and the tight coupling of its toolchain, paired with Apple’s firm control over the direction of its projects. We also lack a visionary—someone to oversee and communicate where things are headed, assuring everyone that Apple cares about Swift breaking free from its ecosystem. Imagine someone saying, “Yes, SwiftUI should have been open source, and we’re taking steps to make that happen. It’ll be open source because we want people to take it to new platforms.”</p>
<p>This is a long-term investment that’s hard to justify because the returns are distant in both time and impact. A brilliant idea born from a more open toolchain might emerge years from now, and its connection to that openness might not be immediately obvious. Will it happen? Who knows—it’s Apple. But I believe it will require new leadership that embraces a more open, ecosystem-building approach. A leadership that shares a vision for their technologies beyond Apple devices.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Tuist&#x27;s plans</title>
      <link>https://pepicrft.me/blog/tuist-plans/</link>
      <guid>https://pepicrft.me/blog/tuist-plans/</guid>
      <pubDate>Wed, 02 Apr 2025 12:00:00 +0000</pubDate>
      <description>This is an stream of thoughts around the future of Tuist.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Since we decided to turn Tuist into a business to ensure we could continue supporting teams and individuals, we've thought a lot about what we want Tuist to look like in the future.</p>
<p>With codebases growing larger and the speed of business demands increasing, we believe Tuist should position itself as a productivity tool for app developers. The "app developers" part is crucial. While some challenges extend beyond app development, we believe app development is where we originated, where we understand the challenges thoroughly, and where we can deliver the most value. Other ecosystems already have established productivity solutions, so venturing into them would be counterproductive.</p>
<p>We believe we should cover the entire lifecycle, from the early stages of an app to its distribution and the scaling of its development. Apple provides some basic tools, but they are insufficient. Developers must handle initial plumbing themselves and eventually delegate it to what companies call "platform teams." We want to be that virtual platform team and eliminate all plumbing work. Tuist needs to feel "plug &amp; play." Its adoption should be as simple as installing a GitHub App in your repository. The developer experience we aim to enable already exists in other ecosystems. The web has <a rel="external" href="https://vercel.com">Vercel</a>. React Native has <a rel="external" href="https://expo.dev">Expo</a>. We want to play a similar role in native development.</p>
<p>You might think you don’t need this—that you can grab the tools yourself and wire everything to build your own experiences. I understand. Many people felt the same about managing their servers and using <a rel="external" href="https://kubernetes.io/">Kubernetes</a> to orchestrate their own deployments. But let’s be honest: that’s fun to build, but not fun to interact with every day. All the energy spent maintaining such a stack is energy not directed toward solving problems. I like to say that your building momentum is frequently interrupted in app development. There’s something magical about doing a <code>git push</code> and seeing a URL to preview your changes shortly after.</p>
<p>Now the question is how to enable that future. We are limited in resources and capital. Some might see this as a limitation, but I see it as an asset. Limits force us to think creatively, and they’ve helped us realize that we have the most valuable asset in the developer ecosystem: a community. Communities take significant time and human capital to build, and at Tuist, we’ve invested heavily in that since we wrote the first line of code in 2017.</p>
<p>I touched on the role of communities in <a href="https://pepicrft.me/blog/tuist-plans/__GHOST_URL__/blog/2025/03/31/software-commoditizes">the commoditization trap</a>. The long-story-short version is that a community is the best asset a company can have these days. For instance, <a href="https://pepicrft.me/blog/tuist-plans/__GHOST_URL__/blog/2025/03/25/mobile-ci-is-plateauing">Mobile CI is plateauing</a> because they failed to build a community. Every company builds communities differently. We want to grow ours on the same foundation that gave birth to the community: open source.</p>
<p>We had to close-source part of Tuist because the project was at risk of free-riding, but we want to return to everything being open source, and we have a plan in place for it. But first, let’s talk about open source for a bit.</p>
<p>We want to continue developing open-source technologies. We are shifting the focus away from project generation, so expect innovation in other app spaces. These are gifts to the community to foster innovation. We’ll then figure out how those technologies can be extended by leveraging the capabilities of a server to build a revenue source for the company. A server brings three elements:</p>
<ul>
<li>A remotely accessible database - A public HTTP interface to interact with - Background jobs</li>
</ul>
<p>We envision a model where the client-side technology can work independently without the server. You can build your own server using our client-side open-source components if you want—they’ll be permissively licensed. We’ll support any open-source efforts that align with this direction, like <a rel="external" href="https://github.com/trycua/lume">Lume’s virtualization solution</a>.</p>
<p>We’ll also make part of the server open source with a permissive license. This means you can self-host the server too and not pay a dime for it. You’re right—we need to address this. Experience has taught us two key lessons:</p>
<ol>
<li>The needs of large enterprises differ greatly from those of small and medium companies. 2. Large enterprises are the ones with significant capital to invest in these tools.</li>
</ol>
<p>Instead of trying to capture 100% of a market—which traditional companies attempt, only to end up building vendor-locked ecosystems—what if we figure out how to capture value from the 20% of large companies that could bring 80% of our revenue (Pareto principle at work)? We could treat the remaining 80% as companies contributing other types of capital: - Feedback - Word-of-mouth marketing - Code contributions</p>
<p>Business owners often view everything through a financial lens because it’s measurable. But there are other forms of capital that make a company valuable, which we continue to struggle to quantify. The companies that value these are the most likely to thrive.</p>
<p>For Tuist, we’ll place some features or capabilities under a different license that large companies would need to pay for, while everything else would be MIT-licensed with a ready-to-deploy Docker instance. Note that over time, hosting Tuist will become more complex—not because we’ll force complexity, but because it will naturally evolve, especially as we invest in capabilities like low-latency cache servers and features based on running ephemeral builds. At that point, even that 80% might be inclined to pay for us to host it.</p>
<p>This isn’t a new model. You see it in <a rel="external" href="https://gitlab.com">GitLab</a>, <a rel="external" href="https://posthog.com">PostHog</a>, <a rel="external" href="https://cal.com">Cal.com</a>, and <a rel="external" href="https://grafana.net">Grafana</a>. It’s just not common in the app development productivity space because companies there often have a strong sales and business profile. We’re bringing a different take on business.</p>
<p>There’s one catch to the open-source model: besides marketing being more effective because you build a loyal community that spreads the word organically (as opposed to throwing money at marketing, which is expensive and doesn’t guarantee results), you open yourself to a diverse pool of talent and ideas that contribute to the project. Let me tell you, you can’t beat a product built by a community. We’ve learned that with Linux. I’m surprised we haven’t seen more of this in this space. That’s why we’re enabling it with Tuist.</p>
<p>So, picture a world where Tuist is open source, with some enterprise-related features or capabilities under a different license.</p>
<p>To enable that vision, we are focusing strongly on the following pillars:</p>
<h2 id="foundational-blocks">Foundational blocks</h2>
<p>We are investing heavily in automation and establishing the right foundations so people can build with them easily. Contributing to Tuist should feel like playing with LEGO. This is why we’re investing in a design system for the CLI and the web, Noora. Developers without much design experience can contribute features and design them themselves.</p>
<h2 id="standardizing-data-and-making-it-accessible">Standardizing data and making it accessible</h2>
<p>Apple’s development environment is well-known for its proprietary formats. We’re going to standardize them and make them accessible via the web. Want to access the results of your last build? It’s just one request away. The web is a tool for accessibility, so we’re embracing it fully. As part of Tuist, we’re building an API—currently used only by the CLI—but we plan to productize it so people can build their own tools with their project data. The API will be part of the product, not just an implementation detail.</p>
<h2 id="virtualization-capabilities">Virtualization capabilities</h2>
<p>We’ll invest in developing the ability to run virtual ephemeral builds—first, to enable web-driven workflows like releasing an app or creating a preview with a button click, and second, to break the strong vendor lock-in organizations face with CI providers, allowing them to take control of their data and infrastructure.</p>
<h2 id="top-notch-dx">Top-notch DX</h2>
<p>Developer experience (DX) is front and center in Tuist. We can’t afford to degrade someone’s experience compared to Vercel, Supabase, or Linear. Tuist needs to be a joy to use—something whose value is conveyed through its design. We don’t want it to be a tool made by developers trying to be designers. No, we need to think deeply about design, crafting workflows and visual hierarchies that are delightful to navigate.</p>
<p>I’ve never been this excited about Tuist’s plans. I firmly believe this strategy will pay off in the long run. As mentioned, it requires significant human and time capital investment. But while other companies come and go, outcompeted by better open-source alternatives, we’ll keep rowing, building the best and most open development productivity tool for app developers.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The commoditization trap: why software needs community to thrive</title>
      <link>https://pepicrft.me/blog/software-commoditizes/</link>
      <guid>https://pepicrft.me/blog/software-commoditizes/</guid>
      <pubDate>Mon, 31 Mar 2025 12:00:00 +0000</pubDate>
      <description>Software commoditizes fast. Without an economic moat, open source and giants like Amazon can erode value. Build a community-driven ecosystem to endure.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Whether you like it or not, software tends to commoditize—including yours. This is a key reality to understand if you’re building a software company.</p>
<p>Imagine a new market, say, one based on AI. You might be among the first companies to dive into AI-generated UI. Everyone’s impressed by this novel need you’re addressing, and it’s tempting to believe you’re uniquely positioned to dominate the market. But you’re not. Your company lacks an economic moat. You’re easy to replicate.</p>
<p>As I mentioned in <a href="https://pepicrft.me/blog/software-commoditizes/__GHOST_URL__/blog/2025/04/24/open-source-business">If a business can be open source, it'll be open source</a>, an open-source solution is likely to emerge. It might take longer, but when it does, it will probably limit your ability to capture value—most likely due to its fairer pricing and superior product. Open source can afford to do this with far less capital involved.</p>
<p>Some companies try to defend against this by expanding their offerings. There’s no better example than CI (continuous integration) companies, which now provide a suite of development tools—from caching to test analysis—to stay competitive. But once again, many of these solutions are easily replicable in open source. Even more surprisingly, some don’t require a server at all. This expansion can be a tricky move: you risk drifting from what your users know you for, reframing yourself as something more comprehensive. That shift can take years for people to grasp. In fact, it’s a challenge we’re currently facing at <a rel="external" href="https://tuist.dev">Tuist</a>, where people still see us as just a project generation tool.</p>
<p>Another approach companies take is <strong>capturing value through infrastructure</strong>. The software has value, but without well-managed infrastructure, that value isn’t fully realized. This depends on the type of software. For a native app with self-contained value, it’s trickier—though people are also less incentivized to open-source it in the same form. Your advantage lies in maximizing platform capabilities. You’ll always have an audience there, but don’t expect endless growth. Just ask <a rel="external" href="https://www.sketch.com/">Sketch</a>. Betting on something other than the web might give you an early edge, but it can leave you at a disadvantage in a world that favors collaborative solutions over individual ones. People crave connection—they love the <a rel="external" href="https://www.figma.com/">Figmas</a>, <a rel="external" href="https://www.notion.com/">Notions</a>, and <a rel="external" href="https://slack.com">Slacks</a> of software.</p>
<p>That said, providing value through infrastructure is easier to replicate if you’re up against a cloud giant like <a rel="external" href="https://aws.amazon.com/">Amazon</a>. All they need is enough incentive to target your market. That’s why Google acquired <a rel="external" href="https://firebase.google.com/">Firebase</a> and <a rel="external" href="https://fastlane.tools/">Fastlane</a>—they saw an opportunity in the mobile space, though it didn’t fully pan out as expected. I wouldn’t be surprised if Firebase gets sunsetted in the coming years. A strong example of capturing value through infrastructure is <a rel="external" href="https://supabase.com">Supabase</a>, which we use at Tuist. The software has value, but there’s even more in managing and scaling your database—something they handle for you. It’s not something we’d ever consider doing ourselves because we’re focused on building our product.</p>
<p>A better model is <strong>creating an ecosystem and a community around it—one built on long-term incentives</strong>, not short-term gains. This distinction matters because it’s easy to create the illusion of an ecosystem or community by throwing money at it. But the best ones take time to nurture. You can tap into basic human needs and desires—like the pursuit of higher status—but that only works until people realize meritocracy is a dystopian mirage. Take the “indie developer” dream, for instance. We all fantasize about making a living from our software. Many products target these communities, feeding the illusion that their tool is the key to success, just like the stories they’ve heard. But as YouTube has shown, it’s more complicated than that. It might work briefly, but it can quickly turn into deception.</p>
<p>In my view, the best model is the one <a rel="external" href="https://github.com/">GitHub</a>, <a rel="external" href="https://www.strava.com/">Strava</a>, and, to some extent, <a rel="external" href="https://www.spotify.com/">Spotify</a> have mastered. These platforms amass social capital that makes leaving emotionally unthinkable. A GitHub profile is a developer’s CV. A Strava profile showcases a healthy life and connections with others. Spotify’s profile curates your musical tastes with recommendations no one else can match. This model is incredibly hard to replicate today. It’s not just about a critical mass of users—you need a product designed to capture that value fast, before anyone else does. Years ago, who’d have thought our profiles on these platforms would become so valuable?</p>
<p>In a tech world moving at breakneck speed, where society grows more individualistic despite collaboration yielding better outcomes and more happiness, I believe open source—and its community component—offers a sustainable alternative. <strong>The economic moat lies in its community value</strong>, rooted in the idea of building shared commons, rather than struggling to stay afloat in an industry that commoditizes itself.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Mobile CI is plateauing</title>
      <link>https://pepicrft.me/blog/mobile-ci-is-plateauing/</link>
      <guid>https://pepicrft.me/blog/mobile-ci-is-plateauing/</guid>
      <pubDate>Tue, 25 Mar 2025 12:00:00 +0000</pubDate>
      <description>In this blog post I share how we might be on the verge of a revolution in mobile CI.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>We are considering solving some problems at <a rel="external" href="https://tuist.dev">Tuist</a> that require virtualizing macOS environments. As part of this, I’ve invested some mental energy into understanding the finances and technology stack of the mobile CI landscape. What I’ve discovered is that the landscape is plateauing, CI companies are responding to this shift, and we might be on the verge of either a devaluation of CI companies or a revolution. To better understand the situation, let’s dive into the stack:</p>
<h2 id="the-stack">The stack</h2>
<p>Technologies can be broken down into layers, and CI is no exception. Starting from the bottom:</p>
<ul>
<li><strong>Machines</strong>: We need environments—physical or virtual—where a set of steps can run. This is already offered as a service by most cloud providers. The availability of Apple hardware has been somewhat limited, but this is changing as more players enter the space. - <strong>Virtualization</strong>: CI services run builds in disposable, virtualized environments to prevent data leakage across builds. In the Linux world, this is highly commoditized with tools like Docker or Podman. For macOS environments, Apple took the first step toward commoditization by releasing the Virtualization Framework. Tart followed with a source-available, Docker-like solution, while Lume and <a rel="external" href="https://github.com/macvmio">macvm</a> joined the game with open-source-licensed alternatives. - <strong>Orchestration</strong>: For Linux environments, where provisioning new environments is fast, orchestration is typically handled by the cloud provider. However, macOS is a different story. Since macOS images are not lightweight, you need a system that can provision a fleet of Apple hardware, configure the environments, load them with the appropriate images, and make them available for use. - <strong>User Layer</strong>: At the topmost layer are the features users interact with directly (beyond just the UI). This includes viewing logs, retrieving them along with build artifacts, and parsing and executing pipelines.</li>
</ul>
<p>If you use a CI service, you probably don’t think about this structure. But once you understand how it’s organized, it’s striking to realize how close we are to full commoditization. Let me highlight some key developments that led me to this conclusion.</p>
<h2 id="the-commoditization-of-the-space">The commoditization of the space</h2>
<p>In 2019, <a rel="external" href="https://github.com/">GitHub</a> released GitHub Actions, which introduced hosted runners alongside the concept of “bring your own runners.” You could either provide your own runners or use partners that integrate directly into your GitHub organization. This meant GitHub would handle the user layer and the entire stack—unless you chose to bring your own.</p>
<p>Let’s be honest: it’s hard to compete with GitHub’s user-layer experience. It’s embedded where collaboration happens, and its proximity enables features that CI providers can’t replicate—such as declaring permissions for the exposed <code>GITHUB_TOKEN</code>. GitHub also built a rich ecosystem of reusable actions to base your workflows on.</p>
<p>This shift gave rise to companies like <a rel="external" href="https://cirruslabs.org/">Cirrus Labs</a>, <a rel="external" href="https://cirun.io/">Cirun</a>, and <a rel="external" href="https://depot.dev/">Depot</a>, which handle the runner provisioning for you. From the layers above, they manage orchestration, while GitHub takes care of the rest. The adoption process is remarkably straightforward, and there’s no need to migrate pipelines from one proprietary format to another.</p>
<p>GitHub isn’t alone in this trend—<a rel="external" href="https://docs.gitlab.com/runner/">GitLab</a> and <a rel="external" href="https://forgejo.org/docs/latest/admin/runner-installation/">Forgejo</a> also support bringing your own runners.</p>
<p>Another recent change is in virtualization. <a rel="external" href="https://github.com/cirruslabs/tart">Tart</a> brought Docker-like concepts to Apple’s Virtualization Framework, but now it faces competition from permissively licensed alternatives like <a rel="external" href="https://github.com/trycua/cua">Lume</a> and <a rel="external" href="https://github.com/macvmio/curie">Curie</a>. Virtualization is getting cheaper. While Tart may still lead in capabilities, open-source projects have a knack for catching up quickly due to community contributions. I believe it’s only a matter of time before they’re on par.</p>
<h2 id="what-s-keeping-people-with-ci-providers">What’s keeping people with CI providers?</h2>
<p>I ask myself this question daily, and I think the answer is straightforward: vendor lock-in. By design, users are tied to platforms they chose years ago through proprietary YAML formats that are costly to migrate and ecosystems of steps that tightly couple their automation to the service.</p>
<p>But people are waking up. <a rel="external" href="https://dagger.io/">Dagger</a> is leading the charge by proposing that automation shouldn’t be tied to a single company. Pipelines should be portable, just like OCI images. Absolutely! Dagger builds on a foundation that doesn’t yet seamlessly support macOS-dependent builds (due to its approach to virtualizing steps), but there are still many ways to make automation portable. I wrote about this in <a rel="external" href="https://tuist.dev/blog/2025/03/11/own-your-automation">Tuist’s blog</a>. Your automation should belong to you, not a company.</p>
<p>CI providers know they must offer more to differentiate themselves from GitHub Actions. However, they often lack the expertise to meet developers where they are. Instead, they double down on vendor lock-in with serverless solutions that could simply be open-source CLIs. This confuses users—CI companies were supposed to focus on CI, but now they’re tackling signing, release management, and security promises that large enterprises obsess over. Meanwhile, solutions like <a rel="external" href="https://www.runway.team/">Runway</a> are emerging, focusing on doing one thing exceptionally well and easily capturing customers.</p>
<h2 id="plateauing">Plateauing</h2>
<p>Looking at the layers above, orchestration is the next to commoditize. We’re one open-source project away from a service where you input an AWS or Scaleway key, install a GitHub app, and you’re set. This is already happening in other domains, like <a rel="external" href="https://www.coolify.io/">app hosting</a> and <a rel="external" href="https://supabase.com/">database hosting</a>. If an orchestration layer goes open-source and invites companies to collaborate on building the best plug-and-play solution for your Git forge, CI providers could lose market share quickly.</p>
<p>I predict this will happen. Orchestrating virtualized macOS environments will become cheaper, potentially even offered as a foundational service for others to build upon. This could spark more innovation in the space—an area where mobile CI has lagged behind the web, largely due to innovation being locked in proprietary systems. That’s why I’m excited about this shift. We need more players thinking creatively, and commoditization enables that accessibility.</p>
<p>At Tuist, we’ll ride this wave of commoditization and explore how virtualization can solve some of our needs and challenges while delivering a better developer experience.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Nightly builds are the wrong solution to the right problem</title>
      <link>https://pepicrft.me/blog/nightly-builds/</link>
      <guid>https://pepicrft.me/blog/nightly-builds/</guid>
      <pubDate>Wed, 19 Mar 2025 12:00:00 +0000</pubDate>
      <description>In this blog post I share why today nightly builds are the wrong solution to the problem, and the alternative that we are proposing.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Nightly builds in app development are the wrong solution to the problem. We keep cargo-culting because:</p>
<ol>
<li>People are familiar with the term. 2. You don't need to go back to first principles.</li>
</ol>
<p>This happens not just in the context of app development productivity, but everywhere else. Someone uncovers a new problem or need, for which they build a solution—not necessarily the best one today, but the best one at the time, considering the constraints then. Then, you see a stream of companies jumping into the new markets. Eventually, everything commoditizes, and we get stuck with something that doesn't feel right.</p>
<p>Rinse and repeat.</p>
<p>This is how nightly builds feel to me. The sunsetting of <a rel="external" href="https://learn.microsoft.com/en-us/appcenter/retirement">App Center</a> and everyone's rush to profit from it with yet another solution like App Center smells fishy to me.</p>
<p>But what would be the alternative? If we go back to first principles, nightly builds solve testing changes and providing feedback. However, nightly builds are detached in time and space from where the changes originated, often pull requests. Pull requests are the place where conversations around changes happen. Trying to do something distant from that creates a source of friction and a foundation for even more complexity.</p>
<p>Feedback needs to happen in PRs.</p>
<p>And that requires creating builds (which in Tuist we refer to as <a rel="external" href="https://docs.tuist.dev/en/guides/share/previews">previews</a>) quickly, when needed, and from anywhere. Let's break that down:</p>
<ol>
<li><strong>Fast</strong>: You don't want to wait half an hour for a preview because, by the time you get the build, the PR might have already been merged. That's why we built <a rel="external" href="https://docs.tuist.dev/en/guides/develop/cache">binary caching</a>, and we plan to invest in it further. 2. <strong>When needed</strong>: You should have control over when you want a preview and of what, because, sadly, macOS computing resources are still expensive. You don't want to depend on some pipeline being configured to get what you need. 3. <strong>From anywhere</strong>: By posting a comment on a PR, sending an email, asking your LLM of choice, or tapping a button in a mobile app.</li>
</ol>
<p>We are actively working on #1, and we are building technology and infrastructure to enable #2 and #3.</p>
<p>Are previews nightly builds? No, they are not. They have in common that the token of exchange is an installable build. The former aligns with collaboration expectations, while the latter makes collaboration less enticing.</p>
<p>Does it suck from a business perspective? Oh yeah! We need to market a new concept and bring people back to the problem that originates the need for something like nightly builds. But this is the type of company we are building—one that focuses on the problems, strives to build the best solutions, and challenges the status quo, adapting as the environment changes. A lot has changed since app builds were proposed, and it's time for something different.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Setting up Docker DinD in Forgejo Actions</title>
      <link>https://pepicrft.me/blog/docker-dind-forgejo-actions/</link>
      <guid>https://pepicrft.me/blog/docker-dind-forgejo-actions/</guid>
      <pubDate>Sun, 16 Mar 2025 12:00:00 +0000</pubDate>
      <description>Learn how to use Docker from your Forgejo Actions pipeline.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I spent a fair amount of time today trying to get Docker DinD working in Forgejo Actions, so I thought I'd share the steps for my future self or anyone running into a similar need.</p>
<p>If you want to build a Docker image from Forgejo Actions when using Docker as a runner, you'll have to use <a rel="external" href="https://www.docker.com/resources/docker-in-docker-containerized-ci-workflows-dockercon-2023/">Docker-in-Docker</a>.</p>
<h2 id="steps">Steps</h2>
<ol>
<li>The first thing you'll need to do is enable <code>privileged</code> mode when launching task containers. This is done by setting the attribute <code>container.privileged</code> to <code>true</code> in your runner's <code>config.yml</code> file.</li>
</ol>
<p><strong>Note:</strong> This has security implications, so use it with caution. Before running actions for external contributions, ensure that they are not malicious.</p>
<ol start="2">
<li>Once you've made this change, restart the runner.</li>
<li>The next step is configuring your pipeline to start a sidecar service with Docker DinD:</li>
</ol>
<pre><code>name: MyProject
on:
 push:
 branches:
 - main
 pull_request: {}
jobs:
 build-image:
 name: Build image
 runs-on: debian-latest
 container:
 image: node:20-bookworm
 options: &gt;-
 --privileged
 env:
 DOCKER_HOST: &quot;tcp://docker:2375&quot;
 DOCKER_TLS_CERTDIR: &quot;&quot;
 services:
 docker:
 image: docker:24.0.5-dind
 options: &gt;-
 --privileged
 env:
 DOCKER_TLS_CERTDIR: &quot;&quot;
 steps:
 - uses: actions/checkout@v3
 - name: Install Docker
 run: |
 apt-get update
 apt-get install -y ca-certificates curl gnupg
 install -m 0755 -d /etc/apt/keyrings
 curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
 chmod a+r /etc/apt/keyrings/docker.asc
 # Add the repository to Apt sources:
 echo \
 &quot;deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
 $(. /etc/os-release &amp;&amp; echo &quot;$VERSION_CODENAME&quot;) stable&quot; | \
 tee /etc/apt/sources.list.d/docker.list &gt; /dev/null
 apt-get update
 apt-get install -y docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
 - name: Build image
 run: |
 docker build -t my-project .
</code></pre>
<p><strong>Note:</strong> The above pipeline is designed for Debian as the OS, so you might need to tweak it according to your specific requirements.</p>
<p>That's all you need. The <code>--privileged</code> flag is one of the most important elements - without it, things simply won't work.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Dogfood if you can</title>
      <link>https://pepicrft.me/blog/dogfooding/</link>
      <guid>https://pepicrft.me/blog/dogfooding/</guid>
      <pubDate>Wed, 12 Mar 2025 12:00:00 +0000</pubDate>
      <description>If you can dogfood your product, do it. It&#x27;s a great way to build a better product.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've noticed that when using various products, I frequently encounter frustrating bugs that seem obvious - issues I would have fixed immediately had it been my own product. This is precisely why I'm drawn to open source software: the ability to directly implement fixes and submit pull requests to repositories.</p>
<p>When developers regularly use their own products (dogfooding), they naturally identify and address pain points. Without this practice, teams must rely solely on empathy for users' challenges. In our increasingly individualistic society - partly influenced by current social media dynamics - genuine empathy is becoming less common.</p>
<p>Entire ecosystems suffer from this disconnect. Take localization tools, for instance - using them often leaves me wondering if their creators have ever experienced them from a user's perspective. Investigation typically reveals they don't localize their own tools, which explains the subpar user experience.</p>
<p>While dogfooding can be challenging in some contexts, leadership should integrate it into company culture whenever possible. During my time at Shopify, though developers rarely maintained their own stores, they utilized a tool called "tophat" that simplified testing new changes. This led to more meaningful code reviews based on actual usage experience rather than just inspecting code or confirming passing tests.</p>
<p>At Tuist, we build our CLI and app using our own tools, using them daily. This creates a natural alignment between the improvements we identify and the needs of our users. While users typically only report major blockers, daily usage reveals numerous small opportunities for enhancement that collectively create exceptional products no competitor offers.</p>
<p>For example, we recently began improving our CLI's user interface, not because of user complaints, but because our own daily usage showed clear opportunities for enhancement. This approach to continuous refinement is what makes products like Linear superior to alternatives like Jira.</p>
<p>Developer tools are uniquely positioned to benefit from this practice. Developers at GitHub use GitHub; developers at GitLab use GitLab. Companies that create developer tools without using them internally are missing a crucial opportunity, and their products inevitably reflect this disconnect.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Lynx is an invitation for UI frameworks to support mobile development</title>
      <link>https://pepicrft.me/blog/lynx/</link>
      <guid>https://pepicrft.me/blog/lynx/</guid>
      <pubDate>Mon, 10 Mar 2025 12:00:00 +0000</pubDate>
      <description>The appearance of Lynx is an invitation for UI frameworks to support mobile development.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>A week ago, <a rel="external" href="https://www.bytedance.com/en/">ByteDance</a> announced the release of <a rel="external" href="https://github.com/lynx-family/lynx">Lynx</a>, a technology for building mobile apps using Web technologies. ByteDance had been using it to power many of their apps, and they decided to package it up and open-source it. Having Lynx enter the space with a new approach is great news for the community.</p>
<p>Something that slightly bothered me about the alternatives to native development is that they were strongly dependent on Google in the case of <a rel="external" href="https://flutter.dev/">Flutter</a>, or <a rel="external" href="https://expo.dev/">Expo</a>, which Meta recommends as the framework to use because they deemed it's not their responsibility to address that part for the community. These companies became dominant players in those spaces respectively, and that came at the cost of killing competitiveness, which fosters innovation.</p>
<p>Lynx challenges the status quo, in the same way AI is challenging Apple's ability to catch up with the rest of the industry. And it does so by presenting a technology that's UI framework agnostic. It comes with support for React, but people are already working on adding support for <a rel="external" href="https://github.com/lynx-family/lynx/issues/193">Vue</a>, and I expect SolidJS, Svelte, and others to follow soon.</p>
<p>In other words, <strong>Lynx paved the way for other frameworks to support mobile development</strong>, unlike React Native, which coupled its solution to React as a framework. It also comes with a fast Rust toolchain, so technologies building upon it don't have to re-invent that part. This is an area where Meta said, "We use different tooling at our scale, so we are not going to bother to support a toolchain," and if you ask me, that's a shame. Lynx recognized that both go hand in hand, and that's amazing.</p>
<p>It's still early days for Lynx, so the future is a bit uncertain, but if I had to make a bet, I strongly believe the fact that it allows other UI frameworks to build upon it will create a unique ecosystem of tools, resources, and libraries that React Native won't be able to compete with.</p>
<p>It's a matter of time, but if ByteDance does well at building a thriving community, I think it can happen. The React Native ecosystem could have gone a similar path, owning an integrated toolchain, and providing the ecosystem with the resources to build great packages, but instead sold it to Expo. Expo is amazing. I think having only Expo is terrible.</p>
<p>With <a rel="external" href="https://tuist.dev">Tuist</a> transforming into a platform, I want to play with Lynx to see where we could bring value on the server-side, for example easing the distribution of previews, providing sign-in to the bundling process, or conceptually compressing mobile intricacies. Or maybe helping them break the dependency on <a rel="external" href="https://cocoapods.org/">CocoaPods</a>.</p>
<p>The future of mobile development is bright.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>AI as a tool to reduce OSS maintenance costs</title>
      <link>https://pepicrft.me/blog/ai-oss-cost/</link>
      <guid>https://pepicrft.me/blog/ai-oss-cost/</guid>
      <pubDate>Sun, 09 Mar 2025 12:00:00 +0000</pubDate>
      <description>How AI can help you maintain your open source project.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>GitHub recently introduced GitHub Copilot as a reviewer tool for pull requests. I gave it a shot with low expectations and had a pleasant surprise. The reviews you get could easily be mistaken for those from a human reviewer.</p>
<p>This made me think about the role that AI could play in reducing the cost of maintaining OSS. As you might know, the classic challenge of open source is the cost of maintenance. This is, in fact, the reason why we started working on evolving <a rel="external" href="https://tuist.dev">Tuist</a> into a business.</p>
<p>Issues and pull requests pile up, you don't have the time to review them all, and you have to process the emotions that come with feeling like you're lagging behind or not meeting the community's expectations. But if most of this can be delegated to AI, that changes everything.</p>
<p>I believe we, open source maintainers, should invest in having the right CI checks to ensure the code that is merged is of the quality we want to ship, along with rules to guide GitHub Copilot to do its best work. How those rules are provided to AI agents is still an evolving territory, but once it settles down, I think it makes sense to invest in providing agents with that context.</p>
<p>Who knows... maybe we'll get to a point where GitHub Copilot can also reject PRs that don't align with the direction/vision of the project, or merge others automatically. I think that would be fantastic.</p>
<p>In the context of <a href="https://pepicrft.me/blog/ai-oss-cost/__GHOST_URL__/blog/2025/03/04/tuist-mental-models">open source companies</a>, a subject I've been thinking about a lot lately, this approach gives you access to a developer workforce that's not limited by your location or your number of employees. It means you can move much faster than your competitors, at a much lower cost, allowing you to focus on building revenue from large enterprises while innovating and watching your community foundation grow.</p>
<p>I don't know about you, but I think this is a unique strength. When I think of companies working in the same space as Tuist, none are approaching business this way, so I believe we're in a good position to take advantage of this opportunity.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Own your community</title>
      <link>https://pepicrft.me/blog/own-your-community/</link>
      <guid>https://pepicrft.me/blog/own-your-community/</guid>
      <pubDate>Thu, 06 Mar 2025 12:00:00 +0000</pubDate>
      <description>You&#x27;d better own your community.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>For years, many tech companies have made us dependent on their platforms through the value that we created within them. The moment we signed up, we agreed to terms of service that made them owners of our activity: our photos, messages, files... We trusted corporations. But as time has shown, they are not held accountable for what they do with all of that data. You gave them the rights, so they simply do what's necessary to align with incentives they don't disclose, which are far from the classic "make the world a better place."</p>
<p>Note this isn't true of all companies, but it's really hard to find one that stays true to a set of values. Personally, I don't care about the personal data they've collected from me, or the value I've generated on platforms like X or GitHub. Years ago, I had a different connection with the idea of reputation, but breaking dependency on that was very liberating. I don't share anything of value in those places, and if something has value, I make sure I use technology that ensures I'm the owner of my data—like <a rel="external" href="https://obsidian.md/">Obsidian</a> or Git forges where I can take a Git repo elsewhere if the platform becomes enshittified. Seeing X, Reddit, Strava, and many others building walls was a wake-up call for me. I still use them, but I don't engage with them beyond posting or reading small things here and there.</p>
<p>With <a rel="external" href="https://tuist.dev">Tuist</a>, it's a different story. We are generating a lot of value—not just through the code that we bundle and release as a CLI or a publicly accessible server, but also through resources, ideas, and conversations. For many years, we didn't think much about where the value resided, or whether we were owners of it. Similarly, we had a bit of a wake-up call. <a rel="external" href="https://mastodon.online/@marekfort">@marek</a> is more thoughtful in that regard. We moved our conversations from Slack to <a rel="external" href="https://community.tuist.dev">Discourse</a>. We haven't fully completed the transition, but we encourage more discussions to happen there. For some people, this is uncomfortable. We are breaking the fast-paced conversation cycle that companies have conditioned us to expect, but the slower pace and the ownership of data and community experience are priceless.</p>
<p>I see many open source projects betting on Discord, and I'd wager we're not far from witnessing an enshittification similar to what began with Slack. If I were to start a community again, I would absolutely build it on something like Discourse. Someone might argue that it's costly, but it really just requires getting a server, connecting to it via SSH, and running a command. Sure, it's not a one-click experience, but you're choosing between surrendering to corporate control versus nurturing a community who will appreciate—years from now—being able to search for something and find what they're looking for. If you care about your community's long-term health, you should care about owning the value that community produces.</p>
<p>We've applied this to other areas too. We're close to moving off Google Workspace. We self-host many of the services we use and keep the data in our own databases. It's amazing how many quality open source projects exist that we can contribute to. It's about long-term investment over short-term convenience as the product of an uncertain future you don't control. I don't regret for a moment the move we made, and we'll continue to invest in this direction.</p>
<p>If you're just getting started and don't have the resources, it might make sense to initially be a "product" (which usually means not paying), but eventually flip the switch and become the owner of your digital assets. You'll be thankful for having made such a move.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>China is succeeding at what everyone else is failing at: localization</title>
      <link>https://pepicrft.me/blog/china/</link>
      <guid>https://pepicrft.me/blog/china/</guid>
      <pubDate>Wed, 05 Mar 2025 12:00:00 +0000</pubDate>
      <description>China has learned to localize their products and services to fit the needs of their target audience.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I remember when I was young, everyone had this stereotype in mind that China copies what everyone else is doing. I'm not a fan of stereotypes, but I think they usually reveal something deeper.</p>
<p>In the case of China, I think we are witnessing the reality behind the stereotype unfolding. They are proving to be amazing at localization. When one thinks about localization, it's tempting to think about languages. But localization goes beyond that. It involves understanding the culture that you are building for and adapting your solution to fit the expectations and needs of the target audience.</p>
<p>This takes a lot of empathy that I believe we are losing in what people usually refer to as "the West." Here it's all about you: your success, your entrepreneurship journey, your ability to raise capital, every quantifiable aspect of your life and business. So without empathy, the awareness of the importance of localization is lost.</p>
<p>China has that, perhaps due to their political system. And as open source has shown, which has a community component to it and therefore more empathy embedded in it, you can easily outcompete solutions that lack that, close their systems, and try to solve everything by throwing capital at the problem.</p>
<p>I wouldn't say Chinese copy. Chinese learn and adapt. We build models and impose them on everyone. If we look around, we see plenty of examples of this unfolding. From DeepSeek <a rel="external" href="https://www.deepseek.com/">open-sourcing</a> their models to, most recently, ByteDance open-sourcing a technology to build mobile apps, <a rel="external" href="https://lynxjs.org/">Lynx</a>.</p>
<p>The last one is particularly worthy of analysis. Meta individualistically thought that it's not their concern to package a technology in a ready-to-use solution for the community, so ByteDance went ahead and bundled framework and technology and packaged it in a beautifully productized solution.</p>
<p>They understood that wealth is concentrating in "the West" and that people don't want to feel they are losing their purchasing power, so they adapted many of their products to make sure people continue to feel they can purchase the same or more than before.</p>
<p>The perception towards the Chinese and Chinese products is changing, and "the West," particularly North America, can do little about it. Or maybe they're localizing when it's too late, like Amazon presenting a Chinese-like storefront, <a rel="external" href="https://www.amazon.com/b?node=122341379011">Amazon Haul</a>.</p>
<p>Years ago, the argument they still use to this day—that the Chinese are bad—is getting weaker and weaker, especially as we see Donald Trump's administration's real interests. It's two political regimes with different stories but similar goals.</p>
<p>So I dare to say the war with China has already started. The US is like Leonardo DiCaprio sinking in an ocean that the Chinese have become familiar with and have learned how to navigate better. They can try to tax the world, but that will only prompt the world to reconsider their dependency on their system.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>From open source to open core business</title>
      <link>https://pepicrft.me/blog/tuist-mental-models/</link>
      <guid>https://pepicrft.me/blog/tuist-mental-models/</guid>
      <pubDate>Tue, 04 Mar 2025 12:00:00 +0000</pubDate>
      <description>In this blog post I unfold the journey of Tuist from an open source tool to an open core business.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><a rel="external" href="https://tuist.dev">Tuist</a> started as a pure client-side tool. Through project generation, it made Git conflicts less frequent and modular Xcode projects easier to manage. That work was the foundation to build a strong brand and a community around it. But it made it clear that this approach isn't the most suitable from a sustainability perspective. That's the reason why open-sourcing client apps is more rare than server-side ones. But a closed-source CLI was out of the question.</p>
<p>For context, project generation continues to be the reason why many projects come to Tuist—most of which, surprisingly, are trying to find a developer experience that's better than <a rel="external" href="https://www.swift.org/documentation/package-manager/">SwiftPM</a>'s.</p>
<p>Once you reach the inflection point of having many people using the tool (therefore demanding energy from you) while you're treating it as a side gig, you have to consider doing something about it if you don't want to burn out. In many cases, developers don't do anything, and projects stagnate. Look around; I'm sure you'll find some examples. We were once suggested to move Tuist to a foundation, but foundations don't solve sustainability. So in our case, we decided to evolve Tuist into an open core business.</p>
<p>Transitions like this are not easy. You are going from open source and free to partially open source with some paid features. It's natural to think, "But you didn't tell me about this," but we didn't know either that Tuist would end up being largely adopted. So it's either we do something or let it die. I know it sounds harsh, but it's the truth.</p>
<p>The month that followed came with a lot of learning and questioning around what we'd like the company to be like. Open source is in our DNA, so as you can imagine, that influenced how we are shaping the company.</p>
<p>The first conclusion we reached is that <strong>we had to introduce solving problems that required a server to be solved.</strong> Capturing value through a server (in other words, asking people to pay for it) aligns better with people's mental models. It's still tricky to this date because, since people interface through the CLI, they find it rare that they have to have a paid subscription bound to the account they authenticated with through the CLI. Yet I believe this will shift as we continue to make Tuist server-centered. Solutions like <a rel="external" href="https://docs.tuist.dev/en/guides/develop/cache">cache</a>, <a rel="external" href="https://docs.tuist.dev/en/guides/develop/selective-testing">selective testing</a>, <a rel="external" href="https://docs.tuist.dev/en/guides/share/previews">previews</a>, or analytics were born to solve server-solvable needs.</p>
<p>Our limited capital and the cost of getting a business off the ground led us to making the server closed source to avoid free-riding until we could better understand the market and how to monetize it. We did so contrary to our principle of keeping things open, and as you can imagine, the idea of making it open source again is something we've been pondering since.</p>
<p>When I tell this to developers and other business founders, they look at me and think, "Are you crazy? Opening the sources? You won't build a business like that." But after a lot of reading, discussing, and learning about the models of companies like <a rel="external" href="https://gitlab.com">GitLab</a> or <a rel="external" href="https://posthog.com">PostHog</a>, I believe more than ever that this model is feasible. Let me unfold that for you.</p>
<p>But first things first: the motivations. <strong>We believe the best products are built by communities of people from all over the world.</strong> Despite your efforts of hiring diverse teams, you are limited to your team of 10, 20, or 100 people to build a product that addresses everyone's needs. Our work in the CLI taught us that. Once you experience it, you want to apply it everywhere. The human force you get access to through this model is unbeatable by throwing capital at the problem. Look at <a rel="external" href="https://wikipedia.org">Wikipedia</a>, <a rel="external" href="https://www.discourse.org/">Discourse</a>, or <a rel="external" href="https://grafana.com/">Grafana</a>. Elon Musk is annoyed by Wikipedia, but you can't compete with a group of people motivated by a common goal.</p>
<p>Second, it's important to understand one thing: <strong>businesses generate most of their revenue from large enterprises.</strong> I bet it follows the <a rel="external" href="https://en.wikipedia.org/wiki/Pareto_principle">Pareto Principle</a>, where 20% of your customers generate 80% of your revenue. So with that in mind, the question is how to have the server open source while still capturing the revenue from the 20% of customers. Well... this is what we are trying to understand. There are many good references out there, like GitLab, which charges for advanced features, or <a rel="external" href="https://penpot.app/">Penpot</a>, which charges for control. Our hunch is that our model will be a mix of charging for advanced features or control and for hosting a complex infrastructure.</p>
<p>And here comes an interesting twist: <em>what about the 80% of users?</em> This is where traditional business people get uncomfortable. When you look at this from a monetary angle, they might feel like you are losing an opportunity to capture value there. But <strong>what if the value they contribute back is not monetary, but marketing and contributions to the product, helping make it better for everyone?</strong> When I first reached this idea by myself, it blew my mind. I could finally understand why something like Discourse or Grafana is so successful and why few to none can compete with them. Most of the people in that 80% group wouldn't have paid anyway.</p>
<p>Let's take all this framing further.</p>
<p>We are focusing on shifting value to the server, understanding the needs of the 20% of our customers, and building a mental model around where the line can be drawn. But not just that—in that future where Tuist becomes a community effort, <strong>we need to make ourselves as dispensable as we can be.</strong> In other words, can we shape a world where we can openly iterate on the product with a minimum cost for us? Definitely.</p>
<p>So we are focused on putting the right foundational pieces to ease contributions. If you look at our work in the past weeks, part of our focus has been on building a <a rel="external" href="https://github.com/tuist/Noora/">design system foundation</a> for the CLI and for the web app, such that contributing to Tuist feels like LEGO. You've got an idea for a new dashboard feature to build? Sure! Go ahead, prototype something, and open a PR. Our designers will play more of a reviewer role than an active contribution one. And what's even better than all of this is that GitHub is <a rel="external" href="https://github.blog/changelog/2025-02-26-code-review-in-github-copilot-is-now-in-public-preview/">doubling down on tools to leverage LLMs to review PRs</a>. A few tests that we've done yield impressive results, so our coding will gear towards providing the right rules so agents can do a great job, and we are confident that the work does what it's supposed to do and aligns with the practices of the repo.</p>
<p>Besides what this means for the community, <strong>we'd build the first open source app developer productivity platform for app developers</strong>. Suddenly, it positions us with limited capital but with a world of contributions to expand Tuist in two directions:</p>
<ul>
<li>Into other app development lifecycle phases, for example, release automation. - Into other app development technologies, like <a rel="external" href="https://reactnative.dev/">React Native</a> or <a rel="external" href="https://developer.android.com/">Android</a>.</li>
</ul>
<p>In a traditional model, the above is done by raising endless capital, but that usually comes at the cost of potential misalignment of incentives and products "enshittifying" themselves. We don't want that for Tuist. Hence, we are embracing a model that allows us to create an innovative development environment where the community is an intrinsic part of it, with a world of opportunities to help teams build better apps.</p>
<p>I'm damn excited about this model!.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>A Mise formula for Swift Package development</title>
      <link>https://pepicrft.me/blog/mise-formula-for-swift-packages/</link>
      <guid>https://pepicrft.me/blog/mise-formula-for-swift-packages/</guid>
      <pubDate>Tue, 25 Feb 2025 12:00:00 +0000</pubDate>
      <description>Learn how to easily build and test your Swift packages in the host OS, macOS, and Linux.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If you develop Swift packages from macOS, and support Linux, you might be interested in the following formula to easily build and test your Swift packages in the host OS, macOS, and Linux.</p>
<p>Whenever I create a new package, I create two <a rel="external" href="https://mise.jdx.dev/tasks/">Mise tasks</a>, <code>mise/tasks/build.sh</code> and <code>mise/tasks/test.sh</code>. Then using <a rel="external" href="https://usage.jdx.dev/cli/scripts">usage</a> annotations in the scripts, I can easily add support for using <code>--linux</code> to indicate a different target OS:</p>
<pre><code>#!/usr/bin/env bash
#MISE description=&quot;Build the project&quot;
#USAGE flag &quot;-l --linux&quot;

set -eo pipefail

if [ &quot;$usage_linux&quot; = &quot;true&quot; ]; then
if command -v podman &amp;&gt; /dev/null; then
CONTAINER_ENGINE=&quot;podman&quot;
else
CONTAINER_ENGINE=&quot;docker&quot;
fi

$CONTAINER_ENGINE run --rm \
--volume &quot;$MISE_PROJECT_ROOT:/package&quot; \
--workdir &quot;/package&quot; \
swiftlang/swift:nightly-6.0-focal \
/bin/bash -c \
&quot;swift build --build-path ./.build/linux&quot;
else
swift build --configuration release
fi
</code></pre>
<p>And that's it. You can now do:</p>
<pre><code>mise run build # Build in the host (macOS)
mise run build --linux # Build in Linux
</code></pre>
]]></content:encoded>
    </item>
    
    <item>
      <title>If Swift app development teams had the data...</title>
      <link>https://pepicrft.me/blog/missing-insights/</link>
      <guid>https://pepicrft.me/blog/missing-insights/</guid>
      <pubDate>Tue, 25 Feb 2025 12:00:00 +0000</pubDate>
      <description>What are we waiting to help Swift app development teams be productive?</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>When chatting with organizations that build native Swift apps with Xcode, a common denominator I've found is their limited insights into their development environment.</p>
<p>As you might know, solutions start with understanding. Without it, solutions are chosen blindly and based on assumptions.</p>
<p>The organizations that can afford it throw more engineering resources at the problem, hoping everyone will become more motivated and productive. Others might suggest, "Let's adopt <a rel="external" href="https://reactnative.dev">React Native</a> because I've seen company X successfully implementing it." Or one engineer might propose swapping the build system completely with something like <a rel="external" href="https://bazel.build">Bazel</a>.</p>
<p>But the data is there. It's just not pleasant to obtain and work with.</p>
<p>Want to know more about <code>.xcactivitylog</code> and the <code>.xcresult</code> schema? Search for it on your preferred search engine. You'll most likely end up finding some parser on GitHub. The community has to reverse-engineer these formats, just as we did with the <code>.pbxproj</code> format to build <a rel="external" href="https://github.com/tuist/XcodeProj">XcodeProj</a>.</p>
<p>There's an unfounded obsession with keeping everything close to Xcode, as if development didn't extend beyond your local macOS machine and your <code>Xcode.app</code> instance. Look at Xcode Cloud—it's built right into Xcode. Beautiful. But the capabilities of CI services haven't fundamentally changed. We're just doing the same things, or even worse, but now it's official and native.</p>
<p>It feels as if we're stuck on this idea of "it's native" while watching our builds take an insane amount of time, or our flaky tests blocking people without really knowing how serious the problem is.</p>
<p>So <a rel="external" href="https://tuist.dev">Tuist</a> is jumping in because no one else is:</p>
<ol>
<li>We're collecting the data for you 2. We're making it accessible 3. We're helping you act on it 4. And potentially, we'll be the ones acting on it (e.g., auto-disabling flaky tests)</li>
</ol>
<p>For the first point, we're learning about those proprietary formats to collect and push them to a server. Yes! A server. We love native apps too, and we'll build a native interface to the Tuist platform, but that should be an interface, not the core. A server also means a database, so you can understand how the data evolves over time, and the possibility to interact with other services, integrating with things that happen outside of developers' environments and Xcode. We can't disregard that there's a lot happening out there, because otherwise we end up with a developer experience that's lagging behind in a world where LLM is challenging how we code.</p>
<p>We're standardizing, documenting, presenting, and making the data available to you via an API. Your project, your data.</p>
<p>It's that simple.</p>
<p>We're just a group of developers passionate about this domain. It's not our aim to monetize your data. Our business is helping you solve your problems. Period.</p>
<p>With all our learnings from past years and current interactions with customers, we'll codify that knowledge into a dashboard and a set of tools to make development enjoyable.</p>
<p>I don't understand why this hasn't happened before, but on the upside, it's a great opportunity for us to build something different—something focused on developer experience.</p>
<p>The data is there. We're just going to use it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>CI is commoditizing</title>
      <link>https://pepicrft.me/blog/ci-is-commoditizing/</link>
      <guid>https://pepicrft.me/blog/ci-is-commoditizing/</guid>
      <pubDate>Mon, 24 Feb 2025 12:00:00 +0000</pubDate>
      <description>It&#x27;s time to rethink the CI market.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I remember coming across the idea of Mobile DevOps and wondering: what are they talking about? Isn't Mobile DevOps just <a rel="external" href="https://fastlane.tools/">Fastlane</a>? Why do we need a new term?</p>
<p>I later learned that it was just a marketing term, and a vendor-locking tool to prevent customers from switching to other tools in a market where there are already many options available. The same model is repeating across other CI companies that are rushing to build more than just CI. For example, have you noticed that they all rushed to present an App Center alternative?</p>
<p>Many tech companies, including those in the CI space, typically follow this pattern. They run the infinite game of venture capita. They follow the <a rel="external" href="https://en.wikipedia.org/wiki/Loss_leader">loss-leading</a> script, first bringing and vendor-locking customers into a reasonably-priced solution, and then squeezing as much money as possible from them. Product and innovation become secondary as they focus on the value-cost trade-off.</p>
<p>As someone who likes to see new ideas flourishing and long-standing challenges addressed, I find it sad.</p>
<p>But software and communities that might form around them can be catalysts for change, and I believe we are entering a bit of a wake-up call in this space. Let me unfold that for you.</p>
<p>GitHub Actions started changing the game. First, they built a solution where developers could build and share steps (i.e., GitHub Actions) with others. Sure, platforms other platforms have it too. But think about it for a second. Would you rather have an action in a repository that's part of your CV on GitHub, or commit it to a centralized repository that's more distant from your GitHub profile? It's a subtle but important difference.</p>
<p>They then integrated the UI (e.g., logs) very tightly into the platform. You don't need to leave the platform to see the execution and results of your CI builds. It's right there, in the same place where your code is. And because it's so close, annotating PRs from your builds is as easy as following some conventions in your logs (e.g., <a rel="external" href="https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions">workflow commands</a>).</p>
<p>And last but not least, they embraced <strong>the freedom to bring your own hosts</strong>. This not only became freedom for companies and developers to customize their solution but for companies like <a rel="external" href="https://cirruslabs.org">CirrusLabs</a> or <a rel="external" href="https://depot.dev/blog/ultra-runners-for-macos">Depot</a> to provide hosted runners.</p>
<p>So if your Git forge, most likely GitHub and GitLab, already provides a much better CI experience than other players, gives you access to a marketplace of steps (which, by the way, <a rel="external" href="https://dagger.io">Dagger</a> is commoditizing and making CI-platform-agnostic), and many companies are emerging to provide hosted runners, what are you left with as a CI company?</p>
<p>I'll tell you... You need to share the illusion that you provide more than what you really do, and hope that the years of investing in vendor-locking will prevent companies from leaving you. Ehem, Mobile DevOps. But this model is falling apart. It's a matter of time. And we'll see more companies iterating on the idea that they are a CI company. Give it some time...</p>
<p>How are we doing things differently at <a rel="external" href="https://tuist.io">Tuist</a>? First, we are designing a company that fosters innovation over seeking value-cost tradeoffs. Innovation is in our DNA. And yes, this will mean we'll make bets that won't bring any return, but that's fine. We want to bring some innovation to the CI space, and you'll see that in the following months.</p>
<p>Second, we are embracing people's freedom to choose. We are not about capturing as much as we can from the value that we generate. It's about generating way more value than traditional businesses. And we are going to do that through open source, so we expect to open-source our server and everything that makes Tuist possible. We'll charge for maintaining the services up and running, and the community will be able to contribute to the project, from the CLI to the server. This will make Tuist stand out over competitors that look at openness with fear. We believe this is also the path to get to Android, React Native, and Flutter.</p>
<p>And last but not least, we are placing a strong bet on making everything collaborative. From the moment we have an idea for something we'd like to build, it becomes a shaping process where the community participates. We want people to feel that Tuist is as much theirs as it is ours.</p>
<p>In the following months, we'll see a lot of changes, not just in the CI space, but in app developer tooling, and we are going to drive the change at Tuist.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Science macht besser</title>
      <link>https://pepicrft.me/blog/surgery-day/</link>
      <guid>https://pepicrft.me/blog/surgery-day/</guid>
      <pubDate>Wed, 19 Feb 2025 12:00:00 +0000</pubDate>
      <description>My experience with healthcare in Germany.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It’s 7:00. In six hours, I’ll undergo a five-hour surgery. I’m excited, but at the same time, emotionally exhausted. I just want it to happen already and finally recover from the accident I had while jogging on September 21th.</p>
<p>I’ve spent all this time visiting countless specialists, many of whom were in Germany. I’d like to believe I was just unlucky, but truthfully, I felt abandoned. From MRIs that never happened because they were deemed "unjustified" to doctors telling my wife to take care of me so that I could lose weight and strengthen the muscles that might compensate for my torn ligaments.</p>
<blockquote>
<p><em>“Natur macht besser,”</em> a neurosurgeon said, suggesting I let a nerve—which hasn’t shown any signs of recovery—heal on its own.</p>
</blockquote>
<p>Another doctor seemed more surprised by the fact that <em>I</em> had painted nails rather than my wife. And let’s not even talk about the dismissive comments:</p>
<ul>
<li><em>“Forget about running again—only in the swimming pool.”</em> - The casual bro-like chitchat about a German footballer who played most of his career without ligaments.</li>
</ul>
<p>I would have appreciated a simple, honest response like:</p>
<blockquote>
<p><em>“This is urgent, but I don’t have the resources, experience, or willingness to try a solution.”</em></p>
</blockquote>
<p>That would have been completely fine. No one is an expert in everything.</p>
<p>But was it racism? I doubt it. I’d say it’s more about being on the conservative side of the medical spectrum, leading to a loss of surgical expertise. There was also a bit of the classic <em>“I’ve never seen this before”</em> mental short circuit. So what? The human body is complex. Interestingly, the people that couldn't admit they didn't know about something were male doctors.</p>
<p>And then there’s the specialization issue—<em>“I do muscles,”</em> <em>“I do bones.”</em> Welcome to the inefficiencies of the system. As if dealing with the pain and the looming possibility of a nerve that won’t recover wasn’t enough, I also had to coordinate everything myself.</p>
<p>I’d be lying if I said this whole experience hasn’t made me question what I’m doing in Germany. Sure, I had noticed bureaucratic inefficiencies before, but when it comes to health, the stakes are much higher. My taxes feel worthless—at least on the healthcare front.</p>
<p>Here in Spain, everything feels so much easier. Yes, it helps that I’m a native speaker, but more than that, they guide you through the system until they find a solution. They take responsibility for coordinating your care. I’m going through the private system here—since it was the only way to find a specialist capable of handling my case—but the public system works the same way.</p>
<p>People actually <em>want</em> to help. They generally understand what you’re going through and do their best to make the process more bearable. This is how I always imagined healthcare should be, but Germany’s system failed me.</p>
<p><strong>Wish me luck.</strong> I’ll be fasting for the next six hours, and if everything goes well, I’ll update you tomorrow.</p>
<p>Take care of yourselves.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The missing commoditization</title>
      <link>https://pepicrft.me/blog/missing-commoditization/</link>
      <guid>https://pepicrft.me/blog/missing-commoditization/</guid>
      <pubDate>Thu, 06 Feb 2025 12:00:00 +0000</pubDate>
      <description>I talk about the lack of innovation in the Apple ecosystem and how Tuist is reimagining developer experiences.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Have you noticed that other ecosystems have surpassed Apple’s app development experience in terms of developer tooling? Take <a rel="external" href="https://vercel.com">Vercel</a>, for example—you can preview a website and add comments in just a few clicks. Or look at <a rel="external" href="https://replit.com">Replit</a>, which lets you build and deploy a web app using LLMs in seconds. I can’t help but wonder: why isn’t there more innovation in this space? To be honest, bringing fresh ideas and doing things differently is what drives me at Tuist.</p>
<p>We’re still stuck with the same CI providers we used years ago, dealing with YAML pipelines that are a nightmare to debug, and locked into vendor ecosystems that make it hard to escape predatory sales practices. And what about all those old Ruby scripts no one dares to touch? “They work, so just leave them,” people say. Remote automation and CI are strongly coupled: you automate, push, and check if it works. Want something more intuitive, like a simple “click to release” feature? Not happening. Instead, you build in your CI environment and push the artifacts elsewhere. Need better insights into your projects? Here’s a scattered set of libraries to glue together, a server to maintain, or a build system to replace. Or even worse—an app that locks the data away, when all your manager really wants is a simple link to track team progress.</p>
<p>It’s too much plumbing. <strong>It’s not fun</strong>. And while Apple has made some progress here and there, they’re largely preoccupied with business priorities.</p>
<p>Ironically, the companies best positioned to enter uncontested markets—thanks to their IP and financial capital—are the ones suffering from the <a rel="external" href="https://en.wikipedia.org/wiki/The_Innovator%27s_Dilemma">innovator’s dilemma</a>. They’re too distracted trying to fit their products into the AI narrative. But real innovation starts by looking at problems from a fresh perspective, challenging the status quo, and reimagining what already exists.</p>
<p>At <a rel="external" href="https://tuist.dev">Tuist</a>, we want to be a catalyst for innovation. Our approach? Commoditizing a foundational piece we believe will unlock new ideas: remote virtualization of development environments.</p>
<p>I know, that sounds abstract. But think about Linux containers or web browsers. You can <a rel="external" href="https://stackblitz.com">launch software in a browser</a> using <a rel="external" href="https://webassembly.org">WebAssembly</a> or in a Linux machine with Docker. But macOS? Forget about it. We've wasted years reinventing virtualization—something every CI provider has had to solve. Yet, most see virtualization as just an enabler for CI services, rather than a tool to build new developer experiences.</p>
<p>Now, imagine if the cost of running virtualized environments dropped significantly, thanks to open-source technology and a simple system for orchestrating a pool of hardware. This isn’t a new concept—cloud providers already solved it for running apps and serverless functions. But no one has applied it to improving developer experiences.</p>
<p>Just yesterday, Vercel introduced a new runtime called <a rel="external" href="https://vercel.com/fluid">Fluid</a>. Fluid is how things should be: spinning up virtualized macOS environments seamlessly.</p>
<p>And then, the magic happens:</p>
<ul>
<li>You can release an app with a single click from the list of commits on your Tuist dashboard. - You can run any workflow locally or remotely with just a flag. - You can sign your app remotely, letting us handle all the complexities for you.</li>
</ul>
<p>We’re assembling the pieces to make this future a reality. I can’t wait to see Tuist help the Apple ecosystem catch up with the web. We’re making Tuist the go-to CLI for teams, building the best, most powerful, and beautifully designed dashboard that people love using. We chose Elixir for its robust runtime, which will be crucial in simplifying our solution without compromising power. And we’re developing a few missing technologies, which we’ll also open source.</p>
<p>We’re almost there. We just need to rethink the problem and bring down some costs to make it happen. Will it be expensive to develop? Oh yeah—especially for a small company like us. But once we release it, I bet Tuist will dominate these new spaces.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Where does the value lie in open-source businesses?</title>
      <link>https://pepicrft.me/blog/open-source-business/</link>
      <guid>https://pepicrft.me/blog/open-source-business/</guid>
      <pubDate>Sat, 01 Feb 2025 12:00:00 +0000</pubDate>
      <description>I talk about where we think the value of Tuist lies, and how that&#x27;s evolving towards a sustainable business model.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’ve always enjoyed listening to or reading about open-source projects that find a path to sustainability. This morning, I listened to a podcast (<a rel="external" href="https://podcasts.apple.com/de/podcast/the-business-of-open-source/id1514646781?i=1000686657041">The Business of Open Source</a>) about <a rel="external" href="https://www.xwiki.org/xwiki/bin/view/Main/WebHome">xWiki</a>, an open-source knowledge management tool for companies. It got me thinking about how open-source businesses require constant reflection on their core purpose and value proposition.</p>
<p>At <a rel="external" href="https://tuist.dev">Tuist</a>, we believe that the best way to build a productivity platform is through openness. <strong>Openness fosters accountability</strong>, which keeps us aligned with our mission and pushes us to deliver our best work because everything we do is out in the open. However, openness also presents a challenge: where do we create business value, and how do we monetize it to ensure we can continue doing what we love?</p>
<p>Years ago, Tuist’s value was primarily in its project generation feature, which we now consider a commodity—a gift to the community. Building on that foundation, we introduced optimizations like selective testing and binary caching, which span both the client and server. This marked an inflection point for the business, as server-side value opened up new revenue opportunities. We’ve discussed eventually open-sourcing the server as well, but in its current state—where hosting is simple by design (a necessity given our small team)—organizations might choose to self-host without seeing the value in supporting us financially.</p>
<p>There are interesting models to consider, such as the <a rel="external" href="https://fair.io/licenses/">Fair Source Licenses</a>, but this would distance us from a pure open-source model. Another option is dual licensing, like <a rel="external" href="https://about.gitlab.com">GitLab</a>, where a community edition is extended with paid features. However, I have mixed feelings about this approach because it adds complexity to a product that’s already pioneering a new model in the ecosystem. For instance, Tuist started as a CLI tool, but now there’s a community server and potentially an enterprise server? It feels like too much.</p>
<p>My hope is that, eventually, the value will lie in hosting, maintaining, and scaling the business. At that point, we could even adopt a free software license for the server. Large enterprises often perceive self-hosting as a risk or too complex, making them more inclined to pay for a managed solution. For smaller companies and indie developers, we could offer the service for free up to a certain usage threshold and charge only when usage exceeds that limit. There will always be a group of users who prefer to self-host, and that’s fine—they contribute to improving the product and even help with marketing.</p>
<p>xWiki took the path of monetizing through support, but we are a product-oriented company. <strong>Our goal is to find a balanced SaaS solution that maximizes openness while ensuring sustainability.</strong> The exact model will evolve as we learn and adapt to shifting value propositions. What’s clear to us is that we want to continue contributing open-source tools to the ecosystem while presenting an alternative model for building sustainable open-source businesses.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Tuist is evolving</title>
      <link>https://pepicrft.me/blog/tuist-is-evolving/</link>
      <guid>https://pepicrft.me/blog/tuist-is-evolving/</guid>
      <pubDate>Sun, 26 Jan 2025 12:00:00 +0000</pubDate>
      <description>In this blog post I talk about how Tuist is evolving and how some mental models are transitioning.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As we continue to build a company around <a rel="external" href="https://tuist.dev">Tuist</a> to build more open source sustainably, we are transitioning mental models that solidified in the minds of developers. It’s a natural part of evolving a product, but it might be confusing if you are not close to the evolution. Here’s a summary of what’s happening:</p>
<ul>
<li>Tuist is not just a project generator. Project generation is one of the solutions that we offer along many others. <strong>We see project generation as a component</strong>–a commodity that we might extract from Tuist once we have the resources to execute on it. - The CLI is becoming more of a frontend to a development platform, but it’ll not be the only one. There’s a web-based dashboard and a macOS app, and thanks to our <a rel="external" href="https://tuist.dev/api/docs">documented REST API</a> other frontends might emerge. - We are removing the dependency on generated projects to benefit from the Tuist solutions. Our long-term goal is that <strong>you can plug Tuist into your Xcode projects or Swift packages as they are.</strong> - Our focus continues to be on development productivity, although there are early thoughts about supporting teams more directly with the quality of the apps that they build. We are also expanding our focus to support developers from the moment they have an idea, until they publish it on the store. - We started with a strong focus on the Apple ecosystem, but the problems that we solve span other ecosystems, so we might expand onto Android, React Native, and Flutter in the near future. - There continues to be an appetite to make the server code source available. We might execute on it if the business thrives. We believe this model will lead to shaping the best and more diverse solution in the space.</li>
</ul>
<p>Tuist will look more like <a rel="external" href="https://vercel.com">Vercel</a> or <a rel="external" href="https://expo.dev">Expo</a>. Because developers will expend a lot of time in the dashboard understanding, interacting, and optimizing their development, we deem crucial to provide them with the best experience there. Therefore we are designing a beautiful design system, Noora, that all the features will build upon. We want to build the best DX and most beautiful developer tool for all developers, while building a company around it that embraces innovation and openness in ways that we haven’t seen before in the ecosystem.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Whom do you trust?</title>
      <link>https://pepicrft.me/blog/whom-do-you-trust/</link>
      <guid>https://pepicrft.me/blog/whom-do-you-trust/</guid>
      <pubDate>Sun, 26 Jan 2025 12:00:00 +0000</pubDate>
      <description>It&#x27;s hard to trust solutions in the tech industry these days. In this blog post I talk about my disillusionment with the tech industry and how I make decisions about the technologies I use.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I became somewhat disillusioned with the tech industry. I conceive technology as a tool to support us, humans. Whether that is by giving us a tool to write down our notes, or a framework to create a website like this one in which I'm writing. But when embedded in capitalism, which is what the tech industry is, it can become the least human thing. And this has become more evident to me, specially with the recent events in the US. It's all about extracting as much monetary value as possible from people. We are seen as exploitable resources.</p>
<p>The most obvious example of this, which I'm extremely annoyed by, is the dopamine addiction that social networks have created. It's a silent pandemic. When are we going to stop that? Another one is the ad industry. I was watching yesterday a movie in one of those streaming platforms, where I have a subscription, and despite paying for it, I was bombarded with ads. Then there's this whole AI hype. I get it, LLMs are useful for summarizing, but the environmental cost for society is something we can't ignore. Or most recently, local apps, like note-taking tools, that suddenly become subscription-based, or use proprietary formats to lock you in.</p>
<p>It doesn't need to be like that, but those patterns are becoming more common. I strongly believe we can reverse that trend. For a long time I thought open-source was the answer, but after seeing what Wordpress is turning into, I'm not so sure anymore. Governance and openness are two different things. I use Obsidian to write my notes, which is a closed-source tool. I get why they develop it that way (learned through Tuist). If you make a pure client-side tool open source there's no way you can monetize it to make its development financially sustainable. But what I like about them is that by design and embracement of standards, they give you the freedom to leave. And that's the thing, you can really build a business around a technology, and respect the people's freedom and rights at the same time.</p>
<p>So, whom do you trust? It's hard to say. It's not an easy question because you don't have all the information. But before betting on a particular technology, I do a bit of research to understand the design principles (e.g. standards over proprietary technology), their openness, their governance model and funding structure (this is the most difficult to find). And then based on that I make a decision. I sometimes wish governments did that for you. I can do that because I have the priviledge to have learned about these things due to my close relationship with the tech industry. But if you don't, you should know you might end up mentally sick if you use Instagram and TikTok without limits, in the same one you are reminded that alcohol and tobacco are harmful. But as I said earlier, if anything, with Trump's presidency, this is becoming even more unregeulated.</p>
<p>I'll do what I can in my circles and with Marek through our work on Tuist. We don't need to be like everyone else and jump on the bandwagon. We can build human and long-lasting technology, and not put people in the position of exploitation.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>A convention for frictionless reproduction projects with Mise</title>
      <link>https://pepicrft.me/blog/mise-reproduction-projects/</link>
      <guid>https://pepicrft.me/blog/mise-reproduction-projects/</guid>
      <pubDate>Sat, 11 Jan 2025 12:00:00 +0000</pubDate>
      <description>I just realized Mise has the ingredients to make reproducing issues a breeze, and this is how you can leverage it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>When reporting issues to FOSS projects, developers are often asked to provide a minimal reproduction project. They usually come as <strong>a pair of a tar file and a set of steps to reproduce the issue.</strong>, some of which might be about installing and activating specific versions of dev tools (e.g. I was using Rust version <code>1.82.0</code>). Maintainers then have to pull the tar file, extract it, and go through the steps ensuring that they have the same environment as the reporter. Not only this adds a bit of friction to the reproduction process, but makes it prone to version inconsistencies, which can lead to additional back-and-forth between the reporter and the maintainer. Imagine we could simplify the process down to a single command:</p>
<pre><code>mise run reproduce
</code></pre>
<p>Yesterday, while tinkering with some <a rel="external" href="https://mise.jdx.dev/">Mise</a> features, I realized Mise has the ingredients to make this possible:</p>
<ul>
<li>The capability to install and activate specific versions of dev tools. - An API to define and run <a rel="external" href="https://mise.jdx.dev/tasks/">tasks</a>.</li>
</ul>
<p>Let's see how we can leverage Mise to create a convention for frictionless reproduction projects.</p>
<h2 id="creating-a-reproduction-project">Creating a reproduction project</h2>
<ol>
<li>Create a new directory: <code>mkdir project</code>. 2. Create a <code>.mise.toml</code> file with the following content:</li>
</ol>
<pre><code>[tools]
# Add your tools here

[hooks]
enter = &quot;mise install&quot;
</code></pre>
<ol start="3">
<li>Create a <code>.mise/tasks/reproduce.sh</code> file with the reproduction steps:</li>
</ol>
<pre><code>#!/usr/bin/env bash
# mise description = &quot;Reproduce the project&quot;

# Mise tasks: https://mise.jdx.dev/tasks/file-tasks.html
# Note the root directory is denoted by the env. variable $MISE_PROJECT_ROOT
# Your reproduction steps go here
</code></pre>
<p>And that's all you need to create a reproduction project with Mise. The maintainer can pull the tar file, extract it, and run <code>mise run reproduce</code> to reproduce the issue.</p>
<h2 id="a-ready-to-use-gist">A ready-to-use gist</h2>
<p>I've created a <a rel="external" href="https://gist.github.com/pepicrft/12a2fc6433338489888d660d66d8d0b1">gist</a> with a script that automates the steps above. You can easily run it with the following command:</p>
<pre><code>curl https://gist.githubusercontent.com/pepicrft/12a2fc6433338489888d660d66d8d0b1/raw/907f33c43287c19162c79b2426015c516d4c3cd7/reproduce.sh | sh
</code></pre>
]]></content:encoded>
    </item>
    
    <item>
      <title>Reverting some social recent behavioural and emotional patterns</title>
      <link>https://pepicrft.me/blog/reverting-social-behaviours/</link>
      <guid>https://pepicrft.me/blog/reverting-social-behaviours/</guid>
      <pubDate>Sat, 04 Jan 2025 12:00:00 +0000</pubDate>
      <description>We are evolving Tuist from a CLI to a platform and in this blog post I share some thoughts on how we are doing it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’ve noticed that my interactions and publications on social networks these days tend to be pessimistic, accompanied by anger, frustration, and competitiveness. Overall, they seem to trigger primitive behaviors in me that don’t feel natural when I’m outside that context. Unfortunately, this behavior has started to leak into the offline world.</p>
<p>It wasn’t always like this. I used to be quite positive and enthusiastic—a friend to friends, supportive in my interactions, and always leaning toward collaboration and doing things together. I don’t think that part of me is gone; it’s just overshadowed by these other behaviors and more primitive feelings.</p>
<p>It’s hard to pinpoint where this shift began. I believe social networks’ optimization for extracting these behaviors from people might have played a role. My previous working environment, which was filled with certain toxic patterns, also influenced me because I didn’t know how to set boundaries at the time. Then, of course, there was the pandemic, which isolated all of us, and let’s not forget the many winters in Berlin—those probably didn’t help either.</p>
<p>But here’s the thing: I believe this is something I can change, and I’ll start by leaning into positivity and constructivism. Sure, the world isn’t perfect, and there are things we’d rather not think about, but if we all collaborate more and push back against the individualism that’s been ingrained in us, I think beautiful things can happen. I want to be a catalyst for that change.</p>
<p>Bear with me—it’ll take time—but I really want to do this because it’ll improve my overall well-being. Being a grumpy person on the Internet hurts me deeply in my personal life, and I don’t want that anymore.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>From CLI to platform</title>
      <link>https://pepicrft.me/blog/from-cli-to-platform/</link>
      <guid>https://pepicrft.me/blog/from-cli-to-platform/</guid>
      <pubDate>Mon, 30 Dec 2024 12:00:00 +0000</pubDate>
      <description>We are evolving Tuist from a CLI to a platform and in this blog post I share some thoughts on how we are doing it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the aspects I enjoy most about our work with <a rel="external" href="https://tuist.dev">Tuist</a> is how we continuously evolve the toolchain as we deepen our understanding of the problem space and incorporate feedback from the community. It's an <a rel="external" href="https://en.wikipedia.org/wiki/The_Infinite_Game">infinite game</a>—a journey of constant learning and improvement.</p>
<p>Tuist has gone through three major phases:</p>
<ol>
<li><strong>Xcode Project Generator</strong>: What we now call <a rel="external" href="https://docs.tuist.dev/en/guides/develop/projects">Tuist Projects</a>. 2. <strong>Xcode Project Manager</strong>: Introducing CLI commands like <a rel="external" href="https://docs.tuist.dev/en/cli/run"><code>tuist run</code></a> and <a rel="external" href="https://docs.tuist.dev/en/cli/run"><code>tuist graph</code></a>. 3. <strong>Xcode Project Optimizer</strong>: Featuring tools such as <a rel="external" href="https://docs.tuist.dev/en/guides/develop/build/cache">Tuist Cache</a> and <a rel="external" href="https://docs.tuist.dev/en/cli/run">Tuist Selective Testing</a>.</li>
</ol>
<p>Now, we are entering a new phase. Tuist is becoming <strong>a platform</strong>—a cohesive story that ties all the pieces together. Imagine a <a rel="external" href="https://vercel.com/">Vercel</a> or <a rel="external" href="https://expo.dev/">Expo</a> for Swift app development. A platform that guides you from the spark of an idea to scaling your app for millions of users. A trusted partner empowering you to build the best apps faster.</p>
<p>We aim to streamline the toolchain by peeling back years of accumulated layers of indirection. Our ultimate vision reduces the stack to just GitHub (or any Git forge), Tuist, and Xcode. Tuist will act as a platform integrated into your repository, making the magic happen. And by magic, we mean pure joy:</p>
<ul>
<li><strong>Signing?</strong> We handle it seamlessly—it just works. - <strong>Remote builds?</strong> Done in our environments, hassle-free. - <strong>Analytics?</strong> Integrated with ease. Grafana? Plug it in. - <strong>Releases?</strong> Managed through a user-friendly UI.</li>
</ul>
<p>Think of Tuist as an extension of Xcode that bridges the gaps and connects the community with Apple’s ecosystem. Together, we’re building the future of app development.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Learnings from logging in a Swift CLI</title>
      <link>https://pepicrft.me/blog/clis-ui/</link>
      <guid>https://pepicrft.me/blog/clis-ui/</guid>
      <pubDate>Tue, 24 Dec 2024 12:00:00 +0000</pubDate>
      <description>Some thoughts on how to treat logging and UI in a Swift CLI.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>When building CLIs, it’s common to conflate UI and logging. That’s something we did at <a rel="external" href="https://tuist.dev">Tuist</a>, most likely because in both cases, text is taken as input. So it’s natural to think that they should be the same thing or that UI is a subset of logging. However, as we worked towards improving the developer experience of the CLI, we realized that it’s better to treat both as separate elements, even though they both work with text and there might be some overlap.</p>
<p><strong>Logging is useful to debug the execution of the program</strong>, especially in situations where an invocation didn’t yield the expected result. Although often those logs are forwarded through the standard pipelines, they don’t need to be. They can be forwarded to <a rel="external" href="https://developer.apple.com/documentation/os/oslog">OSLog</a> or to a file in the file system. Apple’s Swift Log package is designed with this in mind and allows setting up what they call logging backends or handlers.</p>
<p>At Tuist, we dynamically plug one backend at runtime based on the user preferences at invocation time. The preferences are modeled based on two variables: how quiet or verbose they want logs to be, and where they want things to be logged.</p>
<p>This leads to the following scenario. The default logging configuration pipes out logs (except the verbose ones) through the standard pipelines, so developers have a sense of progress without too much noise. The problem? If things fail, developers need to run the command again, opting into verbosity with <code>--verbose</code>. But what if the issue is not easily reproducible, and that was the only opportunity to capture what happened? Well, the opportunity is gone. Plus, having to run the same command again just to see it fail with more detailed logs is not the best experience.</p>
<p>I think we should approach this differently. The default is right. You want to see a concise output that indicates how things are progressing throughout the execution. However, we should also have a second handler/backend that forwards the most verbose version of the logs to <code>oslog</code> and to a file in the file system. Why? Because on completion, you can point people to the logs, and they can use filtering tools provided by the Console app to get what they need. By doing that, once it completes, if you need the logs for anything—for example, to debug a failure—you have the link to the file right there, so you don’t need to run it again.</p>
<p>Is that enough? I don’t think so. I started the blog post mentioning that we conflate logging and UI, but that they should be different things. <strong>When I think of logs, I think of traces that tell a story of how things are being executed.</strong> But where does an interactive prompt fit into it? It’s not a trace. You use the terminal capabilities with cursors to make it feel interactive, but from the logging perspective, you are only interested in two things: something is being prompted, and the user responded to the prompt. So in non-interactive CLIs, you might just merge UI into logging, but in more interactive CLIs like Tuist’s, I think it’s better to treat it as something independent.</p>
<p>UIs are for developers using the tool. Logs are usually for developers debugging the tool. The needs are different. When you design the text to be an output for the user, there are traits like formatting and spacing that are very important. These traits are not relevant in the context of logs. All you care about in logs is understanding the sequence of events. Therefore, separating the two things forces you to think more deeply about the presentation layer of your CLI. I like to say that text output is the UI layer of CLIs—SwiftUI, if you will. The UI is something you might also be interested in testing with snapshot testing techniques, in the same way you do with your SwiftUI views. It’s tightly connected to the DX, and you don’t want it to be an afterthought.</p>
<p>So at Tuist, we are correcting the course. We are drawing a line between logging and UI, plugging our verbose logs to <code>oslog</code>, and revisiting the UI of every component to ensure the experience of each command from the UI standpoint is the most consistent and beautiful that we can ship.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Us or them</title>
      <link>https://pepicrft.me/blog/us-or-them/</link>
      <guid>https://pepicrft.me/blog/us-or-them/</guid>
      <pubDate>Thu, 19 Dec 2024 12:00:00 +0000</pubDate>
      <description>Focusing on others over self-promotion is a powerful way to build a company.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Continuing with my thoughts on building a company, I want to discuss a pattern I’ve noticed among companies and influencers, and how we are shaping <a rel="external" href="https://tuist.dev">Tuist</a> to do things differently.</p>
<p>Social networks have made us more individualistic. Much of the content shared online revolves around “me”: the lessons I’ve learned, the products I’ve built, the places I’ve traveled to... It’s as if these platforms have hit the narcissism button, and we’ve forgotten the value of collaboration. Interestingly, research shows that collaboration leads to better outcomes. However, when the primary goal is to feed an algorithm designed to capture attention, collaboration might feel like a wasted effort.</p>
<p>Unfortunately, this pattern is also apparent in how many tech companies operate today. Months are spent working behind closed doors on what could be the next big success, only to emerge and hope for <a rel="external" href="https://en.wikipedia.org/wiki/Product-market_fit">“product-market fit”</a> to materialize. It’s like throwing a dart and hoping it sticks. They buy expensive domains, design flashy websites, hire influencers to promote their product, and hope that self-promotion will eventually lead to success. Even small wins are often packaged into narratives to attract more capital—much like how chickens are overfed to grow rapidly. The result is either building a big business or failing fast.</p>
<p>What surprises me is how secondary the actual problem—and the people experiencing it—has become in this equation. Many companies are busy building “serverless X” without truly addressing what it means or whom it serves. It’s reminiscent of the clickbait culture on YouTube, where influencers use catchy thumbnails and titles to reel you in. Companies employ similar tactics: “Pay for what you use.” Sounds appealing, doesn’t it? Yet, you might end up paying more without even realizing it. This lack of ethics is becoming normalized—anything goes as long as it stays within legal boundaries.</p>
<p><strong>Building a different kind of company requires only a small yet significant shift: focusing on people instead of the company itself. But this isn’t an easy shift.</strong> It demands overcoming ego and suppressing narcissistic impulses. It requires listening, becoming a platform for others, and enabling their success. It’s costly because it introduces a social component to the business, which might feel unfamiliar to more logical thinkers. Yet, the value it brings far outweighs the costs.</p>
<p>When I think of one of Tuist’s key strengths, it’s our strong focus on people. These values stem from our open-source roots and permeate how we shape the business. Every decision we make prioritizes what the community wants, rather than what we want to sell. For example, in 2025, we’re launching a newsletter, <a rel="external" href="https://tuist.dev/newsletter">Swift Stories</a>, to curate ideas from the community that might otherwise go unnoticed. We open-source components like <a rel="external" href="https://github.com/tuist/xcodegraph">XcodeGraph</a> and <a rel="external" href="https://github.com/tuist/xcodeproj">XcodeProj</a> to empower the community and foster innovation, rather than keeping them private as competitive advantages. Another example is our localization efforts—seemingly small initiatives that make our project more inclusive and accessible, but carry significant meaning.</p>
<p>When you focus on people, remarkable things happen—things that aren’t often talked about.</p>
<ol>
<li>You don’t have to search for “product-market fit.” By creating a safe space, people naturally share what they need and what they’d pay for. 2. Customers gravitate toward you because they’re inspired by your values and prefer supporting you over competitors.</li>
</ol>
<p>Every customer we’ve gained so far has come from our community. Some have even told us they’d prefer a CI service from us over others simply because of our approach. This shift in focus has a profound impact. For example, our <a rel="external" href="https://tuist.dev/blog/2024/12/16/trendyol">most recent blog post from Trendyol</a> happened without us prompting them. When things occur organically, they carry a unique energy that money can’t replicate.</p>
<p>If you’re building a company, I encourage you to put people first. It’s challenging and may feel like swimming against the current, but believe me—people value connection and collaboration. They’ll appreciate your authenticity and the unique way you do things.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The paradox of OSS</title>
      <link>https://pepicrft.me/blog/oss-paradox/</link>
      <guid>https://pepicrft.me/blog/oss-paradox/</guid>
      <pubDate>Mon, 16 Dec 2024 12:00:00 +0000</pubDate>
      <description>In this post, we discuss the paradox of open-source software and how you can support its sustainability.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Building open-source software (OSS) is a privilege. You need a very precious asset that's scarce in the world: time. Some people have it, for whatever reason—that's outside the scope of this post. Others don't, yet from an unprivileged position, they still manage to squeeze out some time to contribute to OSS. <strong>They often do so because they believe in its value and the freedom it brings to the world.</strong></p>
<p>Open-source is better than closed-source software. We've learned that story <a rel="external" href="https://www.harpercollins.com/products/just-for-fun-linus-torvaldsdavid-diamond?variant=32118179364898">throughout the history of software</a>. Yet, we get irritated when open-source mentions the word "sustainability". Let's pause for a moment.</p>
<p>If a software is closed-source, which comes with high risks for the person or company using it, they are comfortable not only with the idea of paying for it but also with being a product of the company. But if the software is open-source, which significantly reduces the risks of using it, people are rarely comfortable with the idea of paying for it.</p>
<h2 id="the-paradox-of-oss">The paradox of OSS</h2>
<p>Let's break down this paradox in the context of developer tools.</p>
<p>You are willing to pay for a service to bring CI/CD to your project. You come across a closed-source service that everyone talks about. They don't list the price on their website, and after some back and forth with the sales team, you end up paying an expensive subscription. Your product leans on proprietary design decisions because you are a product of the company.</p>
<p>Your entire company has migrated to this service, and two years down the line—in the spirit of meeting their VCs' expectations and knowing that moving away would be extremely difficult—they multiply the price by 10.</p>
<p>Back then, you had the alternative of paying for the cloud service of an open-source project. They offered a cloud plan to sustain the development of the project. But you could not wrap your head around the idea of paying for something whose source code is available. Not many people were talking about it at the time, so it felt more natural to pay for that flashy closed-source service that could afford to pour millions into marketing and associating their brand with the open-source community.</p>
<p>Now you find yourself having to decide between paying 10 times more for the same service or stopping business development for months to migrate to a service you could have paid for initially.</p>
<h2 id="supporting-oss-sustainability">Supporting OSS Sustainability</h2>
<p>If you come across an open-source project figuring out sustainability, offer them a hand. Sustainability can take many shapes:</p>
<ol>
<li>It can be an AGPL-3.0 license with a dual-license for enterprise. And despite what you've heard, AGPL-3.0 is not a viral license. Businesses want you to believe that, but a license only enters into effect when you distribute the software, which is not the case when you use it internally. In case of doubt about what "distribution" means in this context, the developers behind the project are usually happy to clarify. 2. Sustainability can also mean building cloud services, like we are doing with Tuist. If we were privileged enough to have the time to build open-source without worrying about money, we'd happily do it, but unfortunately, that's not the case.</li>
</ol>
<p>We need to draw a line between what's free and what's paid. We do this for three simple reasons:</p>
<ol>
<li>We want the project to thrive and continue supporting users. 2. We want to do more open-source work to advance the Swift ecosystem. 3. We want to move the ecosystem away from closed-source tools.</li>
</ol>
<h2 id="making-informed-decisions-when-choosing-a-tool-consider-the-following">Making informed decisions When choosing a tool, consider the following:</h2>
<ol>
<li>Open-source, even if not fully, is better than closed-source. You eliminate risks for your business. 2. If you can afford it, pay for the open-source tools you use. It's a way to support the developers, the ecosystem, and even your brand. 3. If you can't afford it, contribute to the project in other ways. Report bugs, write documentation, or spread the word about it.</li>
</ol>
<p>We are not privileged to have the time to build open-source without worrying about money. But we hope to reach a point where we don't have to think about finances, so we can gift more open-source tools to the Swift ecosystem and foster innovation through the commoditization of the tools we use to build software.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>If it can be open-source, it&#x27;ll be open source</title>
      <link>https://pepicrft.me/blog/it-ll-be-open-source/</link>
      <guid>https://pepicrft.me/blog/it-ll-be-open-source/</guid>
      <pubDate>Wed, 11 Dec 2024 12:00:00 +0000</pubDate>
      <description>Open source business models are the future of software development.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Whether businesses like it or not, open and collaborative approaches to building technology are the foundation for creating long-lasting solutions. In other words, if a business's value lies solely in closed-source software and nothing else, chances are it will be disrupted by a competitor leveraging open-source software to build a better product.</p>
<p>I emphasized "solely" because some businesses provide value beyond their software, either through infrastructure or connections to external systems that are difficult to replicate. For example, an open-source e-commerce platform that competes with Shopify can be built. In fact, <a rel="external" href="https://medusajs.com/">it exists</a>. But what about card readers? Payment processing? Taxes?</p>
<p>On the other hand, Calendly? <a rel="external" href="https://cal.com/">Done</a>. DocuSign? <a rel="external" href="https://documenso.com/">Done too</a>. GitHub? Absolutely—<a rel="external" href="https://about.gitlab.com">here’s one example</a>, and <a rel="external" href="https://forgejo.org/">another</a>. Even <a rel="external" href="https://woodpecker-ci.org/">CI</a>, <a rel="external" href="https://grafana.com/">telemetry</a>, and <a rel="external" href="https://posthog.com/">analytics</a> have open-source counterparts.</p>
<p>What do all these successful open-source products have in common? Something money can’t easily buy: stronger communities and better products. When you embrace open collaboration and welcome ideas from diverse perspectives, your product becomes more inclusive and innovative.</p>
<p>The alternative? Designing what you <em>think</em> is the best product from a conference room in San Francisco, assuming it solves problems for people in South Korea. Spoiler alert: it probably doesn’t.</p>
<p>And here’s the best part: AI is <a rel="external" href="https://x.com/cognition_labs/status/1866535305773568191">reducing the cost of maintaining open-source software</a>, a cost that has traditionally been higher than developing behind closed doors.</p>
<p>At Tuist, we want to set a precedent in the Apple developer tooling space. Too often, closed-source and proprietary solutions emerge, plastering "contact sales" buttons on their websites and finding shady ways to lock developers into their ecosystems. But it doesn’t have to be this way.</p>
<p>We’re committed to building open solutions for scaling challenges and making them accessible to everyone. We’ll continue to commoditize tools—not just for accessibility but to push the ecosystem to innovate. Because we believe the time for closed-source developer tools is over.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Programming languages are just tools</title>
      <link>https://pepicrft.me/blog/programming-languages-are-tools/</link>
      <guid>https://pepicrft.me/blog/programming-languages-are-tools/</guid>
      <pubDate>Mon, 02 Dec 2024 12:00:00 +0000</pubDate>
      <description>I&#x27;m working on seeing programming languages as tools to solve problems, and not engaging in comparing and commenting on how one programming language is better than the other.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I came across <a rel="external" href="https://hazelweakly.me/blog/you-have-one-voice/">You Have One Voice</a>, and it made me think about how my relationship with technology is evolving.</p>
<p>When I was younger, I was very passionate about, and sometimes even religious about Swift. You know when you try to take the language everywhere, that was me. However, as I've grown older, and got to work in other technology stacks, I've realized that Swift is just a tool. I worked with Ruby building CLIs, then I built CLIs with JavaScript and NodeJS, and tinkered with web technologies like Ruby on Rails in between.</p>
<p>This distancing of Swift felt at times like a betrayal and a lose of identity, and other times like a liberation. My wife loves to say that learning spoken languages opens your mind, and I think it applies to programming languages as well. I have my opinions and preferences, and love to learn from the communities around them, but I'm not married to any of them. I'm seeing them as tools to solve problems.</p>
<p>The mistake that I sometimes make, that's mentioned in the blog post, and that I should work hard on stop doing, is comparing and commeting on how one programming language is better than the other. It's just a subjective opinion, and it's not helpin anyone. All programming languages have their pros and cons, and are surrounded by social and technical contexts that make them unique.</p>
<p>The world is better of if we all work on making our tools better, and cross-pollinate ideas between communities. So I'll stop comparing and commenting on how one programming language is better than the other. If I love something about Elixir, I'll say it out loud, because I think it's important to share the joy, but I won't do so in the expense of another language.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Growth, growth, growth</title>
      <link>https://pepicrft.me/blog/growth-growth-growth/</link>
      <guid>https://pepicrft.me/blog/growth-growth-growth/</guid>
      <pubDate>Thu, 28 Nov 2024 12:00:00 +0000</pubDate>
      <description>Growth is a metric many businesses aspire to, but it&#x27;s not the model that we align with at Tuist. We believe in prioritizing people&#x27;s joy over growth.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>We’ve become obsessed with growth in building businesses. It has turned into the metric that most aspire to: more users, more revenue, more investment. If you’re not growing, it’s seen as a sign you’re doing something wrong.</p>
<p>But when growth becomes the ultimate goal, <strong>the people you’re building for often become an afterthought.</strong> Instead of creating for them, you use them as tools to achieve growth. This dehumanizes them, leading to strategies that often feel exploitative.</p>
<p>For example, some businesses publicly criticize others’ work to exploit <a rel="external" href="https://en.wikipedia.org/wiki/Schadenfreude">“schadenfreude.”</a> They actively look for people making mistakes to capitalize on the audience’s curiosity for negativity—using it as a marketing tool. How crazy is that? Sure, anything is possible in business, but come on—it’s perfectly fine to grow more slowly if it means contributing to a better, healthier society instead of making it worse.</p>
<p>Another practice I find exploitative is what I call <a rel="external" href="https://en.wikipedia.org/wiki/Openwashing">“open-washing.”</a> Some companies, desperate for shortcuts to growth, <strong>think they can buy everything with money</strong>—including the intangible assets of open-source projects, such as their brands and communities. They treat these assets as mere marketing tools. They throw a few crumbs in the form of donations or sponsorships and then loudly claim to be "an open-source company." It’s not much different from brands sending cheap promotional items to influencers, hoping for exposure. This is capital-rich companies taking advantage of the human-centered work of others who truly know how to build and nurture communities.</p>
<p>This insatiable appetite for growth shows up in many areas—not just marketing. Products are riddled with “contact sales” buttons, proprietary technologies designed to create vendor lock-in, and intentionally opaque pricing models that exploit customers’ negotiation skills. The list goes on. Sadly, when you search for companies that define success differently, the options are few and far between. These companies exist, but they’re rare.</p>
<p>We could follow these same exploitative paths ourselves, but we refuse to fuel those strategies. In fact, we’re actively working to reverse these models. We believe we need healthier, more human ecosystems—where individualism gives way to community, proprietary technology is replaced by open solutions, and people’s agency to choose the best tools for their needs is respected rather than manipulated.</p>
<p>This shift is only possible if we prioritize people’s joy over growth—and that’s exactly what we’re doing at <a rel="external" href="https://tuist.dev">Tuist</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Setting up a Forgejo runner in Hetzner</title>
      <link>https://pepicrft.me/blog/forgejo-runner-in-hetzner/</link>
      <guid>https://pepicrft.me/blog/forgejo-runner-in-hetzner/</guid>
      <pubDate>Sun, 24 Nov 2024 12:00:00 +0000</pubDate>
      <description>Learn how to configure a Hetzner server as a Forgejo runner to run CI&#x2F;CD jobs for your projects hosted on Codeberg.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Weeks ago, I <a href="https://pepicrft.me/blog/forgejo-runner-in-hetzner/__GHOST_URL__/blog/2024/11/05/woodpecker-ci-for-codeberg">wrote</a> about configuring a Hetzner server with Woodpecker to run CI jobs. At the time, I was not aware of the existence of <a rel="external" href="https://forgejo.org/docs/latest/user/actions/">Forgejo actions</a>, which are integrated right into the open source Git forge that powers Codeberg, where I'm currently hosting my personal website and code crafts. After giving it a try, I decided to switch to Forgejo actions for my CI/CD needs. This blog post is the counterpart to the previous one, where I'll show you how to set up a Forgejo runner in Hetzner. Let's dive in!</p>
<p>The first thing that you'll need is a Hetzner server. It can be a server from any other provider, which provides you with a Linux machine and SSH access to it. In my case I selected the x86 (Intel/AMD) CX22 machine in Germany with Ubuntu 24.04. Note that the steps that follow assume Ubuntu as the operating system.</p>
<p>Once the machine is up and running, SSH into it using its IP address and the root user. Once in, <a rel="external" href="https://docs.docker.com/engine/install/ubuntu/">install Docker</a>, which Forgejo runner can use to virtualize the execution of CI/CD pipelines:</p>
<pre><code># Add Docker&#39;s official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
 &quot;deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
 $(. /etc/os-release &amp;&amp; echo &quot;$VERSION_CODENAME&quot;) stable&quot; | \
 sudo tee /etc/apt/sources.list.d/docker.list &gt; /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
</code></pre>
<p>You can verify that Docker is installed correctly by running:</p>
<pre><code>sudo docker run hello-world
</code></pre>
<p>Then run the following command to ensure the engine starts on boot:</p>
<pre><code>systemctl enable docker
</code></pre>
<h2 id="install-the-forgejo-runner">Install the Forgejo runner</h2>
<p>The next step is installing the Forgejo runner.</p>
<pre><code>sudo apt-get install -y curl jq wget
RUNNER_VERSION=$(curl -s https://code.forgejo.org/api/v1/repos/forgejo/runner/releases/latest | jq -r &#39;.tag_name&#39; | cut -c 2-)
wget -O /usr/local/bin/forgejo-runner &quot;https://code.forgejo.org/forgejo/runner/releases/download/v$RUNNER_VERSION/forgejo-runner-$RUNNER_VERSION-linux-amd64&quot;
chmod +x /usr/local/bin/forgejo-runner
</code></pre>
<p>Once the runner is installed, you'll have to register it. To do so, you'll need a registration token, which you can get from your user or organization's settings on Codeberg under the "Actions" tab. Then you can run <code>/usr/local/bin/forgejo-runner register</code>, which will guide you through the registration process.</p>
<pre><code>INFO Enter the Forgejo instance URL (for example, https://next.forgejo.org/):
https://codeberg.org
INFO Enter the runner token:
xxxxxxxxxx
INFO Enter the runner name (if set empty, use hostname: ci):
ci
INFO Enter the runner labels, leave blank to use the default labels (comma-separated, for example, ubuntu-20.04:docker://node:20-bookworm,ubuntu-18.04:docker://node:20-bookworm):
ubuntu-22.04:docker://node:20-bullseye
INFO Registering runner, name=ci, instance=https://codeberg.org, labels=[docker:docker://ubuntu:22.04].
DEBU Successfully pinged the Forgejo instance server
INFO Runner registered successfully.
</code></pre>
<p>The registration will create a <code>.runner</code> file in the current working directory, which if you haven't changed it, will be <code>/root</code>. The file will contain the runner's integration configuration.</p>
<p>You can then run the following command to create a configuration file to configure the runner's runtime behavior:</p>
<pre><code>/usr/local/bin/forgejo-runner generate-config &gt; config.yml
</code></pre>
<p>You might want to modify the <code>runner.capacity</code> attribute from the configuration file to specify the maximum number of jobs the runner can handle concurrently.</p>
<p>The last step is to configure the runner as a systemd service, which allows it to start automatically when the machine boots up. You'll have to create the following file at <code>/etc/systemd/system/forgejo-runner.service</code>:</p>
<pre><code>[Unit]
Description=Forgejo Runner
After=network.target

[Service]
WorkingDirectory=/root
ExecStart=/usr/local/bin/forgejo-runner daemon --config /root/config.yml
Restart=always

[Install]
WantedBy=multi-user.target
</code></pre>
<p>Once the file is created, you can enable and start the service by running:</p>
<pre><code>systemctl daemon-reload
systemctl enable forgejo-runner
systemctl start forgejo-runner
</code></pre>
<p>After completing all the above steps, you should see the runner showing up in the "Runners" tab of your Codeberg organization or user's "Actions" settings.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Tuist is a product</title>
      <link>https://pepicrft.me/blog/tuist-is-a-product/</link>
      <guid>https://pepicrft.me/blog/tuist-is-a-product/</guid>
      <pubDate>Fri, 22 Nov 2024 12:00:00 +0000</pubDate>
      <description>How I choose the technology I use</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I listened to a <a rel="external" href="https://www.emilyomier.com/podcast/applying-the-lessons-from-docker-with-solomon-hykes">podcast interview</a> with <a rel="external" href="https://fr.wikipedia.org/wiki/Solomon_Hykes">Solomon Hykes</a>, and I liked it a lot. Many of the points he touched on are things we’ve experienced or discussed in shaping the Tuist product. It was great to hear and learn from the experiences of someone else.</p>
<p>Solomon Hykes, the founder of Docker and now Dagger, shares our love for building developer products. Both Docker and Dagger are open-source businesses, meaning their core revolves around open source, community, and open discussions—even when those discussions lean more toward the business side of things. I believe this is how the best and most enduring companies are built. However, as he points out, achieving this is not easy. Why is that?</p>
<p>He differentiates between <strong>products and components</strong>. Components are open-source, standardized pieces that become industry commodities. They often evolve from a product once they’ve matured. It makes sense for such components to belong to a foundation once they’ve reached critical mass. Examples of components include Kubernetes and containerd. Typically, their licenses and trademarks, which are usually managed by foundations, are permissive. This allows businesses to use them as enablers or even integrate them as part of their offerings.</p>
<p>However, <a rel="external" href="https://dagger.io/">Dagger</a> and <a rel="external" href="https://www.docker.com/">Docker</a> are not components—they are products. What’s the distinction? Products are fully integrated developer experiences that deliver value, often have ecosystems around them, and monetize certain features to fund further development. This funding often extends to investments in components. Solomon emphasizes this distinction as critical for building great developer tools, and we agree.</p>
<p>Some organizations may dislike this approach because it prevents them from leveraging communities and streams of capital to outcompete you and extract value from the community. They often argue, “You’re not open enough,” as Bitrise did when they suggested that Tuist should be part of the <a rel="external" href="https://github.com/MobileNativeFoundation">Mobile Native Foundation</a>. It was amusing to see them use the same tactics that cloud providers once used against Docker. We don’t have anything against the foundation; in fact, we’re considering extracting Tuist’s generation logic into a component. However, Tuist itself is not a commodity—it’s a product, most of which is open source. This distinction is subtle but important.</p>
<p>Since Tuist is a product, it has features like the <code>login</code> command to authenticate with Tuist itself, the vendor behind the product. We see being a product as a critical distinction with significant implications. For example, it’s the reason we’re gradually transforming Tuist into an integrated extension of Apple’s tooling. This evolution wouldn’t have been possible if Tuist were a commodity, which would have led to stagnation. Simply put, we don’t want Tuist to stagnate.</p>
<p>We expect some organizations to dislike this model, and that’s fine. But there are many others who understand the need for this approach—especially from a financial perspective—and are eager to participate in shaping Tuist and its community. Like Docker in its early days, this is where our focus should be. Only by focusing here can we create a truly great product.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Whom do I trust?</title>
      <link>https://pepicrft.me/blog/whom-do-i-trust/</link>
      <guid>https://pepicrft.me/blog/whom-do-i-trust/</guid>
      <pubDate>Tue, 19 Nov 2024 12:00:00 +0000</pubDate>
      <description>How I choose the technology I use</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Once while reading the book <a rel="external" href="https://hackingcapitalism.io/">"Hacking Capitalism,"</a> I read a sentence that struck me: "The tech industry is technology embedded in capitalism." I had never thought about it that way, but it made total sense. The book focuses on that fact from the perspective of a worker in that system and how to "hack" it to have a healthy relationship with it, yet I believe there's also another angle worth reflecting on: the perspective of the people who consume technology. I don't like to call that group users, because I believe it dehumanizes them.</p>
<p>I always conceived of technology as an extension of our lives to make certain things more convenient. For a long time, I assumed good intentions from the makers of those technologies, from the executives of Facebook to those from Apple. Isn't it amazing to have the tools to be connected to so many people? Or hardware like iPhones that lower the entry barrier to technology? "We aim to make the world a better place." I also bought into this story when I joined Shopify and stayed there for many years. Their version of making the world a better place was making e-commerce better for everyone. I'd call my 20s a phase of illusion with technology. How naive I was...</p>
<p>Fast forward to today, what I feel is a lot of disappointment with the tech industry. Seeing the leaders whom I long respected celebrating Trump becoming the winner makes me sad. Years ago, they didn't dare to talk about such things publicly. But we've normalized a reality where they feel comfortable doing so. It's all about money, and which millionaire isn't happy with their taxes being cut? And the worst part is, many of us are so exhausted, confused, and driven by primitive emotions whose buttons were pressed by these same people, that we are unable to think clearly. This is not the tech industry I want to be part of. But <strong>whom do I trust?</strong></p>
<p>If anything, I think this whole experience has taught me whom to trust and why. First and foremost, I trust the <strong>tools that don't push solutions that could work offline into a service behind a subscription for the sake of monetization.</strong> For instance, I'm on board with paying a license for a macOS note-taking app. But a subscription? No way. Recently, I came across an app that had note features built in and forced you to pay once you went above x notes. Sorry, not for me.</p>
<p>Then from those solutions, I prefer the ones that choose <strong>standard formats and/or expose APIs to enable interoperability.</strong> I believe someone should stay with a service because they like it, not because the service made it hard for them to leave. As we are building Tuist, we see that pattern in the developer tooling space, and we are working on changing it. We believe the right to freely choose the solution to one's problems should be respected. When a service respects that, it signals what values they stand for. Sure, this can change, but once you stand for certain values, changing them is unlikely because it would damage your reputation. This is why I choose tools like <a rel="external" href="https://logseq.com/">Logseq</a> or <a rel="external" href="https://ia.net/writer">iA Writer</a> that use plain markdown files, which I can store in a Git repository for synchronization.</p>
<p>If the solution is open source, even better. I'll gladly support the developer or the organization behind it financially. This often means a drop in UX compared to the closed-source alternatives, but I've learned to appreciate that instead of being negative about it. I care much more these days about the values than the presentation of the solution itself. Note that open source doesn't necessarily mean longevity. But if they steer the direction of a popular tool poorly, it's likely that the community will fork and continue its development. I can also contribute my own ideas and code to improve the tools that I use, which I think is amazing.</p>
<p>I'm fine if the tool is VC-backed as long as the investment is reasonable relative to the value the tool is generating and its market. When a tool has been thrown onto a hyper-growth path, I can tell because their desperation to meet investors' expectations is often reflected in the tool becoming a Swiss army knife, releasing one feature after another. Alternative models are possible, but rare. The reason why I'm fine with tools that receive investment is that there are creators who are not financially privileged enough to quit their jobs and start their own businesses without initial funding. Investment solves this, and good investment can yield amazing outcomes. <a rel="external" href="https://penpot.app/">Penpot</a> and <a rel="external" href="https://zed.dev/">Zed</a> are examples of that, and I'm optimistic they'll get off the ground business-wise and become references in their space.</p>
<p>Choosing the right technology that's future-proof, respects people's values, and is fair is getting trickier, but I now have my own framework, and it has been working great for me. It often means I don't jump on the hyper-marketed trains that come and go, but I'm fine with that. I'm no longer excited by the shiny technology but by the human one.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>I am out of X</title>
      <link>https://pepicrft.me/blog/i-am-out-of-x/</link>
      <guid>https://pepicrft.me/blog/i-am-out-of-x/</guid>
      <pubDate>Sun, 17 Nov 2024 12:00:00 +0000</pubDate>
      <description>I find it a hostile place for my mental health and society and I don&#x27;t want to contribute to it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’m completely out of X. I still <a rel="external" href="https://x.com/pepicrft">keep my account</a> there so no one takes the handle or in case someone wants to reach me. We’ve done the same with the <a rel="external" href="https://x.com/tuistdev">Tuist account</a>.</p>
<p>For my personal account, leaving was easier than I expected. Sure, my account held value through the connections and reputation I’d built over the years—<em>but so what?</em> In the end, that value is abstract and can evaporate overnight. The constant pressure to build a reputation and stay active for the sake of "growing a brand" was seriously affecting my mental health. I was barely present in my real life because most of my mental energy was spent figuring out what to post next. These past weeks off X have been the healthiest and most present moments I’ve had in a long time.</p>
<p>Tuist’s account was harder to step away from. Every company in the developer tooling space seems focused on building their reputation and brand by throwing money at the problem—buying badges or paying for visibility in someone else’s feed. Since we’re working to get a business off the ground, the thought that haunted us was: Will we be forgotten? But the more we reflected on it, the clearer it became that there are other, better ways for people to discover us. In fact, those ways align more closely with the values we want our company to represent. A side benefit is that we’re not contributing to a platform that’s causing harm to society. Sure, as a business, making money is important—but we believe moral and social responsibility are equally important and should hold the same weight.</p>
<p>So, we decided to do the same for the Tuist account. We’re now active on <a rel="external" href="https://bsky.app/profile/tuist.dev">Bluesky</a>, <a rel="external" href="https://fosstodon.org/@tuist">Mastodon</a>, and other platforms, as well as our community forum. These alternatives are SEO-friendly and eliminate barriers, making it easier for anyone to find our content and ideas without being manipulated by algorithms. We’ve noticed some players in our space adopt tactics similar to insurance companies, pressing the buttons of fear and other primal emotions. We’ve chosen a different path: putting out good content, being open about the problems we’re solving, and inviting people into the process. We trust that approach—and the people it reaches—to spread our message naturally. We don’t need an X account for that.</p>
<p>Personally, I plan to use this blog more actively too. I’m considering building a small Phoenix publishing tool to create internet "digital gardens"—simple, personal spaces that support syndication and other formats, like photos or save-for-later articles. It would be fun to work on and a great way to share ideas.</p>
<p>The internet is amazing without walls. We’ve decided we won’t contribute to building them or making society worse.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Set up a Woodpecker CI in Hetzner server for your Codeberg account</title>
      <link>https://pepicrft.me/blog/woodpecker-ci-for-codeberg/</link>
      <guid>https://pepicrft.me/blog/woodpecker-ci-for-codeberg/</guid>
      <pubDate>Tue, 05 Nov 2024 12:00:00 +0000</pubDate>
      <description>A guide to setting up a self-managed Woodpecker CI on a Hetzner server for continuous deployment of a website hosted on Codeberg.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Lately, I've been reducing my reliance on closed-source platforms and replacing them with open-source alternatives. One of those platforms is GitHub, which I've used for years. While GitHub will remain the home for projects like Tuist—since we’ve built a community there—I don’t really need it for my personal projects, which at this point mainly include my website, the one you're reading right now.</p>
<p>So, I thought, why not move it to an open-source Git forge backed by a non-profit organization? That's exactly what I did. The website is now hosted on Codeberg.</p>
<p>Unfortunately, as you might expect, these transitions come with some costs. Platforms like GitHub have invested heavily in providing a high level of convenience and free services, such as CI for open-source repositories. Losing those perks is frustrating, right?</p>
<p>On Codeberg, I have issues, pull requests, and a file explorer—but no CI. So, how am I going to continuously deploy my website on every commit to main? #shade</p>
<p>So my nerdy self couldn't resist and explored what a self-managed CI solution integrated with Codeberg would look like. This blog post is a documentation of the setup I came up with, which I expect to be useful to my future self, and also to anyone else who might be in the same boat.</p>
<h2 id="woodpecker-ci">Woodpecker CI</h2>
<p>One of the best aspects of open-source is that there are powerful alternatives for nearly everything. Codeberg recommends <a rel="external" href="https://woodpecker-ci.org">Woodpecker CI</a>, a robust CI solution written in Go. Sure, the UI might not be its strongest feature, but it gets the job done incredibly well. It even includes advanced features like auto-scaling, which might interest more experienced users.</p>
<p>Our setup will involve a publicly accessible server running the Woodpecker server, the Woodpecker agent, and CI workflows within Docker containers. Additionally, we’ll configure a reverse proxy to handle TLS termination with Let’s Encrypt certificates.</p>
<h2 id="installing-docker-on-the-host">Installing Docker on the Host</h2>
<p>Having obtained a server that's accessible via SSH, which in my case is one of the cheapest options from Hetzner with the x86_64 architecture and Ubuntu pre-installed, you can install Docker by following the <a rel="external" href="https://docs.docker.com/engine/install/ubuntu/">official documentation</a>. To verify that Docker is up and running, you can run the command:</p>
<pre><code>sudo docker run hello-world
</code></pre>
<p>The success of the command will indicate a successful installation.</p>
<blockquote>
<p>Note about the connection: You'll need to have SSH access to the server. In my case, I use VSCode's SSH capabilities not only to open a terminal session but also to edit files directly on the remote server.</p>
</blockquote>
<h2 id="creating-a-docker-compose-file">Creating a Docker Compose File</h2>
<p>To orchestrate the launching of all the services, we are going to use Docker Compose. Create a file at <code>/opt/woodpecker/docker-compose.yml</code> and add the following content:</p>
<pre><code>services:
 traefik:
 image: &quot;traefik:v3.1&quot;
 container_name: &quot;traefik&quot;
 command:
 - &quot;--log.level=TRACE&quot;
 - &quot;--api.insecure=true&quot;
 - &quot;--providers.docker=true&quot;
 - &quot;--providers.docker.exposedbydefault=true&quot;
 - &quot;--entryPoints.web.address=:80&quot;
 - &quot;--entryPoints.websecure.address=:443&quot;
 - &quot;--certificatesresolvers.ci.acme.httpchallenge=true&quot;
 - &quot;--certificatesresolvers.ci.acme.httpchallenge.entrypoint=web&quot;
 - &quot;--certificatesresolvers.ci.acme.email=postmaster@pepicrft.me&quot;
 - &quot;--certificatesresolvers.ci.acme.storage=/letsencrypt/acme.json&quot;
 ports:
 - &quot;443:443&quot;
 - &quot;80:80&quot;
 volumes:
 - &quot;./letsencrypt:/letsencrypt&quot;

 woodpecker-server:
 image: woodpeckerci/woodpecker-server:v2.7.1
 container_name: woodpecker-server
 ports:
 - 8000:8000
 labels:
 # Web secure
 - &quot;traefik.http.routers.woodpecker-secure.rule=Host(`ci.pepicrft.me`)&quot;
 - &quot;traefik.http.routers.woodpecker-secure.entrypoints=websecure&quot;
 - &quot;traefik.http.routers.woodpecker-secure.tls.certresolver=ci&quot;
 - &quot;traefik.http.routers.woodpecker-secure.tls=true&quot;
 - &quot;traefik.http.services.woodpecker-secure.loadbalancer.server.port=8000&quot;
 # Web
 - &quot;traefik.http.routers.woodpecker-http.rule=Host(`ci.pepicrft.me`)&quot;
 - &quot;traefik.http.routers.woodpecker-http.entrypoints=web&quot;
 - &quot;traefik.http.routers.woodpecker-http.middlewares=redirect-to-https&quot;
 # Redirect middleware
 - &quot;traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https&quot;
 volumes:
 - woodpecker-server-data:/var/lib/woodpecker/
 environment:
 - WOODPECKER_ADMIN=pepicrft
 - WOODPECKER_OPEN=true
 - WOODPECKER_HOST=https://ci.pepicrft.me
 - WOODPECKER_FORGEJO=true
 - WOODPECKER_FORGEJO_URL=https://codeberg.org
 - WOODPECKER_FORGEJO_CLIENT=client_id
 - WOODPECKER_FORGEJO_SECRET=secret
 - WOODPECKER_AGENT_SECRET=agent_secret
 - WOODPECKER_SERVER_ADDR=:8000

 woodpecker-agent:
 image: woodpeckerci/woodpecker-agent:latest
 command: agent
 restart: always
 depends_on:
 - woodpecker-server
 volumes:
 - woodpecker-agent-config:/etc/woodpecker
 - /var/run/docker.sock:/var/run/docker.sock
 environment:
 - WOODPECKER_SERVER=woodpecker-server:9000
 - WOODPECKER_AGENT_SECRET=agent_secret
 - WOODPECKER_MAX_WORKFLOWS=8
volumes:
 woodpecker-server-data:
 woodpecker-agent-config:
</code></pre>
<p>Now that we have three services, Traefik, Woodpecker Server, and Woodpecker Agent. Traefik acts as a reverse proxy and a TLS terminator for Woodpecker Server. One cool thing about Traefik is that the configuration can be passed through CLI arguments or Docker labels, which makes it super easy to manage the configuration of the services. Note that we are mounting the <code>/opt/woodpecker/letsencrypt</code> directory to store the Let's Encrypt certificates and reuse them across runs.</p>
<p>The second service is the Woodpecker Server. This one starts the HTTP service that orchestrates the CI/CD pipelines and provides a web interface to manage the workflows. In my case, I'm using Codeberg, which uses the Forgejo Git forge, but you can use GitLab, GitHub, and the handful of others available out there. To authenticate, you'll need to create an OAuth application in your Git forge account and use the client ID and secret in the <code>WOODPECKER_FORGEJO_CLIENT</code> and <code>WOODPECKER_FORGEJO_SECRET</code> environment variables. Or the respective ones for the other Git forges.</p>
<p>You'll also need to create an agent secret and use it in the <code>WOODPECKER_AGENT_SECRET</code> environment variable. You can do so by running the following command:</p>
<pre><code>openssl rand -base64 32
</code></pre>
<p>And last but not least, you'll need the agent service, which is the one that will run the CI/CD pipelines. Note in the environment variables that we are setting <code>WOODPECKER_SERVER</code> to instruct the agent to connect to the server we just started. And <code>WOODPECKER_MAX_WORKFLOWS</code> to limit the number of workflows that can run concurrently.</p>
<p>One thing that's important to call out is the following volume that we mount:</p>
<pre><code>- /var/run/docker.sock:/var/run/docker.sock
</code></pre>
<p>If your workflows don't need Docker, you can skip this volume. However, if you plan to use Docker from your workflows, you'll need to mount the Docker socket. In my case, I need it for the deployment pipelines because I'm deploying the website using OCI images built using Docker.</p>
<p><strong>Note</strong> that with that line you are escalating the permissions of the <code>woodpecker-agent</code> service to have access to the Docker socket, which runs on the host machine. So I'd recommend that you configure the workflows from branches opened by external contributors to require approval from maintainers before running the workflows.</p>
<h2 id="systemd-service">Systemd Service</h2>
<p>To run the services we just created, we can create a Systemd service. Create a file at <code>/etc/systemd/system/docker-compose@.service</code> and add the following content:</p>
<pre><code>[Unit]
Description=%i service with docker compose
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=true
WorkingDirectory=/opt/%i
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down

[Install]
WantedBy=default.target
</code></pre>
<p>The service will start the Docker Compose file we created at <code>/opt/%i/docker-compose.yml</code> and remove the containers when the service is stopped. Note that the systemd service is generic, which means you can use it with other Docker Compose files by just changing the directory.</p>
<p>To start the service, run the following command:</p>
<pre><code>sudo systemctl start docker-compose@woodpecker
</code></pre>
<p>And voilà! You should now have a fully functional CI/CD service running on your server.</p>
<h2 id="dns">DNS</h2>
<p>Remember to point a DNS A record to the Hetzner server's public IP address. In my case, that was <code>ci.pepicrft.me</code>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>If system APIs where awaitable</title>
      <link>https://pepicrft.me/blog/if-system-apis-were-awaitable/</link>
      <guid>https://pepicrft.me/blog/if-system-apis-were-awaitable/</guid>
      <pubDate>Fri, 25 Oct 2024 12:00:00 +0000</pubDate>
      <description>Swift’s async&#x2F;await concurrency is a game-changer, but to fully leverage it, foundational APIs need to be designed with concurrency in mind.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Swift’s async/await concurrency reminds me a lot of when a similar pattern was introduced in JavaScript. Syntactically, it was a game-changer, making the code much easier to reason about. But performance-wise, it didn’t meet the expectation that sprinkling async and await statements everywhere would make code faster.</p>
<p>Many APIs back then remained synchronous, wrapped or not in an awaitable promise—similar to how some Foundation APIs, like FileManager, are still synchronous today. Wrapping calls to FileManager in something awaitable doesn’t actually make a difference since FileManager will still block the system thread until it finishes. This means you can’t reuse that thread to do something else while FileManager is busy.</p>
<p>In other words, to truly take advantage of async/await, the underlying APIs need to be designed to leverage it. Otherwise, you’re just wrapping synchronous code, gaining syntactic benefits without performance improvements.</p>
<p>This is why we began replacing <a rel="external" href="https://developer.apple.com/documentation/foundation/filemanager">FileManager</a> with <a rel="external" href="https://swiftpackageindex.com/apple/swift-nio/">NIOFileSystem</a>, which is designed with concurrency in mind. Unfortunately, its design has some flaws that lead to worse performance than FileManager’s blocking API. Plus, it doesn’t shield consumers from the limited number of available handles.</p>
<p>I’d love to see Apple invest resources in revisiting foundational APIs, so code built on top of them can fully utilize hardware capabilities without requiring too much additional effort.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Concurrent work in non-concurrent brains</title>
      <link>https://pepicrft.me/blog/concurrent-brains/</link>
      <guid>https://pepicrft.me/blog/concurrent-brains/</guid>
      <pubDate>Sat, 19 Oct 2024 12:00:00 +0000</pubDate>
      <description>Trying to process concurrent tasks in a non-concurrent brain can be exhausting. Here&#x27;s how I manage it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've noticed that I often try to hold more in my mind than I can handle.</p>
<p>When I have an open PR waiting for review, I start working on something else, but that PR still lingers in my thoughts. If, while working on the new task, a Slack message comes through, I pause what I'm doing to respond, all while keeping track of the pause so I can return to it. If an idea pops into my head, I let it simmer for a bit. On days when I let my brain juggle multiple things like this, I end up feeling mentally exhausted.</p>
<p>So, what am I doing to manage this? I’m practicing holding fewer things in my mind by using a queue system. When I finish a task, like reviewing a PR, I add it to the queue. If a new idea comes up, I put it in a queue for later. If a support request comes in, I queue that as well. Instead of a single queue, I have multiple ones, and I allocate specific time slots for each. My email inbox is a queue that I only process once a day. The same goes for support issues and PRs. I don’t let them distract me throughout the day.</p>
<p>The downside to this approach is that it can feel like working on a production line—doing one thing after another until the day is over. What about the creative work our brains thrive on? I make sure to leave space for that too. The chain-like tasks are important but often not the most exciting. Creative work, on the other hand, is the most exciting but doesn't always have an immediate impact on the project at hand. Balancing these two types of work is key to maintaining my mental well-being, and I’m continuously working on finding that balance.</p>
<p>What about you? How do you manage your mental input and workload?</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Small but sexy</title>
      <link>https://pepicrft.me/blog/small-but-sexy/</link>
      <guid>https://pepicrft.me/blog/small-but-sexy/</guid>
      <pubDate>Sat, 19 Oct 2024 12:00:00 +0000</pubDate>
      <description>The tech industry is obsessed with hyper-growth, but at Tuist, we prioritize quality over quantity. We are committed to building a product that sparks joy, investing in design, and embracing simplicity. Our focus on standards and open-source contributions drives our long-term growth.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>When observing the tech industry today, one can't help but notice an obsession with hyper-growth. This trend is often fueled by the expectations of venture capitalists who seek high returns in a short timeframe. However, this obsession frequently leads to inferior products, where design decisions are driven by sales and marketing rather than user experience. It results in short-sighted technical choices that prioritize flashy, trendy technologies over battle-tested, future-proof standards.</p>
<p>Recently, I’ve examined the dashboards of various tools in our space and was astonished by the neglect evident in their design. They bombard users with banners urging upgrades to higher plans, overwhelming amounts of competing information, and a persistent push to contact sales. While I understand the need to generate revenue, such an obsession often sacrifices the craftsmanship of the product.</p>
<p>At <a rel="external" href="https://tuist.io">Tuist</a>, we refuse to compromise on quality. This commitment is deeply rooted in our principles. We prioritize creating a product that sparks joy, which is why we’ve invested in hiring a product designer, even within our limited budget. We believe that aesthetics are crucial for evoking positive emotions when using our tool. As a result, our growth may not match the rapid pace of other players in the industry, but that’s not our goal. We are focused on building for the long term, emphasizing slow and steady growth driven by product quality, our open-source contributions, and ongoing community support.</p>
<p>Our relationship with open source is genuine; it’s not merely a marketing strategy like brands paying influencers to promote their products. We are committed to leveraging open-source as a means to drive innovation in the industry, dedicating our time and resources to make it a reality.</p>
<p><strong>We are turning Tuist into a commercial business so that we can do more MIT open source for the Apple ecosystem.</strong></p>
<p>This mindset also shapes our technical decisions. As a small team, we recognize the need to keep our technology stack simple, as we cannot afford the complexity of maintaining a convoluted system. There’s a crucial distinction between a system that is inherently simple and one that merely appears simple because a third-party service manages the complexity. For this reason, we’ve chosen <a rel="external" href="https://elixir-lang.org">Elixir</a>, and we couldn’t be happier with our decision.</p>
<p>Embracing simplicity has significant advantages, particularly for our on-premise customers who need to self-host the server. The requirements are minimal: a server, a <a rel="external" href="https://www.postgresql.org">PostgreSQL</a> database, and S3 storage. If scaling is necessary, it’s as easy as adding more cores and memory to your instance. Furthermore, we prioritize standards across the board. Our stack doesn’t rely on a build tool; we write vanilla CSS and JavaScript—yes, no <a rel="external" href="https://tailwindcss.com">Tailwind</a>. This approach is liberating, as the web platform is designed for longevity, and we intend to leverage that durability.</p>
<p>Do we worry about breaking changes in <a rel="external" href="https://nextjs.org">Next.js</a>? Not at all. What about Tailwind or <a rel="external" href="https://www.typescriptlang.org">TypeScript</a>? We remain unconcerned. While others may spend time updating their toolchains, we focus on building useful features with our straightforward CSS and JavaScript. Our productivity has never been higher, and once we establish our design system using <a rel="external" href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components">web components</a>, creating new features in Tuist will feel as effortless as playing with LEGO.</p>
<p>Eventually, we plan to open-source our server, allowing you to contribute and extend it as you wish. We are steadily building momentum that will become unstoppable.</p>
<p>Will we reach every corner of the app development ecosystem? I doubt it. However, we will gradually convert teams into believers in our craft and contributors to a common vision that advances the industry. Will this take years? Absolutely—so what? We are designing our company to maximize momentum with minimal resources while ensuring that everyone involved in making Tuist possible enjoys the best professional experience of their lives as they build our product.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Brains are complex</title>
      <link>https://pepicrft.me/blog/brains-are-complex/</link>
      <guid>https://pepicrft.me/blog/brains-are-complex/</guid>
      <pubDate>Tue, 15 Oct 2024 12:00:00 +0000</pubDate>
      <description>In this blog post I reflect on the complexity of the brain and how I&#x27;m trying to be nice with mine.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Brains are complex. I don’t understand mine. I sometimes try to understand what it happens in it, and I can’t. It’s reaches limits, and that’s ok, so I’m trying to be nice with it.</p>
<p>Trying to find reasons why it sometimes feel exhausted is pointless. When it happens, I take breaks. Specially now, where as part of building <a rel="external" href="https://tuist.io">Tuist</a>, I feel I’m constantly switching between different areas of the brain.</p>
<p>When I’m responding emails, it puts my brain in a mode that’s not inspired to code. When I’m coding, it’s not inspired to be social. And if I force it, it’s not natural so I exhaust it and reach frustration. <em>Tricky, isn’t it?</em></p>
<p>Impostor syndrome invades me a lot too. I boycot myself. <em>What if Tuist doesn’t work? What if we don’t reach the point of financial sustainability that we are aspiring to have? What if we disappoint the organizations that are betting on us? What if I don’t have the mental clarity to pull this off?</em></p>
<p>And social networks don't help here. I'd isolate myself from the world and focus on the craft, which brings me a lot of joy, but <em>how would people know about Tuist?</em> But if I spend too much time in it, envy and comparison start to creep in. <em>Are we doing enough? Should we do more?</em></p>
<p>I don't have answers. But I know what makes my brain feel good, so I'm giving it what it needs. I enjoy creating things. I enjoy writing. I enjoy going for long walks. I enjoy sleeping a good siesta. So I'm prioritizing those things throughout my day, because otherwise, I'm not good to anyone.</p>
<p>Brains are complex, treat yours well. I didn't listen to mine for a long time, and it's time to change that.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Makers and takers</title>
      <link>https://pepicrft.me/blog/makers-and-takers/</link>
      <guid>https://pepicrft.me/blog/makers-and-takers/</guid>
      <pubDate>Sun, 13 Oct 2024 12:00:00 +0000</pubDate>
      <description>In this blog post I reflect on Dries Buytaert&#x27;s piece about balancing makers and takers in open source, and how it relates to Tuist.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I recently came across <a rel="external" href="https://dri.es/balancing-makers-and-takers-to-scale-and-sustain-open-source">this piece</a> by the creator of Drupal, <a rel="external" href="https://dri.es/about">Dries Buytaert</a>, and it helped me articulate, through mental models, how I've been thinking about open source sustainability.</p>
<p>Open source and free software are <strong>non-excludable</strong> and, contrary to what many believe, <strong>rivalrous</strong>—because the resources available to maintain and improve them are limited. This makes them a <a rel="external" href="https://en.wikipedia.org/wiki/Common_good">common good</a>, a concept I first encountered while reading the book <a rel="external" href="https://press.stripe.com/working-in-public">Working in Public</a>.</p>
<p>However, I hadn't fully realized that, from the perspective of open source companies like the one we are building at <a rel="external" href="https://tuist.io">Tuist</a>, open source is also rivalrous in another way: the shared resource is the <strong>customer</strong>, who cannot be shared by two companies at the same time.</p>
<p><strong>Tuist has become a common good.</strong> And like any common good, it began to experience the <a rel="external" href="https://en.wikipedia.org/wiki/Tragedy_of_the_commons">tragedy of the commons</a>—sustaining the project became increasingly difficult. When you reach that point, you must consider how to balance the makers and the takers. Otherwise, the project will die. This is something I’ve observed in many open source projects in the ecosystem where Tuist operates: they struggle to keep up with demand and slowly fade away.</p>
<p>In <a rel="external" href="https://dri.es/balancing-makers-and-takers-to-scale-and-sustain-open-source">his blog post</a>, and drawing on ideas from past research, Dries shares three patterns to address this issue, which we have considered at Tuist:</p>
<ol>
<li><strong>Self-governance:</strong> This is unfeasible at a large scale where many takers have conflicting interests. Making this work would require most of the limited resources available to be spent on governance. 2. <strong>Privatization:</strong> This is the approach we are currently exploring at Tuist, similar to what companies like Mozilla have done. Through our <a rel="external" href="https://docs.tuist.io/en/server/introduction/why-a-server">paid server features</a>, we gain a commercial advantage over takers, while still creating a positive social impact for all users of the open source project, including the takers. In other words, privatization allows for a win-win scenario. 3. <strong>Centralization:</strong> This approach mirrors how governments manage common goods (e.g., highways). In open source, we see this in foundations that govern projects. The challenge with this model lies in the accuracy of monitoring and the effectiveness of rewarding (or sanctioning). As Dries notes:</li>
</ol>
<blockquote>
<p>Because Open Source contribution comes in different forms, tracking and valuing Open Source contribution is a very difficult and expensive process, not to mention full of conflict. Running this centralized, government-like organization also needs to be paid for, and that can be its own challenge.</p>
</blockquote>
<p>It's reassuring to see that what we are experiencing at Tuist is not unique. The imbalance created by having more takers than makers is a common problem in open source, and there are ways to address it. We've discarded self-governance and centralization for now due to the costs involved. Instead, we are exploring privatization as a way to bring in funding to support continued open source development.</p>
<p>Not long ago, a new group of licenses emerged: <a rel="external" href="https://fair.io">fair</a>. These licenses look promising as a way to explore open-sourcing the innovations we are bringing to the server.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Monkey brain</title>
      <link>https://pepicrft.me/blog/monkey-brains/</link>
      <guid>https://pepicrft.me/blog/monkey-brains/</guid>
      <pubDate>Tue, 08 Oct 2024 12:00:00 +0000</pubDate>
      <description>My brain is juggling too many programming languages and paradigms. It&#x27;s time to focus on the essentials.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>The other day, while watching <a rel="external" href="https://www.youtube.com/watch?v=-cEn_83zRFw">a talk by DHH</a>, he mentioned a term that stuck with me: monkey brains. He used it to describe our brain’s limited capacity to hold multiple things at once and emphasized the importance of <strong>conceptually compressing complexities to reduce the mental load.</strong></p>
<p>Why bring this up? Because I think I’m stretching my brain to hold too many programming languages and paradigms. Over the past year, I’ve gone from being highly proficient in Swift to learning and familiarizing myself with <a rel="external" href="https://www.ruby-lang.org/en/">Ruby</a>, <a rel="external" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript">JavaScript</a> (in the context of <a rel="external" href="https://nodejs.org/en">Node.js</a>), and most recently, <a rel="external" href="https://elixir-lang.org">Elixir</a>. I’ve also explored <a rel="external" href="https://www.rust-lang.org">Rust</a> and, more recently, <a rel="external" href="https://ziglang.org">Zig</a>. There’s something valuable about staying informed—you gain new ideas and consolidate concepts across languages. For instance, many concepts in Swift are rooted in Rust, and learning Rust helps deepen your understanding of Swift. But this juggling act is becoming overwhelming for my "monkey brain."</p>
<p>What makes it especially draining is that much of my mental energy is now focused on understanding the complexities of building a company. I’m asking my brain to absorb information like it did 10 years ago, which often leads to days of mental exhaustion—a situation I’m not happy about. I need to become more comfortable <strong>focusing on the essential knowledge required to build the company, while maintaining a sense of curiosity without the pressure to master everything</strong>. It’s simply not feasible.</p>
<p>At the same time, <a rel="external" href="https://tuist.io">Tuist</a> has the potential to make a significant impact in the Swift ecosystem, particularly in developer tools and packages. With more focus, we could capitalize on that opportunity. For example, I want to create a design system for the CLI, which would elevate the Tuist user experience and lay the groundwork for other CLIs. Or I could dive into Swift’s concurrency updates and develop a resource that benefits both us and the broader community. Unfortunately, I haven’t been able to pursue these goals because I’ve been preoccupied with learning other technologies. It’s time for a change.</p>
<p>Moving forward, I’ll concentrate on three areas: building the company, Elixir, and Swift. Going deep in these areas will enable me to make meaningful contributions to Tuist.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Licenses, governance, and trademarks in the open-source world</title>
      <link>https://pepicrft.me/blog/oss-thoughts/</link>
      <guid>https://pepicrft.me/blog/oss-thoughts/</guid>
      <pubDate>Sat, 05 Oct 2024 12:00:00 +0000</pubDate>
      <description>I reflect on the recent WordPress and WP Engine controversy and how it relates to the open-source world.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>You might have heard about the recent <a rel="external" href="https://www.theverge.com/2024/10/2/24260158/automattic-demand-wp-engine-revenue-wordpress-battle">controversy</a> between WordPress and WP Engine. As someone who has gone through a small-scale version of that, I've been reflecting a lot on the case. My conclusion is that while there are aspects we could blame on <a rel="external" href="https://automattic.com">Automattic</a>, some of the blame, though fair, arises from misunderstandings about the open-source world. To grasp this fully, we need to talk about three key things: <em>licenses, trademarks, and governance.</em></p>
<h2 id="licenses">Licenses</h2>
<p>Licenses define what you can and cannot do with a piece of software. Some, like the <a rel="external" href="https://opensource.org/licenses/MIT">MIT</a>, <a rel="external" href="https://opensource.org/licenses/Apache-2.0">Apache 2.0</a>, or <a rel="external" href="https://opensource.org/licenses/GPL-3.0">GPL</a>, are approved by the <a rel="external" href="https://opensource.org/">Open Source Initiative</a>. Others, like the group of <a rel="external" href="https://fair.io">Fair Source</a> licenses, aren't, yet they remain equally valid and enforceable.</p>
<p>It's important to highlight three things:</p>
<ol>
<li>A license grants you rights over the code. 2. However, it <strong>doesn't give you the right to decide the project's direction</strong> (often misunderstood). 3. The existence of a trademark prevents you from using the project's name freely (often overlooked).</li>
</ol>
<p>Many conflicts stem from the mistaken belief that having rights over the software also grants rights over its direction, which is entirely incorrect. Companies and developers should remember that while disagreements over a project’s direction are inevitable, <strong>unlike with closed-source software, open-source projects allow you the freedom to fork the project and take it in the direction you desire.</strong> Though it's often easier to lobby maintainers to change their stance, it's not the only path. This is why companies like <a rel="external" href="https://shopify.com">Shopify</a> or <a rel="external" href="https://github.com">GitHub</a> ensure they have a voice in the direction of Ruby and Ruby on Rails or join foundations like the <a rel="external" href="https://shopify.engineering/shopify-rust-systems-programming">Rust Foundation</a>.</p>
<p>The world is diverse, and different developers and companies have different visions for a project, which is perfectly fine. Expecting a single direction to please everyone is utopian. Disagreements over the project’s direction are normal and valid, and expressing them publicly is encouraged. However, depending on the project's governance model, you might have more or less entitlement to influence its direction. Let's delve into governance.</p>
<h2 id="governance">Governance</h2>
<p>The governance of an open-source project refers to the rules and processes that define how decisions are made. Many projects lack formal governance, often resulting in the <a rel="external" href="https://en.wikipedia.org/wiki/Benevolent_dictatorship">benevolent dictator</a> model, where the project’s creator or a select group of maintainers have the final say. This is the model that <a rel="external" href="https://rubyonrails.org/2021/5/2/rails-governance">Rails follows</a>. I'm not here to debate which model is better, but I will say that the absence of governance is a problem and often the root of many conflicts.</p>
<p>At <a rel="external" href="https://tuist.io">Tuist</a>, we currently lack a formal governance model, so we implicitly follow the benevolent dictator approach. We are working to change that. Bitrise could have <a rel="external" href="https://bitrise.io/blog/post/tuist-bitrise-build-cache-update">publicly raised</a> concerns about our lack of governance, and that would have been a fair point. Due to this lack, they wrongly assumed our intentions:</p>
<blockquote>
<p>"The maintainers are showing more interest in extracting revenue from their community than in making decisions that are best for the project and its end users." — Zach Gray, Bitrise</p>
</blockquote>
<p>This is completely false. Our focus has always been on making the project sustainable. The work we've done, not only since committing the first line of code but even after that blog post, is a testament to our true incentives. We closed off some parts of the code to prevent an unsustainable imbalance they were unwilling to help us solve.</p>
<p>Here’s the thing: When you're just starting out, you don't spend time crafting the perfect governance model or considering the legal implications of your licenses and trademarks. But as your project grows and garners community value, you're inevitably drawn into capitalist dynamics you never wanted to be a part of. Suddenly, you need to learn and adapt to those dynamics quickly, with far fewer resources than the companies challenging you.</p>
<p>More democratic models are rare in open source. One exception is the Berlin-based Git forge <a rel="external" href="https://codeberg.org">Codeberg</a>, which has a non-profit foundation backing it, with a board that makes decisions. Anyone can join the board and vote on matters. But this is unique—most projects follow the benevolent dictator model, and that’s okay. While the dictator may act democratically at times, they still have the final say.</p>
<p>If having a say in a project’s direction matters to you, consider this when choosing open-source software. If not, accept the risks of misalignment. You can voice your concerns publicly and try to lobby for changes, but don’t expect maintainers to comply.</p>
<p>To summarize:</p>
<ol>
<li>Governance determines how decisions are made in a project. 2. The absence of governance usually implies a benevolent dictator model. 3. Pure democracy is rare in open source. Benevolent dictators may adopt some democratic practices, but they have the final say.</li>
</ol>
<h2 id="trademarks">Trademarks</h2>
<p>Lastly, let’s talk about trademarks. Open-source projects develop a brand around their name. It’s an intangible asset that represents the project’s values and quality. <strong>Registering it is essential to protect it from misuse.</strong></p>
<p>The creator of <a rel="external" href="https://docker.com">Docker</a> acknowledged the mistake of not registering the trademark earlier and took a different approach with <a rel="external" href="https://dagger.io">Dagger</a>, registering the trademark early and publishing <a rel="external" href="https://dagger.io/trademark-guidelines">guidelines</a> on its use. We did the same with Tuist. The Tuist trademark is owned by Tuist GmbH, and we’ve published <a rel="external" href="https://tuist.io/trademark-guidelines">guidelines</a> for its usage. Without these protections, anyone could use the Tuist name to create a fork, misleading users into thinking it was the official project, potentially damaging the project's reputation and years of work.</p>
<p>But note this: The trademark must be registered under a legal entity or person. If there’s no company or foundation behind the project, the creator must own it. The creator of WordPress initially registered it under his name, transferred it to the WordPress Foundation, and later granted rights to Automattic for commercialization.</p>
<p>Problems in this area often arise from the subjectivity around trademark usage. I can somewhat understand Matt's concerns about the WordPress trademark’s use by WP Engine. Based on his comments, it seems he had been in talks with them for over a year, expressing these concerns. This reminds me of conversations we had with Bitrise about Tuist's sustainability (we didn't have a trademark at the time). They forked Tuist, directed their customers to use it, and had full freedom to do so, misleading their customers into thinking it was the official project. Naturally, customers didn’t want to rely on a fork not maintained by the original team, and Bitrise didn’t want to work with us to make the project sustainable. It's a bit of the issue between Automattic and WP Engine but a small scale. Automattic wanted a share of WP Engine's revenue or more active contributions to the project, and we only wanted to make the project sustainable. We could have reached good terms, and they'd have benefited from partnering with us, and we'd have benefited from their contributions. And since they were not only unwilling to help us, but also marketed their service as much better than ours, we had to act to protect our project.</p>
<p>In my opinion, having a trademark is crucial. If you maintain an open-source project, I recommend registering the trademark under a legal entity or person as soon as the project gains traction. You'll thank me later.</p>
<p>To summarize:</p>
<ol>
<li>A trademark is an intangible asset that represents the project's values and quality. 2. Without it, misuse of the project’s name can harm its reputation. 3. The trademark owner controls its usage. 4. Guidelines for trademark use can be subjective, leading to conflicts.</li>
</ol>
<h2 id="closing-words">Closing Words</h2>
<p>Licenses, trademarks, and governance models are the three pillars of open-source projects.</p>
<p>As <strong>a maintainer</strong>, you shouldn't neglect any of them. Define these aspects early, communicate them clearly (where we could have done better at Tuist), and ensure they are respected. Most importantly, iterate on them as necessary, as the environment and the needs of your project evolve.</p>
<p>As <strong>a consumer of open-source software</strong>, define what matters most to you. Choose projects that align with your values. If direction matters to you, find a way to influence it. Often, in a benevolent dictator model, contributing actively can give you that influence. If you don’t care about the direction, accept the risks and costs of potential misalignment. You can voice your disagreement, but don’t expect maintainers to change their minds. Remember, you often only have entitlement to the code, not to the direction.</p>
<p>Finally, open source is still better than closed source. You may disagree with the direction of an open-source project, but you can fork and maintain it yourself. You can’t say the same about closed-source software—companies providing critical services can shut down anytime, and you won’t get access to the code.</p>
<p>In my view, we need more open source and more education and awareness around these topics.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>A non-concurrent design in a conrurrent world</title>
      <link>https://pepicrft.me/blog/non-concurrent-design-in-a-concurrent-world/</link>
      <guid>https://pepicrft.me/blog/non-concurrent-design-in-a-concurrent-world/</guid>
      <pubDate>Thu, 26 Sep 2024 12:00:00 +0000</pubDate>
      <description>I reflect on the complexity of Swift&#x27;s concurrency model and how it could have been avoided.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As you might know, concurrency is a hot topic in the Swift ecosystem. Everyone is trying to make their code "data-race safe". Thanks to <a rel="external" href="https://github.com/waltflanagan">Mike's</a> exceptional work enabling strict concurrency Tuist's main repositories, I haven't had the chance to tinker much with it as to form an opinion on it. Yet, when I see the discussions on Mastodon, the feeling that I get is that it's a complex topic that everyone is trying to figure out.</p>
<p>When I something complex, I like to go deep into understanding where the complexity comes from. Because only then I'll be able to make an informed decision on how to approach it. Through Erlang, I realized that a problem space with the right modelling can make layers of complexity disappear. Erlang does it through their concept of <a rel="external" href="https://www.erlang.org/doc/system/ref_man_processes.html">processes</a>. So my wonder with Swift and data-race safety was: <em>"Is its complexity avoidable?"</em></p>
<p>Swift is in a bit of an unfair position to make that avoidable. First, it had to reconcile Objective-C's OOP paradigm, which is known for embracing mutability, which is the culprit of data-races. Wouldn't it have been awesome if they didn't have to support compatibility with Objective-C? Definitively! But Apple and many developers couldn't have afforded that.</p>
<p>Moreover, Swift was pushed beyond the Apple ecosystem, more specifically to the server-side. Server-side applications are known to be highly-concurrent, which means, data-race issues become more apparent. This explains Apple's recent push for the actor model and structured concurrency, which you need to propagate the cancellation of work, when for example a request is cancelled. All this push makes sense when looked from the angle of Swift in the server-side, but from the perspective of an app developer, or in our case a CLI developer, it feels somewhat unnecessary.</p>
<p>Because Swift's origins had a strong focus on Apple platforms, not as highly concurrent as servers, some language design patterns were not optimized for concurrency. Erlang started with processes, and everything built from there. Imagine if Swift had started with a similar concept, and built all the frameworks on it. The story would have likely been different.</p>
<p>So Apple has done a great job navigating how the language has been evolving and reaching new environments. However, the debt is accumulating and taking shape in the form of language complexity. Or at least that's my perception. Perhaps in a few years, we'll all become that familiar with it, that it won't conceive it as complex anymore. This poses a very interesting question, somewhat philosophical about the future of Swift: <em>Is trying Swift to do too much?</em></p>
<p>I understand why Apple is trying to take Swift to many places. And it's quite impressive to see what the community is achieving with it. For example the <a rel="external" href="https://www.pointfree.co/">PointFree</a> folks coming up with patterns for cross-platform UIs, compiling <a rel="external" href="https://swiftwasm.org/">Swift to Wasm</a>, and potentially leveraging that soon for expanding Swift Macros, or running Swift on the server with projects like <a rel="external" href="https://vapor.codes/">Vapor</a> or <a rel="external" href="https://github.com/hummingbird-project/hummingbird">Hummingbird</a>. It's truly inspiring. Yet, I can't help but have a feeling that Apple is just partially supporting the idea that Swift can be a language for everything. I sense a bit of fear in involving the community more in the governance of the language and finding incentives to make it more community-driven. Some frameworks remain closed-source, and the language evolution is still very much driven by Apple's needs.</p>
<p>The question is, is Apple going to change that and throw themselves full into taking Swift everywhere? Or will we forever be in this let's try Swift here and there adding language features and needed without a big picture of how the language should evolve?</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The iPad as a creativity device</title>
      <link>https://pepicrft.me/blog/ipad/</link>
      <guid>https://pepicrft.me/blog/ipad/</guid>
      <pubDate>Thu, 19 Sep 2024 12:00:00 +0000</pubDate>
      <description>“I’d never thought that I could use my iPad beyond reading with it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As a kid, I used to paint a lot—mostly with oils. It was the one activity that could keep me still. Unfortunately, over time, I let it slip away, replaced by more logical pursuits like programming and my studies, which took over the space that creative work once held.</p>
<p>In an effort to balance building a company and coding with activities unrelated to work, I’ve recently returned to painting—this time, using an iPad. I was genuinely surprised by the power of these devices, which I had previously used only for reading. It once seemed almost pointless to own one, but now I understand why creatives gravitate toward it, and why Apple markets it to them. It’s a remarkably powerful and portable tool for creative expression.</p>
<p>I’m even considering exploring video editing with it, using some short clips I recorded in Berlin—just to see how far I can stretch my creativity. It feels like there’s a part of my brain that’s been dormant, waiting to be reawakened. There’s also something truly beautiful about engaging in these activities without any expectation of outcome, unlike coding, which has become more outcome-driven now that there’s a company to build. If there’s one thing I’ve learned, it’s that my mind thrives when it has room to roam. To code for the joy of coding, to paint for the joy of painting, to walk for the joy of walking...</p>
<p>Anyway, I’m on a flight to Madrid to attend NSSpain, and I thought I’d share some thoughts on iPads after spending some time drawing on mine.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>On taking shortcuts to build communities</title>
      <link>https://pepicrft.me/blog/communities/</link>
      <guid>https://pepicrft.me/blog/communities/</guid>
      <pubDate>Sun, 15 Sep 2024 12:00:00 +0000</pubDate>
      <description>This post is about building communities around products and how many companies take shortcuts by throwing money at the problem. It&#x27;s not about money, but about building for the community without expecting anything in return.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Many companies aspire to build communities around their products, as these communities are often formed by true believers—people who have intrinsic motivation to contribute, such as by evangelizing the product wherever they go. However, I’ve noticed that many companies, especially in the developer tooling space, attempt to take shortcuts by throwing money at the problem to build these communities. Things don’t work like that.</p>
<p><strong>Money can buy a false sense of community.</strong> People may gather because you send them freebies or because they follow what an influencer, paid by you, says about your product. But this engagement fades when the money stops flowing. Their motivation is purely extrinsic, and there’s nothing in your product that makes them stick around. You're just a sales-oriented company. If you truly cared about community, you’d build your company around it from the start, not the other way around.</p>
<p>Building a community takes time. It requires putting people first, being open to them, and involving them in how your product is shaped. Interestingly, involving them also brings a diversity of ideas, which can improve your product. It also means building for the community without expecting anything in return. Using your privileged position to commoditize the space reveals a lot about your values. When you care about advancing the ecosystem and inviting others to participate, everyone wins—the community, the ecosystem, and ultimately, you. But when you only focus on your own gain, greed may become your worst enemy, whether that happens down the road, or after you’ve exited or gone public and can claim you've succeeded.</p>
<p>Many challenges faced by tech organizations aren’t technical, but social. It’s not just about how big or crowded a market is or how feasible a technical solution might be, but about how willing you are to focus on your community and gain their trust by building for them without expecting anything in return. I’ve noticed that many companies aren’t willing to do this, and that’s why they fail in the long run. It’s inconceivable for them to do something without an immediate return.</p>
<p>And this doesn’t necessarily mean going open source. Look at <a rel="external" href="https://fly.io">Fly.io</a>—they offer incredibly valuable resources for free, which they create themselves, rather than paying for low-quality content like I’ve seen other companies do. They also hired and provided a safety net to maintainers of popular projects, like <a rel="external" href="https://www.phoenixframework.org/">Phoenix</a> in the <a rel="external" href="https://elixir-lang.org/">Elixir</a> ecosystem, indirectly supporting the community and the broader ecosystem. You can also earn a community’s respect and trust by betting on open standards instead of locking users into your product. This is especially important when building for developers, who understand the significance of standards and their role in the long-term health of the ecosystem. If your solution is walled off, developers might use it out of necessity, but sooner or later, someone will come along with a solution built on different values, and your entire platform could fall apart.</p>
<p>For seven years, we were privileged to have jobs while working on <a rel="external" href="https://tuist.io">Tuist</a> on the side. Our focus was on solving problems, advancing scalable app development, and building tools that others could build upon. Now, we are working on turning this into an open business that embraces the same values. It requires setting the right boundaries in certain areas, but if we get it right, we’ll continue building these tools while supporting the communities we serve. This isn’t about trying to dominate every corner of the app development space. It’s about building a healthy business that supports the communities we’re building for.</p>
<p>We are embedding seven years of open-source experience into how we’re shaping this company. Though our progress might be slow at first, we see this as a marathon. We’ll keep running and building for the long term.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The missing narrow waist in CI</title>
      <link>https://pepicrft.me/blog/ci-narrow-waist/</link>
      <guid>https://pepicrft.me/blog/ci-narrow-waist/</guid>
      <pubDate>Sun, 08 Sep 2024 12:00:00 +0000</pubDate>
      <description>It’s time for innovation to happen in the CI space through the narrow waist that Dagger brings to the table.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Did you notice how much development power CI companies have wasted on creating solutions that flood the market with nearly identical offerings? It’s a waste of talent that could have been directed toward innovation. The closest we’ve come to innovation—at least in the app development space—has been the concept of Mobile DevOps, if you can even call that innovation. In simple terms, they’ve attempted to create vendor lock-in through a proprietary automation layer built on a foundation of community steps, which developers have little incentive to maintain. It’s 2024, and the space is in desperate need of fresh ideas.</p>
<p>Remember the revolution that containers brought to the shipping industry? Suddenly, transportation methods adhered to a standard, allowing innovation at different layers. There are many examples of this on the internet, and the phenomenon is called the “narrow waist.” Narrow waists shift focus from redundant efforts to new forms of innovation.</p>
<p>What we are missing in automation is the equivalent of containers or narrow waists. Fortunately, <a rel="external" href="https://dagger.io">Dagger</a> is building just that. No more vendor lock-in through proprietary pipeline formats or walled-off automation experiences built into SaaS products. A brighter future for automation is on the horizon, and Tuist is betting on it.</p>
<p>Mobile DevOps? Free Automation Ops is better. It’s free because it gives organizations the freedom to choose and move across services with minimal costs. As a result, it forces existing CI providers to innovate. My guess is that many will fall victim to the sunk cost fallacy, throwing money at marketing their Mobile DevOps solutions. Good luck! We need to bring freedom back to organizations.</p>
<p>Dagger will not only be instrumental in gaining freedom but also in transitioning automation from languages like Ruby or bash scripts to languages such as Swift, Kotlin, or any other language of choice. Yes, you read that right: transitioning away from Fastlane is possible. Fastlane is fantastic, but when you blur the line between automation and CI—allowing workflows to run locally or remotely, as needed—the developer experience becomes truly magical. Developers will also have access to a community-driven ecosystem of steps from Dagger.</p>
<p>Tuist will enable Dagger pipelines to run in macOS environments, triggered by a CLI command or a GitHub event. It’s simple:</p>
<pre><code>tuist workflows run test –remote xcode-15
</code></pre>
<p>This command means: “Take my project, run the workflow in a remote environment with Xcode 15, and make it feel like it’s running locally by forwarding the standard pipeline events.”</p>
<p>Want to see a running build? Easy:</p>
<pre><code>tuist workflows logs 1234 –tail
</code></pre>
<p>There’s no need to build web-based terminal experiences when developers already spend their time in terminals.</p>
<p>In 2024 or early 2025, Xcode developers will be able to do this and choose a CI provider that maximizes their freedom.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>About mental health</title>
      <link>https://pepicrft.me/blog/about-mental-health/</link>
      <guid>https://pepicrft.me/blog/about-mental-health/</guid>
      <pubDate>Wed, 04 Sep 2024 12:00:00 +0000</pubDate>
      <description>This post is a follow-up on my previous post about mental health. I talk about how I&#x27;m trying to establish limits to protect my mental health and how that&#x27;s needed to build a healthy company.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It’s not the first time I’m talking about mental health, and it won’t be the last one. I do so to structure my thoughts and leave my story in the hope that people can avoid falling into the same traps that I did.</p>
<p>I’d describe my 20s as the decade of professional success: get a higher salary, climb the ladder, and get recognized in the industry. The dream was suddenly spoiled, and I was overwhelmed by many feelings. I was disappointed about the reality of the tech industry and how businesses work, which I hadn’t realized before. I also found myself with an identity toxically intertwined with my professional self. My work defined myself. Coding had evolved from a pure craft activity I loved into a tool to be recognized or successful in an industry filled with entrepreneurs and indie builders. I ought to be like them; I thought many times: work, work, work, and work. I made my health and the Pedro outside of work secondary. As bad as it sounds, I forgot about myself. <strong>I became addicated to working.</strong></p>
<p><a rel="external" href="https://hackingcapitalism.io/">“Hacking Capitalism”</a> by <a rel="external" href="https://krisnova.net/bio/">Kris Nóva</a> started to open my eyes. It helped me better understand capitalism and the tech industry and shift the focus toward myself and my passion for the craft. However, we needed to turn <a rel="external" href="https://tuist.io">Tuist</a> into something we could make a living off, so I inevitably threw myself into the industry I had come out disillusioned. On one side, I conceived it as an opportunity to codify its values and a healthier approach to doing business with technology, one that values openness and empowers both the people who use our tools and the people who make it possible. However, you still need to navigate the unfair practices of the industry: <em>people saying that you have no chance to succeed with two founders being technical, companies refusing to correspond to the value that they get through financial contributions, or feeling tiny against the giants that have endless streams of capital to outcompete you or take their privilege position to shit on you.</em> It has been challenging to navigate, but I learned something about it. <strong>Perhaps I’m still too connected to work?</strong></p>
<p>Another book further opened my eyes here. It’s called <a rel="external" href="https://www.penguin.co.uk/books/451795/technofeudalism-by-varoufakis-yanis/9781529926095">“Technofeudalism”</a> by <a rel="external" href="https://www.penguin.co.uk/authors/237985/yanis-varoufakis">Yanis Varoufakis</a>. It talks about the idea of cloud capital and how it tore down the walls that gave us freedom in this capitalistic world. The freedom to be someone else outside of work. The freedom to think without thinking about whether something should be posted. The freedom to take a nap without thinking about meetings. The freedom to have a timeless hobby. All of that is gone in this world that Technofeudalism is shaping, and I fell victim to that. This is not only due to the amount of thinking that went into work but also the peripheral X doom-scrolling and the ongoing feeling of having to work on my and Tuist’s brand to succeed in building a business. I succumbed to the cloud capital participating in it with my attention and time.</p>
<p>I think <strong>establishing limits there is needed for my mental health, and my mental health is, in fact, needed to build a healthy company</strong>, so I’m not doing either myself or Tuist a favor by trying to be always online and giving away investing in myself. So I started to change that. It won’t be easy because I have to revert to many patterns that I acquired over the years, but it’s a must-do to remain mentally healthy. I uninstalled Slack and removed my work email address from the phone. I’m also limiting my time on social channels and stopped using X. More and more, it’s becoming a very hostile environment. I like it in Mastodon, and while the reach of what we post there is smaller, I’m becoming comfortable with that. It’s not my role to capture people’s eyeballs with shiny posts on X, but to share humane stories that people can read at their own pace if they feel like it. This last thing aligns more with our values, but it feels odd having jumped on the Twitter and X train for many years.</p>
<p>I’m trying not to do things outside of work: resting, walking, or exercising. I’m reverting this idea that my life has to feel productive. I’m not a machine, and therefore, I shouldn’t treat myself like that. I have emotions, a complex brain that I need to take care of, a family to love and spend time with, and a life to live and enjoy instead of spending it jumping on the hamster wheels of becoming successful, whatever that means.</p>
<p>I want to live a simple life with the people I love. Really.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>An intrinsically motivated person in a extrinsically motivated environment</title>
      <link>https://pepicrft.me/blog/intrinsic-motivations/</link>
      <guid>https://pepicrft.me/blog/intrinsic-motivations/</guid>
      <pubDate>Sat, 24 Aug 2024 12:00:00 +0000</pubDate>
      <description>I admire Pieter Levels for focusing on what matters. My motivation is intrinsic, and while money is important, it’s not my sole goal.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Have you listened to Lex Fridman's <a rel="external" href="https://www.youtube.com/watch?v=oFtjKbXKqbg">most recent interview</a> with <a rel="external" href="https://x.com/levelsio">@levelsio</a>? If not, I’d recommend giving it a listen.</p>
<p>I've been following Pieter for some time, and I really appreciate his ability to cut through the noise and focus on what truly matters. This is a skill I find difficult to acquire, partly due to the many years I’ve spent perfecting software craftsmanship, which often leads me to <a rel="external" href="https://en.wikipedia.org/wiki/Analysis_paralysis">analysis paralysis</a>. You know, before you build that tech piece, you have to find the perfect technology, set up continuous integration, choose the right framework, and by the time you have everything set up, you've lost the motivation to build the actual product. I’ve been there many times, and if you’re a software craftsman like me, I’m sure you’ve experienced it too.</p>
<p>You can’t imagine how many times I’ve wondered if I should be more scrappy in my work, focusing on making money quickly and monetizing the skills I’ve acquired over the years. I even feel guilty at times for not doing so. Am I foolish or what, Pedro? You might be like those people who are always waiting for the perfect moment to start a business and capitalize on the frenzy of the ecosystem, because if you don’t, someone else will. All that open-source work I’ve done is great, but it doesn’t pay the bills. That’s a mental struggle I often go through, especially when I see indie hackers like Pieter Levels discussing their MRRs and how they’re making a living from their work.</p>
<p>But you know what? My conclusion is often the same: I’m not like them. <strong>My motivations are intrinsic</strong>, and this is something I can’t ignore. When I hear them talk about people as mere tools for making money, I can’t help but feel disgusted. I know we live in a capitalist society and money is important, but I view it as a result of the work I do in supporting others, not as the sole goal.</p>
<p>The best technologies we’ve seen were created by people who worked for fun and were intrinsically motivated: <a rel="external" href="https://www.linux.org">Linux</a>, <a rel="external" href="https://en.wikipedia.org/wiki/Git">Git</a>, <a rel="external" href="https://www.wikipedia.org">Wikipedia</a>, <a rel="external" href="https://ghost.org">Ghost</a>, <a rel="external" href="https://www.ruby-lang.org/en/">Ruby</a>, and many others. If you ask me, that’s the kind of technology I want to build—one that leaves a lasting impact on the world and inspires others to do the same. The challenge is achieving this in a world where we are increasingly selling the image that we should be obsessed with money and fame. Those who chase extrinsic motivations often find it has a unique momentum that can’t be stopped. Microsoft <a rel="external" href="https://en.wikipedia.org/wiki/Encarta">knows it well</a>.</p>
<p>So yeah, it’s tricky being an intrinsically motivated person in an extrinsically motivated environment, but the happiness of doing what you love is worth it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Open design</title>
      <link>https://pepicrft.me/blog/open-design/</link>
      <guid>https://pepicrft.me/blog/open-design/</guid>
      <pubDate>Tue, 20 Aug 2024 12:00:00 +0000</pubDate>
      <description>Working in the open fosters diverse ideas. At Tuist, we&#x27;re embracing open design and welcoming Asmit Malakannawar to help shape our vision.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've said it a few times: Working in the open is fantastic. You open yourself to diverse ideas you wouldn't otherwise have access to. Sadly, other ecosystems don't enjoy the foundational tools that we developers have access to, like GitHub or GitLab, which early on put the focus on making coding a social activity.</p>
<p>Ideas like code reviews through pull requests, which have a sophisticated diffing interface, or <code>LICENSE.md</code>, which makes it possible to bind contributions to a specific license, are rare in design. <a rel="external" href="https://www.figma.com/">Figma</a> and <a rel="external" href="https://www.pentpot.com/">Pentpot</a> are trying to lay out the pieces, but we still have some way to go. Imagine if designers built curricula through open design projects, which would be the counterpart to open source but in design. They could review each other's work before merging it into a "branch" (or the equivalent of that concept in design) and be able to license their work under a specific license.</p>
<p>We were eager to explore this idea in Tuist, so we joined some communities, and we were lucky to find <a rel="external" href="https://www.asmitbm.me/">Asmit Malakannawar</a>, who immediately connected with us, the ideas behind Tuist, and our vision for a fully open platform to extend the capabilities of native tools. Like us, Asmit turned out to be a huge advocate for open source. He is involved in the GNOME community, where he made significant contributions in the past. Marek and I could not believe we crossed paths with him, but this is the beauty of open source. You cross paths with very talented people who place a strong focus on the people and the craft, and they can impact the software in very distinct ways.</p>
<p>It's been a few weeks since he's taken on some ownership from us, exploring ideas that have been in our backlog for some time, and taking the lead design role in the Tuist project. As part of that work, we'll explore the idea of open design, make designs open under a permissive license so that anyone can use them, including developers who will be able to extend the platform in the future. We'll also contribute design-related pieces of technology to the Elixir ecosystem, which is a language we're passionate about. We want to inspire more designers to get involved in open source, and make our small contribution to making "open design" a reality.</p>
<p>I won't cease to repeat this: Being open, and balancing that with building a thriving business that can support working in the open, is a unique strength in a space where people have become secondary in how we do business. We are placing people at the forefront of our business, and inviting a diversity of ideas to give existing native tools the superpowers necessary to use them at scale.</p>
<p>Welcome, Asmit, to the team!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Fair Source: Sustainability with no customer risk</title>
      <link>https://pepicrft.me/blog/open-tuist/</link>
      <guid>https://pepicrft.me/blog/open-tuist/</guid>
      <pubDate>Tue, 13 Aug 2024 12:00:00 +0000</pubDate>
      <description>In this post, I explore the idea of a fully open Tuist platform.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As you might know, we aim to make <a rel="external" href="https://tuist.io">Tuist</a> a fully open project. A project with thriving businesses behind it that protects organizations' and developers' freedom and minimizes any risks when betting on us.</p>
<p>We achieve this by:</p>
<ol>
<li>Building on and embracing standards over proprietary formats. 2. Exposing and documenting programmatic interfaces so developers can access the data from Tuist's domain. 3. Opening the code that powers the platform.</li>
</ol>
<p>It sounds fantastic on paper, but in practice, 3. poses the most significant challenge. How do we prevent putting Tuist at risk?</p>
<p>Open Source and permissive licenses like <a rel="external" href="https://opensource.org/license/mit/">MIT</a> and <a rel="external" href="https://www.apache.org/licenses/LICENSE-2.0">Apache</a> bring freedom but don't protect the business. Companies can try to benefit from it in a predatory way without ensuring a healthy balance that benefits all stakeholders. They even dare to <a rel="external" href="https://bitrise.io/blog/post/tuist-bitrise-build-cache-update">go wild publicly</a> when you spoil their plans to protect Tuist.</p>
<p>Other organizations seek protection by adopting AGPLv3, which many companies have policies against, and selling dual licenses and enterprise features. Those businesses are often referred to as <a rel="external" href="https://en.wikipedia.org/wiki/Open-core_model">Open Core</a>. However, companies are still facing litigation risks, which we do not want for our customers. So what's the alternative?</p>
<p>I think the answer for Tuist is Sentry's new license concept: <a rel="external" href="https://fair.io/">Fair Source</a>, particularly their <a rel="external" href="https://fsl.software/">Functional Source License (FSL)</a>. The license beautifully strikes a good balance between the freedom of Open Source and the protection of the business.</p>
<p>The code is available (Customer freedom). You can check out the code, use it, extend it, contribute to it, and host it as long as you don't try to compete with the business (Business protection) so that the project can thrive and benefit everyone. And after two years, the code becomes MIT, so if the business dies, anyone can take it over and continue to thrive.</p>
<p>David Cramer puts it very well in his blog post <a rel="external" href="https://cra.mr/open-source-is-not-a-business-model">Open Source is not a Business Model</a>:</p>
<blockquote>
<p>"If they choose AGPL they’ll deter all but the most determined competitors, but given its a GPL-based license, it might also scare off certain customers. If they choose MIT they might as well rely on thoughts and prayers, as nothing protects them from predatory companies. So what do they do? Well, most of them choose Closed Source."</p>
</blockquote>
<p>So I think a fully open Tuist platform could unfold this way:</p>
<ul>
<li><strong>We expand our current narrow TAM.</strong> The milestone here will be releasing Tuist Workflows. This continuous integration blurs the line between CI/CD, a build system, and local and remote environments, opening Tuist up to many ecosystems. Swift will become the ecosystem where we started and the tool to enable the best developer experience of the Tuist platform. - <strong>We open the server code under FSL</strong> allowing companies to self-host and charge companies for hosting the software ourselves, which we'll be experts at.</li>
</ul>
<p>Not everything needs to be FSL. Some components like the Tuist CLI or technologies we'll develop to enable this vision can and will be MIT. They'll be our gifts to inspire others to build thriving open businesses.</p>
<p>Marek and I are still sleeping on these ideas, but we intend to make this happen. We can only build the best in class productivity platform if we embrace openness.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>DX vendor locking</title>
      <link>https://pepicrft.me/blog/dx-vendor-locking/</link>
      <guid>https://pepicrft.me/blog/dx-vendor-locking/</guid>
      <pubDate>Mon, 05 Aug 2024 12:00:00 +0000</pubDate>
      <description>In a world where companies are increasingly locking us into their ecosystems, it&#x27;s important to invest in tools and standards that allow us to craft software the way we want.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Today, many internet companies have taken control of our content and data, placing it behind paywalls and subscription models to lock us into their ecosystems. Our photos are in the cloud, our music is behind a Spotify subscription, and our photo editing tools are accessible only through Adobe Cloud services. Isn’t this peculiar, especially considering the increasing power of our hardware? It becomes even more concerning when they use our data to train AI models to further maximize their profits.</p>
<p>This pattern, which originated in the consumer space, has also infiltrated the developer tooling space. Companies argue that runtimes and ecosystems like JavaScript are too complex, so they create coupled abstractions for their services. Tasks that can be solved client-side are often pushed to the server to sell services. While some problems genuinely require server-side solutions, those that can be handled on the client side should be, in my opinion.</p>
<p>Need a database? Use a remote one we manage for you, with a CLI to interact with. Implementing authentication? There’s a remote service for that too. Running your app in the same environment as production? Use a proprietary runtime accessible through the company’s CLI. Want to avoid environment setup? Use the browser, and we’ll provide an environment for you.</p>
<p>This not only causes a loss of control over your data and content but also over your development experience, costs, and the ability to craft software offline. I can't subscribe to that model.</p>
<p>Elixir and Erlang might not be trendy, but they don’t create unnecessary complexity like JavaScript does with its “Complexity Abstraction As A Service” (CAAAS). Proprietary abstractions rarely claim to solve problems that can be easily addressed with a few lines of code in Elixir. Long-running server processes? Mainstream solutions suggest serverless, but serverless doesn’t handle background jobs well. So, there are additional services for that. You’d think production uses the same local NodeJS runtime, right? Not exactly; you need the platform’s proprietary environment. And the list goes on.</p>
<p>If this is the future of software development, I’m out. I’ll invest my time in learning and using tools and standards that allow me to craft software the way I want.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Where do I see myself in 10 years?</title>
      <link>https://pepicrft.me/blog/where-do-i-see-myself/</link>
      <guid>https://pepicrft.me/blog/where-do-i-see-myself/</guid>
      <pubDate>Mon, 05 Aug 2024 12:00:00 +0000</pubDate>
      <description>This blog post reflects on the importance of living a simple life and the impact of social media on our definition of success.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Where do I see myself in 10 years? That’s a question my therapist asked me a week ago. My answer was <strong>being healthy, living a simple life, and having a business where people feel inspired and creative.</strong></p>
<p>In recent years, I’ve learned through life circumstances that a simple life brings a peace of mind that’s priceless. This is hard because sometimes the environment pushes you to seek happiness through material possessions, but those, in the end, bring additional problems that I wouldn’t have had in the first place. For example, I wouldn’t have felt angry at Apple wanting to charge me €250 to fix an <a rel="external" href="https://www.apple.com/de/airpods-max/">AirPods Max</a> that they broke with a software update if I hadn’t bought them. Now I use old earphones with cables, and not only do they last longer, but I don’t have the responsibility of having to charge them. I don’t have a car, and I don’t plan to buy one. I fell into the trap of buying an <a rel="external" href="https://www.apple.com/watch/">Apple Watch</a>, and now I have to remember to charge it every night. I don’t know... life is simple, and we are pushed to make it more complicated. I think that complication puts us in mental exhaustion, which is the perfect ground for hyper-capitalists to keep pushing more stuff on us. Note that I say hyper-capitalists to differentiate from other forms of capitalism that bet on <a rel="external" href="https://www.europarl.europa.eu/topics/en/article/20151201STO05603/circular-economy-definition-importance-and-benefits">circular economies</a>.</p>
<p>I never felt the need to buy to show off. If I was lucky enough to get a bit of extra money through my work, I saved it or took my parents on holiday in return for all they invested in me over the years. Their happiness is priceless and something that I’d pay for endlessly.</p>
<p>When I scroll through X or <a rel="external" href="https://linkedin.com">LinkedIn</a>, a lot of what I see makes me allergic to those platforms. There is a definition of success based on how many impressions your publications got or how large your last round of investment was. They are pushing us to redefine happiness and success based on monetary and fame goals, and it’s very common to fall into that trap and pursue the same things, only to realize that you might end up being more miserable despite all those impressions of your posts. I feel allergic to that, but I must admit I fell into that a few times in the past. Those platforms were designed for that.</p>
<p>And now that we are <a rel="external" href="https://tuist.io">building a company</a>, it feels like rowing in a different direction, but it’s a lot of fun doing something based on our own intuition and definition of happiness. Companies build proprietary walls that we tear down. <a href="https://pepicrft.me/blog/where-do-i-see-myself/__GHOST_URL__/blog/2023/11/10/dear-bitrise">We make others angry</a> by protecting a piece of software to ensure every organization can continue using it for as long as they can. We step into established domains like CI with the energy to do things differently. We share what and how we do it because we’d like to inspire others to do the same and build trust through transparency.</p>
<p>So yeah, a simple and social life optimizing for fun is what I see myself doing in 10 years. And I’ll push away anything that tries to steer my life in a different direction.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Continuous releases with automated changelog generation</title>
      <link>https://pepicrft.me/blog/continuous-releases-with-automated-changelog-generation/</link>
      <guid>https://pepicrft.me/blog/continuous-releases-with-automated-changelog-generation/</guid>
      <pubDate>Sun, 04 Aug 2024 12:00:00 +0000</pubDate>
      <description>Automate the continuous release of releasable changes with git-cliff and CI.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As part of our work on <a rel="external" href="https://tuist.io">Tuist</a>, we open source small pieces of technology that aim to commoditize the development of Swift tools. An example of that is <a rel="external" href="https://github.com/tuist/xcodeproj">XcodeProj</a>. Because those projects are not actively worked on, it was important to have a process that would automate the release of new versions when releasable changes were merged.</p>
<p>To achieve that, I used a tool that I discovered recently through <a rel="external" href="https://mise.jdx.dev/">Mise</a>, <a rel="external" href="https://git-cliff.org/">git-cliff</a>, which automates the generation of changelogs based on the repository's local and remote history (e.g., GitHub pull requests). Once the tool is installed, something that you can achieve easily with Mise:</p>
<pre><code>[tools]
&quot;git-cliff&quot; = &quot;2.4.0&quot;
</code></pre>
<p>You can initialize it by running:</p>
<pre><code>git cliff --init github
</code></pre>
<p>The argument <code>github</code> instructs the initialization command to use the vendored GitHub template. You can check out <a rel="external" href="https://git-cliff.org/docs/usage/initializing">this list</a> of other templates. The command generates a <code>cliff.</code> <code>toml</code> with a default configuration, which in my case I left as is.</p>
<h2 id="the-workflow">The workflow</h2>
<p>We use GitHub Actions, so the first thing we'll need in the release workflow at <code>.github/workflows/release.yml</code> is the configuration to run for every commit in the <code>main</code> branch:</p>
<pre><code>on:
 push:
 branches:
 - main
</code></pre>
<p>As one of the first steps after checking out the repository, we'll need to check whether a release is necessary. We can do that by comparing the persisted <code>CHANGELOG.md</code>, which I had previously generated with <code>git cliff -o CHANGELOG.md</code>, and the one that would be generated with the bumped version, which I can obtain with <code>git cliff --bump</code>:</p>
<pre><code>- name: Check if there are releasable changes
 id: is-releasable
 run: |
 bumped_output=$(git cliff --bump)
 changelog_content=$(cat CHANGELOG.md)
 if [ &quot;${bumped_output}&quot; = &quot;${changelog_content}&quot; ]; then
 echo &quot;should-release=false&quot; &gt;&gt; $GITHUB_ENV
 else
 echo &quot;should-release=true&quot; &gt;&gt; $GITHUB_ENV
 fi
</code></pre>
<p>Note that I set <code>git.filter_unconventional = true</code> to only consider releasable those commits that follow the conventional commit format.</p>
<p>From there, we can obtain the next version (note that we skip if we shouldn't release):</p>
<pre><code>- name: Get next version
 id: next-version
 if: env.should-release == &#39;true&#39;
 env:
 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 run: echo &quot;NEXT_VERSION=$(git cliff --bumped-version)&quot; &gt;&gt; &quot;$GITHUB_OUTPUT&quot;
</code></pre>
<p>And the release notes:</p>
<pre><code>- name: Get release notes
 id: release-notes
 if: env.should-release == &#39;true&#39;
 env:
 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 run: |
 echo &quot;RELEASE_NOTES&lt;&gt; &quot;$GITHUB_OUTPUT&quot;
 git cliff --unreleased &gt;&gt; &quot;$GITHUB_OUTPUT&quot;
 echo &quot;EOF&quot; &gt;&gt; &quot;$GITHUB_OUTPUT&quot;
</code></pre>
<p>The remaining steps are just updating the <code>CHANGELOG.md</code>, committing the changes tagged with the version, pushing the changes upstream, and creating a release on GitHub.</p>
<pre><code>- name: Update CHANGELOG.md
 if: env.should-release == &#39;true&#39;
 env:
 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 run: git cliff --bump -o CHANGELOG.md
- name: Commit changes
 id: auto-commit-action
 uses: stefanzweifel/git-auto-commit-action@v5
 if: env.should-release == &#39;true&#39;
 with:
 commit_options: &#39;--allow-empty&#39;
 tagging_message: ${{ steps.next-version.outputs.NEXT_VERSION }}
 skip_dirty_check: true
 commit_message: &quot;[Release] Command ${{ steps.next-version.outputs.NEXT_VERSION }}&quot;
- name: Create GitHub Release
 uses: softprops/action-gh-release@v2
 if: env.should-release == &#39;true&#39;
 with:
 draft: false
 repository: tuist/Command
 name: ${{ steps.next-version.outputs.NEXT_VERSION }}
 tag_name: ${{ steps.next-version.outputs.NEXT_VERSION }}
 body: ${{ steps.changelog.outputs.CHANGELOG }}
 target_commitish: ${{ steps.auto-commit-action.outputs.commit_hash }}
</code></pre>
<p>I'm quite happy with the result, which you can check out completely <a rel="external" href="https://github.com/tuist/Command/blob/main/.github/workflows/command.yml">in this file</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Exploring commercial OSS</title>
      <link>https://pepicrft.me/blog/commercial-oss/</link>
      <guid>https://pepicrft.me/blog/commercial-oss/</guid>
      <pubDate>Fri, 02 Aug 2024 12:00:00 +0000</pubDate>
      <description>This post touches on the models we looked at to draw inspiration to make Tuist financially viable.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>How and when we can make Tuist fully open source end to end is an ongoing conversation between Marek and me. We conceive open source as a key element in building the best platform to create better apps faster. Open source is freedom; it’s diversity of ideas, it’s accountability, and it’s empowering others to explore new ideas. However, doing this while remaining financially viable is where the challenge lies. In this blog post, I’d like to share with you our learnings, the mental models that we built around sustainability in open source, and how we see the future of Tuist.</p>
<p>If your software has low packaging, distribution, and scaling costs, you’ll have a hard time building a source of revenue for the project—at least with an open-source license. Examples of those are CLIs or client-side desktop or mobile apps. Anyone can easily repackage your app and CLI and throw resources that you might not have into monetizing it. We’ve seen many examples of this, from storage solutions like <a rel="external" href="https://www.mongodb.com">MongoDB</a> to Tuist itself. It’s such a known thing that it’s gotten a name—being “Jeff’ed”—which comes from the idea of Jeff Bezos packaging your software and selling it as part of their cloud offering. I said earlier that this is a model that happens when the cost of scaling is low, but if you are an Amazon, that’s not really a problem because you have a large pool of resources to figure out scaling. They might be able to offer a better and cheaper solution, and there’s no way you can compete with them. Tuist was close to being Jeffed. Thanks to that, we learned an important lesson: companies can embrace this model without feeling any need to support the underlying pieces of technology. If this had happened at a different moment in the lifecycle of Tuist, we wouldn’t have minded, but at the time this happened, we were very limited in resources, which is something we were open to them about, and the additional bump in support and feature load would have put us at risk of burnout. So we had to put a pause on our idea of everything being open source.</p>
<p>There are some models to prevent this. Some embrace what’s called source available. They choose a license that’s not approved as an open source license by the <a rel="external" href="https://opensource.org/">Open Source Initiative</a>, like <a rel="external" href="https://blog.sentry.io/introducing-the-functional-source-license-freedom-without-free-riding/">Functional Source License</a> or <a rel="external" href="https://openpath.chadwhitacre.com/2024/the-historical-case-for-fair-source/">Fair Source</a>. The code is available in those cases, but the license limits what companies and developers can do with it, usually putting the focus on financially protecting the project. For example, <a rel="external" href="https://github.com/cirruslabs/tart/blob/main/LICENSE">Tart</a> limits the users that can use the license. I personally like the balance that this model achieves because small companies or indie developers can use it in their projects, but if they grow, which usually means they have financial resources to support the project, they can pay for another license. It’s called <a rel="external" href="https://fossa.com/blog/dual-licensing-models-explained/">dual licensing</a>. There’s one caveat to this model: you might get fewer contributions because you have to require developers to sign a contribution license agreement to own the rights of their contributions to be able to provide a dual license for that code. Those same rights can be used to even close the source code, change the license down the road, or sell those rights to another company. When using an open-source license and no CLA, in scenarios like those, the community has the freedom to fork the project and continue its development in a different direction and most likely under a different name. For example, when Terraform <a rel="external" href="https://www.hashicorp.com/blog/hashicorp-adopts-business-source-license">changed their license</a>, limiting the freedom of the software, a bunch of companies with the support of the Linux Foundation forked the project <a rel="external" href="https://opentofu.org/">under the name OpenTofu</a>.</p>
<p>Soon after being close to being Jeff’ed, we learned through the creator of Docker, <a rel="external" href="https://github.com/shykes">Solomon Hykes</a>, about the importance of trademarks. He mentioned in a podcast that we developers tend to put a strong focus on the license and forget about trademarks, despite this one playing a crucial role in situations like the one described above. When someone builds a project, there’s value in the code, but also in the brand that emerges and the community around it. Terraform and OpenTofu have a point in time in common, but the brand of the former might have more value and support, which the latter does not. That’s why when forks happen, they either happen with enough support from a big portion of the community and companies, or you are prone to have a difficult time promoting it. Imagine if AWS had to sell Redis under a different name. Do you think people will be more inclined to get it from there vs from the organization that created it? A brand is something that takes many years to build, and shortcuts with money don’t usually yield good results, especially if the people that you build for are developers.</p>
<p>We have a trademark now in Europe and the US, but we didn’t have one back then, so a company took the freedom to fork the tool and use the brand to market an integration from their service. An open conversation with them about our concerns went nowhere, so the question of whether trademark guidelines would have nudged this in a different direction remains. I have high doubts we’d have reached an agreement, but at least we could have pushed to stop using the Tuist name under their umbrella of services. In hindsight, I think close-sourcing part of the code was the right move. That was not an easy decision emotionally, but we felt it was the right thing to do, and I’m proud of the job we’ve done to navigate that and think about a future where we can go back to everything being open source.</p>
<p>There are open source projects that fit the above model and remain with a permissive license and in some cases no trademark. In those cases, maintainers have a full-time job at a company and treat working on open-source as a gift for a community that they do in their free time. I respect that model and admire maintainers that are able to do it sustainably, especially if the project is successful, because the maintainer’s limited attention and time are impossible to scale. Hence why there are many cases of burnout. And at the end of the day, the project itself also suffers because they tend to stagnate, often with the hope of not increasing more the load of requests the maintainers receive. Tools like Fastlane, Mise, or many Swift Packages fit into that model.</p>
<p>There are companies like <a rel="external" href="https://37signals.com">37Signals</a> that open source some of the tools that they develop internally to support the development of products that are not related to the tools they are open sourcing. For example, Ruby on Rails or the many utilities that the company open sources. I like this model. That open source is often a gift and is published with no strings attached. It’s a bit like we are doing well, and we are contributing some of our work to some commons for others to build businesses upon. However, the closed-source products miss the opportunity of bringing diversity of external contributions. I think it’s beautiful, but the more I familiarize myself with sustainability models, the more I realize that it might not be possible with all kinds of products. I’ll expand on this later on.</p>
<p>A different model, which is the one we are starting to embrace, is providing value from the server side. Because it comes with some costs and complexity of hosting and keeping up with the software updates, some companies will be inclined to pay, especially if the complexity of maintaining the service running is significant. An example of that is <a rel="external" href="https://cal.com">Cal.com</a>. Most people will pay for their hosted version because they are not developers and most likely don’t know how to self-host. The ones that do know, and that’s ok. You might think that they are not contributing back, or at least financially, but there’s a chance that they do so through code. They sometimes also become evangelists of your software, which is an excellent marketing tool. Some projects extend this model with some features that are released under a paid license. Those are usually the ones that large enterprises need. They also do dual licensing for companies that have strict policies against copyleft licenses like <a rel="external" href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPL3.0</a>. However, do note that hosting AGPL3.0 software on your server is entirely compliant with the license. An Amazon could still take a service, host it, and sell it, but without owning a trademark, that’s a very unlikely thing to happen because they’d need to make a huge effort to understand software that they are not maintainers of and market it under a different name.</p>
<p>The challenge with the above model is that if your market is small, and it’s mostly developers, then you can find many companies, especially the ones outside of the US, that are willing to take the little risk of hosting AGPL3.0 software on their servers, and some are willing to go even further and self-host the pieces that are under a different license. At the end of the day, it’s impossible for you as the creator of the software to know if something like that is happening, and even if you knew, would you go the legal path against a small random company somewhere in the world? Cal.com can afford this because their market is huge, but ours is small still, so doing something like that will slow down reaching financial viability and be detrimental to the product. There are products like <a rel="external" href="https://supabase.com">Supabase</a> that can afford that, even if they haven’t captured a big chunk of the market yet because their value of the software lies also in the complexity of scaling a database. In our case, the value at the moment is mostly on the client, so until we have more value on the server and some complexities or enterprise features that make the product compelling to pay for, I doubt we’ll make the server open source. We believe we can get there, but it’s a matter of time to do that shift in value. What we know for sure is that we are not going to introduce complexity for the sake of making paying for Tuist compelling. For instance, once we step into the continuous integration space with Tuist Workflow, that might change the story. We could become the first CI service for app developers that’s open source, and the complexities associated to that are worth having company dealing with them. Note though that there are projects like <a rel="external" href="https://yunohost.org/">YunoHost</a> or <a rel="external" href="https://www.cloudron.io/">Cloudron</a> that make the installation of services like GitLab, that are in theory complex to run and update, a one-click action, so I believe having a few features for large enterprises under a different license will be key too.</p>
<p>We discarded other models like Pointfree’s of selling courses. We’ve learned a lot about Xcode and Xcode projects and that’s certainly a sellable thing, but we find joy in building a useful platform, so we went this path instead. Along the journey we’ve been open-sourcing, and we’ll continue to do so, MIT-licensed gifts to lift innovation at a layer above the layers that are common across similar businesses out there so that we don’t waste time building proprietary technologies in silos.</p>
<p>We see in 5 years an open-source <a rel="external" href="https://vercel.com">Vercel</a> or an <a rel="external" href="https://expo.com">Expo</a> that bets on standards to support teams in the journey of turning an idea into something that they can share with people (not users). It’s a matter of shifting value to the server and expanding the market that we can open source everything. Can’t wait!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>What is urgent?</title>
      <link>https://pepicrft.me/blog/what-is-urgent/</link>
      <guid>https://pepicrft.me/blog/what-is-urgent/</guid>
      <pubDate>Wed, 31 Jul 2024 12:00:00 +0000</pubDate>
      <description>With many things competing for our attention, what is truly urgent?</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Over the years of being embedded in the tech industry, I've noticed that the meaning of urgency is morphing and is being used as a tool to capture our attention. And I think I've been a victim of this.</p>
<p><strong>Everything feels urgent:</strong> that message on my WhatsApp, the email I just received, or those RSS updates I need to go through. If everything competes to be urgent, what is truly urgent?</p>
<p>I sometimes feel as if a concurrent world of urgencies were competing for my parallel mental processing. For non-tech-savvy people, concurrency and parallelism <a rel="external" href="https://www.geeksforgeeks.org/difference-between-concurrency-and-parallelism/">are not the same thing</a>. I jump from one thing to another, considering everything urgent, and ending up exhausted at the end of the day. I think it's normal, considering those jumps are sometimes between non-related domains.</p>
<p>I did not realize my tendency to consider many things urgent and my consequential mental exhaustion. I've been thinking about it for some time, but with the building of the company, I'm noticing I have to get better at identifying where the urgency lays, if any, and how to deal with it.</p>
<p>Suppose you wonder <strong>how it manifests.</strong> I can have the mail application closed, but it feels uncomfortable because I do so with the feeling that something urgent might come up. Or some message shows up from a person seeking support, and I feel like stopping what I'm doing to provide help. Or I have some spare time, filling it with checking social channels just in case something worth my attention is happening. Is it an addiction? Maybe? It's as if my brain was constantly alert, waiting for the next urgent thing. It's exhausting.</p>
<p>Brains are damn difficult to understand.</p>
<p>And to make matters worse, I'm terrible at establishing systems or processes. My brain is a bit chaotic, and I think some of my creativity is rooted in that chaos. In the connections that emerge from there. However, the mix is dangerous if you combine that with the constant feeling of urgency.</p>
<p>So, despite how comfortable it might feel, I'll try to establish some system, both at work and at the personal level. First, I'll treat the stream of things as a queue, where the focus is not on the urgency (or the importance) of something but on whether it is well-categorized. Then, I'll devote the last 30 minutes to review, assign urgency and importance, and plan my next day based on that. This one step is the one I need to build a routine around.</p>
<p>If something comes up during the day, I'll resist jumping into it and instead add it to the queue. Then, review it at the end of the day and repeat the process. And I'll establish a boundary between work and personal life:</p>
<ul>
<li><strong>Work:</strong> Slack, GitHub, Desktop Mail - <strong>Personal:</strong> Telegram, WhatsApp, iPhone Mail, In-person</li>
</ul>
<p>I used to have work things on my phone, but that blurred the line between work and personal life in a way that was not healthy for me or the company.</p>
<p>Will this work? It will if I commit to building the habit and stick to it. Whether I'll be able to commit is a whole different story, but let's talk about that in a future blog post.</p>
<p><strong>If you are going through <strong>some mental struggles or learning</strong> about mental health and want to chat, I'm always up for it. Just reach out.</strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Openness as a tool of trust</title>
      <link>https://pepicrft.me/blog/openness-as-a-tool-of-trust/</link>
      <guid>https://pepicrft.me/blog/openness-as-a-tool-of-trust/</guid>
      <pubDate>Mon, 22 Jul 2024 12:00:00 +0000</pubDate>
      <description>A healthy relationship with technology is possible if we embrace openness.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>While reading a chapter about media in the book <a rel="external" href="https://www.theschooloflife.com/shop/how-to-survive-the-modern-world/">"How to Survive the modern world"</a>, and in particular a chapter on the role of newspapers, I couldn't avoid but think of the similar role that technology plays in our lives.</p>
<p>As newspapers developed, they took the role that centuries before letters. Letters served as a tool between royal courts and the distant parts of their kingdom to send information to be acted upon (e.g., grain shortage). Newspapers took this role and expanded it to the general public. When reaching someone's doorstep in the morning, much of this information was liable to feel urgent and alarming. This led to a paradoxical state of mind in modern democratic states: one is at once extremely well-informed, deeply exercised–and completely powerless.</p>
<p>The sense of urgency and alarm that newspapers brought to the general public and the need to feel informed and up-to-date with the latest news became the perfect channel between governments and the public to share their views and influence public opinion. The public expected them to be impartial and objective–an accountability tool for the government. However, as history has proven in many countries, like Spain, they can be easily manipulated, leading to societies losing trust in both the media and the government. But what's the solution?</p>
<p>We see <strong>similar patterns when we look at the tech industry</strong>, which is the result of technology embedded in capitalism. Through stories, we've been told about aspirations where technology will save us from our problems or make our lives easier. It became the modern newspaper that also made us well-connected and informed, yet with the same powerlessness. We were convinced that every problem should be solved with technology and were forced to trust the people behind it to make the right decisions. We put our privacy aside (except for the Germans), and we gave them our data to make our lives easier. We put all our photos and documents in unlimited cloud storage. We traded our free time in our pursuit of feeding the algorithms with reactions or content. Being a content creator was the new cool thing.</p>
<p>And we ended up in the same situation as with newspapers. <strong>Sooner or later, they can't hide the power structures and the real interests behind them</strong>. The interest of a few people who want to become wealthier and more powerful at any cost, whether they are politicians or <a rel="external" href="https://a16z.com/the-techno-optimist-manifesto/">techno optimists</a> (e/acc). They can go as far as <a rel="external" href="https://interface.media/blog/2024/05/21/ai-is-undermining-microsofts-sustainability-goals/">postponing sustainability plans</a>, <a rel="external" href="https://www.shopify.com/news/important-team-and-business-changes">laying off workers</a> to increase market value, <a rel="external" href="https://futurism.com/the-byte/ai-gig-slave-labor">using slave labor</a> to fine-tune their AI models, building the <a rel="external" href="https://en.wikipedia.org/wiki/Cryptocurrency">largest pyramid scheme</a> in history, or laying out an echo chamber that <a rel="external" href="https://www.amnesty.org/en/latest/news/2022/09/myanmar-facebooks-systems-promoted-violence-against-rohingya-meta-owes-reparations-new-report/">leads to civil wars</a>.</p>
<p>I don't know about you, but I have low trust in many technology organizations and leaders, such as newspapers and politicians. The loss of trust grew as I gained perspective on the industry after <a rel="external" href="https://www.shopify.com/news/important-team-and-business-changes">Shopify's move after some of my colleagues started to form a union</a>. When I looked around, I noticed the number of proprietary technologies, hyper-growth companies, the lack of transparency in the industry, and the ongoing re-shaping of the story to keep us engaged, from the metaverse to the AI through the blockchain. Connected to the Internet, but more exhausted than ever. Something is terribly wrong. I want a technology that's closer to how <a rel="external" href="https://en.wikipedia.org/wiki/Aaron_Swartz">Aaron Swartz</a> <a rel="external" href="https://en.wikipedia.org/wiki/Guerilla_Open_Access_Manifesto">envisioned it</a>. We need to stop this.</p>
<p>We might feel powerless in front of these giants. But I strongly believe there's one tool that can help steer the ship in the right direction: openness. When a government or a business is open about its decisions and actions and builds solutions that are also open in nature, we can build trust through transparency and not through the words of a PR department or a newspaper. We'd still rely on them telling the truth, but we'd tear down the walls to make them accountable for their actions. We wouldn't rely on institutions realizing that damage is serious and worth reporting. If Meta had shaped their systems in the open, a public debate would have surfaced that what they were doing would have caused a lot of harm. They could have connected us without making us more individualist, polarized, and addicted. Who knows, maybe Twitter wouldn't be the shitshow it is today, where a clown does whatever he wants.</p>
<p>Moreover, openness has the power to attract communities of people to build wonderful technology. Look at <a rel="external" href="https://en.wikipedia.org/wiki/Linux">Linux</a>, <a rel="external" href="https://wordpress.com/">Wodpress</a>, <a rel="external" href="https://www.wikipedia.org/">Wikipedia</a>, <a rel="external" href="https://ghost.org/">Ghost</a>, <a rel="external" href="https://plausible.io/">Plausible</a>, <a rel="external" href="https://codeberg.org/">Codeberg</a>. Suddenly Microsoft, and many others are interested in open-source, yet do little to support the most critical pieces of today's infrastructure. There's something beautiful in the idea of a community of people building something together, where everyone can contribute and benefit from it. That's why Marek and I don't believe <a rel="external" href="https://tuist.io">Tuist</a> is a traditional company. We want it to be an open and calm company with a community of people who share the same values and want to build something great together.</p>
<p>I made openness and the usage of standards requirements when choosing the tools I use these days. I still have a long way to go, but I'm happy with the progress I've made. I can right away recognize which tools I'd rather stay away from. For example, you won't see me something like <a rel="external" href="https://www.notion.so/">Notion</a>. Or I'm migrating from <a rel="external" href="https://www.figma.com/">Figma</a> to <a rel="external" href="https://penpot.app/">Penpot</a>.</p>
<p>I gave governments and technologies my trust, and they failed me. It's my turn to take it back and put it in the hands of the people who deserve it. I believe healthier, long-lasting, and human technology is possible if we embrace openness, both as a consumer and as a producer. And I'm going to do my best to make it happen.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How synchronized groups work at the .pbxproj level</title>
      <link>https://pepicrft.me/blog/how-synchronized-groups-work-at-the-pbxproj-level/</link>
      <guid>https://pepicrft.me/blog/how-synchronized-groups-work-at-the-pbxproj-level/</guid>
      <pubDate>Sat, 20 Jul 2024 12:00:00 +0000</pubDate>
      <description>Learn about the new PBXObject types introduced in Xcode 16 to support synchronized groups.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I started working on <a rel="external" href="https://github.com/tuist/XcodeProj/pull/827">supporting Xcode 16's features</a> in <a rel="external" href="https://github.com/tuist/xcodeproj">XcodeProj</a>. One of those features is internal <em>"synchronized groups"</em>, which Apple introduced to minimize git conflicts in Xcode projects. In a nutshell, they replace many references to files in the file system with a reference to a folder containing a set of files that are part of a target. Xcode dynamically synchronizes the files, hence the name, in the same way packages are synchronized when needed.</p>
<p>I'm excited about it because it addresses an issue that has remained unaddressed for many years and that motivated many people to adopt <a rel="external" href="https://tuist.io">Tuist</a> or SPM as a project manager. However, I wonder if adding more dynamically-resolved features, like the resolution of packages,</p>
<p>Whether that'll lead to the best developer experience is something we'll see down the road, but that's not the point of this blog post.</p>
<p>If you wonder what the changes mean at the <code>.pbxproj</code> file level, a format I got very familiar with thanks to my work on Tuist, here's an overview of what I learned today. Groups can now have a child of type <code>PBXFileSystemSynchronizedRootGroup</code>. They reference a folder whose files will be automatically synced and tied to a target. For example, there are a bunch of Swift source files. In the example below, that folder is <code>Frameworks</code>, relative to the parent containing this group:</p>
<pre><code>/* Begin PBXFileSystemSynchronizedRootGroup section */
		6C14E0CA2C4BC30C00635BF3 /* Framework */ = {
 isa = PBXFileSystemSynchronizedRootGroup; 
 exceptions = (6C14E0E62C4BC38800635BF3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); 
 explicitFileTypes = {}; 
 explicitFolders = (); 
 path = Framework; 
 sourceTree = &quot;&quot;; 
 };
/* End PBXFileSystemSynchronizedRootGroup section */
</code></pre>
<p>The glue between that object and the targets happens in the new <code>fileSystemSynchronizedGroups</code> property of the <code>PBXTarget</code> object.</p>
<p>Then Apple also introduced another object, <code>PBXFileSystemSynchronizedBuildFileExceptionSet</code>, which is used to provide "exceptions." Those exceptions are used for three things, and maybe others that I'm yet to uncover:</p>
<ul>
<li>Filtering out certain files and folders. - Overriding the default file type. - Configuring the type visibility.</li>
</ul>
<p>Those are the only two models that are needed to enable this functionality. Once we land this feature in XcoeProj, I'll explore what the API could look like in Tuist for users who want to opt into it, although the value is not that significative in this case since git conflicts are not that much of an issue in Tuist land.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The specified item could not be found in the keychain</title>
      <link>https://pepicrft.me/blog/keychain-item-not-found/</link>
      <guid>https://pepicrft.me/blog/keychain-item-not-found/</guid>
      <pubDate>Sat, 20 Jul 2024 12:00:00 +0000</pubDate>
      <description>Fix the not found keychain item issue by making the keychain the system default</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Trying to <code>codesign</code> a macOS CLI on CI using certificates in a temporary keychain yielded the following error:</p>
<pre><code>The specified item could not be found in the keychain
</code></pre>
<p>It turns out that even when passing the keychain with flags like <code>--keychain</code>, if the keychain is not made the default one, it fails. Therefore, I ended up making it the default:</p>
<pre><code>security create-keychain -p $KEYCHAIN_PASSWORD $TMP_KEYCHAIN_PATH
security default-keychain -s $TMP_KEYCHAIN_PATH
security import $CERTIFICATE_PATH -P $CERTIFICATE_PASSWORD -A
</code></pre>
<p>So, this blog post is a note for my future self because I'm sure I'll come across this again. Or perhaps for anyone coming across the same issue.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The best products tell stories</title>
      <link>https://pepicrft.me/blog/best-products-tell-stories/</link>
      <guid>https://pepicrft.me/blog/best-products-tell-stories/</guid>
      <pubDate>Mon, 15 Jul 2024 12:00:00 +0000</pubDate>
      <description>In this blog post I share how stories help people connect with the products they use.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As part of our work in <a rel="external" href="https://tuist.io">Tuist</a>, we have to put a lot of thinking into how the Tuist is presented as a product. As developers, we might think that it's just a matter of solving a problem or a bunch of problems, and putting them under an umbrella name along with documentation and a website. However, when I think of the products that I love and use every day, all of them have something in common: <em>they tell stories.</em></p>
<p>Humans love stories. Stories bring us together. Capitalism, democracy, and religion are all stories that we tell ourselves. We need stories to identify ourselves with, and developer tools are no exception.</p>
<p>But what's Tuist story you might wonder? At first, Tuist was a solution to a problem: <em>Xcode projects are hard to maintain</em>. We didn't have a story back then, but organizations felt so much pain working with Xcode, that the pain led to the adoption of Tuist. And we kept adding on top of that, so as you can imagine, the story was not clear. <em>What is Tuist?</em> A project generator? A project generator and a Fastlane? A CLI for automation? A tool to optimize the development experience?</p>
<p>When there's no story, or the story is not clear, people don't know how to identify themselves with the product. Note that I prefer to talk about people and not users because the term users dehumanizes the relationship between the product and the people using it.</p>
<p>So for the past few months, I've been thinking about what the story of Tuist should be, and I'm starting to see it. The common denominator of all the features we've been adding is that <strong>we want to make developers happier and more productive.</strong> We believe this leads to better apps. We also believe there's a possibility to take this to other platforms, but as of today, that feels more like a new chapter in the story.</p>
<p>But "happiness" and "productivity" feel too abstract. I'm already happy with my Xcode project. I don't need you. It's very natural to feel that way. Hence why we are presenting it as something developers are familiar with. We aim to become a virtual platform team. Or like the AI jargon likes to say: a copilot.</p>
<p>But that's not enough. By talking about platform teams, developers might have a vague idea of the role that Tuist plays, but how do you present the features? Are you going to say that you are just providing tools X, Y, and Z where X, Y, and Z are just some random marketing names that you came up with but that mean nothing to the developer? That doesn't sound like a good idea.</p>
<p>It's already an effort for developers to understand what a virtual platform team means, so we shouldn't add to that. Therefore, we are going to build on stories and mental models that developers are already familiar with. We are going to use the same terminology that developers use, and place them in various phases of the app development lifecycle: <strong>start, build, share, and measure.</strong></p>
<p>You don't need to explain what those are. Every developer, even non-Apple developers should be familiar with them. Tuist is just integrating into mental models to increase the level of happiness and productivity.</p>
<p>So we are currently in the process of iterating in the story or coming up with one since I wouldn't say we had a well-defined one before. And going forward, we are going to make sure we treat it as a dynamic organism that evolves with the product and the people using it. I'm very excited about this new chapter, and all the possibilities that it opens up.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Does it need to be in JavaScript?</title>
      <link>https://pepicrft.me/blog/does-it-need-to-be-in-js/</link>
      <guid>https://pepicrft.me/blog/does-it-need-to-be-in-js/</guid>
      <pubDate>Sat, 13 Jul 2024 12:00:00 +0000</pubDate>
      <description>Is JavaScript necessary to enable atomic and reusable components on the web?</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I believe the reason why React and the many JS-based UI paradigms became so popular is because they brought closer markup, style, and behavior making components an atomic and shareable unit of composition. It’s unquestionable that it’s a mental model that developers like, so much, that other technologies started introducing the idea of components.</p>
<p>Similarly, Tailwind enabled the portability of styled components. And developers loved that. So much, so that it’s rare to see a UI tool kit or design system that’s not built on Tailwind. Developers prefer to learn the semantics of an abstraction, instead of the semantics of the underlying standard. It’s bizarre when you think of it, but portability is key, and it’s becoming even more apparent with all those AI tools that generate a website for you.</p>
<p>The problem with it is that if your stack is not JS, you feel left out. Developers find themselves having to decide between having access to that ecosystem of paradigms and reusable component kits at the cost of adding a JavaScript runtime to their stack, or not adding any JavaScript runtime and having limited access to resources and DX. Many end up leading on the former, which often also means building an SPA, and you know all the implications that come with it. The cost is high.</p>
<p>For some time I've been thinking about whether JavaScript is required to enable that experience, or if it was more of an accidental implementation detail because React started with a focus on the client (browser) where a JavaScript runtime is available by default. The more I thought about it, the more it became clear that it's very likely an accidental implementation detail. At the end of the day, those technologies are functions from components and data to HTML, CSS, and JS (or Wasm). So why not have the compiler in let's say Rust, with bindings for the many languages and runtimes with popular web frameworks like Ruby, Python, and Elixir? I believe pushing the solution one level down and making it runtime-agnostic would suddenly decide on technology more of a language preference than anything else.</p>
<p>Such a solution could come with a registry to share components. Imagine a design agency bundling a design system and distributing it to you to consume regardless of your technology stack. We'd save all those organizations an insane amount of time and money having to port their solutions to the multiple technologies they support. It'd become the missing <a rel="external" href="https://www.oilshell.org/blog/2022/02/diagrams.html">narrow-waist</a> in how people build UI for the web. Or imagine something like <a rel="external" href="https://storybook.js.org/">Storybook</a> too. It'd unlock a whole new world of possibilities and perhaps a new type of discipline: UI developers, which would feel comfortable writing components and iterating on them without the distractions and complexities of a full-stack application.</p>
<p><em>Where am I going with this?</em> I don't know, but I want to tinker a bit with the idea in my spare time and see how far can go. It's also an excuse to write a bit of Rust :).</p>
<p>Happy Saturday.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Falling behind</title>
      <link>https://pepicrft.me/blog/falling-behind/</link>
      <guid>https://pepicrft.me/blog/falling-behind/</guid>
      <pubDate>Sat, 13 Jul 2024 12:00:00 +0000</pubDate>
      <description>In this blog post I reflect on this feeling of falling behind that I&#x27;ve been experiencing lately.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h1 id="falling-behind">Falling behind</h1>
<p>It’s impossible to live these days without the ongoing feeling of falling behind:</p>
<ul>
<li>News you have to read. - Podcasts that you have to listen to. - Recommended restaurants to try. - X posts to catch up with. - Emails and Slack messages to read. - GitHub notifications to go through. - Travel experiences to experience. - Technologies to catch up with. - Workouts to do. - Kilos to lose to match the stereotypes. - WhatsApp audio messages to listen.</li>
</ul>
<p>I feel the world around me has got so hectic so quickly, that my brain hasn’t been able to scale. In fact, <em>I don’t think it should.</em> Trying to scale puts me in the perfect mode that capitalism likes: <a rel="external" href="https://en.wikipedia.org/wiki/Overconsumption_(economics)">over-consumerism</a>. But what about our mental exhaustion? That’s something only the person suffering cares about.</p>
<p>These days I feel a lot like falling behind, like jumping from one thing to another until I go to sleep. Everything ends up being irritating as a consequence.</p>
<p>And this is a mode I don’t like. I’m aware I don’t like to go through my days that way, nor that is something healthy, but somehow I find it hard to escape. When I manage to ignore all of that and put the focus on myself, which for instance happens a lot when I’m flying, then I have the most mental relief and joy. It’s a forced disconnection that I wish I could force myself at any time without having to step on a plane. It’s a gift being able to do that in a so connected world.</p>
<p>So I’m figuring my way out, but I don’t have the formula yet. I’ll try to go through the pain of reverting some mental patterns that are the consequence of many years of mindlessly embracing a lifestyle that has proven not to be healthy at all. Hopefully, I’ll get through it and restore some mental sanity.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>When you are open</title>
      <link>https://pepicrft.me/blog/when-you-are-open/</link>
      <guid>https://pepicrft.me/blog/when-you-are-open/</guid>
      <pubDate>Tue, 09 Jul 2024 12:00:00 +0000</pubDate>
      <description>While many companies see openness as a business risk, I see it as an opportunity to build a different type of company.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Openness is often perceived as a business risk, but I look at it differently.</p>
<p>When you are open, you are more broadly accountable for your work, and your craft is at stake, so people show the best version of themselves.</p>
<p>When you are open, people can build trust through your work and not through third-party auditing companies and certificates. If you had anything to hide, you wouldn't open it.</p>
<p>When you are open, you can invite external people to contribute, which means a diversity of ideas flowing into the project, which leads to better solutions.</p>
<p>When you are open, anyone can find the information they need to have the agency to make decisions. The organization is more agile.</p>
<p>When you are open, people might end up using your work without paying for it, not worrying about complying with it legally, but those who wouldn't have paid for the software in the first place become evangelists instead.</p>
<p>When you are open, you inspire others to create more open businesses on commodities you might have created.</p>
<p>When you are open, you might make some people uncomfortable, but they decide to go a different path.</p>
<p>We chose This one for Tuist because we want to build a different type of company—openness for the win.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>It&#x27;s a marathon</title>
      <link>https://pepicrft.me/blog/its-a-marathon/</link>
      <guid>https://pepicrft.me/blog/its-a-marathon/</guid>
      <pubDate>Thu, 04 Jul 2024 12:00:00 +0000</pubDate>
      <description>With Tuist we are running a marathon, not a sprint. It&#x27;s time to regain patience and perseverance.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As we continue to work on turning Tuist into a long-term sustainable business, I've been learning a lot about <strong>the importance of patience and perseverance.</strong></p>
<p>This is something that I used to have years ago, but that I lost when I was embedded in a working culture of <em>making great decisions fast</em> with tight deadlines and a very competitive environment. When something spans several days, weeks, or months, I feel like I'm not making progress. Part of me thinks that those are steps in the right direction, but the other part of me feels like I'm not moving fast enough. And because we are limited in resources, I wonder if we are making the right decisions. Suddenly I'm flooded with doubts and fears.</p>
<p>When I look around, I see companies in a similar space that are moving fast, raising money, and hiring people, part of me feels like we are falling behind. However, if I look closely, all I see are attempts to run sprints one after the other, fear of being open and transparent about their business, obsession with growth at all costs, complex pricing models to squeeze as much money as possible from customers...</p>
<p>We are <a href="https://pepicrft.me/blog/its-a-marathon/__GHOST_URL__/blog/2024/07/04/its-a-marathon">running a marathon</a>, and that takes time. And I need to get comfortable with that regaining the patience and perseverance that I once had.</p>
<p>And when I calm down, I notice I can show the best version of myself. I'm inspired to help, to bet on unique ideas, to be open and transparent, and to build a company that I'm proud of. It'll just take a bit of emotional work to get there. But I'm confident that we'll get there.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The technology does matter</title>
      <link>https://pepicrft.me/blog/technology-matters/</link>
      <guid>https://pepicrft.me/blog/technology-matters/</guid>
      <pubDate>Thu, 04 Jul 2024 12:00:00 +0000</pubDate>
      <description>The decision of which technology to use in a project can have a significant impact. In this blog post I talk about the impact that Elixir is having in Tuist.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If you’ve been following me for some time, you might already know how much I advocate for Elixir. We even rewrote the Tuist server, which was previously written in Ruby.</p>
<p>Developers often say that the technology doesn’t matter, that if you prove a solution solves a problem, you can always rewrite it. But Tuist was already a validated idea, and we had just learned about how nicely Elixir can help achieve and scale so much with a simple stack and very few resources. It felt uncomfortable at first because we were not entirely familiar with the syntax, but more and more we are realizing it was such a great decision.</p>
<p>The most recent reaffirmation happened when we tried to add telemetry to the instance for on-premise organizations. Erlang provides a standard telemetry API that many packages use to report telemetry information, including packages like Phoenix (the web framework) and Ecto (an ORM to access databases). Without a single line of code, we had all that information available, and with just a few lines, we had it converted and served to Prometheus via a /metrics endpoint. Mind-blowing.</p>
<p>Phoenix LiveView was another reaffirmation that took us some time to appreciate as we familiarized ourselves with the technology. It’s common to see many companies bet on React as a way to have a top-notch experience for building UIs, without realizing the pile of complexity and abstractions that becomes their technical debt forever. With LiveView, you get the former without the latter. You barely need to write JavaScript and can declare UI that’s a representation of state entirely in Elixir.</p>
<p>So in our particular case, technology does matter, and it matters a lot. And that’s without even mentioning anything about the concurrent model and the many data races that don’t happen because of it, saving us time we’d otherwise waste on debugging.</p>
<p>If you are building a web service and can afford to learn a new technology, Elixir is a great resource to have in your toolbox.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>A different company</title>
      <link>https://pepicrft.me/blog/a-different-company/</link>
      <guid>https://pepicrft.me/blog/a-different-company/</guid>
      <pubDate>Sat, 29 Jun 2024 12:00:00 +0000</pubDate>
      <description>As we shape Tuist’s future, we are committed to true open source, embracing standards, and simplifying developers’ lives. It’s not just business</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Since we began working on transforming Tuist into a sustainable business, I’ve been deeply reflecting on the type of company we aspire to build. Here are some key observations and ideas that have been shaping our vision:</p>
<h2 id="open-source-as-a-foundation-not-just-a-marketing-tool">Open Source as a Foundation, Not Just a Marketing Tool</h2>
<p>Unlike many companies in our space that treat open source merely as a marketing tool, we view it as the foundation for building better tools. We believe that openness and diverse contributions are crucial for long-term success and inspiring others to create their own open-source solutions and businesses. We plan to open-source our entire business, including the server implementation, following in the footsteps of successful open-source companies like Ghost, GitLab, Posthog, and Penpot. We’re committed to commoditizing many of our technologies with permissive licenses, as evidenced by our work on extracting Xcode project generation logic into a Tuist-agnostic package. Stay tuned for two new open-source projects we’ll be announcing in the coming months!</p>
<h2 id="embracing-standards-for-long-term-sustainability">Embracing Standards for Long-Term Sustainability</h2>
<p>We’re betting on widely-adopted standards when choosing technologies, formats, and designing our product. This approach aligns with our goal of building a long-term solution that can withstand the test of time. We aim to avoid the pitfalls of constantly refactoring due to rapidly changing frameworks or vendor lock-in. For example, our web setup uses raw HTML, CSS, and JS, intentionally sidestepping the complexities of the JavaScript ecosystem.</p>
<h2 id="openness-beyond-software">Openness Beyond Software</h2>
<p>Our commitment to openness extends beyond our code. We’ll be transparent about our pricing (with the exception of custom on-premise solutions), drawing inspiration from Posthog’s model. Additionally, we’ll maintain an open handbook documenting our company’s operations. This transparency will help potential clients make informed decisions and support our goal of building an asynchronous remote company by fostering a culture of comprehensive documentation.</p>
<h2 id="simplifying-the-developer-experience">Simplifying the Developer Experience</h2>
<p>We believe that teams shouldn’t have to rely on complex scripting to glue tools and services together by default. Tuist will continue to help teams streamline their setups, advocating for simpler, more integrated solutions. Our goal is to provide a single, cohesive tool with multiple well-integrated features, rather than a collection of independently negotiated tools that prioritize profit over user experience. We put people first, and unnecessary complexity is not part of our equation.</p>
<h2 id="challenging-convention-and-fostering-innovation">Challenging Convention and Fostering Innovation</h2>
<p>We’re leveraging our culture of innovation to challenge cargo-culted solutions and move the ecosystem forward. In the coming months, I’ll be sharing more ideas on how we plan to approach common problems in novel ways.</p>
<p>Building Tuist is like working with a blank canvas, allowing us to create the company we envision based on our values. We’re not simply copying what’s been done before, but rather reflecting deeply on what we want to achieve. Our goal is to build a unique company that embraces open source without fear.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>BREAKME.md</title>
      <link>https://pepicrft.me/blog/breakme/</link>
      <guid>https://pepicrft.me/blog/breakme/</guid>
      <pubDate>Tue, 25 Jun 2024 12:00:00 +0000</pubDate>
      <description>BREAKME.md is a new convention across Tuist repositories to keep track of breaking changes that we would like to introduce in the future.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If you are responsible for maintaining a <a rel="external" href="https://semver.org/">semver</a>-versioned piece of software, you might have come across a scenario where you believe <strong>a breaking change would lead to a better design</strong>, but you can't because it would break the existing users of your software.</p>
<p>This is a need that we sometimes have when working on any of the <a rel="external" href="https://github.com/tuist">Tuist</a> repositories, and I found it a bit annoying having to note them down in issues that can get lost over time. The need for introducing a breaking change, and the rationale behind it, needs to be part of the Git history of the repository, close to the changes that prompted the developers to consider it. Therefore, I decided to <a rel="external" href="https://github.com/tuist/XcodeGraph/pull/17">introduce</a> a new convention across Tuist repositories: a <code>BREAKME.md</code> file.</p>
<p>As its name suggests, it contains a list of breaking changes that we would like to introduce in the future. Every change should include what needs to be changed, and the rationale behind it. When working on future releases, developers can refer to this file to understand the breaking changes that we have been considering.</p>
<p>With that file, I feel more comfortable proposing breaking changes, since I know that they won't get lost in the noise of issues and pull requests.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Parallelism and programming languages</title>
      <link>https://pepicrft.me/blog/parallelism-and-programming-languages/</link>
      <guid>https://pepicrft.me/blog/parallelism-and-programming-languages/</guid>
      <pubDate>Mon, 24 Jun 2024 12:00:00 +0000</pubDate>
      <description>In this blog post I touch on the subject of parallelism in programming languages and how to achieve it without compromising the ergonomy of the language and the complexity of the programs.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Over the weekend I spent some time watching the updates on the Swift <a rel="external" href="https://www.swift.org/documentation/concurrency/">complete concurrency model</a>, and I couldn't avoid but think: the language ergonomy is suffering. It reminded me a bit of the transition from Objective-C to Swift, where framework APIs were not designed with Swift in mind. But look at today, things have changed a lot, so I remain optimistic that Apple can lean back on the language ergonomy and make it more pleasant to work with concurrency in Swift.</p>
<p>Still, Swift and its approach to concurrency was not meant to be the subject of this post. I wanted to talk about concurrency in parallelism in programming languages, and how to achieve those without compromising the ergonomy of the language and the complexity of the programs.</p>
<p>There are <strong>interpreted programming languages</strong> like <a rel="external" href="https://www.ruby-lang.org/en/">Ruby</a> or <a rel="external" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript">JavaScript</a> that can run IO-bound operations concurrently but require introducing complexity to do things in parallel. That's why they are very suitable languages to validate business ideas, but are costly to scale after validation. Costly not only in terms of complexity but also in engineering time and production infrastructure. Programs also get harder to reason about and maintain, because parallelism is often achieved through the persistence of a state and pool of processes that subscribe to state changes and run tasks in parallel. If that's a model you are happy with, then you are good to go. However, it's not mine.</p>
<p>Then there are programming languages that have <strong>built-in primitives to run tasks in parallel</strong>. Programming languages like Swift, <a rel="external" href="https://en.wikipedia.org/wiki/Java_(programming_language)">Java</a>, or <a rel="external" href="https://ziglang.org/">Zig</a>. But they all share one thing in common. They put the burden on developers to prevent <a rel="external" href="https://en.wiktionary.org/wiki/data_race">data race</a> issues. As a developer, that's not something I'd like to think about. Apple is well aware of this and is trying to move to a model where the compiler can help developers prevent that. But sadly, and as mentioned earlier, it does so by compromising the ergonomy of the language to hint the compiler about the intention of the developer.</p>
<p>An interesting programming language in the above group is <a rel="external" href="https://www.rust-lang.org/">Rust</a>, which prevents data races with a new approach to memory management. However, there's a bit of a learning curve associated with it and is a cost that many want to avoid, especially if they are just getting started and want to validate the business idea. An approach that one could take is starting with something like Ruby and JavaScript and doing a rewrite later on if the business proves to be successful. But who wants to go through that pain? Another question that I ask myself often is, why would you adopt a programming language that, even providing parallelism, can't catch data races potentially causing production servers to blow up?</p>
<p><a rel="external" href="https://en.wikipedia.org/wiki/Functional_programming#:~:text=Functional%20programming%20has%20historically%20been,OCaml%2C%20Haskell%2C%20and%20F%23.">Functional programming languages</a> can solve the above issue by not sharing mutable states. But like Rust, many functional programming languages, especially the ones that are pure, have a learning curve that many want to avoid. I've seen the DX of <a rel="external" href="https://clojure.org/">Clojure</a>, and it's mind-blowing to experience, but it's a whole different approach to building, debugging, and testing software. Is it worth it? What's clear though is that there's something unique in the functional programming paradigm that we can't ignore. When the state is mutated as it's passed around, data race problems are gone and you can take full advantage of the hardware where the software is running. Your production servers and development scales by throwing more CPU cores and memory. Does your test suite take a long time to execute? Increase its parallelism. And the best part? You can do that without being worried about flakiness levels increasing. It's beautiful.</p>
<p>The best of all is that there's a programming language that blends the best of both worlds: <a rel="external" href="https://elixir-lang.org/">Elixir</a>. From Ruby and JavaScript, it draws the high-level abstractions and the ease of use. It's also hot-reloadable, which at the end of the day is a productivity booster (this is achieved through the Erlang VM). From Rust, Java, and Swift, it draws the ability to run tasks in parallel without worrying about data races. It just doesn't happen because there's no shared mutable state. Logic is encapsulated in processes that communicate passing copies of the state. It's amazing. It's the most productive and amazing stack I've ever worked with. Zero complexity. Full parallelism. So yeah, if you are looking for a programming language that can scale with your business idea, I'd recommend Elixir.</p>
<p>This is a non-sponsored post. It's a love letter to Elixir.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Lazy-learning</title>
      <link>https://pepicrft.me/blog/lazy-learning/</link>
      <guid>https://pepicrft.me/blog/lazy-learning/</guid>
      <pubDate>Sun, 23 Jun 2024 12:00:00 +0000</pubDate>
      <description>Learning for the sake of learning might not be the most effective way to learn. I&#x27;m trying a new approach: lazy-learning.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've been thinking lately about my approach to learning. When I become interested in a technical subject (e.g., Rust), I tend to throw myself into learning it, even if I don't have a specific problem to solve with it. I'm driven by curiosity and the desire to understand how things work. Which is excellent from the standpoint of cross-pollinating ideas. However, since I don't use them, I end up forgetting them, leading to a feeling of having wasted my time.</p>
<p>With many developers on Mastodon and X talking about <a rel="external" href="https://developer.apple.com/wwdc24/">WWDC</a>, I can't avoid but think: <em>Should I watch some of the talks?</em> Part of me thinks that I should because I might get ideas for problems to solve with <a rel="external" href="https://tuist.io">Tuist</a>. But the other part of me thinks that the ideas presented in it, and which I've seen people talking about on various social networks, are enough for me to envision the problems that I could solve with Tuist. When the time to work with them comes, for example enabling complete <a rel="external" href="https://www.swift.org/documentation/concurrency/">strict Swift concurrency</a> in Tuist, I can simply look up the documentation and learn what I need to know. I feel it's a more effective way of learning because it's goal-oriented. I decided to call it <strong>lazy-learning.</strong></p>
<p>So I'll try to apply this approach going forward. I'm currently diving into <a rel="external" href="https://developer.apple.com/documentation/virtualization">Apple's Virtualization Framework</a>, <a rel="external" href="https://github.com/apple/swift-testing">Swift Testing</a>, and <a rel="external" href="https://www.orrick.com/en/Insights/2024/06/Orrick-Legal-Ninja-Series-OLNS-7-Flip-it-Right">how to flip a German company to the US</a>, because these are the problems I'm facing right now.</p>
<p>And you? What's your approach to learning?</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Website redesign</title>
      <link>https://pepicrft.me/blog/website-redesign/</link>
      <guid>https://pepicrft.me/blog/website-redesign/</guid>
      <pubDate>Sat, 22 Jun 2024 12:00:00 +0000</pubDate>
      <description>I redesigned my website to make it visually simpler and added new pages.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Working on <a rel="external" href="https://tuist.io">Tuist</a> dashboard, and learning and writing HTML and CSS, motivated me to redesign my <a rel="external" href="https://github.com/pepicrft/website">website</a>, which is powered by <a rel="external" href="https://phoenixframework.org/">Elixir Phoenix</a>.</p>
<p>The <strong>design principle</strong> that I followed was to make it as simple as possible. I used the same <code>font-size</code> and <code>font</code> throughout the website and played with the <code>font-weight</code> and <code>gap</code> to create a visual hierarchy. I'm quite happy with the result.</p>
<p>I took the opportunity to add <strong>new pages</strong>. I added a <a href="https://pepicrft.me/blog/website-redesign/__GHOST_URL__/feed">feed</a> page to surface my posts from Mastodon, and <a href="https://pepicrft.me/blog/website-redesign/__GHOST_URL__/photos">photos</a> to do the same with my Pixelfed posts. Since those pages are rendered on the server, I fetch the data from the respective APIs and populate the pages with it. I also added a <a href="https://pepicrft.me/blog/website-redesign/__GHOST_URL__/now">now</a> page that I plan to keep up to date with the latest ideas, thoughts, and things I'm interested in.</p>
<p>After having done this work, I'm quite excited about using the web platform in its rawest form. No TailwindCSS, no static site generators, <a rel="external" href="https://world.hey.com/dhh/you-can-t-get-faster-than-no-build-7a44131c">#nobuild</a> setup.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Emotional breakdowns</title>
      <link>https://pepicrft.me/blog/mental-breakdowns/</link>
      <guid>https://pepicrft.me/blog/mental-breakdowns/</guid>
      <pubDate>Wed, 12 Jun 2024 12:00:00 +0000</pubDate>
      <description>In this blog post I talk about a recent emotional breakdown that I had and how I&#x27;m processing it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Yesterday, I came back from work and had an emotional breakdown. I sat on the sofa and felt sad. I could not pinpoint the reason. I just felt low. I tried not to overthink it too much, but I couldn't avoid it. Why is it happening to me more often? Could it be something that comes with age? Or maybe the long-term consequences of the pandemic or the intense work that I did during that time? Perhaps it comes from putting pressure on myself regarding the success of Tuist as a company.</p>
<p>Don't people say that solving a problem starts with acknowledging it? I feel I'm going through that phase. I'm trying to demand less from myself.</p>
<p>Less perfection. Less pressure. Less being online. Less you need to succeed. Less pleasing everyone but myself. Less work taking all my mental space.</p>
<p>I guess this is part of the journey of life. Learning about ourselves and our mental health. The largest disregarded part of our health.</p>
<p>I'll prioritize the things that feel great in my brain. Running feels great on me. It's my meditation. It's the fresh air. At which moment did I deprioritize it?</p>
<p>How do you deal with emotional breakdowns?</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Why you need the -ObjC flag</title>
      <link>https://pepicrft.me/blog/why-you-need-objc/</link>
      <guid>https://pepicrft.me/blog/why-you-need-objc/</guid>
      <pubDate>Tue, 04 Jun 2024 12:00:00 +0000</pubDate>
      <description>In this blog post, I explain why you might need to set the -ObjC flag in the OTHER_LDFLAGS build setting of your Xcode project.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Tuist provides a <a rel="external" href="https://docs.tuist.io/guide/project/dependencies.html#tuist-s-xcodeproj-based-integration">method</a> for integrating Swift Packages, previously resolved by SPM, into Xcode projects using XcodeProj primitives such as targets, build settings and phases. This feature uncovered a need that some packages in the ecosystem have, and that's the need for upstream targets to pass <code>-force_load</code> or <code>-ObjC</code> through the build setting <code>OTHER_LDFLAGS</code>. Why is that needed? Thanks to <a rel="external" href="https://github.com/thedavidharris">David</a>, who put together some <a rel="external" href="https://docs.tuist.io/guide/project/dependencies.html#troubleshooting">troubleshooting</a> guidance and provided <a rel="external" href="https://github.com/tuist/tuist/issues/6320#issuecomment-2146534862">some references</a> to discussions, I could better understand what the problem was. This post is my attempt to write down my understanding of the problem, to help other developers in the future come across the same issue.</p>
<p>In simple words, the problem is that the linker <strong>overoptimizes the binary removing symbols that are needed at runtime.</strong> The linker's dead-stripping logic can't delete dynamically referenced symbols. And this is something that happens not only when referencing Objective-C symbols, but <a rel="external" href="https://forums.swift.org/t/linker-flag-objc-force-loads-swift-libraries/47466/3">Swift too</a>. For example, when integrating Composable Architecture, when integrating it with Tuist via Xcode targets, developers might need to add explicit references to those symbols or the flags above to the build settings.</p>
<p>What's the solution? There are a few options:</p>
<ul>
<li>The package maintainer can add static references to those symbols to prevent the dead-stripping logic from removing them (e.g., <a rel="external" href="https://github.com/google/promises/pull/221">Promises</a>, <a rel="external" href="https://github.com/Instagram/IGListKit/pull/957">IGListKit</a>) - You set the <code>-force_load</code> or <code>-ObjC</code> flag in the <code>OTHER_LDFLAGS</code> build setting of the target that links those packages statically. Note that this has some effects, like potentially increasing the binary size. - You turn those dependencies into dynamic targets, which as a caveat might end up increasing the launch time of your app.</li>
</ul>
<p>This is a bit unfortunate because it requires developers to go a bit deeper in understanding their dependencies , but hopefully this write-up helps you understand the problem and the potential solutions.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Simplicity, standards, and the platform</title>
      <link>https://pepicrft.me/blog/building-software-that-lasts/</link>
      <guid>https://pepicrft.me/blog/building-software-that-lasts/</guid>
      <pubDate>Sat, 25 May 2024 12:00:00 +0000</pubDate>
      <description>In this blog post I share the principles that we embrace at Tuist to build a future-proof productivity platform for app developers.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>While listening to an interview with <a rel="external" href="https://www.youtube.com/watch?v=KIrLxaM_ipk">José Valim</a>, the creator of <a rel="external" href="https://elixir-lang.org/">the Elixir programming language</a>, I started thinking about the principles that we've been following at <a rel="external" href="https://tuist.io">Tuist</a> to build a future-proof platform for App productivity.</p>
<p>As you might know, we migrated <a rel="external" href="https://tuist.io">Tuist</a>'s server implementation from Ruby to Elixir. Whenever we brought this up, it was common to hear developers saying that it sounded unnecessary. Almost as if we didn't care about the problem space and we were distracted by the technology. But the reality is quite the opposite.</p>
<p>Many organizations bootstrapping businesses treat their initial work as a disposable prototype. If it works, they'll rewrite it with a more robust technology. But Tuist is a validated product and foundation that needs to be as future-proof as possible. And it's bootstrapped, which means we don't have the luxury of throwing extra money at problems or paying for services that abstract complexity away. And that's where Elixir shines.</p>
<p>So our approach to building a future-proof platform for App productivity builds on the following principles:</p>
<ul>
<li>Embrace simplicity - Embrace the platform - Embrace standards</li>
</ul>
<p><strong>Erlang's programming model enhanced by Elixir's language is what we'd describe as a simple yet powerful technology that scales well.</strong> Dot. It's been three decades since Erlang was created to solve telecommunication challenges that resemble the ones that we face today with Internet companies and that we are trying to solve with endless layers of abstractions. Will we have access to less resources and talent than other technologies? Very likely, but the few that we'll have access to will last longer compared to ecosystems like JavaScript, which are in constant flux.</p>
<p>Note that abstracted complexity is still complexity. It's just deferred complexity. Down the road, you'll have to deal with it yourself, either by throwing expensive resources at it (e.g., engineers), or paying for services that abstract it away while creating a vendor lock-in. This is in a nutshell the JavaScript ecosystem, which on top of it adds the disposable and fragmented nature to the layers of abstractions. How fun is that?</p>
<p><strong>Then there are the platforms that we build upon, Apple's platforms and the web.</strong> They might not be perfect, but they are the most stable and future-proof platforms that we have access to. We are intentionally avoiding abstracting them. For example, we don't use build tools on the Tuist web app. Instead, let the browser load CSS and JS files. We love and believe in CSS. Our Swift codebase doesn't use any convoluted architecture or code patterns. It's just classes and structs (and soon actors) that pass data around trying to follow good programming practices. Is it perfect? No. But anyone can jump in and look around without having to learn abstractions. It's priceless in open-source, which we expect to embrace end-to-end.</p>
<p>And last but not least, we are <strong>embracing standards over proprietary formats.</strong> Many companies these days have incentives to create proprietary formats that lock users in. We bet on platforms that bet on standards. For example, our cloud provider, <a rel="external" href="https://fly.io/">Fly</a>, uses Docker containers as a deployment format, a runtime-agnostic solution, <a rel="external" href="https://fly.io/blog/rethinking-serverless-with-flame/">Flame</a> for elastic auto-scaling of applications, or <a rel="external" href="https://fly.io/docs/metrics-and-logs/metrics/#managed-grafana">Grafana</a> for data visualization. Standard is something we are going to embrace too when designing the Tuist product, drawing a lot of inspiration from Fly, which is a company that we admire.</p>
<p>We are in the early days of building a productivity platform for app developers, but we believe that by embracing simplicity, the platform, and standards, we'll build a future-proof platform that will last for decades.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Meeting developers where they are</title>
      <link>https://pepicrft.me/blog/meeting-developers-where-they-are/</link>
      <guid>https://pepicrft.me/blog/meeting-developers-where-they-are/</guid>
      <pubDate>Mon, 20 May 2024 12:00:00 +0000</pubDate>
      <description>In this blog post I reflect on why I believe not more organizations are adopting Bazel and why Tuist is taking a different approach.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've been thinking a lot lately about how Tuist compares to <a rel="external" href="https://bazel.build">Bazel</a>, a build system commonly used by large enterprises that face scaling issues with Xcode. Using Bazel reminds me <a rel="external" href="https://nixos.org/">Nix</a>. The theory behind them is astounding. They are an engineering masterpiece. However, I don't find any joy in using them. I'll try to unpack why.</p>
<p>Ecosystems traditionally have their default or broadly adopted build systems. Android has <a rel="external" href="https://gradle.org/">Gradle</a>, the JavaScript ecosystem has <a rel="external" href="https://vitejs.dev/">Vite</a> (among many others), and the Swift ecosystem has Xcode's build system. They might not be as advanced as Bazel, but over the years, they defined building blocks, mental models, and extensibility APIs upon which ecosystems have been built. Vite is a great example of the latter. Extending the build system is as easy as adding a plugin, usually distributed as an NPM package, and adding one line to the configuration file.</p>
<p>When you use Bazel, you are trading off not only the ecosystem of tools, but very likely a lot of ideas, patterns, and resources from the community. This is a big deal that can't be underestimated. If the community innovates in a particular direction, you might not be able to leverage that innovation because you are using a different build system. Oftentimes, you have to port those ideas over to Bazel yourself or wait for someone to do it for you. In an ideal world, everyone uses Bazel, and everyone innovates on the same foundation, but how likely is that to happen? Very unlikely I'd say. I believe this explains why many organizations remain hesitant to adopt Bazel. Put differently, the few that adopt it, are because they adopt it across the board and therefore the cost is more justified.</p>
<p>My stance, and also Tuist's stance, is that we embrace the limitations of existing build systems, and try to innovate within those constraints. By doing so, we don't disrupt organizations' workflows, and they are still able to leverage the community's innovations. Moreover, we also meet developers where they are by embracing elements that are familiar to them. For example, we purposely chose <a rel="external" href="https://www.swift.org/">Swift</a> over something like <a rel="external" href="https://bazel.build/rules/language">Starlark</a> to describe projects. It might seem like a subtle thing, but it's not. Developers love using Swift and Xcode, so why not leverage that? We also reused the same concepts that Xcode uses: schemes, targets, build settings... Why push a new language onto them if the existing one works? When you combine all these elements, then organizations find a tool that's a joy to use. Sure, it won't reach the level of sophistication of a build system like Bazel, which has been battle-tested by Google and many other companies across various tech stacks, but it provides organizations with the right trade-offs.</p>
<p>I strongly believe that problems should not only be looked at from a technical perspective. Ecosystems have opinions, trends, and communities, that can either be embraced and integrated with, or ignored. Doing the latter often leads to a tool that's technically superior but people don't want to use.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The non-technological open source problem</title>
      <link>https://pepicrft.me/blog/non-technological-open-source-problem/</link>
      <guid>https://pepicrft.me/blog/non-technological-open-source-problem/</guid>
      <pubDate>Thu, 16 May 2024 12:00:00 +0000</pubDate>
      <description>Open-source sustainability is hard, and while it’s necessary to have the tools to reward and pay contributors for their work, the problem requires more of us, developers, speaking out loud about the importance of contributing to the software that we depend on.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I noticed lately the emergence of tools that aim to tackle the problem of open source sustainability by treating it as a technological platform, such as <a rel="external" href="https://polar.sh/">Polar</a> and the <a rel="external" href="https://tea.xyz/">Tea Protocol</a>. While it is exciting to see more companies trying to solve such a critical problem in our industry, the root of <strong>the problem lies in some social expectations and assumptions that I highly doubt can be changed with more tools.</strong> Don’t get me wrong, we need tools that pave the way for people and organizations that want to contribute to open source, but that’s not enough.</p>
<p>If you asked many citizens to contribute financially to the construction of a park where they’ll be able to relax and bring their kids to play, most will refuse, saying that they expect those things to be free. Now imagine the same thing but with digital infrastructure that many can’t see and on which many for-profit organizations build. Why would they pay if, by doing so, they’d increase their costs? They’d rather not. Not only that, but they take part in echoing misleading ideas such as GPL licenses, like considering them infectious. Why not say my software is incompatible with this license instead? Infectiousness places the blame on the open source software. Would you consider someone infectious because their need to receive a salary for the service they provide as an employee is incompatible with the company’s cost structure? Most likely not. So why do we do that to people who have contributed hours to develop something and therefore have the right to publish it under a license of their choice?</p>
<p>As I mentioned in past blog posts, the backlash from developers often arises when you have to make some changes in a model to protect the project’s sustainability, like we had to do with Tuist. But it was so hard for us to imagine how much work <a rel="external" href="https://tuist.io">Tuist</a> would require 7 years later, that we couldn’t have agreed on an ideal model when we started. This is not unique to open source, but companies have to go through decision-making that won’t please every user, and that’s alright.</p>
<p>So, going forward, the model that I’m embracing is similar to <a rel="external" href="https://37signals.com/">37Signals’</a>. I’ll layer the paid software that I build, and publish as <a rel="external" href="https://opensource.org/license/mit">MIT-licensed</a> those layers that I believe would benefit from commodification and that the community might be interested in building upon and contributing to. For example, we are going to extract all the generation logic from Tuist, so anyone could build their own project generation tool upon a battle-tested logic to understand graphs and translate them to Xcode primitives.</p>
<p>Open source sustainability is hard, and while it’s necessary to have the tools to reward and pay contributors for their work, the problem requires more of us, developers, speaking out loud about the importance of contributing to the software that we depend on, like we do directly through our taxes to have spaces where we can live and enjoy. Software is no different there, just something more abstract.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>When you become infrastructure</title>
      <link>https://pepicrft.me/blog/when-you-become-infastructure/</link>
      <guid>https://pepicrft.me/blog/when-you-become-infastructure/</guid>
      <pubDate>Fri, 26 Apr 2024 12:00:00 +0000</pubDate>
      <description>A reflection on the importance of maintaining the open-source projects that become the infrastructure for many companies.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>While listening to <a rel="external" href="https://www.youtube.com/watch?v=PCCVPo6PjBI">this interview</a>, where the interviewee, <a rel="external" href="https://www.linkedin.com/in/adrianagroh">Adriana Goh</a> talks about open-source sustainability and the role that <a rel="external" href="https://www.sovereigntechfund.de/">sovereign tech fund</a> aims to play there, I started thinking about <a rel="external" href="https://tuist.io">Tuist</a> and how it has become the infrastructure for many companies.</p>
<p>As Adriana points out, unlike digital infrastructure, in <strong>physical infrastructure boundaries are more clear and the need for maintenance is more evident</strong>. Although it's common in societies to only realize the importance of infrastructure when it's not working. The thing is, and I feel this is something that many developers are unable to realize, that a piece of open-source software that you developed in your spare time can become the infrastructure for many companies. It's not that you set out to build infrastructure for the world, but you accidentally end up doing so.</p>
<p>Most companies know about this. Looking from the financial perspective, it's <strong>cost savings</strong>. This allows them to gear their resources towards other things, for example innovating at a different layer, which is fantastic. The problem is that along with most societies, which haven't yet realized the criticality of digital infrastructure, many turn a blind eye to the importance of maintaining it. The response is often in the shape of a donation, which is appreciated, but it doesn't solve the problem in most cases.</p>
<p>I've seen some companies emerging to solve this problem, but I'm highly skeptical about their approach. <strong>They approach the problem thinking that it's a technical one</strong>, but I believe it's a social one. Hence why I'm excited about the German government's initiative to create a sovereign tech fund to create awareness and support the maintenance of open-source projects. Sure, you can try to remind companies about the importance of maintaining the infrastructure they rely on, but <em>"reminding them about a cost they should take care of"</em> is not something that they want to hear.</p>
<p>In the case of Tuist, we had to start evolving the project into a company to ensure that we could maintain it. Our mental health was at the table, and we were running a bit out of energy trying to maintain the project in our spare time. Did everyone like the move of turning Tuist into a company? Not everyone. Some thought "I chose Tuist because it was open and free, and now there's a portion of it that is not." They felt betrayed. But we didn't know anything about what the project would become and what that would mean for us in terms of time and energy. So we decided to place our mental health and project long-term sustainability first over the interest of getting everything for free yet at the risk of the project dying.</p>
<p>I wish more companies and people would realize the importance of maintaining the infrastructure they rely on. But until that happens, or until governments like the German one step in to create awareness and support the maintenance of open-source projects, open-source developers like us will have to come up with creative ways to ensure that the infrastructure we build is maintained healthily.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Connecting App Signal with Incident.io using Cloudflare Workers</title>
      <link>https://pepicrft.me/blog/connecting-app-signal-with-incident/</link>
      <guid>https://pepicrft.me/blog/connecting-app-signal-with-incident/</guid>
      <pubDate>Thu, 25 Apr 2024 12:00:00 +0000</pubDate>
      <description>In this blog post I share how we used Cloudflare Workers to connect AppSignal with Incident.io.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>We started using <a rel="external" href="https://incident.io">Incident.io</a> on <a rel="external" href="https://tuist.io">Tuist</a> for incident management. The tool is great, but we were missing a way to connect it with our monitoring system, <a rel="external" href="https://appsignal.com">AppSignal</a>. When you look at the integrations available, App Signal isn't there.</p>
<p>Luckily AppSignal supports sending <a rel="external" href="https://docs.appsignal.com/application/integrations/webhooks.html#anomaly-detection">webhooks when anomalies are detected</a>, but the schema of the payload and the headers didn't match what Incident.io expected. For example, Incident.io expects the requests to come with an <code>Authorization: Bearer xxx</code> header.</p>
<p>To make the integration work, we decided to use <a rel="external" href="https://workers.cloudflare.com/">Cloudflare Workers</a>. We created a worker that transforms the payload sent by AppSignal into the one that Incident.io expects, and adds the <code>Authorization</code> header. The worker is deployed to Cloudflare, and we configured AppSignal to send the webhooks to the worker's URL. Below is the code of the worker:</p>
<pre><code>const token = &quot;....&quot;
export default {
 async fetch(request, env, ctx) {
 const alert = await request.json()
 const { alert_id, metric_name, human_comparison_value, trigger_description } = alert;
 // https://docs.appsignal.com/application/integrations/webhooks.html#exception-incidents

 await fetch(&quot;https://api.incident.io/v2/alert_events/http/....&quot;, { headers: {
 &quot;Authorization&quot;: `Bearer ${token}`,
 &quot;Content-Type&quot;: &quot;application/json&quot;
 }, method: &quot;POST&quot;, body: JSON.stringify({
 &quot;title&quot;: `${metric_name} peaked above ${human_comparison_value}`,
 &quot;description&quot;: trigger_description,
 &quot;deduplication_key&quot;: `${alert_id}`,
 &quot;status&quot;: &quot;firing&quot;,
 &quot;metadata&quot;: {
 ...alert
 }
 })})
 return new Response(JSON.stringify({status: &quot;success&quot;}), {status: 200, headers: {&quot;Content-Type&quot;: &quot;application/json&quot;}});
 },
};
</code></pre>
<p>Hopefully, Incident.io will provide an integration with AppSignal in the future, but until then, this solution works well for us.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Standards, standards, standards</title>
      <link>https://pepicrft.me/blog/standards/</link>
      <guid>https://pepicrft.me/blog/standards/</guid>
      <pubDate>Thu, 04 Apr 2024 12:00:00 +0000</pubDate>
      <description>Proprietary solutions are a dime a dozen, but standards will outlast them all.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>In the tech world, where <a rel="external" href="https://en.wikipedia.org/wiki/Enshittification">"enshittification"</a> is rampant, the importance of standards becomes clear as they protect us from platform interests that may not align with our own. As you observe your surroundings, you'll find numerous examples:</p>
<ul>
<li>Why opt for <a rel="external" href="https://figma.com">Figma</a> and its proprietary file format when you could use <a rel="external" href="https://penpot.app/">Penpot</a>, which utilizes SVG? - Why use serverless proprietary JavaScript runtimes when you can deploy <a rel="external" href="https://github.com/opencontainers/image-spec">OCI images</a> to platforms like <a rel="external" href="https://fly.io">Fly</a>? - Why choose <a rel="external" href="https://tailwindcss.com/">Tailwind</a> for styling your website when you can achieve the same with standard CSS, which has improved significantly over the years? - Why use <a rel="external" href="https://notion.com">Notion</a> when you can write your content in Markdown files and manage them with tools like <a rel="external" href="https://obsidian.md/">Obsidian</a> or <a rel="external" href="https://logseq.com/">Logseq</a>? - Why bind yourself to the complexity of <a rel="external" href="https://logseq.com/">React</a> when you could embrace the platform and use <a rel="external" href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components">web components</a>?</li>
</ul>
<p>I understand... standards can seem dull. They often lack the flashy, modern websites that play on psychology to convince you of their worth, yet they possess a unique value. They will outlast any proprietary format. <em>React?</em> It will eventually lose its appeal, leading people to chase the next trend. You have the chance to decide whether this results in a burdensome migration for you or has no impact at all. <em>Should Notion decide to change its terms of service and raise the price for accessing your content?</em> You can choose to avoid that situation entirely.</p>
<p>With the current overload of noise on social channels, it's easy to mistake something's value for how frequently it's discussed. You won't find many tech influencers evangelizing Markdown because it's not deemed "cool." It's more fashionable to talk about a React-like Markdown format that blends Markdown with JSX. <em>Unfamiliar with it?</em> Consider introducing it to your project.</p>
<p>The JavaScript ecosystem undoubtedly epitomizes the realm of proprietary solutions. The absence of standards beyond the language itself has transformed the ecosystem into a Wild West. Try to name a single problem layer where solutions are standardized; you'll find none. Take runtime as an example: each attempts to introduce a proprietary set of APIs until they realize the inevitability of Node's standards, forcing them to ensure compatibility with Node's APIs so that packages in the NPM ecosystem work seamlessly. Or consider cloud runtimes that mimic Node but aren't actually Node. The code that functions locally fails in production because you're using Node locally and something different in the cloud. As a result, new layers emerge to shield developers from the myriad proprietary solutions, like <a rel="external" href="https://github.com/honojs/hono">Honos</a>, which abstracts the various methods of handling HTTP request-response cycles.</p>
<p>There are developers who enjoy hopping from one proprietary solution to another. I don't. Perhaps it's a sign of aging or a decreasing tolerance for trends that distract from creating anything of value. However, <strong>the moment I see a company promoting something proprietary, I instantly become wary</strong>. That's why I prefer CSS over Tailwind, Fly over Vercel, Markdown over Notion, and runtimes like Erlang over Deno or Bun. The peace of mind that comes from betting on standards is invaluable, granting me the focus needed to build great tools with technology.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Thoughts on Open-Source</title>
      <link>https://pepicrft.me/blog/thoughts-on-open-source/</link>
      <guid>https://pepicrft.me/blog/thoughts-on-open-source/</guid>
      <pubDate>Tue, 19 Mar 2024 12:00:00 +0000</pubDate>
      <description>In this post, I share my thoughts on open source and how it aligns with my principles. I also talk about the different models that I&#x27;ve seen in the industry and how I&#x27;d like to see it evolve.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If you’ve been reading me for a while, you might know that I advocate <a rel="external" href="https://opensource.org/">open-source software</a>. I can’t pinpoint exactly what makes me connect with it so strongly, but I believe it has something to do with communities.</p>
<p>I noticed that <strong>I like to build with other people</strong> and leave a lasting impact on them. I have a similar personality outside of the context of open source, and I noticed that my dad is the same. I also enjoy empowering others through my work, sharing thoughts like these, or collaborating with them on exciting challenges. This might sound odd in a very capitalist world, but the peace of mind this creates is priceless. I wouldn’t change it for anything else.</p>
<p>The problem is that money will get in your day whether you like it or not. The most common case is when you are an open-source developer and realize that you need to do something to make a living from it. Many open source developers get a job and continue to work on open source in their free time, but this might be a huge mental stretch, especially in some life phases. That was the case when I got the job at Shopify. They met me through my work on <a rel="external" href="https://tuist.io">Tuist</a>, which received no support from the company, neither by using it internally nor allowing me to spend some time contributing to it. <strong>I was younger and emotionally more dynamic to navigate it well.</strong></p>
<p>In other cases, the open source developer gives the company the unique value that companies can’t compete with, such as a community and the recognition that comes with it. So, <strong>the developer becomes an influencer for the company</strong>, on top of meeting their daily responsibilities. If you look around, you’ll find some examples of that–<em>a developer X who built Y and works now at Z, and therefore, I want to work for Z too because X is there.</em> I sometimes wonder if open-source developers should charge for that or be paid more because, in terms of responsibilities, they are bringing tons of value to the company. At Shopify, I hired people who came through my open-source work. Even I talked so many times publicly about the exciting stuff my teams were working on. I did it naively, not knowing how those organizations operate, and to this day, I still feel guilty and somewhat stupid for having done that. But as I said earlier, whether you like it or not, the intrinsically motivated work that builds communities sooner or later meets the extrinsic motivations of a company that wants to profit from it. I won’t get into <a href="https://pepicrft.me/blog/thoughts-on-open-source/__GHOST_URL__/blog/2023/11/10/dear-bitrise">Bitrise</a> because I have already talked about it.</p>
<p>The one model, which a few try because it requires wearing a different hat, is evolving the open source model to have a commercial component associated with it. This is the approach that we are taking with <a rel="external" href="https://tuist.io/cloud/">Tuist Cloud</a>. We build something on the open source foundation but to build the source of revenue necessary to maintain the open source side. My Northstar is a product developed in Spain, <a rel="external" href="https://penpot.app/">Penpot</a>, an open-source alternative to Figma that embraces standards over proprietary formats with rugged portability. It’d be my dream if we could achieve that with Tuist.</p>
<p>This is a model that we are seeing getting popular as <strong>COSS</strong>. However, I’ve seen some of those projects taking a different approach. Rather than being intrinsically motivated by open source values and what they enable, they are extrinsically motivated by making money and embracing open source as a marketing strategy. Most of them have VC funding and have <a rel="external" href="https://en.wikipedia.org/wiki/Contributor_License_Agreement">contribution license agreements (CLA)</a> to make them owners of your contributions. So even if they pitch it as <em>“it’s open,”</em> which is very sexy on a landing page.</p>
<p>The above model doesn’t align with my principles. I’d rather have a permissive component that anyone can take and do whatever they want and a closed-source extension to ensure funding for the project. Ideally, everything is open source, but we might make things unnecessarily challenging when bootstrapping a business. Our goal with Tuist Cloud is to open-source it eventually.</p>
<p><strong>Re-connecting with the things that bring me joy is bringing back the mental health that I lost</strong> by being embedded into an environment designed for competition with all sorts of psychological tricks to make you overcommit and squeeze every gram of creative energy. Not anymore. I love collaboration, building, and empowering people, and doing that makes me stay mentally healthy and happy.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Transitioning Tuist Cloud from Ruby to Elixir</title>
      <link>https://pepicrft.me/blog/transitioning-from-ruby-to-elixir/</link>
      <guid>https://pepicrft.me/blog/transitioning-from-ruby-to-elixir/</guid>
      <pubDate>Thu, 14 Mar 2024 12:00:00 +0000</pubDate>
      <description>Ruby proved not to be the most suitable runtime for apps that are IO-heavy. We evaluated Swift, but ultimately decided on Elixir for various reasons.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>We've recently started moving Tuist Cloud's current implementation from Ruby to Elixir. The TL;DR version of the motivation is that Ruby is not the most suitable runtime for apps that are IO-heavy—something that might change in the future. As part of the decision-making process, we also evaluated Swift, which powers the Tuist CLI, and some organizations are using it server-side. Ultimately, we decided on Elixir for various reasons that I’d like to share in this blog post in order of importance.</p>
<p>I don’t like the debates around a technology’s ability to scale because, at the end of the day, any technology can scale if you throw enough money at the problem. However, since we are a small bootstrapped company, we can’t afford to throw money at a problem—we need low-cost, easy scaling of not just the production servers but also development, and Elixir and the VM (BEAM) are uniquely positioned there. Thanks to the virtual machine and the functional nature of the language, you can scale by increasing cores and memory instead of horizontally adding more servers, which comes with its part of complexity.</p>
<p>Someone at this point might wonder: Isn’t this easy scaling also achievable in JavaScript with serverless JavaScript runtimes? Yes and no. The provider of the serverless environments supposedly abstracts that away from you, very likely with a proprietary runtime that looks like Node but it’s not Node. But that, at the end of the day, is a loss-leading commercial strategy for you to eventually pay more than what you’d pay if you had it as a long-running process in a server. And that goes without talking about the pain points of having inconsistent runtimes across environments. A JavaScript/TypeScript developer would tell you WinterCG is here to fix all these fragmentations caused by cloud providers, but that’s just a flat illusion, like many things in the ecosystem: Serverless, Lambdas, Functions, JamStack. They are constantly trying to reinvent everything to try to sell services with significantly more costs than value. So as you can imagine, JavaScript was a no-go for us.</p>
<p>Swift’s production servers can scale easily and cheaply. However, development might not because of Apple’s continuous strong focus on their platforms. The ecosystem lacks many tools and workflows that can play a significant difference in productivity. One of the workflows, for instance, that we find extremely valuable these days is being able to open a remote console with the runtime and run code in it. Obviously, this is a workflow that’s not a good idea long-term, but in this current phase, it’s life-changing.</p>
<p>We had a bit of a moment of thinking: should we bet on Swift and help move the ecosystem forward? However, we don’t have the financial luxury of making this investment. We were afraid the decision would lead us to rabbit holes of Swift issues in Linux environments that would distract us from shipping a great product. We are not entirely opposed to using Swift on the server. We just think that right now is not the best time for it. We remain excited about what the future holds for Swift on Linux and Server.</p>
<p>It was also important for us to have access to an ecosystem of community packages to help us with various problems and needs we’d face. Swift was way behind here compared to ecosystems like Ruby, NodeJS, Rust, or Go, which have plenty of tools for building server apps that run on Linux servers. From that list, we also discarded Rust and Go because we’d lack hot-reloading, which is a small issue at a small scale but can become significant when reached a certain scale. We deem it important for our productivity to change code and see it automatically hot-reloaded in the runtime. Once again, the combination of functional programming in Elixir plus Erlang’s VM capabilities make that possible. It’s insanely fast.</p>
<p>And last, and potentially very important in the future, is having access to primitives that will allow us to build real-time features around collaboration, without having to introduce additional pieces of infrastructure. Elixir makes that extremely easy. So easy that even platforms like Supabase offer that as a service for other ecosystems. We can see some Tuist Cloud features being real-time, like seeing builds test results data flowing into a dashboard and getting automatically refreshed.</p>
<p>We believe this is the best decision for the project, and we can’t wait to start investing in a unified dashboard for Xcode teams.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Elixir scales better</title>
      <link>https://pepicrft.me/blog/elixir-scales-better/</link>
      <guid>https://pepicrft.me/blog/elixir-scales-better/</guid>
      <pubDate>Tue, 05 Mar 2024 12:00:00 +0000</pubDate>
      <description>In this blog post, I talk about the scaling challenges we faced with Rails, and why we decided to transition to Elixir.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><a rel="external" href="https://tuist.io">Tuist</a> is powered by <a rel="external" href="https://rubyonrails.org/">Ruby on Rails</a>. When making the decision, we decided on Rails because of its maturity, productivity, and the ecosystem around it. We could move fast with it and convert some early customers. However, we hit some scaling challenges earlier than we anticipated, and they made us question whether Rails was the right choice for us in the long term. Let me give you some context on the service first.</p>
<p>The service has a very basic UI, which might change soon, and a REST API that the CLI interacts with. Most of the interaction with the service is done through the API because teams interact with it through the CLI. By design, we aimed at keeping an S3-compliant storage, provided by <a rel="external" href="https://www.cloudflare.com/">Cloudflare</a> in this case, as the source of truth for whether a given binary exists or not. We didn't think it made sense to replicate that state in the database, and add additional synchronization logic to keep both in sync. That meant that all the requests would spend around 90% of their time waiting for IO operations to complete. To our surprise, we started seeing slow requests that timed out, and some which came back with 500s. What was going on? I started searching, and I came across <a rel="external" href="https://github.com/rails/rails/issues/50450">this issue</a> by @dhh. And there was a piece of his comment that grabbed my attention:</p>
<blockquote>
<p>It's not a good default for apps with quick SQL queries and 3rd party calls running via jobs, <strong>which is the recommended way to make Rails applications.</strong></p>
</blockquote>
<p>3rd party calls are what we were doing (against Cloudflare's APIs), so he was clearly referring to our use case, but I couldn't wrap my head around the idea of having to use jobs for that. I mean, I don't mind adding jobs, but I'm a huge advocate of simple solutions, and that didn't feel simple. So I continued digging into how <a rel="external" href="https://github.com/puma/puma">Puma</a> works, how they use <a rel="external" href="https://ruby-doc.org/core-2.5.1/Thread.html">Ruby threads</a> and system processes, and how you have to figure out the sweet-spot configuration for your service to have the latency and throughput intended. I learned that the issue that we were facing with Tuist was related to having a low number of threads, which resulted in requests having to wait a long time in the Puma queue, and eventually timing out or being rejected. I added some additional cores to the production machines, did some tweaking of processes and threads, and got it to a point where it was acceptable. But still, it didn't feel right. What are we going to do with our on-premise customers? Are we going to provide them with guidelines to figure out the right value for the production machines? Are we going to point them to lengthy guidelines around Rails and performance? It all felt wrong. Sorry Rails. You scale, but the cost of it is barely talked about.</p>
<p>All we want is a solution that's able to use all the resources available in the machine, without much configuration or tweaking to find the ideal values, and a runtime that's able to handle IO-bound operations efficiently. At the same time, we want to keep the productivity that Rails provides. The good news is that such technology exists, and I've already talked many times about it in the past. It's <a rel="external" href="https://elixir-lang.org/">Elixir</a>. It feels like the right tool for the job. I don't have to use jobs because a runtime's global lock is not going to be optimal for the nature of my app. We can scale the service by throwing more cores at the machine. Look at Discord, Pinterest, and Supabase, which are all powered by Elixir. Development is very scalable too. You can use also all the cores available in the machine, and because it's a functional language, you do so with minimal risk of introducing flakiness.</p>
<p>So as you might have guessed at this point, we'll transition to Elixir. We won't do a full rewrite. Rather, we'll place a proxy in front of the Rails service, and run the Elixir service in parallel. We'll route the traffic to the Elixir service as we migrate endpoints. It's going to be awesome when we give our on-premise customers a Docker image that can use all the resources available without any configuration required on their end. Or even better, gear our energies toward building products instead of figuring out how to scale our API.</p>
<p><strong>Rails scales, but Elixir scales better.</strong></p>
<p>PS: Despite our excitement for Swift on the Server, we decided to go with Elixir because of the productivity and the ecosystem around it. Erlang's hot-reloading of modules is an unbeatable productivity tool.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Gain back attention</title>
      <link>https://pepicrft.me/blog/gaining-back-attention/</link>
      <guid>https://pepicrft.me/blog/gaining-back-attention/</guid>
      <pubDate>Mon, 04 Mar 2024 12:00:00 +0000</pubDate>
      <description>In this post, I reflect on how the digital world has hijacked my attention and what I&#x27;m doing to gain it back.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've been thinking lately about how hard it is for me nowadays to slow down and enjoy deep focus. It feels as if I became addicted to the dopamine of jumping from one thing to another feeding my brain with the illusion of productivity. I think it's a consequence of the fast-paced world we live in. I've gotten used to the endless scrolling on social media, the synchronous working style that tools like Slack have brought to us, and the constant notifications from my phone and watch. I feel <strong>my attention has been hijacked by the digital world</strong>. And I don't like it. I want my attention back.</p>
<p>To do so, I've been trying to change my habits. The first one is to prefer <strong>asynchronous communication over synchronous.</strong> For instance, in the <a rel="external" href="https://tuist.io">Tuist</a> Slack group, we encourage more users and contributors to move the discussions to GitHub issues and pull requests. They could theoretically move the same communication style from Slack to GitHub, but the long-form body of the issues and pull requests makes it harder to have a synchronous conversation. It makes the initiator of the conversation think more about the message they want to convey, In Slack it's natural to feel entitled to grab someone's attention and expect an immediate response.</p>
<p>Another thing that <strong>I started doing is using X less</strong>. The algorithmic feed is designed to keep me scrolling and scrolling and engaging with the polarizing content. Instead, I'm using Mastodon, where the feed is chronological and feels so much more peaceful. It sometimes feels so boring that I don't use it at all. It almost feels like an intermediate step to get rid of the addiction. I don't know if it's because of the people that I follow there, but I don't have the feeling that people are trying to grab my attention. Every conversation that I see is meaningful and respectful. X makes me anxious, and Mastodon doesn't.</p>
<p>I'm also working on caring less about what people think about me. What does it have to do with attention? I started to notice that I sometimes did work to get the approval of others. I liked getting that attention. I think it's an X/Twitter-induced behavior because it keeps me engaged and active on the platform. I still like sharing the things that I learn and think about, hence why I'm writing this blog post here. But similar to asynchronous communication over Slack, I'm trying to use more this website over X or Mastodon. Not only does writing here relax me, but makes me the owner of the content. I'm getting a bit fed up with all the companies using AI to ruin the content humanity has been generating for years. Do you like the content here? Sweet, there's an <a rel="external" href="https://en.wikipedia.org/wiki/RSS">RSS</a> feed for you to subscribe to. Do you want to engage in a conversation? Just <a href="mailto:hola@pepicrft.me">send me an email</a>. F***ck the algorithms and enshittification of the Internet.</p>
<p>It's time to gain the attention back and have a more meaningful and calmed relationship with myself and others on the Internet.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>If I could just parallelize my tests execution</title>
      <link>https://pepicrft.me/blog/parallel-testing/</link>
      <guid>https://pepicrft.me/blog/parallel-testing/</guid>
      <pubDate>Thu, 29 Feb 2024 12:00:00 +0000</pubDate>
      <description>Schemes in Xcode have an option to run tests in parallel, but if your code isn&#x27;t designed for it, you are in for a world of pain.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Did you notice that Xcode project schemes have an option to run tests in parallel? It makes sense, considering we have powerful multi-core CPUs and a programming language with concurrency built-in. But let me tell you something: <em>all of that is useless if your code isn't designed for it.</em></p>
<p><a rel="external" href="https://developer.apple.com/swift/">Swift</a> allows having global state, whether protected or not, to prevent data races. It all starts with a stateless singleton instance for memory optimization purposes and better ergonomics: <code>Client.shared</code>, <code>FileManager.shared</code>... Sooner or later, someone adds state, and you end up with code making assumptions on the value of that state. The breakage of these assumptions is often not covered by tests, but that’s a subject for another post. So, part of your codebase is directly or indirectly dependent on mutable state. <em>What could go wrong?</em> Nothing if you run your tests sequentially. Run them in parallel and wait for the first signs of flakiness to arise. But it doesn’t happen to me, Pedro, because I'm mostly writing unit tests where I mock all the subject dependencies. And you are right, but in some scenarios, <a rel="external" href="https://en.wikipedia.org/wiki/Integration_testing">integration tests</a> can bring a lot of value, and in those, your stateful components are very likely far from the subject under test.</p>
<p>To run the code in parallel, you need to be able to scope that state to the test being executed. How do you do that in Swift? Well... using <a rel="external" href="https://en.wikipedia.org/wiki/Dependency_injection">dependency injection</a>, which will lead to a lot of refactoring and some boilerplate in function signatures.</p>
<p>I started working on the above for <a rel="external" href="https://tuist.io">Tuist</a>, but I find it very annoying, honestly. Elixir solves this very beautifully through the concept of processes and their unique ids. Because a test is a process, and a process has an id, you can leverage that to swap modules depending on the id of the process the module is accessed from. Mind-blowing. Swift, please, bring that.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>On protecting my creative energy</title>
      <link>https://pepicrft.me/blog/on-protecting-someones-creative-energy/</link>
      <guid>https://pepicrft.me/blog/on-protecting-someones-creative-energy/</guid>
      <pubDate>Fri, 23 Feb 2024 12:00:00 +0000</pubDate>
      <description>In this post, I share my thoughts on protecting my creative energy and how I&#x27;m doing it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Has it ever happened to you that your work style drains your creative energy? This is something I've noticed with <a rel="external" href="https://tuist.io">Tuist</a>. Since the number of contributors and users outweighs the number of maintainers, our attention is often divided into different areas. For instance, over the past few days, I've been planning a trip to attend some conferences in Asia, ordering swag to bring with us, searching for a professional tax advisor in Germany, reviewing PRs, organizing ticket raffles on social accounts, and shipping code. For most of these tasks, you don’t need to be very creative. You just have to learn about the process and follow it. It’s very routine, and I don’t mind doing it, but if I do it for too long, my brain gets tired and leaves me with no energy to do creative work, which is what I enjoy the most.</p>
<p>I’m now fully aware of it, and I’m taking steps to protect my creative energy. I've started allocating some time to work on stuff that was not a priority but that I enjoy doing and that I believe can have a high impact on the community. At first, I felt guilty. My brain was telling me that I should be doing something else that was more urgent. And I felt bad for feeling that way. Sure, there’ll always be something more urgent, but I can’t be working like that all the time or I’ll feel like a hamster on a wheel. I think my creativity is one of my most valuable assets, and I have to protect it.</p>
<p>For instance, I recently started working on new MIT-licensed gifts for the Swift community under the Tuist umbrella. One of them is a design system for building CLIs. I noticed that unlike other ecosystems like Go’s and Rust’s, Swift lacks a proper toolchain for building stunning CLIs. So I started <a rel="external" href="https://github.com/tuist/swiftterminal">building it</a>. Is it a priority? Hell no. There’s a business to run. But through that work, we can positively impact the experience of Tuist users and the users of many other Swift CLIs that might be built in the future. I’ve also been playing with Apple’s virtualization and containerization technologies. I find it's such an unexplored area in the Swift community, where we could also have an impact with some open-source work that could serve as a foundation to diversify our <a rel="external" href="https://tuist.io/cloud">Tuist Cloud</a> offering. If no one tries those things, we’ll never know if they are worth it.</p>
<p><em>Do you feel the same?</em> <em>If so, how do you protect your creative energy?</em> This is one of the topics in my therapy sessions, and we are coming up with strategies to protect it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Global state is future debt</title>
      <link>https://pepicrft.me/blog/global-state-is-future-debt/</link>
      <guid>https://pepicrft.me/blog/global-state-is-future-debt/</guid>
      <pubDate>Thu, 15 Feb 2024 12:00:00 +0000</pubDate>
      <description>In this post, I share my thoughts on global state and how it&#x27;s future debt.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've been thinking a lot about global state lately. When writing software, state is everywhere, in memory, in the file system, and in storage solutions. It's the object that the business logic works with. State has a lifecycle. We often read about <strong>local state</strong> and <strong>global state</strong> to refer to state whose lifecycle is short and bound to a specific context, and state whose lifecycle is long and shared across different contexts. We've learned from <a rel="external" href="https://en.wikipedia.org/wiki/Functional_programming">functional programming</a> that <strong>local state</strong> is easier to reason, and that global state is a source of complexity and bugs, but the latter is impossible to avoid because it escapes the program's boundaries. For instance, in a purely functional program, you can have global state in a database that's shared across different contexts.</p>
<p>I'm not a fan of pure functional programming languages because their syntax and semantics don't click with me. However, and having learned that the hard way, it became clear to me that global state is future debt that sooner or later you'll have to pay. If this sounds too abstract, let me guide you through what I mean by that.</p>
<p>When writing software, it's easy to add global state for the sake of convenience, for example via the <a rel="external" href="https://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>. A singleton is not necessarily a bad thing, because you can use it as a tool to use memory efficiently, but by introducing it you are laying the ground for global state to grow. Developers will plant the seeds, and you won't notice it in your PR reviews. CI pass, developers will continue shipping features, and everything will seemingly work fine. It will until it doesn't. You notice it when you have concurrent access to the global state, and the behaviour of your software becomes unpredictable due to <a rel="external" href="https://www.google.com/search?q=race+conditions&amp;sourceid=chrome&amp;ie=UTF-8">race conditions</a>. In some cases, you'll notice it because users will report bugs that are hard to reproduce. In other cases you'll notice it because parallelizing the execution of tests results in an increase in flakiness. In any case, it's painful for your organiation because you'll definitively have to throw resources at preventing and mitigating it. And the larger the software becomes, the more unmanageable it becomes.</p>
<p>There are some programming languages and runtimes where global state can happen so easily that it's hard to avoid it. For instance, with the JavaScript ES module system, where variables can be defined at the root of the module and modules are singletons, it's very tempting to use global state. In the ecosystem, they tooling refer to them as "side effects". And not only it makes the software harder to reason about and unpredictable, not just for the developers but for the tooling that's unable to understand the software well enough to optimize it. Hence why Webpack decided to <a rel="external" href="https://webpack.js.org/guides/tree-shaking/">introduce</a> a convention at the package level to mark the side effects of a package. Other technology stacks like Ruby and Rails, where global state is common in databases, provides testing tools to scope databases to a particular test so that it's not shared across different tests. Did you notice? Still, nothing prevents a Ruby class from using global state. And once again, a developer is not thinking about that while writing the code. It's a natural inclination towards convenience without thinking deeply about the implications of the decision. That's why when I hear that about Ruby or JavaScript scales, I can avoid it but to think about how many resources are required for that, and how much of the organization's time is going into making that scale. But because that's hard to measure, the framing is often about the number of requests per second.</p>
<p>The nature of the program makes the problem less or more common. For example, in web applications, that follow a request-response model, things are naturally modeled more functionally. A request comes, a set of functions pass that state around, and eventually generate a response that's returned to the client. CLI's are a bit like that too, where a command is executed passing a set of flags and arguments, which resembles a request in an HTTP server, and is passed through a set of functions that transform the state until it's returned to the user. Still, global state can happen and will happen. It happened in <a rel="external" href="https://tuist.io">Tuist</a>, and now it's limiting the test parallelization that we can achieve in some areas. It's still manageable, and we are working on it, but I find it crazy that we reached this point without noticing it earlier.</p>
<p>So what can we do about that? For example, in the context of Tuist, which is a CLI implemented in <a rel="external" href="https://www.swift.com/homepage">Swift</a>, we'll have to resort to dependency injection to escape global state, and use it to isolate the execution of tests. Similar to what Rails and many other web frameworks do with databases. It's feasible, but it comes at the cost of making the code more verbose. Suddenly all your functions take similar arguments, and developers wonder why they have to pass the same arguments over and over again. One could suggest to use a <a rel="external" href="https://en.wikipedia.org/wiki/Service_locator_pattern">service locator</a>, or a dependency injection framework, but that comes at a high cost too. It's a new piece of technology that developers have to learn, and that you need to maintain. For example, Uber has an open-source tool, <a rel="external" href="https://github.com/uber/needle">Needle</a>, which requires an additional code-generation tool installed in the environment. Having required that in the past for Tuist contributors, and learning that it was a source of friction, we are not going to do that again. Sorry. It's dependency injection at the cost of boilerplate the solution? Most likely yes in the context of Tuist, but we'll try to model it to reduce the boilerplate as much as possible.</p>
<p>Someone familiar with functional programming languages like <a rel="external" href="https://clojure.org/">Clojure</a> might read this and think: "I told you so". But as I said earlier, the syntax and semantics of those languages don't click with me, and the purism that naturally comes with them doesn't either. Isn't there a solution that's more pragmatic?</p>
<p>Once again, <a rel="external" href="https://www.erlang.org/">Erlang</a> and <a rel="external" href="https://elixir-lang.org/">Elixir</a> shine. Elixir feels like Ruby with a more functional touch. It really clicks with me. And they have one of the most powerful concepts I've seen since I started my career: <a rel="external" href="https://www.erlang.org/doc/reference_manual/processes">processes</a>. First, the language is functional. Not as pure as Haskell, but it embraces the functional paradigm, so global state is less likely to happen. Do you remember that trick that I mentioned earlier to scope databases to a particular test? <strong>Imagine being able to do that with any piece of state</strong>. In Erlang or Elixir, processes are like classes in OOP. They are cheap, can form a hierarchy, can communicate with each other by sending messages, can hold state, can be supervised, and most importantly, they have a unique identifier–a process ID. Tests are processes, and they have their unique ID (and state). Elixir leverages that to allow swapping a module's implementation at runtime, for a particular test. So you can mock a module's implementation for a particular test without having to pass the mock all the way down through the call stack. And this is truly powerful. I wish many other programming languages had that.</p>
<p>Anyways, because I can't write everything in Elixir, I changed my approach to writing software to avoid either creating state myself or laying the ground for global state to grow. In <a rel="external" href="https://tuist.io">Tuist</a> we'll have to refactor the code to escape global state, and in future projects, I'll embrace the everything is a function paradigm, and figure out the right balance there with the readability and maintainability of the code.</p>
<p>Avoid global state.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>It takes a lot of determination</title>
      <link>https://pepicrft.me/blog/it-takes-determination/</link>
      <guid>https://pepicrft.me/blog/it-takes-determination/</guid>
      <pubDate>Tue, 13 Feb 2024 12:00:00 +0000</pubDate>
      <description>The world needs more people who are determined to make a difference. In this post, I share my thoughts on the importance of determination and how it has helped me in my life.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the best skills that I learned from my parents and that I'll forever be grateful for is <strong>determination</strong>. My family worked and works at a cafe selling <a rel="external" href="https://en.wikipedia.org/wiki/Churro">"churros"</a>, a common breakfast in Spain. Fun fact, I used to work there on the weekends when I was a teenager. I used the money that I earned to buy technology. My parents had no financial, or entrepreneurship education, yet they threw their little savings into paying for higher education and trusted me to go on my own. At some point, I crossed their limits of what they could comprehend and support, but they never stopped me from pursuing my dreams. They never stopped me from being determined.</p>
<p>I was on my own. Often with no idea of what I was doing. But filled with curiosity and determination. I remember every single moment of my life when I learned what other people have the privilege to learn earlier, due to the education system in their countries or the higher education of their parents. For example, it took me more than a year working at Shopify to understand that what I was given as part of my compensation alongside my salary were real shares of the company, and they had value. To put things in context, my parents have always been firm believers in not putting the money in the bank but under the mattress. Every one of those moments brings me a feeling of unfairness, but also a bit of: <em>I'll throw myself into it and figure it out.</em></p>
<p>Being determined has been key to many of the successes and also happiness that I've had in my life. It's what has allowed me to push through the challenges of building something new, like <a rel="external" href="https://tuist.io">Tuist</a>, and to keep going when things get tough. It's what has allowed me to keep pushing for new ideas, like the idea of a <a href="https://pepicrft.me/blog/it-takes-determination/__GHOST_URL__/blog/2024/02/07/the-js-experience-without-js">web compiler</a>, even when people tell me that it's not possible or that it's not worth it. If you listen to the naysayers, you'll never get anywhere. You have to be determined to keep going, even when things get tough <em>(I just learned about the concept of naysayers thanks to the wonderful Copilot helping structure my thoughts)</em>.</p>
<p>I feel so lucky to have learned this, that I feel extremely entitled to empower others to go through the same, regardless of their starting point. And that's why I like open source so much. OSS connects me with people who have the potential to create a lasting impact in the world, but they might not feel the confidence to do so. They instead remain quiet and don't share their thoughts, ideas, and code with the world. Because the world is noisy with people who have the privilege to be loud.</p>
<p>Having gone through the Tuist journey and up the corporate ladder at Shopify, gave me a window into a world of privileges where it's about oneself and not about the collective– about not valuing you because of your background while we throw resources around to train people on unconscious bias. A world of I'm more than you. A world purely looked through the lenses of numbers and financial productivity. That world is not for me. It makes me extremely uncomfortable. I don't enjoy it.</p>
<p>And it's tremendously unfair because the best leaders who might be able to stop the most pressing problems the world will be presented with are quietly waiting for someone to empower them. I enjoy working on Tuist because I see others being empowered to build things that they wouldn't have been able to build otherwise. I'm pouring some of my spare time into <a rel="external" href="https://glossia.ai">Glossia</a>, because <a rel="external" href="https://www.linkedin.com/in/mariajosesalmeron/">María José</a> is one of those people with huge potential that could have a long-lasting impact in the world, but she's faced with one rejection and question after another. I like to tinker with ideas in the open because they can be a foundation for other ideas to emerge and empower others to build things that they wouldn't have been able to build otherwise. And that's why the layoff at Shopify, although feeling like a punch in the stomach, was one of the most liberating things that could have happened to me.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>It&#x27;s not about what, but how</title>
      <link>https://pepicrft.me/blog/not-what-but-how/</link>
      <guid>https://pepicrft.me/blog/not-what-but-how/</guid>
      <pubDate>Sat, 10 Feb 2024 12:00:00 +0000</pubDate>
      <description>In this post, I share my thoughts on the challenges of building something new and how it&#x27;s important to focus on the &#x27;how&#x27; rather than the &#x27;what.&#x27;</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>You might not believe it, but I suffer from a lot of <a rel="external" href="https://en.wikipedia.org/wiki/Impostor_syndrome">imposter syndrome</a> when building <a rel="external" href="https://tuist.io">Tuist</a>. When I started it, I was very determined and convinced that the ideas I was playing with in my head could work. It was just me, Xcode, and a GitHub repository where I could push my code for anyone to check and use. Part of me thought, <em>"We are just doing project generation, and there are a handful of other tools out there that do the same thing,"</em> but the other part of me thought, <em>"But there’s something unique in the way we are going to approach it, so why not?"</em></p>
<p><strong>It takes a lot of determination to build something these days.</strong> The moment you share <em>"what"</em> you are building, you'll face loads of comparisons with other tools that seemingly do the same. And they might be right in that they solve the same problem that we are aiming to solve, but the important question is really <em>"how."</em> Tuist's strength lies in how it helps organizations overcome challenges. What makes it unique is the right balance between the value that organizations can get from it compared to the investment that they have to make to introduce it. It's so well-balanced that even small organizations can afford to have it very early in the lifecycle of their projects.</p>
<p>People ask me what I think about <a rel="external" href="https://bazel.build/">Bazel</a>. I don't know what they expect, but my answer is always: <em>it's amazing</em>. And what about <a rel="external" href="https://github.com/yonaskolb/XcodeGen">XcodeGen</a>? It's an amazing tool. But I respond to them with another question: <em>"Do you think it's the right tool for you?"</em> And this is only a question they'll be able to answer, not me. I can share the pros and cons of Tuist's approach to solving problems, but ultimately it's up to them, who know their environment better than me, to decide which tool fits them best.</p>
<p><strong>And why am I talking about it?</strong> I recently started thinking about <a href="https://pepicrft.me/blog/not-what-but-how/__GHOST_URL__/blog/2024/02/07/the-js-experience-without-js">the state of the web</a> and the lack of a standard language for building and sharing components that are weakly coupled to the JavaScript ecosystem, and the reaction of people reminded me of the reaction of people when I started building Tuist: <em>"But isn't there Svelte, React, Preact, Vue, and the many others that are already solving that problem?"</em> And once again, the problem is the same, but the important point is really the "how." The lack of a <a rel="external" href="https://www.oilshell.org/blog/2022/02/diagrams.html">narrow waist</a> in the ecosystem has led us to a fragmentation of solutions and tools in the JavaScript layer and a degradation in DX in other ecosystems that are not JavaScript. This is far from ideal, and the whole ecosystem would benefit from a different approach to how to solve the problem.</p>
<p><strong>It's terribly challenging to push through it.</strong> My personality helps a lot. I pushed hard with Tuist. I pushed hard at Shopify about the idea of having frameworks for apps, which indeed caused a lot of frustration in the end because my idea was only accepted when the CEO mandated it. I'm going to push hard with the idea of a web compiler. <em>Will it work?</em> I don't know. But I won't let anyone stop me from finding new solutions to problem spaces that have accumulated an absurd amount of complexity.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>JavaScript DX without JavaScript</title>
      <link>https://pepicrft.me/blog/the-js-experience-without-js/</link>
      <guid>https://pepicrft.me/blog/the-js-experience-without-js/</guid>
      <pubDate>Wed, 07 Feb 2024 12:00:00 +0000</pubDate>
      <description>In this post, I explore the idea of having a platform-agnostic and technology-agnostic compiler that can be plugged in as an in-code backend for rendering purposes in any other stack (Rails, Phoenix, Express).</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’ve been thinking a lot lately about web UIs after seeing that the best UI component kits or design systems are so strongly coupled to the JavaScript ecosystem. From <a rel="external" href="https://tailwindcss.com/">Tailwind</a> to <a rel="external" href="https://react.dev/">React</a> through <a rel="external" href="https://css-tricks.com/a-thorough-analysis-of-css-in-js/">CSS-in-JS</a>, with a necessary stop at <a rel="external" href="https://storybook.js.org/">Storybook</a>, it’s inconceivable to have an excellent experience building web UIs without using JavaScript. <a rel="external" href="https://htmx.org/">HTMX</a>, <a rel="external" href="https://hotwired.dev/">Rails Hotwire</a>, <a rel="external" href="https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html">Phoenix LiveView</a>, which claim that they stay true to the platform, feel like a downgrade when coming from something like React. They are religious about their approach, but they fail to recognize the joy of using React, <a rel="external" href="https://svelte.dev/">Svelte</a>, or <a rel="external" href="https://vuejs.org/">Vue</a> to enhance the developer experience. <strong>I sympathize with their idea of not wanting to bring the complexity of a JavaScript toolchain though.</strong> If you want to stay true to the Rails framework while not giving up on the experience that JavaScript tools can bring, you’ll most likely find yourself moving everything to the client as an <a rel="external" href="https://en.wikipedia.org/wiki/Single-page_application">SPA</a> with a build tool like <a rel="external" href="https://vitejs.dev/">Vite</a>. Fun fact, Shopify suffered a bit from this—teams built internal services following the SPA model because developers wanted to have access to the React-based design system Polaris. Voilà, you’ve got a new problem: maintaining the JavaScript stack, the REST API (or GraphQL if you want to live at the limit), the client-side state, and the hundreds of issues that might arise from packages in the <code>node_modules</code> directory.</p>
<p><a rel="external" href="https://www.erlang.org/">Erlang</a> taught me that with the right modeling of the problem space, you have the potential to eliminate a whole set of problems that emerge at higher layers. Erlang does so with its concept of <a rel="external" href="https://www.erlang.org/doc/reference_manual/processes">processes</a>, and <a rel="external" href="https://elixir-lang.org/">Elixir</a> added the layer of programming language that we are used to. <em>What if we need to peel layers, escape JavaScript, and move down levels to model the problem at a different layer?</em></p>
<p>If we look at the common denominator across all of them, what we find is <strong>a function</strong> that goes from a domain where we find components like <code>.svelte</code>, <code>.vue</code>, <code>.jsx</code> to <code>.html</code>, <code>.css</code>, and <code>.js</code> that our browsers can read. They all support being hydrated on the client, and some do it through a <a rel="external" href="https://legacy.reactjs.org/docs/faq-internals.html#:~:text=The%20virtual%20DOM%20(VDOM)%20is,This%20process%20is%20called%20reconciliation.">virtual DOM</a>. We have <strong>a compiler</strong>. And this is the foundation upon which many of the tools emerged. But so many emerged that using the compiler directly became unthinkable to the point that React doesn’t recommend it anymore. This made the layer upon the compilers another foundation for frameworks to emerge. Their aim? Abstract away the absurd amount of complexity underneath. Some even went further, like <a rel="external" href="https://vercel.com">Vercel</a>, which built a business upon it. And having so many layers has a cost that depending on who you ask, they say they are willing to pay it. JavaScript developers do; they’ve internalized the brittleness and the frenzies of the ecosystem. They are fine spending days understanding how a deep dependency update resulted in crashes in their apps. Organizations, on the other hand, don’t want this. Still, <strong>they don’t want to miss out on the productivity that JavaScript concepts and tools can bring.</strong></p>
<p>Among the ideas that emerged at the JavaScript layer, there was one that I believe played an important role in the state of things. I’m talking about <strong>sharing components in NPM packages.</strong> Components could be encapsulated in an NPM package, distributed through the <a rel="external" href="https://npm.com">NPM registry</a>, and integrated by build tools like Vite, which can be instructed via plugins for how to do so with every available UI technology. This addresses the natural need that developers have for sharing code of their project. Code that represents UI in this case. <em>Do you know why Tailwind is so successful?</em> I believe one of the important factors is that they allowed a way of sharing components, copying and pasting, in this case, without requiring developing your UI at a JavaScript layer. It’s not a surprise that <a rel="external" href="https://x.com/dhh">DHH</a> supported it. It was solving something that neither Rails nor other technologies that are not based on JavaScript had solved.</p>
<p>And all of this leads me to the most important question: <em>Does all of this have to be solved at the JavaScript layer? Or have we cargo-culted from UI frameworks like React, normalizing the layers of complexity along the process?</em> I believe more the second.</p>
<p>I think the industry is missing a** platform-agnostic and technology-agnostic compiler that can be plugged in as an in-code backend for rendering purposes in any other stack (Rails, Phoenix, Express).** The compiler would support features that developers have grown accustomed to, like writing styles in the component and getting them estranged into CSS or having state that changes over time and that the system takes care of mapping to HTML when it changes. We don’t need to reinvent the wheel at a low level when <a rel="external" href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components">web components</a> exist. They are not there in terms of capabilities, but we can augment the missing bits and bet on the future of them. Moreover, the compiler can support sharing components via packages, making them easier to integrate. For example:</p>
<pre><code>compiler install shadcn
</code></pre>
<p>And I can just write the following in my project:</p>
<pre><code> Click me
</code></pre>
<p>No more do you have to have Tailwind CLI, set it up this way, and have React too, and have this config file at the root. What an absurd amount of unnecessary tools. I just want to install a design system and use it.</p>
<p>If you notice, <strong>being able to write and share UI opens a lot of exciting opportunities.</strong> For example, giving design agencies a standard format to share their work and even charge for it. Instead of having to export it in many formats or just one that the customer uses, you can export it in a universal format that’s easily integratable. Or imagine training AI models with examples of design and having a tool like <a rel="external" href="https://v0.dev/">Vercel’s V0</a> that’s not coupled to React or Next and doesn’t try to lead you into becoming a customer of anything. <strong>Imagine too a Git platform that’s able to visually render the diffs.</strong></p>
<p>I believe this would positively impact the tools built upon it because instead of having to waste time supporting every new UI framework that comes out, they can focus on one and make that experience the same.</p>
<p>Sounds like a giant effort, like <a rel="external" href="https://tuist.io">Tuist</a> seemed when I started working on it, but incrementally and with a lot of time, we arrived at where we are today. I feel I need to give this a shot in my spare time. I dream of enabling an ecosystem of sharing UI like the one that we developers have the luxury of having access to. The impact that a tool of such nature would have on the tech ecosystem is immeasurable. It would also align the experience of all the web frameworks, regardless of the programming language, and the decision of using one or another would be more nuanced.</p>
<p>I threw a repo and started dumping ideas on it at <a rel="external" href="https://github.com/glossia/noora">https://github.com/glossia/noora</a>. I named it after <a rel="external" href="https://en.wikipedia.org/wiki/Noora_(given_name)">Noora</a>, which is an Arabic name that means light—the light in this ocean of complexity in the JavaScript world. Send me an email at <a href="mailto:oss@pepicrft.me">oss@pepicrft.me</a> if the above idea sounds cool and you'd like to contribute.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Incremental Xcode workflows across environments</title>
      <link>https://pepicrft.me/blog/incremental-xcode-workflows/</link>
      <guid>https://pepicrft.me/blog/incremental-xcode-workflows/</guid>
      <pubDate>Fri, 26 Jan 2024 12:00:00 +0000</pubDate>
      <description>Xcode struggles to achieve incremental builds within the same environment. What about across environments? Not even close. Tuist is working on bringing incremental builds and test execution to Xcode projects across environments.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><a rel="external" href="https://en.wikipedia.org/wiki/Incremental_compiler">Incremental compilations</a> are the build-systems' answer to speed up the development cycle. Some like <a rel="external" href="https://bazel.build">Bazel</a> are able to span the incrementallity across environments. But what about Xcode build system? They struggle even to achieve it within the same environment. The reason? <a href="https://pepicrft.me/blog/incremental-xcode-workflows/__GHOST_URL__/blog/2024/01/24/xcode-is-too-magic">Xcode is too magic</a>. There's some <a rel="external" href="https://github.com/apple/swift-driver/pulls?q=%5BCaching%5D">work happening</a>, to improve the situation at the <code>swift-driver</code> level, but they are far from what Bazel can achieve.</p>
<p>Luckily, we have an excellent foundation in <a rel="external" href="https://tuist.io">Tuist</a> to tackle that. The first thing that we built was <strong>binary-caching</strong>, which skips some compilation steps. <a rel="external" href="https://tuist.io/cloud">Tuist Cloud</a> is a service that spans that incrementality across environments. The second feature that we landed to take that incrementality to the next level is <strong>selective testing</strong>. Leveraging the same hashing solution that we use for binary caching, we can run only the test targets that are impacted by the changes. The <strong>combination of binary caching and selective testing</strong> can cut CI times quite significantly. But we are not done yet, we are going to <strong>bring binary caching</strong> to the <code>tuist build</code> workflow too. And, last but not least, we are going to skip the dependency resolution via Swift Package Manager, which can easily add a pair of minutes to every CI build.</p>
<p>The best of all? It's built into Tuist. If your project is described using Tuist's DSL, you get all of the above right away.</p>
<pre><code>tuist cache # Warm the cache with binaries
tuist fetch # Fetch dependencies from the cache (seconds)
tuist test # Use selective testing and binary caching
tuist build # Use cache binaries
</code></pre>
<p>We are working hard on providing organizations with the best balance between convenience and performance.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>AirPods Max died after 2 years</title>
      <link>https://pepicrft.me/blog/airpods-max-broke/</link>
      <guid>https://pepicrft.me/blog/airpods-max-broke/</guid>
      <pubDate>Wed, 24 Jan 2024 12:00:00 +0000</pubDate>
      <description>Apple might have found a legal loophole to charge users for hardware issues caused by software updates.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I bought the first model of <a rel="external" href="https://www.apple.com/airpods-max/">AirPods Max</a> headphones in September 2021 at the official <a rel="external" href="https://www.apple.com/es/retail/nuevacondomina/">Apple Store in Murcia, Spain</a>. From the beginning, I experienced intermittent issues. One issue was the poor microphone quality during meetings with colleagues. The store's solution was to wait for a software update that would fix the problem, but that update never arrived. However, I primarily bought them for listening to music, so it wasn't a major concern.</p>
<p>The music quality was astounding. However, occasionally, they would disconnect automatically, requiring a hard reset and reconnection. This was somewhat annoying, but not enough to warrant a trip to the Apple Store. Despite these issues, I enjoyed listening to music with them and considered it a great purchase.</p>
<p>That feeling lasted until they suddenly stopped working. I attempted to reset them, but instead of the sequence of blinks being three ambers and one white, it was just three ambers. The headphones had become useless. Consequently, I visited the Apple Store in Berlin, where I currently reside.</p>
<p>I explained the issue, and after examining them in a private area, the staff returned, ready to discuss the problem, starting with an unexpected question: "<em>I'm sorry, Mr. Pedro, but do you have insurance for the headphones?"</em> I was surprised. Insurance for headphones? They informed me that the repair would cost up to 250 Euros. I was shocked. <em>"What happened to them? Why are they broken? It's only been two years,"</em> I questioned. I asked if I could send them for an estimate of the repair costs, suspecting a software issue. However, they informed me that if sent for repair, I would have to pay the full amount and would receive a 90-day warranty. I was puzzled and felt like it was a case of <a rel="external" href="https://en.wikipedia.org/wiki/Planned_obsolescence">planned obsolescence</a>. The Apple employee added that if I had reported the intermittent connection issues earlier and had a record of them, the repair would be free. I left the store feeling a mix of disappointment and anger.</p>
<p>At home, I researched the three amber blinks issue and discovered I wasn't alone (<a rel="external" href="https://www.reddit.com/r/Airpodsmax/comments/172phnn/airpods_max_3_amber_flashes/">Reddit</a>, <a rel="external" href="https://www.reddit.com/r/Airpodsmax/comments/1587vjk/3_orange_blinks_of_death_maybe_not/">Reddit</a>, <a rel="external" href="https://discussions.apple.com/thread/254760110?login=true&amp;page=2&amp;sortBy=best">Apple Discussions</a>). Others had similar problems; one person fixed theirs with a software downgrade, which failed again after an automatic update. Some had their headphones replaced for free. Others got it working by putting them in the freezer for a while. <strong>It was unbelievable that Apple could potentially cause hardware issues through a software update without any liability, shifting the responsibility onto the user.</strong></p>
<p>I secured another appointment at the same store in <a rel="external" href="https://www.apple.com/de/retail/rosenthalerstrasse/">Rosenthaler Straße, Berlin</a>. This time, the employee, after consulting with his superiors, offered to cover 50% of the repair cost. I inquired about the specific issue and the warranty duration, but they were unable to provide detailed information about the fault and only offered a 90-day warranty. It seemed they could temporarily fix the issue and charge me 250 Euros without a guarantee of a long-term solution.</p>
<p><strong>Apple seems to have found a legal loophole to charge users, but this is unfair, and I am determined to seek a resolution.</strong> If you're reading this, I would appreciate your help in spreading the word. I am also considering approaching consumer agencies in Europe to file a complaint.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Xcode is too magic</title>
      <link>https://pepicrft.me/blog/xcode-is-too-magic/</link>
      <guid>https://pepicrft.me/blog/xcode-is-too-magic/</guid>
      <pubDate>Wed, 24 Jan 2024 12:00:00 +0000</pubDate>
      <description>Xcode is a great tool for beginners, but it makes it hard for developers to understand what&#x27;s going on under the hood and optimize their workflows.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>While preparing <a rel="external" href="https://www.youtube.com/watch?v=BqKBnFTiWQg">my talk</a> for <a rel="external" href="https://www.swiftable.co/">Swiftable</a>, and thinking about the Xcode challenges that developers face and how Tuist helps overcome them, I realized that a lot of the challenges are rooted in Apple's approach to products with Xcode. They <strong>lean on the convenience side of the spectrum</strong>, which is great for beginners, but it makes it hard for developers to understand what's going on under the hood and optimize their workflows.</p>
<p>There are a handful of examples in Xcode. For example, the <strong>Find implicit dependencies</strong> option in Xcode schemes. It opens an interesting debate about whether a graph with dependencies not explicitly declared in the project should be a valid graph. What we learned with <a rel="external" href="https://tuist.io">Tuist</a> is that the more explicit and side-effect-free the build graph is, the easier it is to reason about it and optimize it. So developers lean on the side of implicitness, which is alright at the beginning because you can type <code>import MyFramework</code> and declare a dependency with <code>MyFramework</code> in code, but a few months later, when the project grows, some features like Xcode Previews don't work and you don't understand why. We've seen organizations adopting Tuist and reporting that their build times became faster after they migrated or that Swift Previews started working. So part of the work that we do with Tuist consists of designing APIs that prevent implicitness in projects.</p>
<p>Another example is Xcode exporting the built products into a directory that's linkable from any target of the project. So if you have a dependency scenario like <code>A &gt; B &gt; C</code> where <code>&gt;</code> represents "depends on", A might be able to import C because by the time Xcode starts building A, the built products of C are already available in the directory that Xcode uses to link the products. You might think this product principle is unique to Xcode projects, but the Swift Package Manager has inherited it too. <strong>Package libraries can mark themselves as <a rel="external" href="https://github.com/apple/swift-package-manager/blob/d25b6345a52c8097010899fdcc961a3820c607aa/Sources/PackageModel/Product.swift#L84">automatic</a></strong>, letting the build system decide what the best linking strategy is. I want to make that decision myself. Especially when the linking might impact the size of the output bundle, for example by having the same static library linked from multiple dynamic frameworks. Once again, leaning on the side of convenience, at the cost of presenting developers with other issues.</p>
<p>As you might have noticed, all this convenience is achieved by making Xcode's build process more magical. You hit compile, and there are a bunch of things in your project that Xcode might be able to resolve magically, or maybe not, and you end up with one of those cryptic errors that developers try to resolve by cleaning the derived data folder.</p>
<p>The more I think about this, the more I think Apple should go back to first principles, flag those as anti-patterns, and provide a migration path for existing projects. The reason why that implicitness was introduced in the first place is because declaring <strong>a dependency graph in Xcode exposes a lot of complexity to the user.</strong> For example, when a dynamic framework should be embedded or not into a final product is something they can infer based on the graph, why are they requiring users to do so? We do that for users and they love it because it's one less thing they have to worry about. What about potential bundle size increase due to static libraries liked in different parts of the dependency graph? They could detect that too and present the user with a warning before they hit compile. There's a lot they could do to make Xcode a tool and a build system that works with large-scale projects, but I guess they are not incentivized to do so. The organizations that have reached that scale, can resort to other build systems like Bazel, or tools like Tuist.</p>
<p>Imagine if they took the opportunity to build a foundation that's extensible like Gradle is so that developers don't have to replace their build systems or resort to additional tools. I think I'm dreaming too much.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>XCBundles</title>
      <link>https://pepicrft.me/blog/xcbundle/</link>
      <guid>https://pepicrft.me/blog/xcbundle/</guid>
      <pubDate>Fri, 19 Jan 2024 12:00:00 +0000</pubDate>
      <description>Xcode doesn&#x27;t have a native container for bundling resources for different platforms and architectures. But nothing stops us from creating our own for Tuist.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>While working on adding support for binary-caching Swift Macros and multi-platform targets in Swift. I realized that there isn't an equivalent to <a rel="external" href="https://developer.apple.com/documentation/xcode/creating-a-multi-platform-binary-framework-bundle">XCFrameworks</a> for bundle targets. Why would you need that?</p>
<p><a rel="external" href="https://tuist.io">Tuist</a> uses XCFrameworks to binary-cache framework targets (soon libraries too). Xcode supports defining links to XCFrameworks and Xcode takes care of using the right framework or library based on the destination. It's very convenient. XCFrameworks is a directory with a convention around how to structure libraries and frameworks for different platforms and architectures.</p>
<p>But Tuist needs to be able to cache resource bundles too, and they are not supported by XCFrameworks. It'd be a huge stretch for the XCFrameworks name :). So I started pondering about creating our internal container, <strong>XCBundle</strong>. The structure of an XCBundle would be similar to the one of an XCFramework, but it'd be used to bundle resources instead of libraries and frameworks:</p>
<pre><code>MyBundle.xcbundle/
 Info.plist
 ios-arm64/
 MyBundle.bundle
 ios-arm64_x86_64-simulator/
 MyBundle.bundle
</code></pre>
<p>This is going to be an internal container not exposed to the public. When generating Xcode projects, we'd introduce the necessary script build phases to copy the right one based on the destination. This is something that Xcode does automatically for XCFrameworks, but we'd have to do it manually for our own container.</p>
<p>This will most likely be worked on after we release Tuist 4, which is going to be a big milestone for us.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Gifting OSS</title>
      <link>https://pepicrft.me/blog/gifting-oss/</link>
      <guid>https://pepicrft.me/blog/gifting-oss/</guid>
      <pubDate>Tue, 16 Jan 2024 12:00:00 +0000</pubDate>
      <description>Navigating the dynamics of Open Source Software (OSS) and sustainability in the tech industry.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’ve been thinking a lot about <a rel="external" href="https://en.wikipedia.org/wiki/Open_source">Open Source Software (OSS)</a> lately.</p>
<p>If you have read my work for a while, you might have noticed that I advocate for it. Many of us are introduced to building craft outside of work. It’s fun. If it goes well, and people use it, you can meet very talented builders. You also build public recognition through the work. Your OSS becomes your CV. This is net positive for you. I know some maintainers who, once they reached a point of recognition, moved on. <strong>OSS was the lever for their professional career.</strong></p>
<p>You’ve probably built a community, and a sense of responsibility has grown within you. At this point, it’s common to hear among contributors, <em>I devote all this free time to the community.</em> But how much of that is pure altruism, and how much is <a rel="external" href="https://www.jstor.org/stable/30024744">self-interested altruism</a>? I ask myself this question every day. Because we humans have a natural inclination towards recognition and appreciation from others. So, <strong>it might just be an exchange of your time for that recognition</strong>, which feels great. But you are putting something limited on the table, your time and attention. So, you might end up stretching it too much to the point of <a rel="external" href="https://en.wikipedia.org/wiki/Emotional_exhaustion">burning out</a>, as is common to see in our industry.</p>
<p>Having reached the inflection point of being unable to satisfy community demand with limited resources, some projects decide to maintain their status and juggle all the demands by setting low expectations for responses. <strong>Being emotionally stable and good at prioritizing is key here.</strong> I’m quite impressed by projects like <a rel="external" href="https://brew.sh">Homebrew</a> and <a rel="external" href="https://github.com/fastlane/fastlane">Fastlane</a> that have managed to do this continuously. Still, I feel bad for the maintainers who need to take part of their free time for their project duties. I can’t help but think: it’s unfair.</p>
<p>Having reached that point, you can alternatively start thinking about ways of funding the project beyond donations, which, in my experience, it's tricky. And depending on the nature of the project, you might have more or less trouble trying to achieve this. For example, if your plan is to provide a cloud service, and the code is OSS, you are competing with cloud providers like Google and Amazon, who can implement a much better and cheaper solution faster (I learned recently that some developers call this being "Jeff'ed"). This happened to <a rel="external" href="https://redis.io/">Redis</a>, and a handful of other projects that had to leverage licenses to avoid exploitation by large tech companies.</p>
<p>I couldn't realize the seriousness of this, especially seeing large tech companies so devoted to OSS these days, until I experienced it myself. There’s a lot of hypocrisy. Companies support OSS because it gives them a great reputation in the developer community, and they might end up getting free (gratis) layers of software to build upon. They design a supply chain where most of it is free developers’ labor. <em>Which business doesn’t like OSS when presented that way?</em> Companies like Microsoft and Apple like being the ones creating and maintaining OSS layers, for example, TypeScript, VSCode, and Swift, because it gives them a great reputation in the developer community, and they might also get some contributions for free. It's a sort of <strong>OSS-washing.</strong> However, when it comes to contributing to other OSS projects that they heavily depend on, the story is completely different. They don't feel a sense of responsibility towards the external OSS tools that they use. The model is perfect for companies.</p>
<p>So despite the importance of OSS in the world, with great examples like <a rel="external" href="https://en.wikipedia.org/wiki/Linux">Linux</a>, we haven’t figured out sustainability, and I doubt we will. We can approximate sustainability, but the closer we get, the further companies will move it. Because while you see it as a lifestyle, as a hobby, as a creative space, as a community, for them it’s just free blocks. <em>If a company like <a rel="external" href="https://github.com">GitHub</a>, which is in the position to deploy a frictionless solution to fund OSS, doesn't, who else will?</em></p>
<p>There's one last model, which I've been seeing a lot lately, and it's the idea of doing OSS because <em>"you are gifting something to the world."</em> <a rel="external" href="https://x.com/dhh">DHH</a> uses it a lot with every piece of OSS the Basecamp folks release. Many developers in Ruby do it too. It's a model I'm starting to align more closely with. So <strong>rather than starting with an OSS project, you start with a business.</strong> You focus on making something that delivers value to society and that can financially sustain itself. And then, you extract the pieces that could be valuable for others. You extract layers of value to support others in their entrepreneurial journey. <a rel="external" href="https://github.com/rails/rails">Rails</a> is a good example of that. And you don’t necessarily need to set high expectations. Quite the opposite, indeed. You can put something out there for people to learn, fork, and extend, but they should not expect you to treat that as your first priority.</p>
<p><strong>I wish a developer could make OSS sustainable without having to delve into the business side of things.</strong> But OSS is embedded in the tech industry, which is embedded in <a rel="external" href="https://hackingcapitalism.io/">capitalism</a>. So the sooner you learn about these dynamics, the better you'll be able to navigate them. It took me years to realize and internalize this. But I'm glad I did.</p>
<p>Going forward, I'll lean on the side of creating businesses that gift OSS bits to the community. And those businesses will inherit goodies from OSS like transparency, open communication, or extensibility. Those traits are not exclusive to OSS. And we have plenty of examples of closed-source businesses doing it beautifully.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Global state, CLIs, and test scalability</title>
      <link>https://pepicrft.me/blog/global-state-clis-and-test-scalability/</link>
      <guid>https://pepicrft.me/blog/global-state-clis-and-test-scalability/</guid>
      <pubDate>Mon, 15 Jan 2024 12:00:00 +0000</pubDate>
      <description>In this post, I talk about how global state in CLIs can make your test suite flaky and how to solve it to scale your test suite.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>When you hear people talking about the goodness of functional programming, one of the things they mention is the lack of global state. States are introduced into the system and passed around mutating them as they go through the different functions. Side effects are also avoided, and when they are necessary, they are isolated and explicit. The most obvious benefit of this approach is that it makes things more predictable and easier to reason about. Another not-so-obvious benefit is that it <strong>eases scaling your test suite</strong>, and that's the topic I want to talk about in this post.</p>
<p>When your program has global mutable state that's shared across different parts of the system, the result of your tests might depend on the order in which they are executed. This might go unnoticed if the test runner has a deterministic order, but if it does not, you might end up with flakiness that's hard to debug and fix. The matter gets worse when you try to run the tests concurrently or in parallel (<a rel="external" href="https://www.geeksforgeeks.org/difference-between-concurrency-and-parallelism/">Difference between Concurrency and Parallelism</a>). And this is something that happens sooner or later in the lifecycle of a project. You first run the tests sequentially in every commit. Then, as the test suite grows, you introduce concurrency or parallelism if the runtime allows it. But that comes with flakiness that's not fun to deal with. You could not anticipate it because you chose a programming language that allows global mutable state (e.g. Ruby). Eventually, you might consider selective test execution, but for that, you need compiler-lever knowledge that either the compiler doesn't provide, or your programming language is compiler-free.</p>
<p>At <a rel="external" href="https://tuist.io">Tuist</a> we are at the point where we'd like to enable more parallelization, but we have some global mutable state that's preventing us from doing so. At some point in the past, we decided to lean on the side of developer ergonomics over test scalability, and now we are paying that debt. For example, every module has a <code>logger</code> instance that they use to output information to the console. For most projects, having a global instance might be fine. But for CLI tools like Tuist, it does not. It does not because what we output and how we output it is connected to the experience of Tuist, and therefore we test it. And what happens if multiple tests are interacting in parallel with a global logger that's storing the logs to run assertions on them? We'll run assertions against logs coming from multiple tests interleaved. Voilà, flakiness. As I talked about in the past, it'd be great if each test run had a unique ID that we could tie global state to, <a href="https://pepicrft.me/blog/global-state-clis-and-test-scalability/__GHOST_URL__/blog/2023/12/20/elixir-processes-testing">like it's possible in Elixir</a>, but unfortunately, we don't have that luxury in Swift. What's the solution then? Passing a logger instance down from the command, to the deepest function that needs it. The challenge is to do so without adding too much noise to the codebase.</p>
<p>Another example of a global mutable state is any system cache that the CLI might need. For example, Tuist uses a global cache to serialize the compilation of manifests and speed up future command executions. Back when we implemented this feature, we added an API to customize the cache directory via an environment variable. We could use that API from our Cucumber-powered Ruby acceptance test suite to have a cache directory per test. However, since we moved the tests to Swift, using environment variables is not a viable option anymore because all the tests run in the same process with the same environment variables. Once again, we need to pass that information down to the deepest function that needs it.</p>
<p>Since this is something that we'll have to do with multiple global states, I'm starting to think it might make sense to have a <code>Context</code> struct that we can pass around and that'd represent an interface with a global state. I'll play with it and see how it goes. Ideally, this is not necessary, and Apple's <a rel="external" href="https://github.com/apple/swift-testing">new testing framework</a> in combination with actors, solves this by assigning unique IDs to each test run, but I'm being too optimistic here. That uniqueness is what makes Erlang and Elixir special, and everything builds upon it. I doubt they'd introduce it just for the sake of solving this one isolated problem.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Deterministic tool versions across environments with Mise</title>
      <link>https://pepicrft.me/blog/deterministic-tool-versions-across-envs/</link>
      <guid>https://pepicrft.me/blog/deterministic-tool-versions-across-envs/</guid>
      <pubDate>Thu, 11 Jan 2024 12:00:00 +0000</pubDate>
      <description>Non-deterministic tool versions across environments is a common source of headaches in development teams. In this post, I share how Mise can help you solve it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>A common source of headaches in development teams are issues coming from <strong>multiple versions of tools used across environments.</strong> The <em>"it works for me"</em> is often followed by a <em>"Which version of X are you using?"</em>. It happens because it's the developers' responsibility to manage their shell and the tools that are active in it through the <code>$PATH</code> environment variable, and CI environments, like GitHub Actions, offer their building block to manage the tools. For example, <a rel="external" href="https://github.com/ruby/setup-ruby">setup-ruby</a> takes care of installing Ruby in the GitHub Actions environment. It uses the convention of using the <code>.ruby-version</code> file to indicate the Ruby version to use, but what if locally, the developers are using a version management tool that doesn't follow the convention? Or what if they decide to manage the installation globally through a tool like <a rel="external" href="https://brew.sh">Homebrew</a>.</p>
<p>This developer experience is far from ideal. Some organizations decide to ignore the problem, perhaps because they are not aware of it. Others like <a rel="external" href="https://shopify.com">Shopify</a> have an entire team dedicated to solving it, which comes at a huge cost for the business. What if you could solve the problem with little to no effort and cost? That's what <a rel="external" href="https://github.com/jdx/mise">Mise</a> is for. We are making it the default installation method for <a rel="external" href="https://tuist.io">Tuist</a>, and also evangelizing it to the Swift community, where project setups have multiple tooling requirements. For example, Ruby to run <a rel="external" href="https://github.com/fastlane/fastlane">Fastlane</a>, <a rel="external" href="https://github.com/realm/SwiftLint">SwiftLint</a> to lint the Swift code, or <a rel="external" href="https://github.com/krzysztofzablocki/Sourcery">Sourcery</a> to do meta-programming. Imagine managing these tools without a unified method that's consistent throughout the local and CI environments...</p>
<p>How does it work? Easy. Once you've installed Mise and added the hook to your shell, you can create a <code>.mise.toml</code> file at the root of your project:</p>
<pre><code>[tools]
tuist = &quot;3.39.3&quot;
swiftlint = &quot;0.54.0&quot;
sourcery = &quot;2.1.3&quot;
ruby = &quot;3.3.0&quot;
</code></pre>
<p>Then you run <code>mise install</code> and Mise will install and <strong>activate</strong> the right version of the tools. Note the "activate" part. Mise ensures the right version is activated when you are in that directory or any sub-directory. That prevents globally-installed versions from taking precedence over the ones specified in the <code>.mise.toml</code> file.</p>
<p>And what about CI? You can also use Mise. If you are using a CI provider like GitHub Actions, the process is very simplified through a custom action, <a rel="external" href="https://github.com/jdx/mise-action">mise-action</a>:</p>
<pre><code>on:
 pull_request:
 branches:
 - main
 push:
 branches:
 - main
jobs:
 lint:
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v3
 - uses: jdx/mise-action@v2
</code></pre>
<p>Mise is by far one of the best tools I've used for configuring and activate my environment for a project. It's one of those tools that you install and forget about it. <a rel="external" href="https://github.com/jdx">@jdx</a>, the creator of the tool, and a developer very passionate about creating terminal tools, has done a fantastic craftsmanship job with it. I'd recommend to give it a try. You won't regret it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>I&#x27;m allergic to complexities</title>
      <link>https://pepicrft.me/blog/allergic-to-complexities/</link>
      <guid>https://pepicrft.me/blog/allergic-to-complexities/</guid>
      <pubDate>Mon, 08 Jan 2024 12:00:00 +0000</pubDate>
      <description>I like understanding complexities to simplify them. In this post, I share some examples of complexities that I&#x27;m intentionally avoiding because they are complex and therefore not fun.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Call me weird, but I'm allergic to complexities. There are software crafters who enjoy understanding and working with complexities in software. <strong>I only enjoy understanding them to conceptually compress</strong> them to build simpler experiences that are fun to work with. At the end of the day, it's not fun if you want to deliver value to people, and your tools, frameworks, and languages slap your face with complexities. Here are some examples of unnecessary complexities that I'm intentionally avoiding because they are not fun:</p>
<ul>
<li><strong>It's not fun</strong> to replace Xcode projects and build system with new building (more advanced) building blocks that break with every Xcode release. I look at you <a rel="external" href="https://bazel.build/">Bazel</a>. - <strong>It's not fun</strong> when your shiny JavaScript-powered project fails to build after you do a minor version dependency update due to a cryptic error message that comes from ten layers of dependencies deep. - <strong>It's not fun</strong> when you can't debug your JavaScript code because it's gone through a series of transformations and optimizations that make it impossible to understand. And it's even less fun when you have to set up a system for your error-tracking solution to be able to help you with source maps. - <strong>It's not fun</strong> when you can't debug your issues because of the layers of abstractions and proprietary tech your project is building upon. I look at NextJS, Vercel, proprietary serverless runtimes, and Xcode. - <strong>It's not fun</strong> when you have to read books and take courses to understand the architecture that software introduced in a code base because they saw everyone in the community talking about it. - <strong>It's not fun</strong> when the programming language that you use gets unnecessarily complex because it's trying to be everything for everyone. I look at you, Swift. - <strong>It's not fun</strong> when you have to build your standard library because the language that you use, JavaScript, lacks it. And it's even less fun when the people who built the packages required for that are often jumping from one project to another, leaving you with a broken project. - <strong>It's not fun</strong> when there are thousands of ways to do the same thing, and you have to spend time learning them to understand the code that you are reading. - <strong>It's not fun</strong> when the tooling that you use tries to be smart about how you want to use it and ends up being a black box that you can't understand. - <strong>It's not fun</strong> when your toolchain and code editor don't integrate well and you have to spend time configuring it to make it work.</li>
</ul>
<p>I believe the ecosystems with the healthiest communities are the ones that can spot the complexities and work together to simplify them. <a rel="external" href="https://rubyonrails.org/">Rails</a> is an excellent example of that. <a rel="external" href="https://www.erlang.org/">Erlang</a> and <a rel="external" href="https://elixir-lang.org/">Elixir</a> have also done a great job at that. That's the reason why I connect with them and enjoy working with them. Because I can stay focused on the problem that I'm trying to solve and not on the tools that I'm using to solve it. And more importantly, I do it with the relief of knowing that they haven't abstracted a huge pile of complexity like JavaScript is obsessed with doing. Because knowing that makes me uncomfortable. That pile of complexity is going to bite me at some point, and I'm going to have to deal with it. Not for me.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Starting therapy next week</title>
      <link>https://pepicrft.me/blog/therapy/</link>
      <guid>https://pepicrft.me/blog/therapy/</guid>
      <pubDate>Fri, 05 Jan 2024 12:00:00 +0000</pubDate>
      <description>2023 was a year of many challenges in my life. Next week I&#x27;m going to start mental therapy with a psychologist.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Next week I'm going to start mental therapy with a psychologist. It's been 4 years since I last went to therapy, and I think it's time to go back and do a regular checkup. 2023 was a year of many challenges in my life:</p>
<ul>
<li><strong><a rel="external" href="https://www.cnbc.com/2023/05/04/shopify-cuts-20percent-of-its-workforce-shares-surge-on-earnings-beat.html">Shopify fired me</a> in May along with many other colleagues</strong>, many of whom happened to live in a country, Germany, where people were organizing to unionize. This was a moment of disappointment for me towards a company that I admired and that I thought was doing things right. I felt lied to and betrayed. After this experience, I looked at other companies with a different lens and a lot of skepticism. Luckily I came across the <a rel="external" href="https://hackingcapitalism.io/">Hacking Capitalism</a> book, which taught me a lot about what no one teaches you about capitalism and how to navigate it. - <strong>My wife was fired too from Shopify.</strong> She's a localization program manager, and she's not as lucky as we still are in the software industry. Everyone is questioning the value of localization in the industry due to AI advancements. She loves languages and would like to continue working on that space, but seeing her suffering and feeling lost is hard for me. It's unfair, but once again, capitalism is not fair. - I decided to <strong>focus on Tuist full-time and turn it into a business.</strong> Some organizations received this transition well, while others didn't. In particular, <a rel="external" href="https://bitrise.io">Bitrise</a>, who was trying to profit from the work we'd done for years without contributing anything back, decided to publish a web page to rant about the project and me as one of the maintainers of the project. Once again, capitalism is in its purest form. If you do things altruistically, you are cool, but if you try to make a living out of it, you are a bad person. I'm not going to lie; it hurt me a lot. I felt like I was being bullied, and I didn't know how to react. I felt powerless. Luckily, I was surrounded by many people, including <a rel="external" href="https://twitter.com/mjsesalm">my wife</a> and <a rel="external" href="https://twitter.com/marekfort">Marek</a>, who understood the situation and helped me to get through it. - I won't lie, trying to turn Tuist into a business puts a question in my head every day: <em>will it work?</em> I have enough savings to not worry about money for a while, but still, I can't stop thinking about it. An impostor syndrome is growing inside me, and I don't know how to stop it. I'm trying to be rational and think about the facts, but it's hard. I used to have more confidence in myself, but since all the Shopify stuff, I feel like I'm not good enough. Crazy, isn't it? Even if it doesn't work, I'm sure I'll learn a lot, and I can always go back to a full-time job and help organizations that are struggling with their Xcode projects. - <strong>My mother and sisters are going through a rough time mentally</strong> caused by a toxic relationship with the family business, which is dominated by patriarchy and slavery practices. I knew it'd happen sooner or later, and tried my best to prevent it, but there are many big elephants in my family's room that no one talks about to avoid conflicts. They prefer conflict avoidance, even if they know that will result in a much larger conflict. My mother was the first one to break down after more than 20 years, of working without any salary adjustment and 7 days a week non-stop. I'd like to build a source of income to retire her and my father and put a hard stop to this situation. The part of the family that benefits from this situation, which includes my uncle and my grandmother, doesn't want to see me around because I bring the whole setup into instability. They don't want me to speak up. This was a rough way for me to end the year.</li>
</ul>
<p>Will 2024 look better? I don't know. I hope. For now I'm going to talk to a psychologist about it and get some help to cope with these situations.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Open-source and the imposter syndrome</title>
      <link>https://pepicrft.me/blog/open-source-and-imposter-syndrome/</link>
      <guid>https://pepicrft.me/blog/open-source-and-imposter-syndrome/</guid>
      <pubDate>Wed, 03 Jan 2024 12:00:00 +0000</pubDate>
      <description>In this post, I talk about how I&#x27;m feeling about my contributions to the open-source community.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>These days working on <a rel="external" href="https://tuist.io">Tuist</a>, I realize that <strong>I'm unable to stay on top of everything that's happening on the project.</strong> The breadth of the project has grown so much, that I lack a lot of context to provide meaningful feedback on pull requests. On one side it's good because it means there are some areas of the project with people that are more knowledgeable than me. So I can trust them to make the right decisions and focus on other areas. However, I feel bad because I'm not able to provide the same level of feedback that I used to.</p>
<p>I'm starting to accept that it's part of the process of growing a project. At some point, you need to trust other people to make decisions. And you need to identify what are your strengths and how you can impact the project the most. In my case, that's helping shape the vision for the project, and fostering a community of contributors that feel empowered to make decisions. Trying to do coding feels like being a manager and trying to write some code. You certainly can do it, but you'll be more effective if you focus on the former. Otherwise, you risk being on the critical path of efforts that could be done by others.</p>
<p>I admire technologists like <a rel="external" href="https://tom.preston-werner.com/">Tom Preston</a>, who were able to build successful companies like <a rel="external" href="https://github.com">GitHub</a>, create and grow successful open-source projects like <a rel="external" href="https://redwoodjs.com/">RedwoodJS</a>, and balance all of that with his family life. I think it must also take a lot of discipline and prioritization to be able to do that. Which I'm still learning to do.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>I&#x27;m sick</title>
      <link>https://pepicrft.me/blog/i-m-sick/</link>
      <guid>https://pepicrft.me/blog/i-m-sick/</guid>
      <pubDate>Thu, 28 Dec 2023 12:00:00 +0000</pubDate>
      <description>Cieza, my hometown, is a beautiful place, but it&#x27;s also a toxic environment that makes me sick. In this post, I reflect on my connection with this city and the Spanish culture.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I'm sick. This has become a recurring event whenever I visit my hometown, <a rel="external" href="https://es.wikipedia.org/wiki/Cieza">Cieza</a>, in the south of Spain. This time, the illness hit me particularly hard. <strong>I'm on the fourth day of a flu</strong>, still feverish and unable to leave the sofa. It's a peculiar way to end the year, isn't it? However, being confined to bed provides ample time for reflection on my connection with this city where I lived until I was 18, and where my parents still reside.</p>
<p>These reflections have led me to realize that many people in this town are also metaphorically 'sick,' due to an inherent toxicity that pervades every aspect of it. This toxicity makes me extremely uncomfortable during my visits, a sentiment that saddens me as my parents, despite their best efforts, cannot mitigate it.</p>
<p>To understand this toxicity's origin, we must delve into the local culture. While my experience is specific to Cieza, I believe many aspects are reflective of the broader <strong>Spanish culture</strong>, which is complex and often surprising. It’s important to note that not everyone conforms to this pattern, but it's common enough to be noticeable.</p>
<p>On the surface, <strong>everyone appears social and supportive.</strong> But upon closer inspection, it's often superficial. There's a lack of genuine empathy and trust. People constantly compare themselves to others and <a rel="external" href="https://en.wikipedia.org/wiki/Gossip">gossip</a> incessantly, almost like a national sport. If you're successful, envy ensues because they attribute your success to luck. If you're struggling, they offer hollow condolences. Non-conformity to societal norms leads to judgment and subtle ostracism. For instance, my sister-in-law, who is vegan and lesbian, faces misunderstanding and indifference from many who are unwilling to challenge their preconceptions. If you don't adhere to societal expectations and seek mental well-being, you must don a façade, a process both exhausting and mentally draining.</p>
<p>Whenever I encounter locals, I feel compelled to <strong>conform to their preconceptions about Germany and Spain.</strong> Challenging these views often leads to social rejection, and amusingly, they report back to my parents, as if to confirm my 'Germanization.' It's infuriating.</p>
<p>Walking around, you often see people drinking large quantities of beer, possibly using alcohol as an escape. I think of the many who suffer because they can't express their true selves. My mother, for instance, struggles with anxiety and stress, and fears the town's judgment for seeking mental health treatment. Ironically, when I moved to Germany, she felt compelled to frame it as a deliberate choice, rather than a lack of local opportunities.</p>
<p>As my parent-in-law often says, Spain lies at the world's edge, Murcia at Spain's, and our town at Murcia's. Being here feels like <strong>time-traveling to a bygone era</strong>, where societal expectations dictate major life decisions like marriage and parenthood, often at the expense of personal desires.</p>
<p>I’ve pondered whether this cultural aspect is recent, but Spanish literature, including <a rel="external" href="https://es.wikipedia.org/wiki/La_vida_de_Lazarillo_de_Tormes"><em>Lazarillo de Tormes</em></a> (1554), Miguel de Cervantes Saavedra, <a rel="external" href="https://es.wikipedia.org/wiki/Don_Quijote_de_la_Mancha"><em>Don Quijote de La Mancha</em></a> (1605), and Federico García Lorca, <a rel="external" href="https://es.wikipedia.org/wiki/La_casa_de_Bernarda_Alba"><em>La Casa de Bernarda Alba</em></a> (1945), reflects similar themes. A line from the latter beautifully encapsulates my feelings about my town:</p>
<blockquote>
<p>"This is how one must speak in this cursed town without a river, a town of wells, where one always drinks water fearing it's poisoned."</p>
</blockquote>
<p>It symbolizes the <strong>pervasive mistrust and fear of public opinion.</strong></p>
<p>So, being in Cieza means not being myself, which in itself makes me 'sick.' When locals advise us to return to Cieza, boasting of its unparalleled lifestyle, I’m reminded that explaining my connection with Berlin is futile.</p>
<p>And regarding health practices like wearing masks during flu season, there's resistance since it's not mandated. Unlike in Germany, where people understand and respect health guidelines, here it’s about following rules, not rationale.</p>
<p><strong>Will this change?</strong> I'm uncertain. It requires a significant investment in education, something I don't see happening. Friends starting their teaching careers are already witnessing discriminatory practices, a disheartening sign that impedes Spain's progress. While there are aspects to celebrate, like our cuisine, they don't overshadow the need for societal evolution.</p>
<p>If I ever return to Spain or Cieza, seeking therapy will be a priority to prepare for confronting a reality I now encounter only a few times a year.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Type safety but at which cost?</title>
      <link>https://pepicrft.me/blog/type-safety-at-which-cost/</link>
      <guid>https://pepicrft.me/blog/type-safety-at-which-cost/</guid>
      <pubDate>Thu, 28 Dec 2023 12:00:00 +0000</pubDate>
      <description>Type safety, while important, can be overrated and lead to over-engineering. In this post, I share my thoughts on the topic.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've come across developers recently who are obsessed with type safety and leveraging the compiler to its fullest extent to catch errors. So much so that they are willing to sacrifice <strong>readability, compilation time, and maintainability</strong> for the sake of type safety. There's no right or wrong here, but I've found myself on the opposite side of the spectrum.</p>
<p>When we decide to invest in type safety, we do so because <strong>we trust the compiler more than we trust ourselves.</strong> For example, if there's a function named <code>getUser(id: ID)</code>, one might be concerned about someone calling the function with an <code>ID</code> that doesn't represent a user <code>ID</code> but a post <code>ID</code>. Sure, we could model our types to have different types for user and post IDs (there must be a mathematical term for this), but isn't the semantics of a function enough to convey its purpose and trust that developers will use it correctly? I think so. Sure, there's a chance that someone will call the function with the wrong type, but there's also a chance that even getting the types right, your software won't do what it's supposed to do.</p>
<p>What this obsession with type safety often leads to is <strong>over-engineering</strong>–teams spending endless hours discussing what the best typing solution is for a particular problem according to theory X or Y. It also <strong>worsens the onboarding experience</strong> for new developers, who have to learn a new type system and its quirks before they can start contributing. Imagine being an engineering manager seeing your team not delivering features because they are stuck in a discussion about types. Sure, one could justify that this is a long-term investment that will pay off in the future, but in software, where requirements change all the time, all the time spent to come up with the perfect type system is time wasted because you'll have to change it anyway soon.</p>
<p>Note I'm not saying you should not care about type safety. I'm saying we might sometimes get too obsessed with it without realizing the cost of it. This obsession will lead to a tax on your team's productivity and happiness. I've seen it happen.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>JavaScript-owned state and accessibility</title>
      <link>https://pepicrft.me/blog/js-owned-state-and-accessibility/</link>
      <guid>https://pepicrft.me/blog/js-owned-state-and-accessibility/</guid>
      <pubDate>Sat, 23 Dec 2023 12:00:00 +0000</pubDate>
      <description>WAI-ARIA attributes are a great layer to persist application state and make the website accessible. However, the convenience of JavaScript APIs to store state makes them store all the state in JavaScript, making the websites less accessible.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've been following the <a rel="external" href="https://ecss.benfrain.com/">Enduring CSS</a> for my projects for a while, including this blog, and a principle that stuck with me is the idea of <a rel="external" href="https://www.w3.org/TR/wai-aria/">WAI-ARIA</a> attributes to persist state. I never thought about it until I read the methodology– if we have HTML markup that represents semantics, and a set of attributes to represent the state making your website accessible, <em>why would I store the state elsewhere?</em></p>
<p>This realization made me think about JavaScript and JavaScript web frameworks and their APIs to store state:</p>
<pre><code>// React
const [state, setState] = useState(false);

// Vue
const state = ref(0);

// Svelte
const state = writable();

// Solid
const [state, setState] = createSignal(0);
</code></pre>
<p>They all have a common pattern: <strong>they are convenient</strong>. But the convenience has a cost– it's so convenient that developers naturally hoist that's representable by ARIA attributes to JavaScript. Instead of embracing the platform, they get distracted by the convenience of the layer in which they are working, and end up with a solution that's not as accessible as it could be. It's not the framework's fault. Not all states are representable by ARIA attributes or should be represented by them. However, I think it'd be great to include a reminder in the documentation of these frameworks to consider ARIA attributes before reaching out to the framework's APIs. Like Enduring CSS does:</p>
<blockquote>
<p>"While the specification is aimed at helping communicate state and properties to users with disability (via assistive technology) it serves the need of a web application project architecture beautifully. Adopting this approach results in what is (perhaps cringingly) referred to as a 'Win Win' situation. We get to improve the accessibility of our web application, while also gaining a clearly defined, well considered lexicon for communicating the states we need in our application logic." <a rel="external" href="https://ecss.benfrain.com/chapter6.html">Enduring CSS - Chapter 6</a></p>
</blockquote>
<p>I love how they put it. <strong>It's a win-win situation.</strong> We should not forget that the web is a powerful platform and that despite how natural it is to get distracted by the convenience of the layer in which we are working, we are ultimately building for users, some of whom might appreciate that we are building directly on top of the platform.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>What if XCTest a concept akin to Elixir&#x27;s processes?</title>
      <link>https://pepicrft.me/blog/elixir-processes-testing/</link>
      <guid>https://pepicrft.me/blog/elixir-processes-testing/</guid>
      <pubDate>Wed, 20 Dec 2023 12:00:00 +0000</pubDate>
      <description>Erlang processes are a powerful concept that allows you to mock dependencies without introducing dependency injection. In this post, I share my thoughts on how XCTest could adopt a similar concept.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If you've been reading this blog for a while, you might know that I've been diving into <a rel="external" href="https://elixir-lang.org/">Elixir</a> lately. I like learning about other languages and technologies because I can cross-pollinate ideas and apply them to my day-to-day work on <a rel="external" href="https://tuist.io">Tuist</a>.</p>
<p>What I find fascinating about Elixir and Erlang, which Elixir is built on top of, is that their modeling of the world makes a whole set of problems disappear. Problems for which ecosystems like <a rel="external" href="https://en.wikipedia.org/wiki/JavaScript">JavaScript</a>, <a rel="external" href="https://developer.apple.com/swift/">Swift</a>, or <a rel="external" href="https://www.ruby-lang.org/en/">Ruby</a> have created a whole set of tools to solve them. There's no quote that better summarizes this than the one from <a rel="external" href="https://twitter.com/rvirding">Robert Virding</a>, the co-creator of Erlang:</p>
<blockquote>
<p>"Any sufficiently complicated concurrent program in another language contains an ad hoc informally-specified bug-ridden slow implementation of half of Erlang."</p>
</blockquote>
<p>But how does it achieve that? I think the reason is rooted in their concept of <a rel="external" href="https://elixir-lang.org/getting-started/processes.html">processes</a>. Everything is either a process or builds on the concept of processes.</p>
<p>There are many effects of processes in how you model your programs, but one that got my attention was <strong>how contracts can be mocked that easily without worsening the design of the code.</strong> In Swift, mocking very likely means that you need to introduce a protocol and use dependency injection to inject the mock. This is fine, and the ergonomics improved recently with the introduction of <a rel="external" href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/">Swift Macros</a>. Still, if you are writing integration tests, which in the case of <a rel="external" href="https://tuist.io">Tuist</a> deliver more value than unit tests, you'll have to pass the mock down to the deep-most layer of your code. And that makes all the interfaces unnecessarily verbose.</p>
<p>Let's look at a concrete example. We use <a rel="external" href="https://github.com/apple/swift-log">swift-log</a> for logging in Tuist. Seeing this piece of code makes me skeptical:</p>
<pre><code>LoggingSystem.bootstrap(MyLogHandler.init)
</code></pre>
<p>The library is using a global internal state to configure the logging system. This is fine as long as it's thread-safe (which I assume it is) and you don't want to run test assertions against the logs and run the tests in parallel (which we do). There's an alternative to that. You can create an instance and pass it down to the layers that need it. But again, it hurts the ergonomics of the code.</p>
<pre><code>let logger = Logger(label: &quot;me.pepicrft.Logger&quot;)
doSomething(logger: logger)
</code></pre>
<p><strong>Can't we have the best of both worlds?</strong> And that's something that Elixir solves beautifully with processes and that I wish <a rel="external" href="https://developer.apple.com/documentation/xctest">XCTest</a> would eventually adopt.</p>
<p>Every test in Elixir is a <a rel="external" href="https://www.erlang.org/doc/reference_manual/processes">process</a>. And processes have a <strong>unique ID</strong>. That process is known by the test logic and also by the code that's being tested, regardless of how deep it is in the call stack. What that allows is <strong>associating a mock with a particular test process</strong>. Let's look at an example using the <a rel="external" href="https://github.com/edgurgel/mimic">Mimic</a> mocking library:</p>
<pre><code># test_helpers.exs
Mimic.copy(Calculator)

use ExUnit.Case, async: true
use Mimic

# calculator_test.exs
test &quot;invokes mult once and add twice&quot; do
 Calculator
 |&gt; stub(:add, fn x, y -&gt; :stub end)
 |&gt; expect(:add, fn x, y -&gt; x + y end)
 |&gt; expect(:mult, 2, fn x, y -&gt; x * y end)

 assert Calculator.add(2, 3) == 5
 assert Calculator.mult(2, 3) == 6

 assert Calculator.add(2, 3) == :stub
end
</code></pre>
<p>Note how no dependency injection is needed. <code>Calculator.stub</code> and <code>Calculator.expect</code> only affect the logic in that particular test process. And you can <strong>safely</strong> run all the tests in parallel without worrying about the state of the mocks leaking between them and causing flakiness.</p>
<p><strong>Will this ever happen in XCTest?</strong> I don't think so. XCTest would need to assign a unique ID to every test and expose it to the code that's being tested. Perhaps through some compile-time magic that's only available when running tests.</p>
<p>Note that the ergonomics might be improvable through dependency injection solutions, but I'm not a big fan of adding something that improves the ergonomics at the expense of making things obscure and introducing a dependency with a third-party library. The trade-off is not worth it.</p>
<p>Erlang, you are so cool.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Learning to love the problem and not the solution</title>
      <link>https://pepicrft.me/blog/love-problem-not-solution/</link>
      <guid>https://pepicrft.me/blog/love-problem-not-solution/</guid>
      <pubDate>Tue, 19 Dec 2023 12:00:00 +0000</pubDate>
      <description>We engineers are vulnerable to getting attached to solutions instead of problems. In this post, I share my experience with this and how I&#x27;m trying to change it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Has it happened to you that you get too attached to a solution to a problem instead of the problem itself? This is something that didn't happen to me earlier in my career, but as I advanced and learned more about other technologies and approaches, which I became excited about, it started to happen more often. This is not the case with <a rel="external" href="https://tuist.io/">Tuist</a> where the technology required to solve the problem is set, <a rel="external" href="https://en.wikipedia.org/wiki/Swift_(programming_language)">Swift</a> and <a rel="external" href="https://developer.apple.com/xcode/">Xcode</a>. But as I poured some spare thinking into the right tech for <a rel="external" href="https://github.com/glossia/glossia">Glossia</a>, I became more indecisive about the right tech to use.</p>
<p>To illustrate this, let me share my most recent experience. When I navigate the web, a pattern that I notice is that many websites that are designed with JavaScript frameworks are well designed. Today, in particular, I was amazed by how well-designed the websites made by the folks behind <a rel="external" href="https://nuxt.com/">NuxtJS</a> and <a rel="external" href="https://vuejs.org/">VueJS</a> are: <a rel="external" href="https://elk.zone">Elk</a>, <a rel="external" href="https://ui.nuxt.com/getting-started">NuxtUI</a>, <a rel="external" href="https://volta.net">Volta</a>, <a rel="external" href="https://vitepress.dev/">VitePress</a>. <em>Guess my thinking after seeing those websites?</em> Is there a cause-effect relationship between the technology and the design? Or did developers with good taste happen to meet in those communities? Will technology like <a rel="external" href="https://nuxt.com/">NuxtJS</a> have a strong connection with a gorgeous design and a first-class experience in <a rel="external" href="https://glossia.ai">Glossia</a>? Should I reconsider the decision to use <a rel="external" href="https://elixir-lang.org/">Elixir</a> now that it's early in the lifetime of the project?</p>
<p>These are the questions that I mentally navigate when I'm exposed to new technologies. And it's draining. I have to make an effort to look at things with enough perspective to realize that:</p>
<ul>
<li>Technology is an implementation detail. You can achieve a great design with any. - Distractions for the technology are a way to procrastinate on the problem. - The problem is the most important thing. The solution is just a means to an end. - Other factors are equally important when choosing a technology, not just the design.</li>
</ul>
<p>I want to change my mindset to stop doing this because it's fatiguing. When I look around and see people that I admire, I see that they are focused on the problem and not the solution. They pick a technology that clicks with them and they stick with it. One of them is <a rel="external" href="https://x.com/dhh">@dhh</a>. He loves Ruby, and he is taking Ruby everywhere. <a rel="external" href="https://twitter.com/levelsio">@levelsio</a> does the same with PHP. There are many examples in the Swift community too, like <a rel="external" href="https://mastodon.social/@johnsundell">John Sundell</a>.</p>
<p>Note that I don't want to isolate myself from other technologies. I learn a lot from them which I can use to cross-pollinate my thinking. However, I need to do it enough so that I can learn from them and not get distracted by them. This is where the challenge lies.</p>
<p>Have you experienced something similar?</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Implicitness in Xcode and SPM. Why Apple?</title>
      <link>https://pepicrft.me/blog/xcode-implicit-dependencies/</link>
      <guid>https://pepicrft.me/blog/xcode-implicit-dependencies/</guid>
      <pubDate>Tue, 19 Dec 2023 12:00:00 +0000</pubDate>
      <description>Apple embraced implicitness in some areas of the build system, and it&#x27;s causing headaches to developers. In this post, I share my thoughts on the topic and how we are planning to address it in Tuist.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Since the beginning of Tuist, one of the principles that we embraced is that <strong>the dependency graph should be explicit.</strong> This is something that we encouraged through the Swift DSL, but that we couldn't enforce because Xcode and its build system allow it.</p>
<p>Why explicitness you might wonder? When the graph is explicit and known upfront, you can <strong>validate</strong>, <strong>reason about</strong>, and <strong>optimize</strong> it. When it's not, you can't do those things. Or you rely on a closed-source build system that you don't control to do it for you. And if things go wrong, you need to file a radar and wait for Apple to fix it.</p>
<p>The worst part is that <strong>Apple is not reversing this trend.</strong> Instead, they are building on it and the Swift Package Manager is inheriting the same problems. For example, they realized that package products defining the <code>static</code> or <code>dynamic</code> nature of the library were a mistake that could lead to duplicated symbols. What did they do to solve it? They solved it with a new linking option, <code>automatic</code>, that's resolved at build-time. Why would you want a build system to make these important decisions for you? Your graph is yours. Tuist gives you agency over the graph while hiding the complexities that are not relevant to you, like the fact that some dynamic frameworks might need to get copied into the app bundle.</p>
<p>One of the issues that is particularly annoying, and that we are coming across often in Tuist's codebase is <strong>being able to import dependencies that are not explicitly declared.</strong> The issue is more apparent now because we optimize our workflows with <a rel="external" href="https://docs.next.tuist.io/documentation/tuist/binary-caching">binary caching</a>. The reason why it happens is that the directory in which Xcode outputs all the project target products, <code>DerivedData/{project}-{hash}/Build/Products/{config}</code>, is visible to the other targets in the project. In other words, they can import them without having them declared as dependencies.</p>
<p>For example, let's say that you have a simple dependency graph <code>A -&gt; B -&gt; C</code> where A (App) depends on B (Framework), and B depends on C (Framework). If we do <code>import C</code> from <code>A</code> it'll work if we build the project through a scheme with the <em>"Find implicit dependencies"</em> enabled or if <code>C</code> has been previously compiled. For example via another scheme. What's particularly annoying about this is that the issues might arise on CI, or weeks later after weeks of CI workflows accidentally working.</p>
<p><strong>This is an itch I'd like to scratch for Tuist and every Tuist user.</strong> I doubt Apple does anything, but I might be wrong. They are in a tricky spot because any step to remove implicitness would very likely break existing projects. It's the same for Tuist, but we can work closely with our users to define a migration path that allows them to transition to an explicit dependency graph. I believe once we do it, things will get more deterministic and stable for everyone. They won't most likely notice it, because teams don't have a metric to measure "how often implicitness caused headaches", but I bet it's more often than we think.</p>
<p>We hope to ship it as part of Tuist 4.0. Stay tuned!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>What I expect from a knowledge management app</title>
      <link>https://pepicrft.me/blog/perfect-knowledge-management-app/</link>
      <guid>https://pepicrft.me/blog/perfect-knowledge-management-app/</guid>
      <pubDate>Mon, 18 Dec 2023 12:00:00 +0000</pubDate>
      <description>In this post, I share what I expect from a knowledge management app.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I still haven't found the perfect knowledge management app. <a rel="external" href="https://logseq.com/">Logseq</a> outline doesn't quite click with me. I end up creating a log of useless blocks that I never revisit and link from other blocks. <a rel="external" href="https://obsidian.md/">Obsidian</a>'s longer text format is better. It makes me think thoroughly about what I'm writing and give it a structure. However, it misses some things that I consider essential:</p>
<ul>
<li><strong>An app that's native to Apple platforms.</strong> Not native in the sense that it compiles to native. But native in the sense that it embraces the platform patterns and capabilities and doesn't try to fit web patterns into the platform. - <strong>Auto-linking</strong> of notes. We've seen a spread of technologies like <a rel="external" href="https://en.wikipedia.org/wiki/Word_embedding">embeddings</a> that can be used to calculate semantic similarity between texts. Imagine using that for suggesting links between notes. - <strong>Inbox</strong> for ideas to process. Sometimes I'm running and I've got an idea that I'd like to jot down and process later into a longer note. I'd like to just press a button, record the idea, and have it transcribed into text. Or share content that I find on the web with the app for later processing. - <strong>A standard structure</strong> that's documented to allow users to port their notes and foster an ecosystem of apps.</li>
</ul>
<p>The itch is becoming too itchy so I don't know if I'll be able to resist the temptation of building it myself as a hobby. Once we ship Tuist 4 and Tuist Cloud and have the business running of course.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Swift Packages default to supporting all platforms</title>
      <link>https://pepicrft.me/blog/packages-default-platforms/</link>
      <guid>https://pepicrft.me/blog/packages-default-platforms/</guid>
      <pubDate>Wed, 13 Dec 2023 12:00:00 +0000</pubDate>
      <description>Swift Package Manager defaults to supporting all platforms when they don&#x27;t specify any. This is a problem for tooling like Tuist that integrates Swift Packages as Xcode project targets.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><strong>Did you know that Swift Packages default to supporting all platforms when they don't specify any?</strong> We, at <a rel="external" href="https://tuist.io">Tuist</a>, didn't know either until we added support recently for multi-platform targets. Tuist integrates Swift Packages as Xcode project targets that give users more control over them and allow optimizations. By the way, kudos to <a rel="external" href="https://github.com/waltflanagan">Mike Simons</a> for the amazing work on this one.</p>
<p>Because Swift Package targets have now multiple platforms, we included the platforms that the Swift Package Manager indicates that are supported. And that works, until it turns out that a given package doesn't support a platform that they seemingly support (at least according to the defaults). In that case, Xcode fails to compile the target. To overcome the issue and eliminate blocks for users, we started adding code like <code>if 'Firebase'</code>... but that would not scale so we needed to do something about it.</p>
<p>Because Tuist knows the dependency graph, we cascade the platform of the project targets down to the dependencies. For example, if the upstream targets compile for iOS, we can narrow down the list of supported platforms for dependencies to iOS. I believe this is something that Xcode must be doing under the hood. The difference with Xcode is that they do it at build time and we do it at generation time.</p>
<p>This shows that assuming that a package supports all platforms by default was not a good idea. Especially when giving support for multiple platforms was not trivial due to inconsistent APIs across Apple and other platforms like Linux. This will hopefully change soon with the new era of <code>Foundation</code>, but until then, Xcode and tooling like Tuist will have to forever deal with this decision.</p>
<p>Please, if you are a package maintainer, <strong>make sure you are very explicit about the platforms that you support and that you validate that through CI</strong>. You'll be making a great favor to the community and to the tooling that depends on your package.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Swinging back to positivity</title>
      <link>https://pepicrft.me/blog/swinging-back-to-positivity/</link>
      <guid>https://pepicrft.me/blog/swinging-back-to-positivity/</guid>
      <pubDate>Wed, 13 Dec 2023 12:00:00 +0000</pubDate>
      <description>2023 was a year full of micro-traumas that led me to a negative mindset. In this blog post, I talk about how I&#x27;m working on swinging back to positivity.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I'm a person who tends to look at things through a positive lens. Or at least, I used to. 2023 was a bit of a traumatic year for me professionally, and that led me to a <strong>negative mindset full of disillusions</strong>.</p>
<p>The first one of those events was the <a rel="external" href="https://www.cnbc.com/2023/05/04/shopify-cuts-20percent-of-its-workforce-shares-surge-on-earnings-beat.html"><strong>Shopify layoffs</strong></a>. For someone who has experienced layoffs before, and that has faced the realities of how businesses operate, that shouldn't have been a big deal. But it was for me. I over-committed to the company and the people I worked with, believing I was on a long-term and successful journey there. That's what they told me, and that's what I believed. But then one day, you are faced with reality. In my case, I was part of the German workforce that supported the unionization efforts. Workers understand their rights. What could be wrong with that? Everything. Techno-optimists and builders, as they like to call themselves, don't understand of anything that hinders their path to wealth and power. If there's something that gets in their way, they'll get rid of it, throwing money at it if needed. That reality shock led me to trace back everything that happened during my time there, and could see a different angle to the whole story. From the removal of the 'dropshipping' word from everywhere after having benefited from it for years, through the support of crypto and NFTs, to the green-washing of the company's activities. It was all a big lie. It felt like a toxic relationship that's hard to escape from and whose big picture you can only see once you are out of it. There's professional growth, but at what cost? I was let go with a mental exhaustion that I'm still recovering from. I couldn't look at other companies without wondering, will they be the same? I started to see patterns everywhere, like having a name for the family (e.g. "shopifolks"), or people continuously talking about how the company changed their lives for the better. I had huge respect for <a rel="external" href="https://twitter.com/tobi">Tobi</a> and his ideas, but I'm having a hard time buying into them now.</p>
<p>I felt so relieved when the layoffs happened, but you can't just get rid of the trauma that easily. It's something that comes back to you here and there. You try to look forward and stay positive, but you have this feeling that you can't trust anyone anymore. Has it happened to you? My escape was to focus on my projects, and in particular <a rel="external" href="https://tuist.io"><strong>Tuist</strong></a>. We built a healthy community and project, in which we could continue to invest, and build something that we could be proud of and that people would be inspired to use and contribute to. I threw myself into the project, working full-time every day. I built a new website, put a plan in place for the rest of the year and started working on it, continued to help more companies get onboarded. People loved the project, and that love for the project fueled us to keep going towards a sustainability point where we could work on it full-time. But in that process, we made the project so financially attractive, that a company like Bitrise thought it was a great idea to wrap it into their product without contributing anything back. And here comes the second trauma. We had to make a quick decision to prevent them from hurting what had taken us 6 years to build. The result? A website telling everyone how terrible deciding for Tuist was, explicitly mentioning me as a bad maintainer for the project. If I didn't have enough with Shopify's micro-trauma, there is another one to add to the list. Luckily, I'm surrounded by great humans, among whom are my lovely wife, <a rel="external" href="https://twitter.com/mjsesalm">María José</a>, my partner in Tuist and Tuist Cloud, <a rel="external" href="https://twitter.com/marekfort">Marek</a>, and the Tuist community itself. They know me well, they know my values and supported me through this emotionally difficult time. Still, like Shopify, is that one thing that you can't get rid of easily.</p>
<p><strong>I started feeling disillusioned with the often cruel reality of the tech industry.</strong> This disillusionment grew a lot of negativity in me, which often resulted in a lot of public criticism as if I could change anything by doing so.</p>
<p>But I'm working on changing that. Criticism does more harm than good to me. If there's something that has always been there, that motivates me to keep going and inspires me to build things, that's having a community of people that I can work with on solving exciting problems. And that's something that open-source provides me with. I'm a very community-oriented person. Building in isolation with the only goal of profit is not something that I enjoy. However, doing it sustainably is something to keep an eye on (thanks Bitrise for the lesson), and that's something that I'm working on. Open-source changed me. I met many wonderful and talented people, some of whom became friends. I see on Mastodon what open-source communities are capable of, and I feel I want to be inspired. When I'm in these communities, I feel I'm in a safe place and very positive. It's when I get closer to the tech industry, in its purest form, which is often on <del>Twitter</del> (X), that I start to feel negative. Perhaps the algorithms are contributing to that.</p>
<p>The micro-traumas of 2023 grew negativity in me, but I'm finding my way out of it thanks to open source and communities. I'll stop criticizing, and start building things that inspire positivity. 2024 is going to be an exciting year.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Open-sourcing the lightning_css Elixir package</title>
      <link>https://pepicrft.me/blog/open-sourcing-lightning-css-hex-package/</link>
      <guid>https://pepicrft.me/blog/open-sourcing-lightning-css-hex-package/</guid>
      <pubDate>Mon, 11 Dec 2023 12:00:00 +0000</pubDate>
      <description>In this blog post I talk about the motivations that led me to build and open-source lightning_css, an Elixir package to bring a more advanced CSS bundler to Elixir and Phoenix projects.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've been reading a lot and connecting with the idea of embracing the web platform and building right on it, without layers and layers of abstractions that make it harder to understand what's going on under the hood, and that make the software less future-proof. For instance, I got rid of <a href="https://pepicrft.me/blog/open-sourcing-lightning-css-hex-package/__GHOST_URL__/blog/2023/11/21/peeling-layers">Tailwind</a> from this website.</p>
<p>When it comes to <strong>styling</strong>, I've been following the <a rel="external" href="https://ecss.benfrain.com/chapter5.html">Enduring CSS</a> methodology. This provides answers for many challenges that CSS presents and embraces accessibility attributes to hold state leading to more accessible websites. Nevertheless, one challenge that I found, in particular in the context of <a rel="external" href="https://elixir-lang.org">Elixir</a> and <a rel="external" href="https://www.phoenixframework.org">Phoenix</a>, is that it's hard to follow <a rel="external" href="https://ecss.benfrain.com">the directory convention</a> that they propose to get styles close to the components. Doing so requires using a tool that's able to resolve <strong>glob patterns</strong> to locate CSS files and bundle them into an output CSS bundle, and the tool that asset pipeline tool Phoenix projects use by default, powered by <a rel="external" href="https://esbuild.github.io">ESBuild</a>, doesn't provide that functionality for CSS.</p>
<p>Luckily, there's a solution for that in the community: <a rel="external" href="https://lightningcss.dev">Lightning CSS</a>. Yet, the integration into Elixir projects requires some tedious plumbing. Because I wanted to overcome that, and also scratch the itch of building an Elixir package. I built and open-sourced <a rel="external" href="https://github.com/glossia/lightning_css">lightning_css</a>. The interface is similar to the one that the Elixir's <code>esbuild</code> package proposes. You first configure profiles in your Mix project's configuration file:</p>
<pre><code>config :lightning_css,
 version: &quot;1.22.1&quot;,
 default: [
 args: ~w(assets/css/app.css --bundle --output-file=priv/static/styles/bundle.css),
 watch_files: &quot;assets/css/**/*.css&quot;,
 cd: Path.expand(&quot;..&quot;, __DIR__),
 env: %{&quot;NODE_PATH&quot; =&gt; Path.expand(&quot;../deps&quot;, __DIR__)}
 ]
</code></pre>
<p>And then you can invoke it right from the terminal using the Mix CLI passing the profile, <code>lightning_css default</code>. In the case of Phoenix projects, you need some <a rel="external" href="https://github.com/glossia/lightning_css#phoenix">additional steps</a> to integrate it into Phoenix tasks and watchers.</p>
<p>I still need to add some tests, which is another itch I want to scratch: getting familiar with Elixir's testing framework. However, I'll leave that for the near future. I'll adjust this website to make use of glob patterns, and start using it in <a rel="external" href="https://glossia.ai">Glossia</a>, in which I plan to continue investing early next year.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>On mental health</title>
      <link>https://pepicrft.me/blog/mental-health-journal/</link>
      <guid>https://pepicrft.me/blog/mental-health-journal/</guid>
      <pubDate>Thu, 07 Dec 2023 12:00:00 +0000</pubDate>
      <description>In this blog post I open myself about recent mental breakdowns and how I&#x27;m dealing with them.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Today I had one of those days of feeling down and not being able to pinpoint the exact reason. We are back from attending a conference in Buenos Aires, <a rel="external" href="https://www.swiftable.co">Swiftable</a>, and found <strong>my mother suffering from anxiety attacks</strong> due to recent traumatic events. It's manifesting as back pains, and she is trying to convince herself that's a physical problem. So I'm trying to convince her about the importance of going to a psychologist. This is affecting me a lot, and I'm trying to be strong for her.</p>
<p><a rel="external" href="https://tuist.io"><strong>Tuist</strong></a> is also draining me a lot. I'm excited about everything that's ahead, but the closer we get to the release, the further I feel from the finish line. And because I continue to work on it full-time without a salary, this is drilling my brain. Not that I don't have savings, but not having a source of income makes me mentally uncomfortable. And the recent Bitrise events didn't help. Someone who has been in business for longer might think this is normal, but I'm not yet emotionally prepared to deal with this type of competition moves. I might go to therapy when I'm back in Berlin to learn how to deal with this.</p>
<p>Besides all of this, I think <strong>my relationship with social networks is not helping.</strong> I think it's important to continue to be present on X and Mastodon because that's where the users of Tuist are. But at the same time, it's a huge mental stretch to my list of responsibilities in the project: development, support, community engagement... Also, being on X and Mastodon triggers many thinking streams. Is it positive? It is, I get many ideas from it. But if I don't limit the bandwidth that I dedicate to it, it can be overwhelming. I get ideas that I'd like to play with, but I don't have the time for them. I can go from excitement to exhaustion from one day to another. When I'm exhausted, my natural reaction is to disconnect from everything.</p>
<p>I'm also emotionally processing some <strong>surprising realities that I learned about the tech industry</strong> by accident. One of them is everything that happened at <a rel="external" href="https://shopify.com">Shopify</a>. It was in May, but it continues to be a recurring thought in my mind. I feel lied and a chip in a game of billionaires. I worked hard towards some professional growth that was all a story to get me to overcommit to the company. I know it won't happen again, but I can't avoid feeling bad about having fallen into that trap. The other one is the exploitable nature of open-source, which I suffered through Tuist. Because open source exists within the tech industry, and the tech industry exists within capitalism, where companies have no obligation to give back to society, they treat open source as a free resource that they can exploit. Companies can go as far as to tell everyone that you are a bad person because you are taking steps to protect yourself from that exploitation. This is tough to process emotionally.</p>
<p>There might be other factors contributing to these emotional swings, but those are the ones I'm the most aware of. I suffer from mental health breakdowns from time to time, and I think it's important to share them. When I feel down, I take a break from everything and use the space to reflect on what's happening. I also make sure exercising is part of my routine. Even though I don't run as often as I used to, but doing casual runs helps me to clear my mind.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>3 package managers + 2 build tools = One big mess</title>
      <link>https://pepicrft.me/blog/xcode-mess/</link>
      <guid>https://pepicrft.me/blog/xcode-mess/</guid>
      <pubDate>Mon, 04 Dec 2023 12:00:00 +0000</pubDate>
      <description>I shared a bit of a reflection on what are the issues with current Apple&#x27;s tooling touching on some of the points that I presented in my Swiftable 2023 talk.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As you know, I've dedicated the past 6 years to overcoming the challenges of using Xcode at scale. That was the theme of my recent talk at Swiftable, <a rel="external" href="https://speakerdeck.com/pepibumur/from-challenge-to-joy-my-journey-developing-tuist-for-scalable-xcode-projects">From challenge to joy: My journey developing Tuist for scalable Xcode Projects</a>. The more I dive into this topic, work on it, and talk with developers about it, I realize in which difficult spot Apple finds itself.</p>
<p>Xcode builds on the Xcode build system, which works with Xcode project files. As the environment changed and things became more complex, Xcode project files were stretched beyond their limits and presented developers with a lot of challenges. Some examples of those are frequent Git conflicts, invalid dependency imports implicitly resolved, and frequent clean builds that make developers lose their time. This is the day-to-day of many developers, or at least it was and is mine when I use Xcode with a modular project.</p>
<p><strong>Apple failed to evolve the project files and the build system that builds on it.</strong></p>
<p>They left the community with only one API to overcome challenges: project generation. This is not great and tells a lot about the foundation. <a rel="external" href="https://cocoapods.org">CocoaPods</a> pioneered this approach, and then project generations like <a rel="external" href="https://github.com/yonaskolb/XcodeGen">XcodeGen</a> and <a rel="external" href="https://tuist.io">Tuist</a> followed. Most recently developers started to use the Swift Package Manager, which Apple integrated tightly with Xcode, to overcome the most pressing challenge, frequent Git conflicts.</p>
<p>But the matter has gotten worse. We have now a fragmentation of dependency management solutions, and many organizations are struggling to move from CocoaPods because it provides a level of extensibility and configurability that the Swift Package Manager doesn't. The same implicitness that Xcode had, and that caused many problems to developers, is now making its way to the Swift Package Manager, like the "automatic" linking mode that Swift Packages now has. Since when is the build system's responsibility to decide the linking of a dependency? Optimizations? Not even think about them. It's Apple's responsibility. If the integration with the Swift Package Manager is suboptimal, you have to wait for Apple to fix it. I'm sorry, but this is too bad.</p>
<p><strong>Apple built a package manager and faced a community using it as a project manager because they were tired of Xcode project issues.</strong></p>
<p>Apple is now in a difficult spot, but one they could move from with support from the community and a clear vision. I think they've reached a point where they need to go back to first principles and evaluate the foundations of the platform. Is it time to evolve everything that's around the Xcode project files? I think so. It's time for the build system to be something closer to what Gradle or Bazel are. A build system that's deterministic, configurable, optimizable, extensible, and overall, easy to reason about. If the convenience that they need for the people getting started is a concern, they can always build a layer of convenience on top of low-level primitives. Android has done that with Gradle. You drop a plugin, and that takes care of everything for you. And if you need to, you can peel layers of complexity.</p>
<p>But there are no signs of that happening. Chatting with developers at the Swiftable conference, I noticed that developers are more confused than ever. They want to use the official tools, but while doing so they realize that they add more complexity and challenges to their problems. It's positive for <a rel="external" href="https://tuist.io">Tuist</a>, because it's a huge opportunity for us to help them, but I feel really bad for those development environments that are not fun to work in. I was in one of them, and you know what leadership decided to do? Move away from native development to <a rel="external" href="https://reactnative.dev">React Native</a>. Simply because leadership doesn't understand that you need to wait an entire year to hopefully have Apple fixing the productivity problems. It's bizarre when looked at from the productivity angle.</p>
<p>I know put a <code>Project.swift</code> next to every package or in every new project that I create. Why? Because the productivity levels that Tuist provides are unmatched. If you haven't tried, I encourage you to do so. You can clone the Tuist repository and play with it. Hopefully, there'll be one day where we won't need project generation anymore, and we can move our optimizations to a more sophisticated build system. But until then, project generation is our answer, and it works damn great.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Peeling layers</title>
      <link>https://pepicrft.me/blog/peeling-layers/</link>
      <guid>https://pepicrft.me/blog/peeling-layers/</guid>
      <pubDate>Tue, 21 Nov 2023 12:00:00 +0000</pubDate>
      <description>This blog post contains a recent reflection over the often over-abstracted web platform, and how powerful it&#x27;s become, making many of the normalized abstractions feel unnecessary.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If you've read the content in this blog, you might have noticed that I have little experience building for the web. The few interactions that I had with it were geared towards putting my personal blog or <a rel="external" href="https://tuist.io">Tuist</a>'s website on the Internet. The process often goes like this:</p>
<ul>
<li>Find a template that I like on the Internet. - Learn about the framework the template is powered with (often JavaScript-based). - Adjust content and structure accordignly. - Publish</li>
</ul>
<p>Did you know that this website has been implemented with technologies like Gatsby, NextJS, Jekyll, Rust, Phoenix?</p>
<p>Sometimes the technology decision was driven by a technology I was getting excited about, like it's the case with the current iteration of this website, which is implemented with Phoenix and Elixir. Other times, it was driven by the template that I'd found–Tuist's template drove the decision to use Astro. Playing with all these different technologies is a lot of fun. Nonetheless, it seems to come at the cost of making projects less future-proof in part, due, in part, to the high stack of layers (abstractions and tools) they build upon. We make the web, a platform that's designed to be backwards-compatible, feel quite the opposite, a platform that breaks more often than not.</p>
<p>I get that <strong>abstractions and tooling are necessary</strong>. For example, to generate HTML pages at build or runtime from templates and content. However, I can't avoid but wonder if we might sometimes be going too high in the stack. This is a question that I find particularly interesting. It's in fact one of the reasons why I like following the Phoenix and Ruby on Rails ecosystems closely. Their love for the web as a platform makes them question every abstraction that arises. I find somewhat some-provoking the swing of the pendulum from the server to the client with SPAs, and recently back to the server but with the additional legacy that they've accumulated in the swinging. React Server Components is a good example of that. They are back at the server, but with a vast list of NPM packages with components that make assumptions about their rendering. It feels wrong. Another one is Tailwind, which has gone from being a tool to being a layer on which entire design systems and templates are built. All you want is to add a design system to your project, and then you find yourself having to integrate the Tailwind toolchain into your stack. Why?</p>
<p>Some organizations and developers might like that working setup. I completely understand it. But I decided that I'm doing the opposite. I'm <strong>diving deep into understanding the web platform to peel layers of abstractions</strong> and build projects that are more future-proof and easier to maintain. Recent conversations with Marek, about the approach we'd take for Tuist Cloud, inspired me to embrace this philosophy. Here's a list of principles and ideas that I embraced in this website and that I'll embrace going forward:</p>
<ul>
<li><strong>Only build tools that are strictly necessary:</strong> For example, no ESBuild and no Tailwind. Recent standards and browser capabilities reduce the list of scenarios for which you needed build tools. - <strong>Plain CSS:</strong> There isn't really a need to learn a new layer of semantics that fill HTML elements with endless lists of utility classes like the ones that Tailwind proposes. CSS has evolved a lot and provides solutions for the problems that led to the emergence of utility-class frameworks like Tailwind. CSS is the abstraction itself, and I can achieve consistency via CSS variables, some of which I can take from the wonderful Open Props. - <strong>Web components:</strong> Web components are supported by the evergreen browsers. If you create a web component, you can rest assured that it'll work forever. The same is not true in <em>use-a-bloated-JS-rendering-technology</em>, where you might need to allocate time in a year or two to adopt a framework, because the technology says it's the recommended way to develop with it, or updating your components to adapt to breaking changes. - <strong>Embrace HTML semantics:</strong> I used to be that developer that 'ed everything making my websites very inaccessible. Now, the first thing that I do is trying to get the semantics right while keeping the design aside. Then, I bring the design into the equation using ARIA attributes to store state, as suggested in the Enduring CSS methodology.</li>
</ul>
<p>The new iteration of this website no longer depends on ESBuild and Tailwind, and uses web standards. Note that the design is simple by design, not by the simplification of the underlying stack. The only dependency is on Elixir and Phoenix, which are responsible for running the HTTP server that serves the website. Can I make it more future-proof by scripting something myself in JavaScript? Definitively. It can be a built-time-generated static website. However, I might add some server-side things down the road, so I'd rather keep the server piece, ensuring I use technologies like Phoenix that embrace the platform instead of abstracting it away.</p>
<p>It's been an elightening process that has shown me how powerful the web platform is. I'll follow the new ideas that abstractions bring to the table, while I slowly build on the lowest layer available.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Ensuring a smooth workshop experience</title>
      <link>https://pepicrft.me/blog/workshop-assert-script/</link>
      <guid>https://pepicrft.me/blog/workshop-assert-script/</guid>
      <pubDate>Fri, 17 Nov 2023 12:00:00 +0000</pubDate>
      <description>In preparation for a workshop that I&#x27;m conducting in Swiftable (Buenos Aires), I came up with an idea to ensure a smooth experience following the workshop</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>While preparing a workshop for <a rel="external" href="https://swiftable.com">Swiftable</a>, I wondered how the attendees could verify that they were ready to continue with the next topic. Jumping to the next topic with their setup in an invalid state can make a difference between enjoying the workshop from beginning to end and feeling completely stuck and lost. To tackle it, I came up with the idea of providing the developers with a script that they can run at the end of every section:</p>
<pre><code>bash &lt;(curl -sSL https://url-to-server.com/assert.sh) 1
</code></pre>
<p><code>1</code> is the number of the section that they just completed. Note how convenient it is to run it because you only need <code>bash</code> in your system, which is a safe assumption to make. I believe the fewer system requirements for the workshop and everything that surrounds it, the better. As a fallback, I provide a Git repository and a commit sha at the end of every section that developers can check out to continue with the workshop.</p>
<p>I'll test the method in a couple of weeks and report back.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Balancing mastery and sustainability</title>
      <link>https://pepicrft.me/blog/mastery-and-sustainability/</link>
      <guid>https://pepicrft.me/blog/mastery-and-sustainability/</guid>
      <pubDate>Tue, 14 Nov 2023 12:00:00 +0000</pubDate>
      <description>Juggling roles in Tuist, from coding to community support, taught the delicate balance between mastery and sustainability in open-source projects.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>My work with Tuist has revealed the intricate evolution of open-source projects into complex systems that demand effective governance. I embarked on this journey with a singular <strong>focus on craft and community</strong>, yet as the project expanded, I found myself juggling numerous roles. These included <em>coding, updating social media, reviewing code, delivering talks, writing documentation, providing support, and even redesigning and implementing websites</em>. Such diverse tasks are typically handled by specialized roles or entire teams in corporations, but in the realm of open-source, these responsibilities often fall on a few individuals, sometimes just one. This can lead to <a rel="external" href="https://en.wikipedia.org/wiki/Emotional_exhaustion">burnout</a>, a struggle often borne in silence due to a fear of appearing vulnerable to the community. It feels like an unspoken obligation to live up to a vision, showcasing the** complex nature of human psychology.**</p>
<p>This experience has taught us to approach our projects with a renewed perspective, particularly considering the significant impact they have on mental health and motivation. These human aspects are crucial to the wellbeing and innovation of the project. My deep-seated passion for Tuist’s problem domain has driven me towards mastery, a trait I share with other maintainers. However, an <strong>exclusive focus on mastery can lead to an imbalance</strong>, potentially risking the project's long-term sustainability. It is encouraging to see individuals and organizations prioritize mastery over profit and growth, but the challenge arises when the system fails to support individuals financially. Therefore, designing and implementing a supportive framework within the project is imperative.</p>
<p>This task is inherently challenging. Any evolution from a well-established model is bound to encounter resistance. Looking back at the inception of Tuist, I ponder whether I could have anticipated the system's current needs. At that time, the project's future was uncertain, with no user base for over a year. In hindsight, there was certainly room for improvement, but <strong>my intense focus on the craft limited my foresight regarding the system’s evolution.</strong> Observing projects like Sourcery and <a rel="external" href="https://www.merowing.info/sourcery-pro/">Sourcery Pro</a>, it’s intriguing to see the acceptance of open-core models contrasted with criticism of open-source projects evolving toward that model.</p>
<p>We acknowledge our imperfections and embrace the learning curve ahead. Our conviction in our decisions remains strong, and we are prepared to learn and pivot as needed, as we have over the past five years. Currently, we are focused on a major update for Tuist, signaling a new and significant phase in the project's journey.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Dear Bitrise</title>
      <link>https://pepicrft.me/blog/dear-bitrise/</link>
      <guid>https://pepicrft.me/blog/dear-bitrise/</guid>
      <pubDate>Fri, 10 Nov 2023 12:00:00 +0000</pubDate>
      <description>Read my personal take on Bitrise&#x27;s actions against Tuist, and how we&#x27;re rallying as a community to uphold our values and vision.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Dear Bitrise Team,</p>
<p>Today, I find it necessary to speak about the <a rel="external" href="https://bitrise.io/blog/post/tuist-bitrise-build-cache-update">recent attack</a> directed at our beloved <a rel="external" href="https://tuist.io">Tuist</a> project. Our journey with Tuist has been one of unwavering dedication. Over the past five years, we have poured our hearts into it, working tirelessly during our free hours. Our commitment led us to develop tools like <a rel="external" href="https://github.com/tuist/xcodeproj">XcodeProj</a>, integral to many in the ecosystem and crucial for systems like <a rel="external" href="https://github.com/MobileNativeFoundation/rules_xcodeproj">Bazel</a>, which you are now steering users toward. We've not only <a rel="external" href="https://github.com/tuist/bitrise-step-tuist">facilitated the integration of Tuist with your CI services</a> but also recommended speakers for your events.</p>
<p>In our community, we've always extended a helping hand to those facing challenges, focusing on support over financial gain. Our approach seems to differ starkly from yours.</p>
<p>Embarking on the Tuist journey, we underestimated the incoming demands for support and the sheer volume of requests. This is <a rel="external" href="https://www.youtube.com/watch?v=XZ3w_jec1v8">a common scenario</a> for open-source maintainers, often leading to <a rel="external" href="https://opensource.com/article/21/7/burnout-open-source">burnout</a>, a situation we have strived to avoid. Your approach, seeking a PR merge without having contributed a single line of code to Tuist, appeared more self-serving than community-focused. It added to our workload, contrary to your public image as an advocate for open-source.</p>
<p>The reality of Tuist's demands became clear – it needed dedicated, full-time attention. Here, we faced a financial dilemma. <a rel="external" href="https://github.com/sponsors/tuist">Donations</a>, which are always welcome and channeled towards <a rel="external" href="https://github.com/tuist/tuist/discussions/4982">bounties</a>, weren't enough. Investment wasn't a viable route either, as it often brings profit-driven motives that could jeopardize the essence of our project. Our independence from such influences allows us to focus solely on our user community's needs and challenges.</p>
<p>Introducing <a rel="external" href="https://tuist.io/cloud/">Tuist Cloud</a> was our strategic response to this need for sustainability. We've designed Tuist to <a rel="external" href="https://docs.tuist.io/tutorial/faq#what-if-the-tool-is-deprecated-at-some-point">minimize vendor lock-in</a>, a detail you may have overlooked given your limited engagement with the project. Users can easily migrate away by committing their Xcode projects and dropping Tuist, a feature common to most tools, <a rel="external" href="https://bazel.build">Bazel</a> and <a rel="external" href="https://bitrise.io">Bitrise</a> included. However, we choose not to retaliate by suggesting alternatives like GitHub Actions.</p>
<p>Tuist Cloud began as an open-source endeavor until we realized that this path wouldn't lead to sustainability. Comparisons with well-funded projects like Bazel are misplaced; unlike these giants and <a rel="external" href="https://bitrise.io/blog/post/weve-raised-60m-series-c-to-help-you-be-faster-more-efficient-and-more-successful-on-mobile">not so giant</a>, we lack substantial financial backing. Your actions, increasing our burden and publicly undermining us, were a blow to our efforts.</p>
<p>We're now developing Tuist Cloud as a closed-source extension for Tuist, a decision forced by circumstances, not choice. Our aim is not to perpetuate closed-source development but to find a sustainable path forward. The distinction between Tuist and Tuist Cloud lies in the realm of project generation versus optimized project generation. We urge our users not to be swayed by fear-mongering about Tuist's future.</p>
<p>Our commitment remains steadfast to a project and community we deeply care about, facing the challenges ahead, and gearing up for major releases. For those in doubt, we encourage conversations with our users to see the value and dedication we bring to the table.</p>
<p>Warm regards, Pedro</p>
<p><em>P.S. Bitrise, we've noticed that you've set up redirects on your pages, funneling readers to a blog post casting Tuist in a negative light. This includes the now-missing comparison page, which previously claimed your service's superiority over ours. Removing this page appears to be an attempt to hide the full story.</em></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Integrating Swift Macros with Xcodeproj native blocks</title>
      <link>https://pepicrft.me/blog/swift-macros-with-xcodeproj-native-blocks/</link>
      <guid>https://pepicrft.me/blog/swift-macros-with-xcodeproj-native-blocks/</guid>
      <pubDate>Wed, 08 Nov 2023 12:00:00 +0000</pubDate>
      <description>Exploring native Swift macro support in Tuist to simplify and accelerate Xcode project builds.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><a rel="external" href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/">Swift Macros</a> were introduced by Apple as a feature bundled within Swift Packages. This approach enhances shareability—a notable limitation of <a rel="external" href="https://github.com/tuist/xcodeproj">XcodeProj</a> elements like <a rel="external" href="https://github.com/tuist/XcodeProj/blob/main/Sources/XcodeProj/Objects/Targets/PBXNativeTarget.swift">targets</a>. However, it also tightens the reliance on seamless integration between Xcode and the Swift Package Manager (SPM), which, from my experience and that of others, can be less than ideal in large projects with numerous dependencies. In fact, some developers are shifting towards Tuist's methodology, reminiscent of <a rel="external" href="https://cocoapods.org">CocoaPods</a>, where projects are immediately ready for compilation upon opening.</p>
<p>Given the suboptimal experience offered by Apple's ecosystem, which precludes optimization opportunities, <strong>Tuist employs SPM to resolve packages before mapping them onto Xcodeproj elements.</strong> While generally effective, this approach has encountered occasional setbacks, which developers can rectify by tweaking the build settings of the generated targets. Yet, it has not supported Swift Macros since their announcement.</p>
<p>Interestingly, developers managing Xcode rules for <a rel="external" href="https://bazel.build">Bazel</a> quickly <a rel="external" href="https://github.com/bazelbuild/rules_swift/pull/1061">devised a method to accommodate Swift Macros using compiler flags</a>. Inspired by this, <em>could Tuist adopt a similar strategy by utilizing targets, dependencies, and build settings?</em> After some investigation, the answer is affirmative. Here's the <strong>blueprint</strong>:</p>
<p>The macro's representative target must be a <strong>macOS command-line target</strong>, encompassing the macro's source code. A secondary, dependent target is required, hosting the public macro definition for import by other targets.</p>
<p>Targets wishing to leverage the macro should: - Establish a dependency on the secondary target for prior compilation. - Include the setting <code>OTHER_SWIFT_FLAGS</code> with the value <code>-load-plugin-executable $BUILT_PRODUCTS_DIR/ExecutableName\#ExecutableName</code>.</p>
<p>This setup is contingent upon the secondary target and the dependent targets producing their outputs in the same directory. If that's not the case, <code>SWIFT_INCLUDE_PATHS</code> will be necessary to make the module available to the dependent targets.</p>
<p>With this mechanism uncovered, the next step is to integrate it into Tuist's Swift-based DSL and combine it with our binary caching feature. This integration will enable developers to concentrate on targets dependent on macros without the overhead of compiling the macros themselves.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Making Tuist easier to work with by saying goodbye to Ruby</title>
      <link>https://pepicrft.me/blog/ruby-and-tuist/</link>
      <guid>https://pepicrft.me/blog/ruby-and-tuist/</guid>
      <pubDate>Tue, 07 Nov 2023 12:00:00 +0000</pubDate>
      <description>We&#x27;re removing Ruby from Tuist, integrating everything into Xcode, replacing Fourier with bash scripts, and rewriting tests in Swift for ease.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>At some point in the life of <a rel="external" href="https://tuist.io">Tuist</a>, we decided to introduce <a rel="external" href="https://www.ruby-lang.org/en/">Ruby</a> into its codebase. The <strong>CI pipelines were beginning to contain a considerable amount of business logic</strong>, and it was somewhat inconvenient for developers to run the same workflows locally. Therefore, I developed a small Ruby-based CLI, which would be included in the repository as <strong>Fourier</strong>.</p>
<p>We also chose to implement the acceptance tests in Ruby. We believed that the <a rel="external" href="https://en.wikipedia.org/wiki/Behavior-driven_development">BDD approach</a>, as proposed by <a rel="external" href="https://cucumber.io">Cucumber</a>, would be most suitable due to its ability to produce very readable scenarios and prevent the tests from being aware of the Swift implementation details.</p>
<p>In hindsight, <strong>it was a mistake</strong>, and we are already taking steps to rectify that.</p>
<p>The main issue is that <strong>it introduces friction to the experience of contributing to the repository for the first time</strong>. In addition to Xcode, which we can safely assume developers have on their systems, they need to install the same version of Ruby that everyone else is using (to avoid inconsistencies), remember to run <code>bundle install</code> to pull dependencies such as Cucumber, and, not least, feel comfortable diving into Ruby code when things don't work as expected. Many developers may not have used Ruby before, and this task can seem very daunting, <strong>resulting in them relying on us</strong>—the maintainers—to resolve issues.</p>
<p>We also noticed considerable hesitance towards writing the tests. Beyond the fact that some steps' implementations needed to be done in Ruby—a task they could manage by referring to other steps—the Regex-based step definitions were also a bit intimidating. Once again, it was we—the maintainers—who would end up writing most of the tests.</p>
<p><em>So, what are we doing about it?</em> We're removing Ruby from the codebase and integrating everything tightly into Xcode. We are <strong>eliminating the Fourier CLI</strong> and replacing it with universal bash scripts that require no additional tooling, some of which can be invoked through make. <a rel="external" href="https://chat.openai.com">ChatGPT</a> has been quite helpful here, as I'm not at all comfortable writing business logic in bash. We are also <strong>rewriting our acceptance tests in Swift</strong> so that they can run in parallel using Xcode and SPM. Developers will be able to execute these tests directly from Xcode and even add breakpoints to debug execution. This change will not only enhance the working experience with these tests but also create a faster feedback loop. This transition has been challenging because PRs took a long time to be ready for merging.</p>
<p>I am eagerly awaiting the implementation of these improvements. It's easy to make incorrect decisions like these, but it's crucial that we periodically reflect on them and adjust our course if necessary—and that's exactly what we are doing.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>From side project to sustainable tool</title>
      <link>https://pepicrft.me/blog/open-source-sustainability/</link>
      <guid>https://pepicrft.me/blog/open-source-sustainability/</guid>
      <pubDate>Sat, 28 Oct 2023 12:00:00 +0000</pubDate>
      <description>Tuist, now 6 years old, has become essential for organizations using Xcode. While initially a side project, its popularity surged. To ensure sustainability, we&#x27;re introducing paid features alongside free ones, navigating challenges like unauthorized forks and finding the right business model.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It's hard to believe, but <a rel="external" href="https://tuist.io">Tuist</a> is now 6 years old and has become an <strong>indispensable tool for medium and large organizations</strong>. I began building it due to my profound understanding of the challenges associated with using Xcode at scale and the inaccessibility of alternative build systems for smaller organizations. Tuist was always a side project — something I built in my spare time.</p>
<p>While I was at <a rel="external" href="https://soundcloud.com">SoundCloud</a>, the organization didn't adopt Tuist until after I had left. Later, at <a rel="external" href="https://shopify.com">Shopify</a>, I attempted to introduce it to address challenges they faced with Xcode. However, there was strong advocacy for using only Apple's official tools, so adoption didn't happen. Interestingly, the company eventually transitioned to <a rel="external" href="https://reactnative.dev/">React Native</a>. While at Shopify, I hired developers I met through Tuist. This <strong>led many to assume that Shopify used Tuist and sponsored me to work on it full-time.</strong> In reality, I could only dedicate my spare time to it, and as time progressed, it became increasingly challenging. Eventually, <a rel="external" href="https://github.com/fortmarek">Marek</a> and the core team took over some responsibilities because I needed a break.</p>
<p>Throughout this period, <strong>word of mouth</strong> was effective. Companies initially approached Tuist for project generation but stayed for the additional features. Today, numerous organizations prefer Tuist over <a rel="external" href="https://github.com/yonaskolb/XcodeGen">XcodeGen</a> as they recognize that Git conflicts aren't the sole challenge of scaling. Defining Tuist is challenging; while many see it simply as a generator, it's much more. We eventually realized that <strong>we had laid the foundation for significant optimizations and an integrated development experience.</strong></p>
<p>The project's popularity surpassed our expectations. With the increase in users came a proportional increase in time and effort. <strong>Continuing on our personal time risked burnout,</strong> which I wanted to avoid both for myself and other dedicated contributors.</p>
<p>So, what next? I researched open source sustainability models to determine what would fit Tuist best.</p>
<p>One idea was to <strong>limit Tuist's scope</strong> to easily maintainable features given our team size. But this would disappoint many users by reducing the tool to just project generation. Although this feature is reliable, extendable, and only requires major updates with new Xcode releases, we decided against this route. Users love the unique extensions that enhance their productivity with Tuist.</p>
<p>While we were eager to have full-time contributors, <strong>donations didn't suffice.</strong> They covered some costs but weren't substantial enough for salaries. We're immensely thankful to our sponsors for their support.</p>
<p>One potential path was to join a large tech firm, similar to <a rel="external" href="https://fastlane.tools/">Fastlane</a>. However, such partnerships often prioritize corporate interests over solving real problems. In Fastlane's case, data became the focus under <a rel="external" href="https://google.com">Google</a>'s ownership. I also contemplated offering <strong>consulting services</strong>, leveraging our expertise. But the reception was lukewarm as most companies had either already transitioned or found their answers online.</p>
<p>We then considered models from similar tools, like <a rel="external" href="https://gradle.org/">Gradle</a> and <a rel="external" href="https://nx.dev/">Nx</a>. These tools offer <strong>server-side paid features</strong> for advanced requirements, which seemed fitting for Tuist. Thus, we began working towards this model, even initiating the process of setting up a legal entity in Germany, Tuist GmbH.</p>
<p><strong>Simply put, if you need project generation, Tuist aims to be the best at it. For optimizations, we'll introduce paid features, priced reasonably in comparison to the benefits they offer.</strong></p>
<p>However, challenges emerged. A prominent Mobile DevOps company, <a rel="external" href="https://bitrise.io/">Bitrise</a>, launched a service for Tuist users, requiring a Tuist fork. This experience taught us <strong>the complexities of business dynamics</strong>. We had previously communicated our intentions to them, so we decided to develop certain client features privately. Our goal remains to return to open source, but first, we need to ensure the project's sustainability.</p>
<p>Another issue was that some organizations <strong>bypassed payments for Tuist Cloud</strong>. While we tried to stress the importance of financial support, some viewed it as optional. Consequently, we're implementing measures to counteract these workarounds.</p>
<p>There are more discussions ahead, but this new phase for Tuist is crucial. We want to ensure that Tuist remains faithful to its core values and principles, delivering consistent value sustainably. Sustainability is central to Tuist's success, and I'm committed to realizing that vision.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Empowering Development: The Journey and Vision of Tuist</title>
      <link>https://pepicrft.me/blog/the-future-we-envision-for-xcode-devs/</link>
      <guid>https://pepicrft.me/blog/the-future-we-envision-for-xcode-devs/</guid>
      <pubDate>Mon, 16 Oct 2023 12:00:00 +0000</pubDate>
      <description>Tuist provides solutions to challenges in large-scale app development overlooked by Apple. It&#x27;s a foundation for developers, promising simplicity and a future filled with actionable insights.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It's been about six years since organizations began to understand the lack of focus Apple has given to the challenges of large-scale development. Within this timeframe, it became evident <strong>how invaluable <a rel="external" href="https://tuist.io">Tuist</a> is in addressing these challenges</strong>. Numerous major projects and white-label apps have come to recognize the prowess of Tuist, valuing its ability to maintain simplicity even while scaling. Some have even transitioned from intricate build systems like <a rel="external" href="https://bazel.build/">Bazel</a>, which, despite their strengths, impose an <strong>unsustainable level of complexity and support demands on many organizations.</strong></p>
<p>Our journey in developing Tuist wasn't an easy one. We juggled multiple roles, from coding to marketing, writing to community support. Each hat we wore was worn out of faith in Tuist and its potential impact on the development community. And let's be clear: <strong>this is only the beginning.</strong></p>
<p>The journey took six years, primarily because it was a side project for us. But imagine the strides we could make if we dedicated our full attention to it! Tuist is more than just a tool; it's a foundation that equips developers with essential tools for sustainable growth. I'm often perplexed as to why Apple hasn't addressed certain metrics:</p>
<ul>
<li><em>How frequently do developers need to perform a clean build after encountering a compilation error?</em> - <em>How long do targets take to build or tests take to run?</em> - <em>How frequently do tests fail, and can they be automatically disabled when they do?</em></li>
</ul>
<p>Apple seems preoccupied, perhaps grappling with legacy decisions in Xcode, while continually rolling out new language features and APIs. While these features are exciting for small projects, they're less so when projects scale up, revealing Xcode's limitations. At this juncture, organizations often either waste time battling these issues or divert to alternative solutions like <a rel="external" href="https://reactnative.dev/">React Native</a>. The good news? Other ecosystems have already tackled these challenges, and there's much we can learn.</p>
<p>For us, this represents an opportunity. <strong>An opportunity to offer a seamlessly integrated solution.</strong> When observing the tools aiming to integrate into developers' workflows, it's evident that many setups are convoluted. <strong>The ideal experience for developers is simplicity.</strong> They should execute a command and have everything work seamlessly. Sadly, Apple doesn't provide the necessary APIs for a smooth integration into Xcode. Many tools lean on <a rel="external" href="https://fastlane.tools/">Fastlane</a>, bringing along the complexities of Ruby, Bundler, and more. With Tuist, all you need is Tuist and a project defined through it.</p>
<p>The future for <a rel="external" href="https://tuist.io/cloud/">Tuist Cloud</a> looks promising. We've laid a solid foundation and cultivated a community that genuinely believes in our mission. As we move forward, we'll introduce exciting features. From boosting developer productivity to providing actionable insights and even automating tasks for developers, the possibilities are boundless.</p>
<p>In summary, while Tuist Cloud is still evolving, the hardest part is behind us. We have a firm foundation and a dedicated community. Now, it's our turn to <strong>supercharge Tuist and empower development teams to foster thriving environments.</strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Recalibrating Mental Models in Elixir Programming</title>
      <link>https://pepicrft.me/blog/reprogramming-my-programming-mental-models/</link>
      <guid>https://pepicrft.me/blog/reprogramming-my-programming-mental-models/</guid>
      <pubDate>Sat, 14 Oct 2023 12:00:00 +0000</pubDate>
      <description>Navigating through Elixir requires a rethinking of traditional OOP mental models, inviting a shift towards domain-centric thinking. Embracing Elixir&#x27;s functional paradigm offers intriguing challenges and a rewarding, fresh perspective on problem-solving in programming.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As I delve deeper into programming with Elixir, I am prompted to reconsider the mental models formulated over years of experience. Initially, when contemplating a problem space and a potential solution, my mind spontaneously navigates towards an <a rel="external" href="https://en.wikipedia.org/wiki/Object-oriented_programming">Object-Oriented Programming (OOP)</a> world, constructing a picture involving repositories, services, and presenters to facilitate various layers of application, especially testing. However, this model doesn’t quite fit seamlessly into <a rel="external" href="https://elixir-lang.org/">Elixir</a>-a functional language where everything condenses down to functions and modules simply act as namespaces to encapsulate them, occasionally embodying semantics similar to interfaces in OOP.</p>
<p>While my mental models are instinctively oriented towards objects and classes, envisioning an ideal—or even a proximate—solution in Elixir poses a challenge. A strategy I’ve adopted to navigate this is to <strong>think in terms of domains instead of the traditional OOP mental model</strong>. Consider the following Elixir functions that interface with a <code>%Plug.Conn{}</code> to manage session information:</p>
<pre><code>Auth.set_authenticated_user(conn, user)
Auth.get_authenticated_user(conn)
Auth.user_authenticated?(conn)
Auth.load_authenticated_user_from_session(conn)
</code></pre>
<p>This code, expressive and reflective of real-world modeling, underscores one of Erlang creator <a rel="external" href="https://en.wikipedia.org/wiki/Joe_Armstrong_(programmer)">Joe Armstrong</a>’s points from his <a rel="external" href="https://erlang.org/download/armstrong_thesis_2003.pdf">renowned paper</a>: the proximate modeling of problems and solutions in Erlang, analogous to real-world scenarios, enhances the maintainability and reasoning of the software. <strong>Adopting this mindset is pivotal and necessitates the relinquishment of numerous concepts ingrained from OOP.</strong></p>
<p>Moreover, abandoning these concepts also means recalibrating practices built upon them, such as testing. Traditional architectural solutions enable isolated testing. For example, testing business logic without the concern of data origin, since we might mock a repository. However, in the functional realm of Elixir, where every entity is a function or a function combination, the narrative is distinctly varied.</p>
<p>Consider a hypothetical scenario: testing a function combination that symbolizes a slice of business logic, which is more user-centric as opposed to stating, "when I call this function with these arguments, I expect this query to be executed to the database". My journey through various codebases has occasionally led me to allow inertia to dictate, perpetuating historical practices. Yet, the pertinent question that perpetually surfaces as I script in Elixir is: <em>Do these tests make sense?</em> <em>Is it logical to test whether storing the authenticated user appears in a specific key inside the connection assigns?</em> Or, <em>would it be more valuable to test, for instance, whether a specific request, requiring user authentication, fails with a designated error if the user is not authenticated?</em></p>
<p>In conclusion, as I savor my Saturday morning coffee ☕️, Elixir continues to captivate me. The challenge of mentally rewiring to adapt to its distinctive paradigms is not only intriguing but also refreshingly fun.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>We do it for the community</title>
      <link>https://pepicrft.me/blog/for-the-community/</link>
      <guid>https://pepicrft.me/blog/for-the-community/</guid>
      <pubDate>Fri, 06 Oct 2023 12:00:00 +0000</pubDate>
      <description>Embarking on a nuanced journey with Tuist, facing ethical dilemmas &amp; aiming for sustainability, I invite you to be part of our personal tech story.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It’s a beautiful sentiment to reflect upon – <em>"We do this for the community."</em> This phrase, delicately expressed to us recently, cast light on the vibrant pulse and potential inherent in our project, <a rel="external" href="https://tuist.io">Tuist</a>. An insightful suggestion about integrating a feature to streamline Tuist remote caching presented not just a technological prospect, but a moment to ponder about <strong>collaborative innovation and ethical praxis in the open-source landscape.</strong></p>
<p>Navigating through this journey of developing Tuist, whilst seeking a viable path to support my family and me, has been a profound exploration. It's not just about discovering solutions for myriad challenges users encounter with Xcode, but also about weaving a tapestry of sustainable development that resonates with community ethos and altruistic collaborations.</p>
<p>In a world where every digital step is entwined with ethical considerations, especially in our endeavour to sustainably develop Tuist, we tread cautiously. While our project is shielded with a <a rel="external" href="https://github.com/tuist/tuist/blob/main/LICENSE.md">permissive license</a>, <strong>the ethical dialogue it intertwines with is both vital and delicate.</strong></p>
<p>At times, miscommunications happen. Perhaps in their zeal to contribute, some may overlook the underlying struggles and aspirations of our team, attempting to harness Tuist’s capabilities for their gain, somewhat overshadowing our journey towards sustainability. It's conceivable - <em>maybe they were unaware of our aspirations to immerse ourselves full-time into Tuist's development?</em> Always leaning into a belief in others’ good intentions, this was a possibility I considered. But understanding evolved through conversations, revealing a knowing that was deeper and more informed.</p>
<p>Despite these revelations, <strong>we've witnessed actions that teetered on the edge of ethical bounds.</strong> Navigating through instances where our sustainability initiatives, like <a rel="external" href="https://tuist.io/cloud">Tuist Cloud</a> were contrasted unfavorably against services of investor-backed entities, was indeed a challenge. But herein, we also found a spark – an ignition of resolve to protect and nurture the sanctity and future of Tuist.</p>
<p>In a realm where open-source projects, like <a rel="external" href="http://fastlane.tools/">Fastlane</a> and <a rel="external" href="https://rubyonrails.org/">Rails</a>, have found sanctuary and sustained development within large organizations and dedicated teams, Tuist weaves a slightly different narrative. The likelihood of a dedicated Tuist infrastructure team materializing within an organization may appear slim, yet what pulses brightly within us is an unbridled passion for problem-solving and innovation within this domain.</p>
<p>So, here we stand, at a pivotal crossroads, choosing to <strong>develop the client-side functionality that fuels Tuist Cloud in private</strong>, at least until we solidify our path to project sustainability. This decision, forged in the crucible of challenges, is imbued with hope - hope that this enclosure is merely a temporary phase, and that we’ll soon fling open the gates to a reservoir of source value once more.</p>
<p>Even as we navigated through the echoes of bold business moves that nudged us unexpectedly, our commitment to positivity and innovation has remained unwavering. Now, we’re not merely players, but steadfast contributors to a different league, an evolved narrative of inspiring sustainable open-source development.</p>
<p>To you, our cherished Tuist users, let your hearts be light and assured. In the embracing and indomitable spirit of us - the people that breathe life into Tuist - you have a trustworthy companion. As we untangle the threads of this challenge and reweave them into a tapestry of innovative solutions and sustainable practices, the horizon looks even more radiant and promising.</p>
<p>There’s an entire universe of solutions we're eager to explore and implement, and with an evolving framework that hopefully <strong>allows us more dedicated time for Tuist</strong>, this will change, blossoming into a reality where our collective dreams and innovations converge, uplifting and empowering each one in our community.</p>
<p>Together, in unity, innovation, and ethical collaboration, let's continue to co-create, inspire, and elevate Tuist into realms where technology and ethical sustainability dance in harmonious synchrony.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Between Simplicity and Limitations: A Developer&#x27;s Take on Apple&#x27;s Tooling Strategy</title>
      <link>https://pepicrft.me/blog/apple-tooling/</link>
      <guid>https://pepicrft.me/blog/apple-tooling/</guid>
      <pubDate>Fri, 29 Sep 2023 12:00:00 +0000</pubDate>
      <description>Apple&#x27;s focus on simplifying basic tasks may overshadow the challenges of complex operations. Developers, often uninformed due to lack of data, face hard choices: pivot to alternatives or revamp systems. </description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Yesterday, I wrote about <a rel="external" href="https://tuist.io/blog/2023/09/23/ios-evolution-and-tuist/">the evolution of iOS development and the role of Tuist in it</a>. I kept reflecting on some of the ideas that I touched on in it. One of them, in particular, is the <strong>tradeoff</strong> that Apple found itself having to make between developers' convenience, which is a key tool to make it easy for developers to get started, and flexibility, which is what medium-to-large apps need to be able to scale.</p>
<p>You might think you won't ever have the need of thinking about scale, but let me tell you that you will. <strong>Scalability is not only about the size of a project but also about the breadth of it.</strong> The moment you decide to support multiple platforms, for example, <a rel="external" href="https://en.wikipedia.org/wiki/IOS">iOS</a> and <a rel="external" href="https://en.wikipedia.org/wiki/WatchOS">watchOS</a>, you'll most likely want to reuse code across targets. This is achievable through shared targets, which introduce you to the world of dependencies that I <a rel="external" href="https://tuist.io/blog/2023/09/23/ios-evolution-and-tuist/">discussed yesterday</a>.</p>
<p>Configuring a <strong>modular Xcode project</strong>, including its external dependencies, is a tedious and error-prone task. If Apple's platform were dynamic like <a rel="external" href="https://en.wikipedia.org/wiki/Node.js">NodeJS</a>, we wouldn't even have to think about the problems I'm going to talk about because modules are dynamically resolved and loaded. Unless you make some <code>node_modules</code>-like design decision, and you find yourself in a spot that's difficult to move away from. What that means is that the build process is more involved, and <strong>the build system and the mental models it works with are more intricate.</strong></p>
<p>If you have built for the Apple ecosystem for a while, you've most likely faced the issue of <em>"duplicated symbols"</em> or apps crashing at runtime because there's a dynamic module that hasn't been copied into the final product (i.e., <em>"framework not found"</em>). Those are hard to debug, aren't they? I became so weirdly obsessed with understanding them that I decided to build <a rel="external" href="https://tuist.io">Tuist</a> so that no one would have to do it themselves manually. The problem is that when Apple recognized that it's not trivial, and the number of use cases that we need to handle in Tuist's codebase is a good proof of that, they decided to go down the path of convenience and <strong>enabled some implicit settings</strong>. What does it mean in practice? There are several places where one can experience that, but the most obvious one is Apple being able to detect target dependencies by looking at who outputs a <code>.framework</code> into a directory that's exposed to our target through the framework search path. Isn't it cool? It is, until it's not. What works for the developer that's getting started, whose dependency graph is small, doesn't work in slightly larger projects where there's a mix of static and dynamic frameworks and libraries. And the matter keeps getting worse because Apple doesn't cease to add new target types. For example, there's now Swift Macros and Build Tools.</p>
<p>So, in order to solve the problem, we had to start by <strong>making the implicit explicit</strong>. And the core-most element that required that explicitness was <strong>the dependency graph</strong>. One might think that the dependency graph refers only to external dependencies, but with it, I'm also referring to the targets that are part of your project - some dependencies are local, and others are remote. They are all dependencies. So when you look at <a rel="external" href="https://tuist.github.io/tuist/main/documentation/projectdescription/project/">Tuist's DSL</a>, you'll notice that it made dependencies front and center. The build settings and phases that are required are an <a rel="external" href="https://github.com/tuist/tuist/blob/main/Sources/TuistGenerator/Generator/BuildPhaseGenerator.swift#L57">implementation detail</a>. If a dynamic framework needs to be copied, we know and configure things properly. The same is true for when the right binary of an <code>.xcframework</code> needs to be selected for the target that's linking against it. As mentioned earlier, the scenarios are endless, and <strong>you really don't want to be doing that yourself.</strong></p>
<p>The problem is that <strong>Apple doesn't reconsider the implicitness path</strong>, which in my opinion is a terrible design idea. At least if we think of a future where apps are multi-platform and very modular, which I think is realistic to think about. A good example of that is that the integration between Xcode and the <a rel="external" href="https://www.swift.org/package-manager/">Swift Package Manager</a> is also very implicit. Xcode's build system and the Swift Package Manager are both communicating and making decisions at build time to keep things convenient. Just flag Swift Packages to be automatically linked, and Xcode will do it for you. Until it doesn't, or the experience is laggy and slow, and you can't do little about it.</p>
<p>I met with a developer over a month ago, and <strong>we chatted a bit about their transition from Tuist to Swift Package Manager</strong>, and they found themselves very limited by the optimization opportunities that the Swift Package Manager offers. I'd be surprised if they can change that without going back to first principles because they should even start with questioning <strong>whether a compiled language, Swift, is the right tool for the job.</strong> When we look at more advanced systems, we see dynamic, fast, and functional DSLs being the common denominator. Xcode's build system should probably be closer to what <a rel="external" href="https://gradle.org/">Gradle</a> is for Android. From all the things compiling Swift could offer, like sharing code across manifest files or coming up with with abstractions, they only use type-related capabilities.</p>
<p>Apple appears to be hindering their own progress. <strong>While they've streamlined basic tasks, they've concurrently made more intricate ones seem unattainable</strong>. This puts developers in a quandary: <em>how can they discern these limitations when Apple doesn't offer comprehensive insights from its tools?</em> Often, developers only recognize these constraints when faced with them directly. Consequently, many organizations either pivot towards alternatives like <a rel="external" href="https://reactnative.dev/">React Native</a> or undertake the daunting task of overhauling the entire build system. I encountered this firsthand at <a rel="external" href="https://shopify.com">Shopify</a>. Despite my persistent efforts to highlight the unsustainability of their unwavering reliance on Xcode, I was met with staunch opposition, culminating in a top-down directive to transition to <a rel="external" href="https://shopify.engineering/react-native-future-mobile-shopify">React Native</a>.</p>
<p>It's not an easy problem to solve, but I believe <strong>it's a problem worth solving</strong>. They should consider <strong>layering their tooling such that there's a very low extensible layer without convenience or implicitness that developers can build upon and extend.</strong> And then another layer on top of it that's the one that provides the convenience and says <em>"we are trying to be smart to help you stay focused."</em> Right now, there's a single layer that stretches too broadly and is more of a hindrance than a help. Xcode would know how to contract with those layers, and alternative build systems like <a rel="external" href="https://bazel.build">Bazel</a> or <a rel="external" href="https://gradle.org/">Gradle</a> would have the possibility to swap pieces as needed.</p>
<p>As someone trying to help solve this problem, <strong>I find the whole situation very frustrating.</strong> It's frustrating because everyone gets eclipsed by what Apple proposes, and they are unable to objectively decide whether that's a good idea or not. Hence why I'm writing blog posts like this one. Hopefully, one day Apple goes back to the root and rethinks the build system. I personally believe the Swift Package Manager path is not the way.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Reclaiming Mental Peace: My Personal Odyssey</title>
      <link>https://pepicrft.me/blog/rebalancing-mental-peace/</link>
      <guid>https://pepicrft.me/blog/rebalancing-mental-peace/</guid>
      <pubDate>Wed, 27 Sep 2023 12:00:00 +0000</pubDate>
      <description>Battling daily mental fatigue, I embarked on a personal journey to rediscover clarity. Through exercise, mindful task management, and self-reflection, I&#x27;m finding my way back.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Every morning, I wake up with a vigor that promises a fruitful day. But come evening, ** my mind clouds over**, leaving me mentally drained. This daily battle with mental fatigue has shadowed me for years. I'd gaze at my reflection, asking the weary eyes staring back, <em>"What am I missing?"</em></p>
<p>During a recent bout of unemployment, I found a quiet moment of clarity to understand the roots of my exhaustion. Today, I'm opening my heart to share w<strong>hat I've unearthed and the measures I'm taking to reclaim my mental peace.</strong></p>
<p>When I share my daily tasks with friends, their eyebrows raise in surprise at my seemingly endless activities. But here's my confession: building software isn't just a job for me, it's a sanctuary. Just as an artist finds solace in their brushstrokes, <strong>I find joy in coding</strong>. It's a family trait, I believe. My parents and sister are ceaseless whirlwinds of energy, and pausing what they love would be like caging a free spirit. I cherish the moments of creativity my craft brings me, ensuring I balance my passion with rest.</p>
<p>However, another culprit silently contributed to my mental turmoil: my dwindling exercise routine. Once, the rhythmic pounding of my feet on the pavement was my daily ritual. Yet, I let life's distractions coax me away from it. But every time I return, like my recent run through the familiar paths of <a rel="external" href="https://es.wikipedia.org/wiki/Cieza">Cieza</a> in Spain, I'm reminded of the mental clarity it grants me. So, I've made a pact with myself - <strong>daily exercise, with occasional breaks.</strong></p>
<p>Diving deeper into my daily life, I noticed a pattern. <strong>My attention flitted like a restless butterfly</strong>: from Slack to coding, coding to email, email to countless other tasks. These ceaseless shifts became second nature, feeding my anxiety. To counteract this, I now set specific times for checking emails, social media, and other apps, training myself to relish moments of stillness without the lure of aimless scrolling.</p>
<p>I've also introduced a faithful companion to my life: <a rel="external" href="https://todoist.com/app/">Todoist</a>, a <strong>TODO app</strong>. Before, I tackled tasks as they appeared, like a ship swaying with the tide. Now, I pen down every thought and prioritize tasks each evening, setting clear intentions for the next day. Adopting this methodical approach has been a challenge, given my instinctive chaotic nature, but its promise of a calmer mind drives me forward.</p>
<p>Coming to terms with the fact that life's to-do list is ever-growing has been a revelation. My labor of love, <a rel="external" href="https://tuist.io">Tuist</a>, always has a fresh challenge. But I've learned the art of setting boundaries, prioritizing mental well-being above all. I've also carved out pockets of time to indulge in tasks <strong>that might not be 'productive' but <a href="https://pepicrft.me/blog/rebalancing-mental-peace/__GHOST_URL__/blog/2023/09/13/passion-profit">nourish my soul</a>.</strong></p>
<p>These changes, though recent, have begun to mend my mental fabric. I now <strong>greet evenings with a clearer mind and a more present heart</strong>. My journey is still unfolding, and I remain a student of life, always eager to refine my ways. Sharing my story here is my way of reaching out, hoping my experiences might resonate with someone else. If you've carved your path to mental well-being, <a href="mailto:hola@pepicrft.me">I'd love to walk a mile in your shoes and learn from it</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Exploring Mocking Solutions in Elixir: Introducing Modulex</title>
      <link>https://pepicrft.me/blog/application-module/</link>
      <guid>https://pepicrft.me/blog/application-module/</guid>
      <pubDate>Thu, 21 Sep 2023 12:00:00 +0000</pubDate>
      <description>Exploring Elixir&#x27;s Mox for mocking reveals boilerplate code issues. A new package, modulex, aims to streamline this process.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've recently delved into the world of mocking in Elixir and have been particularly intrigued by the Mox package, endorsed by José Valim. While studying this approach, I noticed that it could introduce a considerable amount of boilerplate code into a codebase, along with potential inconsistencies in how module references are managed in the application environment. I couldn't help but think there had to be a more streamlined solution.</p>
<p>Take, for example, the typical module structure in such a setup:</p>
<pre><code>defmodule MyModule do
 @behaviour __MODULE__.Behaviour

 def hello(name) do
 application_env_module().hello(name)
 end

 def application_env_module() do
 get_in(Application.get_env(:my_app, :modules), [:my_module]) || __MODULE__.Implementation
 end

 defmodule Implementation do
 @behaviour MyModule.Behaviour

 def hello(name) do
 &quot;Hello #{name}&quot;
 end
 end

 defmodule Behaviour do
 @callback hello(name :: String.t()) :: any()
 end
end
</code></pre>
<p>In this example, <code>MyModule</code> serves as a facade that selects an appropriate module based on the application environment configuration. If a module atom is specified, it's utilized; otherwise, the code defaults to the built-in implementation. However, this structure has some downsides:</p>
<ul>
<li>Boilerplate code that acts as a proxy to the underlying implementation could be automatically generated. - The method <code>application_env_module</code> and related naming conventions can become inconsistent across the codebase.</li>
</ul>
<p>To tackle these challenges and experiment with Elixir macros, I created a new package for the Elixir ecosystem named <a rel="external" href="https://hex.pm/packages/modulex"><code>modulex</code></a>. With this package, the previous example can be refactored as follows:</p>
<pre><code>defmodule MyModule do
 use Application.Module

 defimplementation do
 def hello(name) do
 &quot;Hello #{name}&quot;
 end
 end

 defbehaviour do
 @callback hello(name :: String.t()) :: any()
 end
end
</code></pre>
<p>Notice how much more concise and ergonomic the code has become. I chose to prioritize convention over configuration, thereby standardizing the naming of child modules and the keys within the application environment.</p>
<p>For those who use <a rel="external" href="https://github.com/dashbitco/mox">Mox</a> or <a rel="external" href="https://github.com/msz/hammox">Hammox</a> for mock definitions, you can easily set a mock like so:</p>
<pre><code># test_helper.exs

Mox.defmock(MyApplication.Module.mock_module(), for: MyApplication.Module.behaviour_module())
MyApplication.Module.put_application_env_module(MyApplication.Module.mock_module())
</code></pre>
<p>I'd love to hear any feedback on the implementation or the API design. This is my inaugural venture into Elixir macros, and the journey has been both rewarding and a process of trial and error.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Passion vs. Profit: My Quest for Meaningful Craftsmanship in Tech</title>
      <link>https://pepicrft.me/blog/passion-profit/</link>
      <guid>https://pepicrft.me/blog/passion-profit/</guid>
      <pubDate>Wed, 13 Sep 2023 12:00:00 +0000</pubDate>
      <description>In a world where money often takes the front seat, how do we balance the joy of craftsmanship with the need for financial stability? Here&#x27;s a personal reflection on the intersection of passion, craft, and monetary pursuits.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As I delve deeper into my work on <a rel="external" href="https://github.com/glossia">Glossia</a> and <a rel="external" href="https://github.com/tuist/tuist">Tuist Cloud</a>, I frequently find myself drawn to tasks that, while they influence the final product, aren't necessarily seen as financial priorities by many. This leaves me in a conundrum: <em>I can pursue what I genuinely enjoy but might not be financially rewarding, or I can focus on monetary gains and potentially lose out on the joy of the process.</em> Striking the right balance is an ongoing challenge. It begs the question - what kind of world are we molding if human needs take a backseat?</p>
<p>Strangely enough, <strong>pursuing money doesn't fulfill me.</strong> I recently attended an AI Meetup in Berlin, and left feeling hollow. The majority of conversations revolved around financial pursuits - raising capital, monetizing ideas, or selling startups. Shockingly, there was little to no discussion about the human-centric problems the showcased technology aimed to solve.</p>
<p>Ideally, <strong>I'd like a steady stream of income that lets me forget about financial woes altogether.</strong> But attaining this requires adopting a business-centric mindset which doesn't resonate with me. Wouldn't it be wonderful if financial stability was the byproduct of quality craftsmanship? This was evident with Tuist. A simple change on the website, showcasing logos of companies using our platform, suddenly piqued the interest of many. Ironically, this value was constructed without a monetary focus. Isn't that paradoxical?</p>
<p>A recent endeavor of mine is <a rel="external" href="https://github.com/glossia/noora">Noora</a>, a design system for Glossia, powered by Elixir and inspired by prominent JavaScript design systems. I recognized the superior design systems in JavaScript and felt it unjust for users to integrate additional complexity into their stack merely to access these systems. With Glossia in mind, I opted to embed this into its core and make it universally accessible. This also gave me a chance to delve deeper into <a rel="external" href="https://elixir-lang.org/getting-started/meta/macros.html">Elixir macros</a>. While such endeavors may not directly boost Glossia's profitability, they refine the craftsmanship, enhance the product, and nurture a community - potentially drawing Elixir enthusiasts towards Glossia. A parallel can be drawn with <a rel="external" href="https://shopify.com">Shopify</a> and its significant contributions to the <a rel="external" href="https://www.ruby-lang.org/en/">Ruby community</a>, now a haven for Ruby developers.</p>
<p>Reflecting on this, <strong>I believe such an approach is what sets Tuist apart.</strong> It's a project that oozes humanity and is primarily fueled by passion. Introducing a financial element is a necessity, a means to an end. My earnest hope is that once I reach that financial comfort zone, I can continue to revel in the sheer joy of craftsmanship. I wonder if others resonate with these sentiments? I'd be keen to hear your perspectives.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Tuist: From Passion to Craftsmanship, Charting New Horizons</title>
      <link>https://pepicrft.me/blog/tuist-journey/</link>
      <guid>https://pepicrft.me/blog/tuist-journey/</guid>
      <pubDate>Sat, 19 Aug 2023 12:00:00 +0000</pubDate>
      <description>From its inception in 2018, Tuist has grown through passion and dedication, now embarking on new horizons.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If you've journeyed with me from the onset, you'll recall the birth of <a rel="external" href="https://tuist.io/">Tuist</a> and how I've nurtured it through thick and thin. Since its inception in 2018, we've navigated tumultuous waters, including those frenzied days at my previous job. Today, allow me to pull back the curtain, recounting our <strong>adventures, triumphs, and the promising horizon ahead.</strong></p>
<p>For newcomers, here's a quick sketch: Tuist began as a beacon for developers crafting apps for Apple's platforms using Xcode. It sprung from a desire to simplify and enhance <a rel="external" href="https://developer.apple.com/xcode/">Xcode</a> project scalability. Today, it's not just a tool; it's a foundation. While I had dabbled in open source before, Tuist eclipsed them all in popularity. <em>So, what made Tuist stand out?</em></p>
<p>At its heart, <strong>Tuist was conceived out of profound passion.</strong> The challenges we wrestled with at <a rel="external" href="https://soundcloud.com/">Soundcloud</a> often led to solutions that felt complex and cumbersome. I was determined to simplify this. My time at SoundCloud gifted me insights into scalability, which I infused into Tuist. It's a legacy I wear proudly, one where contributors can engage meaningfully without drowning in the vast sea of code.</p>
<p>However, Tuist's true magic unfolded <strong>unhurriedly</strong>. Balancing it with my full-time job meant limited but quality hours poured into it. This allowed for rich contemplation and design, even if I was just "coding in my head." My style might lean towards the classic in Swift, but <strong>its architecture is solid and purposeful.</strong></p>
<p>Then came the beautiful moment when like-minded souls began rallying around Tuist. <a rel="external" href="https://github.com/kwridan">Kas</a>'s <a rel="external" href="https://github.com/tuist/tuist/issues/172">comprehensive issue</a>, considering its use at Bloomberg, was a pivotal turning point. Soon, <a rel="external" href="https://github.com/fortmarek">Marek</a>, <a rel="external" href="https://github.com/danyf90">Danielle</a>, and many others joined our ranks. The <strong>ebb and flow of contributors</strong>, like the heartbeat of any thriving organization, propelled Tuist forward.</p>
<p>Our strength lay in our foundations, direction, and vibrant community. With our energy levels skyrocketing 🚀, more organizations began embracing Tuist. While Apple endeavored to shift everyone towards the <a rel="external" href="https://www.swift.org/package-manager/">Swift Package Manager</a>, we held our ground, earning our user's trust and appreciation.</p>
<p>Today, <strong>Tuist stands at a crossroads.</strong> To forge ahead and ensure its longevity, we're introducing <a rel="external" href="https://tuist.io/cloud">Tuist Cloud</a> - a premium, integrated suite for organizations. This initiative goes beyond mere donations, <strong>transforming Tuist into a sustainable enterprise.</strong> Yes, it's a path strewn with challenges - from liaising with legal teams to mastering the art of sales. Yet, it's these very challenges that ignite my passion. They're opportunities in disguise, ones that promise to elevate Tuist to greater heights.</p>
<p>I may not have a crystal ball to glimpse into Tuist's distant future, but our commitment is unwavering. We'll continue innovating, always pushing the boundaries, and granting Tuist the superpowers it rightly deserves.</p>
<p>Here's to the boundless possibilities that await.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Fixing request&#x2F;2 is undefined or private with Ueberauth</title>
      <link>https://pepicrft.me/blog/ueberauth-request-error/</link>
      <guid>https://pepicrft.me/blog/ueberauth-request-error/</guid>
      <pubDate>Sun, 06 Aug 2023 12:00:00 +0000</pubDate>
      <description>Tackled &#x27;request&#x2F;2 undefined&#x27; error in Ueberauth setup for Digestfully, sharing solution here.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>In the process of setting up Ueberauth for my latest venture, Digestfully, I stumbled upon an interesting hurdle. A baffling <code>request/2 is undefined or private</code> error surfaced when I attempted to kick-start the authentication flow with one of the providers. This unexpected glitch left me pondering for a while until I found the underlying cause.</p>
<p>After a thorough read-through of the related documentation and a deep dive into community discussions, I stumbled upon an <a rel="external" href="https://github.com/ueberauth/ueberauth/issues/184">enlightening issue</a>. The root of the problem was a mismatch in the library's default path assumptions. While the Ueberauth library naturally presumes <code>/auth</code> as the default path, my project setup didn't adhere to this.</p>
<p>Hence, the necessary step was to clearly specify the correct authentication path to the library during its configuration, like so:</p>
<pre><code>config :ueberauth, Ueberauth,
 base_path: &quot;/other/path&quot;,
 providers: [
 #...
 ]
</code></pre>
<p>The journey to uncover this solution took a fair bit of time, and a handful of head-scratching moments. But, in the spirit of shared learning and community growth, I'm documenting this experience here. To those who may run into the same issue in the future, consider this a digital breadcrumb trail.</p>
<p>And to the mighty Google indexing bots, I hope you pick this up and help those in need find this solution with ease.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The Power of Concurrency: My Journey Learning Elixir</title>
      <link>https://pepicrft.me/blog/magic-in-elixir/</link>
      <guid>https://pepicrft.me/blog/magic-in-elixir/</guid>
      <pubDate>Wed, 26 Jul 2023 12:00:00 +0000</pubDate>
      <description>Exploring Elixir, I discovered the power of concurrency-oriented programming</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>For the past few months, I've been immersed in learning <strong>Elixir</strong>. I can still recall the precise moment when curiosity about Elixir ignited within me. There I was, strolling around New York, while tuning into a podcast that featured <a rel="external" href="https://twitter.com/josevalim?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor">José Valim</a>. He discussed how many programming languages, like <a rel="external" href="https://www.ruby-lang.org/en/">Ruby</a>, were <strong>not designed to scale vertically</strong> (increasing computing power with more CPU processors). Moreover, those that did scale through threading primitives often posed challenges, such as data races. This made the task of writing parallel code less than ideal. Elixir, however, <strong>combined the Ruby-like syntax I favored with the Erlang mental models and virtual machines.</strong> This fusion allowed for the easy construction of scalable, distributed, and fault-tolerant apps. As soon as I returned home, I delved into the <a rel="external" href="https://elixir-lang.org/docs.html">Elixir documentation</a>.</p>
<p>The syntax of the language is reminiscent of Ruby, yet entirely <strong>functional</strong>. It didn't take long for me to get acquainted with the syntax and primitives. Everything is organized into modules placed in various directories in the system, each exposing pure functions that can be piped using the <code>|&gt;</code> operator. Things started getting truly fascinating when I began working with <strong>processes</strong>. This was somewhat of a novel concept for me in a programming language, yet I quickly drew parallels with an OS and its processes. They are <strong>lightweight encapsulations of tasks that don't share CPU or memory resources</strong>. Numerous processes can be created instantaneously, communicating with each other through message exchanges. These processes can also be structured into a tree, enabling the codification of supervisory rules such as automatically restarting any child process that crashes.</p>
<p>This introduces a profound mental shift in how you perceive your programs. When this shift resonated within me, I instantly fell in love with Elixir's approach to programming. The <em>'click'</em> occurred when I started reading <a rel="external" href="https://erlang.org/download/armstrong_thesis_2003.pdf">Joe Armstrong's thesis on Erlang</a>, which fuels the BEAM virtual machine that Elixir operates on, as well as the programming language itself. The thesis opens with an exploration of the system requirements that Armstrong was designing for Ericsson, the need for a programming language, and his vision for solving global issues with software. He then introduces the concept of <strong>concurrency-oriented programming</strong>. Let me share some fragments from the thesis:</p>
<blockquote>
<p>The word concurrency refers to sets of events which happen simulta- neously. The real world is concurrent, and consists of a large number of events many of which happen simultaneously. At an atomic level our bodies are made up of atoms, and molecules, in simultaneous motion. At a macroscopic level the universe is populated with galaxies of stars in simultaneous motion.</p>
</blockquote>
<blockquote>
<p>When we perform a simple action, like driving a car along a freeway, we are aware of the fact that there may be several hundreds of cars within our immediate environment, yet we are able to perform the complex task of driving a car, and avoiding all these potential hazards without even thinking about it. &gt; In the real world sequential activities are a rarity. As we walk down the street we would be very surprised to find only one thing happening, we expect to encounter many simultaneous events.</p>
</blockquote>
<blockquote>
<p>If we did not have the ability to analyze and predict the outcome of many simultaneous events we would live in great danger, and tasks like driving a car would be impossible. The fact that we can do things which require processing massive amounts of parallel information suggests that we are equipped with perceptual mechanisms which allow us to intuitively understand concurrency without consciously thinking about it.</p>
</blockquote>
<blockquote>
<p>When it comes to computer programming things suddenly become inverted. Programming a sequential chain of activities is viewed the norm , and in some sense is thought of as being easy, whereas programming collections of concurrent activities is avoided as much as possible, and is generally perceived as being diecult.</p>
</blockquote>
<blockquote>
<p>I believe that this is due to the poor support which is provided for con- currency in virtually all conventional programming languages. The vast majority of programming languages are essentially sequential; any concur- rency in the language is provided by the underlying operating system, and not by the programming language.</p>
</blockquote>
<p>This perspective is eye-opening, isn't it? <strong>The world is concurrent, but programming languages are forcing us to model the world differently</strong>, using primitives that don't map 1-to-1 to the real world, like controllers, repositories, factories, and builders. Armstrong goes further in explaining how we should observe the world to shape our software. He advocates for a 1:1 mapping of real-world concurrent activities to concurrent processes in our programming language, asserting that this <strong>is critical to minimize the conceptual gap between the problem and its solution</strong>, therefore enhancing maintainability:</p>
<blockquote>
<p>Now we write the program. The structure of the program should exactly follow the structure of the problem. Each real world concurrent activity should be mapped onto exactly one concurrent process in our programming language. If there is a 1:1 mapping of the problem onto the program we say that the program is isomorphic to the problem.</p>
</blockquote>
<blockquote>
<p>It is extremely important that the mapping is exactly 1:1. The reason for this is that it minimizes the conceptual gap between the problem and the solution. If this mapping is not 1:1 the program will quickly degenerate, and become diecult to understand. This degeneration is oden observed when non-CO languages are used to solve concurrent problems. Oden the only way to get the program to work is to force several independent activities to be controlled by the same language thread or process. This leads to a inevitable loss of clarity, and makes the programs subject to complex and irreproducible interference errors.</p>
</blockquote>
<p>This is one of the most potent concepts I've encountered recently, and it's the primary reason I'm smitten with the Erlang VM and Elixir as a modern language on top of it. Just yesterday, someone questioned why I didn't opt for Swift, which <a rel="external" href="https://developer.apple.com/tutorials/app-dev-training/managing-structured-concurrency">is also embracing a similar model</a>. While I appreciate Swift's syntax, the problem lies in its inherited technical debt from supporting the transition from Objective-C. Furthermore, the incorporation of concurrency-oriented programming adds another layer of technical debt. Many libraries and standard library APIs are unprepared for it, which could potentially expose you to data race conditions.</p>
<p>Erlang's processes are the foundation for several other brilliant ideas that I'll explore in future posts. On a side note, did you know that <a rel="external" href="https://glossia.ai">Glossia</a> is powered by Elixir?</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Fixing psych compilation error trying to install Ruby on an Apple M2 laptop</title>
      <link>https://pepicrft.me/blog/psych-issues-installing-ruby/</link>
      <guid>https://pepicrft.me/blog/psych-issues-installing-ruby/</guid>
      <pubDate>Wed, 19 Jul 2023 12:00:00 +0000</pubDate>
      <description>Buckle up for a hilarious adventure in Ruby installation! Unravel the mysteries of rtx, Homebrew, and secret environment variables.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Let me tell you about the hilarious roller coaster ride I had today while attempting to install <a rel="external" href="https://www.ruby-lang.org/en/news/2023/03/30/ruby-3-2-2-released/">Ruby 3.2.2</a> using <a rel="external" href="https://github.com/jdxcode/rtx">rtx</a>, which is basically a turbocharged version of asdf. Man, oh man, did I encounter some wild errors during this wild adventure! But fear not, dear readers, because I've got the solution to this mind-boggling puzzle, and I'm here to share it with you. <strong>Consider it my gift to humanity, saving you precious time and countless headaches.</strong></p>
<p>So, buckle up and let's dive into the wacky world of Ruby installation! The first step on this zany journey is to install a few packages via <a rel="external" href="https://brew.sh">Homebrew</a>. Here's the list of packages you'll need:</p>
<pre><code>brew install zlib readline libyaml libffi
</code></pre>
<p>Once you've got them installed, it's time to do some secret-agent-style stuff with your environment variables. These variables are like <strong>the secret codes that the Ruby compiler uses to link itself to the libraries you just installed through Homebrew</strong>. Sneaky, right?</p>
<p>Open up your <code>~/.zshrc</code> file <em>(or your shell profile of choice)</em> and add the following lines:</p>
<pre><code># ~/.zshrc
export RUBY_YJIT_ENABLE=1
export RUBY_CONFIGURE_OPTS=&quot;--with-zlib-dir=$(brew --prefix zlib) --with-openssl-dir=$(brew --prefix openssl@1.1) --with-readline-dir=$(brew --prefix readline) --with-libyaml-dir=$(brew --prefix libyaml) --with-gdbm-dir=$(brew --prefix gdbm)&quot;
export CFLAGS=&quot;-Wno-error=implicit-function-declaration&quot;
export LDFLAGS=&quot;-L$(brew --prefix libyaml)/lib&quot;
</code></pre>
<p>Now, here's the kicker: to make sure these environment variables actually kick in, you need to either open a fresh terminal session or give your profile a good old source. It's like summoning the magical powers of Ruby by performing a secret ritual. Trust me, it's worth it!</p>
<p>Alright, folks, that's all there is to it! You're now armed with the knowledge to conquer the Ruby installation beast and emerge victorious. May your future terminal sessions be error-free, and may your code flow like a river of laughter.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>An update on the entrepreneurship path</title>
      <link>https://pepicrft.me/blog/entrepreneurship-update/</link>
      <guid>https://pepicrft.me/blog/entrepreneurship-update/</guid>
      <pubDate>Fri, 14 Jul 2023 12:00:00 +0000</pubDate>
      <description>Embarking on a tech-venture adventure; creating value, chasing joy, and conquering challenges.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Just over a month has elapsed since <a href="https://pepicrft.me/blog/entrepreneurship-update/__GHOST_URL__/blog/2023/05/28/indie-developer">I embarked on my <strong>entrepreneurial journey</strong></a>. I thought it would be an enriching experience to share my current standing, the emotional journey, and my forward-looking plans.</p>
<p>Firstly, I revel in the ability to bring my ideas to life without the need for consensus from multiple stakeholders or trying to convince senior leadership about its merits. It feels like a breath of fresh air to not have to deal with those challenges anymore, though it doesn't come without its own set of trade-offs. <strong>The challenge is not to solely chase joy and fulfillment but also to create a profitable, sustainable business.</strong></p>
<p>The primary engine for this is <a rel="external" href="https://tuist.io">Tuist</a> and <strong>Tuist Cloud</strong>. Tuist Cloud, a feature set necessitating an HTTP server, forms the ideal foundation to create a sustainable business model. This is vital to ensure the longevity of <a rel="external" href="https://github.com/tuist/tuist">Tuist</a>, currently buckling under the weight of an influx of support and feature requests. As for whether it will be open source, the jury's still out. Initially, <strong>I aim to establish the most suitable form for the business</strong>, after which it will be prudent to navigate the legalities associated with making it open source. In terms of the programming language and frameworks, I have chosen <a rel="external" href="https://elixir-lang.org">Elixir</a> and <a rel="external" href="https://www.phoenixframework.org">Phoenix</a> for their ability to streamline my processes and accelerate iterations. While Swift on the Server shows promise, it's currently more time-efficient to leverage existing solutions than to build missing components.</p>
<p>Alongside this, I have conceived a tool designed for <a rel="external" href="https://reactnative.dev">React Native</a> developers, using Tuist as a foundation. However, that idea is on hold until the feasibility of Tuist Cloud is confirmed. If Tuist Cloud doesn't meet expectations, this alternate path awaits exploration.</p>
<p>A secondary focus of mine is <a rel="external" href="https://www.linkedin.com/company/glossiaai"><strong>Glossia</strong></a>, an AI-based localization tool I'm co-creating with my wife, a former member of the localization team at <a rel="external" href="https://shopify.com">Shopify</a>. We recognized several issues in the localization process that need addressing:</p>
<ul>
<li>Localization often ends up as an after-thought despite its potential to make products more accessible. * Large localization entities struggle with scaling their efforts and sometimes resort to using Google Translate-based products. * The inherent complexity and obfuscation within localization can be daunting.</li>
</ul>
<p>The solution to these issues appeared elusive <strong>until we delved deeper into the possibilities of AI</strong>. Our subsequent experiments hint at a potential breakthrough. Our combined expertise allows us to envision a solution that's easy to use and integrate into existing workflows. We're vigorously working towards an MVP before summer ends. Provided things go smoothly, we'll cultivate a community of translators and developers and strive for integration with the most popular frameworks, including <a rel="external" href="https://apps.shopify.com">Shopify Apps</a>. We firmly believe in the necessity of translating these apps to ensure accessibility.</p>
<p>In conclusion, <strong>I am thoroughly enjoying this journey despite the financial uncertainty that looms</strong>. I remain hopeful that we will soon see clarity on that front. If by year-end the financial landscape remains murky, we might seek external support, equipped with a solid foundation of work. I look forward to the challenges and opportunities that lie ahead, and I am eager to share more about our journey in future posts.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Integrating Tailwind into your Swift projects</title>
      <link>https://pepicrft.me/blog/introducing-swiftytailwind/</link>
      <guid>https://pepicrft.me/blog/introducing-swiftytailwind/</guid>
      <pubDate>Sun, 18 Jun 2023 12:00:00 +0000</pubDate>
      <description>Tailwind: A game-changer for web styling, with seamless integration into Swift server projects using SwiftyTailwind.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>In recent years, <a rel="external" href="https://tailwindcss.com">Tailwind</a> has gained popularity as a web styling tool. Frameworks such as <a rel="external" href="https://rubyonrails.org">Ruby on Rails</a> and <a rel="external" href="https://www.phoenixframework.org">Phoenix</a> default to using Tailwind for new projects. If you're unfamiliar with Tailwind, it provides <strong>a set of well-defined and configurable utility classes that ensure consistent styling and allow for atomicity of markup and style</strong>. While JavaScript-based UI solutions like <a rel="external" href="https://react.dev">React</a> or <a rel="external" href="https://vuejs.org">Vue</a> already offer this functionality, they rely on the JavaScript ecosystem of tools and packages. Tailwind, on the other hand, brings these benefits to other ecosystems without introducing additional dependencies. It accomplishes this through a simple CLI that runs during build time and outputs CSS, removing any unused classes from the project. Essentially, using Tailwind doesn't require developers to install new system dependencies like <a rel="external" href="https://nodejs.org/en">NodeJS</a>, making it easier to contribute to a project.</p>
<p>When I returned to working with <a rel="external" href="https://www.swift.org">Swift</a>, I noticed that the Swift ecosystem lacked an easy way to integrate Tailwind into Swift on the Server projects, such as those based on <a rel="external" href="https://vapor.codes">Vapor</a> or <a rel="external" href="https://github.com/JohnSundell/Publish">Publish</a>. To address this, I took it upon myself to create a new Swift package called <a rel="external" href="https://github.com/pepicrft/swiftytailwind"><strong>SwiftyTailwind</strong></a>. It allows for the lazy downloading and execution of the Tailwind CLI using system processes. Below, you'll find an example of how to use <code>SwiftyTailwind</code>:</p>
<pre><code>let tailwind = SwiftyTailwind()
try await tailwind.run(input: .init(validating: &quot;/app/app.css&quot;), output: .init(validating: &quot;/app/build/app.css&quot;))
</code></pre>
<h2 id="integrating-it-with-publish">Integrating it with <a rel="external" href="https://github.com/JohnSundell/Publish">Publish</a></h2>
<p>Integrating SwiftyTailwind is a breeze with the use of <a rel="external" href="https://github.com/JohnSundell/Publish#building-plugins">plugins</a>. Simply instantiate and pass a plugin, and Publish will execute the code within the closure, generating the CSS file at <code>./Output/output.css</code>. Remember to include the necessary code in the  tag of your website to load these styles.</p>
<pre><code>try Site().publish(withTheme: .tailwind, plugins: [
 .init(name: &quot;Tailwind&quot;, installer: { context in
 let rootDirectory = try! AbsolutePath(validating: try context.folder(at: &quot;/&quot;).path)
 try await tailwind.run(input: rootDirectory.appending(components: [&quot;Style&quot;, &quot;input.css&quot;]),
 output: rootDirectory.appending(components: [&quot;Output&quot;, &quot;output.css&quot;]))
 })
])
</code></pre>
<h2 id="integrating-it-with-vapor">Integrating it with <a rel="external" href="https://vapor.codes">Vapor</a></h2>
<p>Integrating SwiftyTailwind with a Vapor project is a seamless experience. To begin, you need to configure the app to serve static assets located in the default <code>Public</code> directory by Vapor. Here's an example of the code:</p>
<pre><code>app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
</code></pre>
<p>Next, create an instance of <code>SwiftyTailwind</code> and invoke it by providing the file <code>Resources/Styles/app.css</code> as input. Additionally, set the options <code>watch</code> and <code>content</code> to point to <code>Resources/Views/**/*.leaf</code>. Take a look at the code example below:</p>
<pre><code>// Tailwind
let publicDirectory = try AbsolutePath(validating: app.directory.publicDirectory)
let inputCSSPath = try AbsolutePath(validating: app.directory.resourcesDirectory).appending(.init(&quot;Styles/app.css&quot;))
let outputCSSPath = publicDirectory.appending(component: &quot;app.css&quot;)
async let runTailwind: () = try tailwind.run(input: inputCSSPath, output: outputCSSPath, options: .watch, .content(&quot;Resources/Views/**/*&quot;))
async let runApp: () = try await app.runFromAsyncMainEntrypoint()

_ = await [try runTailwind, try runApp]
</code></pre>
<p>Finally, update the  section of your views to load the generated app.css file from the Public directory. Here's an example:</p>
<pre><code>
</code></pre>
<p>And that's it! <code>SwiftyTailwind</code> will monitor file changes in your <code>Resources/Views</code> directory and automatically regenerate the CSS output.</p>
<p>You can check out the <a rel="external" href="https://github.com/pepicrft/SwiftyTailwind/tree/main/Examples">Examples</a> directory in the project repository.</p>
<h2 id="contributing-to-swift-on-the-server">Contributing to Swift on the Server</h2>
<p>When compared to programming languages that have a more established presence in web development, Swift's ecosystem is still in its early stages. However, I am determined to contribute to changing that by building and sharing utilities with the community. Tailwind was my initial contribution, but I also have plans to introduce <a rel="external" href="https://esbuild.github.io">ESBuild</a> and <a rel="external" href="https://orogene.dev">Orogene</a> to Swift. These additions will enable a more advanced build pipeline in Vapor and facilitate fetching Node dependencies without relying on the NodeJS runtime. Exciting developments are on the horizon, so stay tuned for more updates!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Issues Dockerizing a Vapor project in M2</title>
      <link>https://pepicrft.me/blog/vapor-follow-up/</link>
      <guid>https://pepicrft.me/blog/vapor-follow-up/</guid>
      <pubDate>Fri, 09 Jun 2023 12:00:00 +0000</pubDate>
      <description>Fly CLI + Docker on M1&#x2F;M2 architecture caused issues, so I switched to GitHub Actions for deployment. No more problem!</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It turns out that <a href="https://pepicrft.me/blog/vapor-follow-up/__GHOST_URL__/blog/2023/06/08/vapor-memory">telling the Fly CLI to build with a local Docker</a> is insufficient. When run in an M1 or M2 architecture, Docker uses <a rel="external" href="https://twitter.com/FranzJBusch/status/1667109741452054529?s=20">QEMU</a> to cross-compile the binary, and that causes the issues that I was seeing. To fix it, I could have configured Docker to use <a rel="external" href="https://en.wikipedia.org/wiki/Rosetta_(software)">Rosetta</a>, but instead, I decided to run the deployment from a <a rel="external" href="https://github.com/tuist/cloud/blob/main/.github/workflows/deploy.yml">GitHub Action</a>. Due to the GitHub Actions environment's architecture, issues don't arise, and I was able to deploy the app successfully.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Hitting memory limits deploying Vapor apps to Fly</title>
      <link>https://pepicrft.me/blog/vapor-memory/</link>
      <guid>https://pepicrft.me/blog/vapor-memory/</guid>
      <pubDate>Thu, 08 Jun 2023 12:00:00 +0000</pubDate>
      <description>Deploying a Vapor app to Fly encountered unexpected issues. Swift&#x27;s linter requires more memory than Fly&#x27;s 2048 MB limit. Scaling via fly scale didn&#x27;t solve the problem. Workaround: built locally with Docker, then pushed to Fly&#x27;s image registry for deployment.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've been trying to deploy a <a rel="external" href="https://vapor.codes">Vapor</a> app to <a rel="external" href="https://fly.io">Fly</a>, and the deploy command continuously aborted unexpectedly. It turns out that Swift's static linter needs more memory than the one available in the builders that Fly provides, 2048 MB. I tried to increase the memory using <code>fly scale</code> as suggested in the community forum, but it didn't work. Perhaps because the scale command cannot be used with the builder. I used the <code>--local-only</code> flag to build locally using my local running instance of Docker. Once the image is built, the Fly CLI pushes it to its image registry and continues the deployment.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to Configure VSCode to Use Alternative Shells</title>
      <link>https://pepicrft.me/blog/change-vscode-default-shell/</link>
      <guid>https://pepicrft.me/blog/change-vscode-default-shell/</guid>
      <pubDate>Sun, 02 Apr 2023 12:00:00 +0000</pubDate>
      <description>Learn how to easily configure VSCode to use your preferred alternative shell installation like ZSH or Fish instead of the default profiles.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If manage the installation of alternative shells like <a rel="external" href="https://en.wikipedia.org/wiki/Z_shell">ZSH</a> or <a rel="external" href="https://fishshell.com/">Fish</a>, as I do via <a rel="external" href="https://github.com/pepicrft/dotfiles.nix">Nix</a>, you might consider configuring VSCode to use that installation instead of using the VSCode's default profiles. If so, you can do it easily by opening the VSCode settings, defining a new profile, and setting it up as the default:</p>
<pre><code>&quot;terminal.integrated.profiles.osx&quot;: {
 &quot;Nix-managed ZSH&quot;: {
 &quot;path&quot;: &quot;/Users/pepicrft/.nix-profile/bin/zsh&quot;
 }
},
&quot;terminal.integrated.defaultProfile.windows&quot;: &quot;Nix-managed ZSH&quot;
</code></pre>
]]></content:encoded>
    </item>
    
    <item>
      <title>Generating client secret from Apple&#x27;s P8 key in Elixir</title>
      <link>https://pepicrft.me/blog/apple-sign-in-client-secret/</link>
      <guid>https://pepicrft.me/blog/apple-sign-in-client-secret/</guid>
      <pubDate>Mon, 27 Mar 2023 12:00:00 +0000</pubDate>
      <description>Implementing Sign in with Apple on a macOS app using JWT and Phoenix. Learn how to generate a client secret for web authentication. </description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I had to implement <a rel="external" href="https://developer.apple.com/sign-in-with-apple/">Sign in with Apple</a> as part of a macOS app I'm building with a friend. The login would initiate on the client, and a session would be created server-side in a <a rel="external" href="https://www.phoenixframework.org/">Phoenix application</a>. The work took me down a rabbit hole in understanding <a rel="external" href="https://jwt.io/">JWT</a> and how Apple uses them. Even though, in the end, the solution turned out to be simpler than expected, thanks to <a rel="external" href="https://www.kodeco.com/11436647-sign-in-with-apple-using-vapor-4">this blog post</a> that shed a lot of light, I ended up coming up with a piece of code to generate a client secret, which can be used when doing web authentication and having to validate and refresh the token with Apple's servers. I thought it'd be helpful to share it here for anyone running into the same need, or for <a rel="external" href="https://openai.com/blog/chatgpt">ChatGPT</a> for indexing. By the way, all I needed to do to implement authentication on macOS was to verify server-side that the <a rel="external" href="https://developer.apple.com/documentation/authenticationservices/asauthorizationsinglesignoncredential/3153080-identitytoken">identity token</a> was generated by Apple using their public key.</p>
<p>To generate the <code>client_secret</code> you'll need to add the following dependencies to the project:</p>
<pre><code>{:joken, &quot;~&gt; 2.6.0&quot;},
{:jose, &quot;~&gt; 1.11&quot;}
</code></pre>
<p>Once you have them, the implementation is very concise. The <code>certificate</code> variable in the example below is the content of the <code>.p8</code> file generated by Apple. You can read its content using Elixir's <code>File.read!</code> API. All the code does is using the <code>jose</code> dependency to load the key into memory, and with the help of <code>joken</code> it generates a JWT following Apple's convention:</p>
<pre><code>def client_secret(%{ team_id: team_id, client_id: client_id, certificate: certificate}) do
 {_, key_map} =
 certificate
 |&gt; JOSE.JWK.from_pem()
 |&gt; JOSE.JWK.to_map()

 signer = Joken.Signer.create(&quot;ES256&quot;, key_map)

 claims = %{
 &quot;aud&quot; =&gt; &quot;https://appleid.apple.com&quot;,
 &quot;iss&quot; =&gt; team_id,
 &quot;sub&quot; =&gt; client_id,
 &quot;iat&quot; =&gt; :os.system_time(:second),
 &quot;exp&quot; =&gt; :os.system_time(:second) + 86400 # 1 day
 }

 {:ok, secret} = Joken.Signer.sign(claims, signer)
 secret
end
</code></pre>
]]></content:encoded>
    </item>
    
    <item>
      <title>Typescript not loading in Visual Studio Code</title>
      <link>https://pepicrft.me/blog/typescript-not-working-in-vscode/</link>
      <guid>https://pepicrft.me/blog/typescript-not-working-in-vscode/</guid>
      <pubDate>Thu, 09 Mar 2023 12:00:00 +0000</pubDate>
      <description>I share the investigation into Visual Studio Code not loading Typescript and the solution I found - enabling the @builtin typescript extension.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I spent much time today investigating why Visual Studio Code was not loading Typescript as usual. I initially thought it was due to the Typescript compiler, <code>tsc</code>, not being present in the environment. However, it turned out that Typescript is an internal extension of VSCode, and it was disabled for some reason. If you ever come across the same issue, all you have to do is to search the following extension in VSCode:</p>
<pre><code>@builtin typescript
</code></pre>
<p>The <code>@builtin</code> is essential because the search filters out internal extensions by default. Once you enable it, it'll start working again. What caused it? I don't know, and I think it'll remain a mystery forever.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Iterating on my learning system</title>
      <link>https://pepicrft.me/blog/learning-systems/</link>
      <guid>https://pepicrft.me/blog/learning-systems/</guid>
      <pubDate>Tue, 14 Feb 2023 12:00:00 +0000</pubDate>
      <description>Some notes on what changes I&#x27;m introducing to my learning system.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I find it challenging to retain the things that I learn. In most cases is because I don't need that learning daily. I have many examples of this. I take German lessons, but then I don't have the opportunity to use them. I've learned the basics of Rust several times, and I keep forgetting it because I don't need it. Part of me thinks it's okay to learn new things, even if I'm aware I'll forget them, because I'll be able to create connections with other pieces of knowledge, <strong>and ideas will emerge</strong>. It's indeed one of the reasons why I like to learn new technologies and programming languages. I learn things that I can apply to other domains or make better tradeoffs when making decisions. The connection of multiple pieces of knowledge gives me unique perspectives.</p>
<p>However, my ability to retain and connect things will degrade over time. Hence, I think it's essential to build a system to dump knowledge off my head, making connections with existing knowledge. I'm building that system on the <a rel="external" href="https://logseq.com/">Logseq</a> app. I decided on it for a few reasons:</p>
<ul>
<li>It's open-source - It uses standard formats (e.g., Markdown) - It doesn't create vendor lock-in (I own my knowledge) - It's extensible via plugins - It has a great community around it</li>
</ul>
<p>Dumping knowledge in an app is unnatural, especially when knowledge happens anywhere and anytime. But I'm starting to make it feel natural. Whenever I have an idea or learn something, I open Logseq and dump it there, ensuring I tag it properly. I'm also refraining from using integrations with platforms like <a rel="external" href="https://readwise.io/">Readwise</a> to prevent dumping stuff without manual processing. Another thing that I'm doing is reading about the <a rel="external" href="https://zettelkasten.de/">Zettelkasten method</a>, which Logseq takes inspiration from. Once I'm interiorized the knowledge capturing, I'll move on to working on that knowledge and making connections using the tools that Logseq provides — for example, throwing myself into a part of the graph and navigating it from there, filling knowledge gaps and learning new things along the process.</p>
<p>If knowledge systems are a topic that interests you, I'd love to hear about your system and processes. Drop me a <a rel="external" href="https://twitter.com/pepicrft">DM</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Static imports with ESM and startup time</title>
      <link>https://pepicrft.me/blog/startup-time-in-node-clis/</link>
      <guid>https://pepicrft.me/blog/startup-time-in-node-clis/</guid>
      <pubDate>Fri, 23 Dec 2022 12:00:00 +0000</pubDate>
      <description>When building a Command-line interface (CLI) with Javascript and ESM to run on NodeJS , one can end up with a CLI that&#x27;s slow to launch (above hundreds of milliseconds). It&#x27;s common for developers to use static imports at the top of the sou…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>When building a <a rel="external" href="https://en.wikipedia.org/wiki/Command-line_interface">Command-line interface (CLI)</a> with Javascript and <a rel="external" href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/">ESM</a> to run on <a rel="external" href="https://nodejs.org/en/">NodeJS</a>, one can end up with a CLI that's slow to launch (above hundreds of milliseconds). It's common for developers to use static imports at the top of the source files:</p>
<pre><code>import { groupBy } from &quot;lodash-es&quot;
</code></pre>
<p>Those imports form a module graph that <strong>needs to be loaded before any code gets executed</strong>. And because loading a graph entails doing IO and in-memory parsing operations, some of which can be parallelized, there's a <strong>strong correlation between the size of the graph and the time it takes to load.</strong> It's indeed one of the reasons, among others, why developers choose Rust or Go as programming languages to implement their CLIs. Compilers statically link all the code and the startup time is insignificant.</p>
<p>Note that the problem goes away when working on a client-side rendered app because bundling tools smash all the modules into a single or handful of modules. <a rel="external" href="https://vitejs.dev/">Vite</a> embraces ESM in development but does some bundling-based optimizations with third-party dependencies. In the case of web servers (e.g., Express-based HTTP server) or SPAs, the startup time also gets impacted, but additional seconds during deployment don't impact the developer experience significantly. Orchestrators like Kubernetes wait until the server runs to send traffic to it.</p>
<p><strong>What can we do about this?</strong> You can remain with <a rel="external" href="https://en.wikipedia.org/wiki/CommonJS">CommonJS</a>, although I'd advise not to. ESM is the standard, and more NPM packages are making it their default. CommonJS works synchronously and doesn't have to wait for the whole graph to load to start executing code. First, I recommend <strong>minimizing the number of dependencies</strong> of your project. It is also suitable for security and graph determinism at installation time. If you need to add a dependency, check how they export modules. If they have a single export from where you import everything, then use dynamic imports:</p>
<pre><code>// Static import
import { bar } from &quot;bar&quot;

async function foo() {
 // Dynamic import
 const bar = await import(&quot;bar&quot;)
}
</code></pre>
<p>The best scenario is the dependencies using <a rel="external" href="https://nodejs.org/api/packages.html#subpath-exports">subpath exports</a>, meaning that you only import what you need. However, few dependencies in the ecosystem are designed this way, so it's rare to come across one. As a last resource, you can introduce a compiler that can tree-shake external dependencies and delete unused code. However, code transformation might output Javascript code that blows up at runtime, so you'll have to invest in integration tests.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>An explicit build graph with Nx for a better DX</title>
      <link>https://pepicrft.me/blog/an-explicit-build-graph-for-a-better-dx/</link>
      <guid>https://pepicrft.me/blog/an-explicit-build-graph-for-a-better-dx/</guid>
      <pubDate>Tue, 13 Dec 2022 12:00:00 +0000</pubDate>
      <description>When I started doing Javascript more actively, something that got my attention was the absence of a build system that allowed declaring a build graph explicitly. Most of the time, developers combine package.json scripts with shell operators…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>When I started doing Javascript more actively, something that got my attention was the absence of a build system that allowed declaring a build graph explicitly. Most of the time, developers combine <code>package.json</code> scripts with shell operators:</p>
<pre><code>{
 &quot;scripts&quot;: {
 &quot;clean&quot;: &quot;rimraf dist/&quot;,
 &quot;build&quot;: &quot;pnpm clean &amp;&amp; tsc&quot;
 }
}
</code></pre>
<p>The above setup is standard across Javascript tasks. A task for cleaning the output directory, <code>clean</code>, and another to output Javascript from the Typescript source code, <code>build</code>, which <strong>depends on</strong> <code>clean</code>. Because <code>package.json</code>'s <code>scripts</code> section doesn't have the notion of dependencies, developers have to resort to workarounds like using <code>&amp;&amp;</code>: <em>Do clean, and if it succeeds, build.</em></p>
<p>Defining dependencies that way works if the project is small. However, if a project gets larger and automation more complex, the dependency graph will inevitably be hard to reason about, hindering contribution to the project.</p>
<p>Luckily when I started working on <a rel="external" href="https://github.com/gestaltjs">GestaltJS</a> I came across the <a rel="external" href="https://nx.dev/">Nx</a> build system, which solves the above problem beautifully. Their approach was not new to me since the problem they are solving and how they are solving it is something that I had to do for Xcode projects in <a rel="external" href="https://tuist.io">Tuist</a>. You have a bunch of interdependent modules that a developer can interact with (e.g., test, build, lint), and you want the information to be codified in a graph that can be leveraged to introduce optimizations.</p>
<p>Some minds behind Nx are ex-Googlers that had the chance to work on Google's build system, <a rel="external" href="https://bazel.build/">Bazel</a>. Unlike Bazel, which has a steep learning curve, and you have to learn a Python-like syntax, Nx is extremely easy to get started and add to an existing project. The developer experience (DX) is top-notch.</p>
<p>Once the tasks and the dependencies are declared, you have access to a whole set of tools that can save you a lot of time. One of them is <strong>incremental builds</strong> and being able to run tasks only for the <a rel="external" href="https://nx.dev/concepts/affected">affected packages</a>. How cool is that? They can also cache task outputs across local and remote builds. It reminds me so much of the work we had to do to bring caching to Tuist. You also get a <a rel="external" href="https://nx.dev/core-features/explore-graph"><strong>graph</strong></a> command to visualize the automation dependency graph. So no more navigating across <code>package.json</code> files to understand how tasks are interconnected.</p>
<p>I'd recommend giving the tool a shot if you have a workspace. <a rel="external" href="https://github.com/Shopify/cli/blob/main/nx.json">Shopify's CLI</a> has also had Nx set up since the project was created, and it's been a wonderful experience so far. We haven't had any issues with the tool, and it keeps improving with every release.</p>
<p><strong>Nx is one of my references when devising iterations for the Shopify CLI</strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Hot-reloading and ESM</title>
      <link>https://pepicrft.me/blog/hot-reloading-esm/</link>
      <guid>https://pepicrft.me/blog/hot-reloading-esm/</guid>
      <pubDate>Thu, 01 Dec 2022 12:00:00 +0000</pubDate>
      <description>While building Gestalt , I realized that many web frameworks don’t move away from CommonJS because their usage of modules in ESM would lead to a slower hot-reloading experience. This is primarily due to how module graphs are loaded with ESM…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>While building <a rel="external" href="https://github.com/gestaltjs">Gestalt</a>, I realized that many web frameworks don’t move away from <a rel="external" href="https://en.wikipedia.org/wiki/CommonJS">CommonJS</a> because their usage of modules in <a rel="external" href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/">ESM</a> would lead to a slower hot-reloading experience. This is primarily due to how module graphs are loaded with ESM – the entire graph needs to be fully loaded before the code starts executing. Imagine how slow hot-reloading would be if that had to happen every time we changed a file. Solving it would be doing <strong>dynamic imports</strong> in development or static ones in production. This can be achieved through a build process that is environment-aware.</p>
<pre><code>// Static ESM imports
import { loadRoutes } from &quot;gestaltjs/routes&quot;

// Dynamic ESM imports
function doSomething() {
 const { loadRoutes } = await import(&quot;gestaltjs/routes&quot;)
}
</code></pre>
]]></content:encoded>
    </item>
    
    <item>
      <title>Growing as a Staff Developer</title>
      <link>https://pepicrft.me/blog/growing-as-a-staff/</link>
      <guid>https://pepicrft.me/blog/growing-as-a-staff/</guid>
      <pubDate>Tue, 01 Nov 2022 12:00:00 +0000</pubDate>
      <description>A couple of months ago, I reached Shopify &#x27;s Senior Staff Developer level. They were exciting news and excellent proof that Shopify continues to be a place for growth. Yet they pushed me out of my comfort zone, throwing me into a new realm…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>A couple of months ago, I reached <a rel="external" href="https://shopify.com">Shopify</a>'s Senior Staff Developer level. They were exciting news and excellent proof that Shopify continues to be a place for growth. Yet they pushed me out of my comfort zone, throwing me into a new realm of responsibilities.</p>
<p>Settling into the new role <strong>is taking me some time</strong>. One reason is that I'm going through a process of accepting the change. My new role is less about being hands-on with coding solutions and more about the business. It's about reading, writing, talking, and socializing change in the organization. It's familiar, but I'm not as fluent and comfortable as I wish. Being in front of people and presenting an idea still feels terrifying.</p>
<p><strong>Excellent communication skills</strong> are essential for this role, and mines have a lot of room for improvement. Therefore, I started working on them. I'm writing more regularly now and reading more slowly. While I do, I pay attention to how ideas are structured and connected. As someone with <a rel="external" href="https://en.wikipedia.org/wiki/Attention_deficit_hyperactivity_disorder">ADHD</a>, focusing on a lengthy text piece feels painful. I also scheduled regular chats with people from other teams and leaders. The aim of these conversations is to have a more holistic view of the organization and its direction. This is useful to spot opportunities to support the organization best.</p>
<p>There are so many unknowns ahead of me, but it's part of playing the <a rel="external" href="https://en.wikipedia.org/wiki/The_Infinite_Game">infinite game</a> of the software craft. This as an excellent opportunity to grow professionally and personally. And I'm fortunate to do it surrounded by many talented people I can learn from.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Typing file-system paths in Typescript</title>
      <link>https://pepicrft.me/blog/typing-paths-in-typescript/</link>
      <guid>https://pepicrft.me/blog/typing-paths-in-typescript/</guid>
      <pubDate>Fri, 16 Sep 2022 12:00:00 +0000</pubDate>
      <description>Learn about an NPM package that we published recently, typed-file-system-path, that adds primitives to work with file-system paths more safely using types.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><strong>Have you ever noticed how common it is in standard libraries to treat file system paths as strings?</strong> In fact, Node’s <a rel="external" href="https://nodejs.org/api/path.html">path</a> module exports a handful of convenient functions, all of which expect string arguments. There are a few caveats in following that approach. The first and more prominent one is that developers naturally operate with paths as if they were strings, which often leads to bugs. For example, concatenating a string that represents a relative path (e.g., <code>index.ts</code>) to an absolute one (e.g., <code>/project/src</code>) leads to <code>/project/srcindex.ts</code>, which is wrong. These issues don’t happen if we use the functions provided by the <code>node:path</code> module, but once again, they are strings; why not treat them as such?</p>
<p>The second issue is that APIs with paths as arguments or output values are not explicit enough about the type of paths. This is somewhat solvable with documentation, but wouldn’t it be better if the compiler, Typescript, is the one guiding you to use the APIs correctly. For example, making the compilation fail if you pass a relative path when the API expects an absolute one.</p>
<p>And last but not least, maintaining a piece of business logic that has paths as strings put the developer in the position of having to make assumptions, and that’s always a terrible idea. <em>Is this path here absolute? Or maybe it’s relative? If it’s relative, is it relative to the working directory? Or maybe the project’s directory?</em> You don’t want project contributors to be asking themselves those questions. Instead, you want paths to be made early in your system and pass them around, making it clear that they are operating with an absolute path and not a string prone to misusage.</p>
<p>To solve the above issues, I open-sourced a tiny NPM package, <a rel="external" href="https://www.npmjs.com/package/typed-file-system-path">typed-file-system-path</a>, which provides primitives for modeling absolute and relative paths and operating with them. The API is simple. You have utilities to initialize a relative or an absolute path. They’ll through if you are initializing them with an invalid path. The primitives provide convenient functions to prevent having to import utilities from the <code>node:path</code> module:</p>
<pre><code>import { relativePath, absolutePath } from &quot;typed-file-system-path&quot;

// Initialize an absolute path
// @throws InvalidAbsolutePathError if the path is not absolute.
const dirAbsolutePath = absolutePath(&quot;/path/to/dir&quot;)

// Initialize a relative path
// @throws InvalidRelativePathError if the path is not relative.
const fileRelativePath = relativePath(&quot;./tsconfig.json&quot;)
</code></pre>
<p>The inspiration for this project comes from <a rel="external" href="https://github.com/apple/swift-tools-support-core/blob/main/Sources/TSCBasic/Path.swift">Path.swift</a>, a primitive that Apple built as part of their <a rel="external" href="https://github.com/apple/swift-tools-support-core/blob/main/Sources/TSCBasic/Path.swift">swift-tools-support-core</a> and that I used extensively in <a rel="external" href="https://github.com/pepicrft/typed-file-system-path">Tuist</a>. Up next is adding more convenient functions, and update <a rel="external" href="https://github.com/gestaltjs/gestalt">Gestalt</a> to use the <code>AbsolutePath</code> and <code>RelativePath</code> types.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>On learning Elixir</title>
      <link>https://pepicrft.me/blog/on-learning-elixir/</link>
      <guid>https://pepicrft.me/blog/on-learning-elixir/</guid>
      <pubDate>Thu, 25 Aug 2022 12:00:00 +0000</pubDate>
      <description>As you might have noticed, I’ve been learning Elixir for the past few weeks. Why? You might wonder. I’m a programming languages nerd. I like learning about how different languages solve the same challenges, which gives me new perspectives a…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As you might have noticed, I’ve been learning <a rel="external" href="https://elixir-lang.org/">Elixir</a> for the past few weeks. Why? You might wonder. I’m a programming languages nerd. I like learning about how different languages solve the same challenges, which gives me new perspectives and ideas for solving upcoming problems.</p>
<p>I came across a talk about the <a rel="external" href="https://www.erlang.org/">Erlang</a> virtual machine, <a rel="external" href="https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine)">BEAM</a>, and it blew my mind. I then read about Elixir, and its similarity with Ruby instantly clicked with me. The more I read about it, the more I liked it. At the same time, I also started to feel that I'd better not spend more time with Javascript than what's strictly necessary. The constant need to re-invent every layer of the stack, the VCs' urge to make their way into those layers, and how uncommon it is to embrace good software practices made me highly uncomfortable and stressed. I've discussed this in past blog posts, so I won't repeat myself.</p>
<p>One thing that fascinated me about Erlang is that it defers introducing complexity to your Elixir projects. Needs for which you'd introduce elements like <a rel="external" href="https://redis.io/">Redis</a>, <a rel="external" href="https://kubernetes.io/">Kubernetes</a>, load balancers, and background jobs solutions into your system are well addressed by the VM when you get started. Its pattern matching is different, and I find their approach to functional programming easy to reason about and work with. I believe in building pure functions and dealing with immutable states, but the syntax of strongly functional programming languages like <a rel="external" href="https://clojure.org/">Clojure</a> hasn't clicked on me yet. Talking about sharing mutable states… this is something that bugs me when working with Ruby or Javascript. It's common to see states being stored and mutated at the module level. Everything works until it doesn't, or tests become flaky because of it.</p>
<p>I'm considering moving this blog to Elixir using <a rel="external" href="https://www.phoenixframework.org/">Phoenix</a> to consolidate my learnings. I came across the <a rel="external" href="https://github.com/dashbitco/nimble_publisher">nimble_publisher</a> package that allows embedding static content, for example, blog posts in a Git repo, into the BEAM binaries that end up being deployed. I know this might sound too much for a blog, but what's better than your blog for a bit of over-engineering? Turning my blog into a long-running process will allow me to add some interactive bits to it.</p>
<p>After it, I'm also considering building a tool to scratch an itch that I've had for quite some time. Collecting and processing personal financial information from bank accounts and investment platforms to make better and more informed decisions. As always, it'll be open source, and if it turns out to be helpful, I might host an instance and allow other people to use it too. But first, let's see if I can build it for myself.</p>
<p>Are you also learning Elixir or are familiar with it? What do you like about it?</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>On finding passion in devising developer experiences</title>
      <link>https://pepicrft.me/blog/on-finding-passion-in-devising-developer-experiences/</link>
      <guid>https://pepicrft.me/blog/on-finding-passion-in-devising-developer-experiences/</guid>
      <pubDate>Mon, 27 Jun 2022 12:00:00 +0000</pubDate>
      <description>What am I professionally? I don&#x27;t have a clear answer. I used to say I was an iOS developer with a passion for Swift , but that&#x27;s no longer true. Shopify turned me into a more generalist developer and, more importantly, helped me see techno…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><strong>What am I professionally?</strong> I don't have a clear answer. I used to say I was an iOS developer with a passion for <a rel="external" href="https://developer.apple.com/swift/">Swift</a>, but that's no longer true. <a href="https://pepicrft.me/blog/on-finding-passion-in-devising-developer-experiences/https//shopify.com">Shopify</a> turned me into a more generalist developer and, more importantly, helped me see technology as an implementation detail. I'm no longer as excited about a particular technology as I am about finding the best solution to a problem. But not any problem domain; I love the <strong>developer tooling</strong> space. It feels fantastic building developer experiences because I can scratch my own itches.</p>
<p>Moreover, I think I've developed a good sense for building great experiences through projects like <a rel="external" href="https://tuist.io">Tuist</a>, <a rel="external" href="https://github.com/gestaltjs">Gestalt</a>, and a lot of inspiration from <a rel="external" href="https://www.ruby-lang.org/en/">Ruby</a> and <a rel="external" href="https://rubyonrails.org/">Rails</a>. Devising developer experiences is more of a product role, but <strong>I'm not a product designer</strong>. <em>Should I dive into what it entails to be a product designer and apply it to the developer tooling domain?</em></p>
<p>It feels odd that product and development is a binary distinction in companies. It causes me a lot of impostor syndrome and a lack of identity. It'd be great if the gap between product and development was a spectrum, and you could grow within it too. Imagine one day wearing a technical hat because there's a problem you want to go really deep into solving because you think it'll positively impact DX. But the next day, you build prototypes around new workflows that you think users will love.</p>
<p>The reason <strong>why I love open source</strong> so much is that it's not who I am but about what experiences I want to create. I feel highly empowered when I free any labels and can navigate domains.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Modular projects, Typescript, and developer experience</title>
      <link>https://pepicrft.me/blog/modular-typescript/</link>
      <guid>https://pepicrft.me/blog/modular-typescript/</guid>
      <pubDate>Thu, 23 Jun 2022 12:00:00 +0000</pubDate>
      <description>Have you tried to set up a modular Typescript project with multiple NPM packages? It&#x27;s painful. Typescript tried to solve that with project references , an API to declare the project graph to Typescript for it to build the packages in the c…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Have you tried to set up a modular Typescript project with multiple NPM packages? It's painful. Typescript tried to solve that with <a rel="external" href="https://www.typescriptlang.org/docs/handbook/project-references.html">project references</a>, an API to declare the project graph to Typescript for it to build the packages in the correct order. Still, it presents a terrible developer experience (DX) editing the code. It's widespread, especially when the project is in a clean state (i.e., <code>dist/</code> not populated with Javascript and definition files), that the language server protocol can't find interfaces. One can mitigate the issue by calling <code>tsc</code> to emit declaration files, but they get outdated as soon as you start changing the public interfaces across packages.</p>
<p>The <strong>solution</strong> we adopted on the new <a rel="external" href="https://github.com/shopify/cli">Shopify CLI</a> and <a rel="external" href="https://github.com/gestaltjs/gestalt">Gestalt</a> is using the <a rel="external" href="https://www.typescriptlang.org/tsconfig#paths">paths</a> option in the <code>tsconfig.json</code> file. The API is intended to be used for re-mapping imports within a particular module, but it also works to define aliases cross packages. <a rel="external" href="https://github.com/Shopify/cli/blob/main/configurations/tsconfig.json#L17">Here</a> is an example of how we use them in the Shopify CLI. Thanks to it, Typescript can resolve cross-package typed contracts instantly. Note that when transpiling or bundling the code of each package, you'll need to tell the build tool to treat those imports as external dependencies and leave them as they are. <a rel="external" href="https://github.com/Shopify/cli/blob/main/configurations/rollup.config.js#L13">Here</a> is an example of how we do it for <a rel="external" href="https://rollupjs.org">Rollup</a>.</p>
<p>One <strong>caveat</strong> of the above approach is that since the Typescript configuration is static, you won't be able to extract the aliasing configuration and share it across Typescript and build tools. This means you'll end up with various sources of truth for the same information. I hope that Typescript allows the configuration to be more dynamic through a Javascript-based interface.</p>
<p>If you run into a similar use case, I hope you find the setup described in this blog post helpful. Also, if you know another strategy that works better than this one, I'd love to know about it.</p>
<p>Happy Typescripting!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>On embracing my chaos</title>
      <link>https://pepicrft.me/blog/on-embracing-my-chaos/</link>
      <guid>https://pepicrft.me/blog/on-embracing-my-chaos/</guid>
      <pubDate>Fri, 27 May 2022 12:00:00 +0000</pubDate>
      <description>Over the past few years, I’ve tried and failed many times at giving my chaotic self some order — something that inevitably made me feel anxious . I tried to organize myself using todo apps. I always used any random piece of paper that I fou…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Over the past few years, I’ve tried and failed many times at giving my chaotic self some order — <strong>something that inevitably made me feel anxious</strong>.</p>
<p>I tried to organize myself using todo apps. I always used any random piece of paper that I found near me. I also tried to file, categorize, and prioritize issues on a GitHub repository. Still, I ended up resorting to a .gitignored <code>TODO.md</code> document. My note-taking apps are a mess. Thinking about how to label and organize my notes is an unnecessary mental burden for me. When something pops in my head, I want to jot it down and move on.</p>
<p>A caveat to my chaos is that it is <strong>not very compatible when collaborating with other people</strong>, for example, at work or doing open source. Some level structure is necessary for coordination to happen. Because of that, I sometimes pause, reflect, and give my chaos some structure to work with others toward a common goal. It’s not natural to me, but I don’t know about a better way. For example, I write up project roadmaps and visions, capture ideas or bugs on GitHub issues, or do brain dumps in the shape of blog posts. I did a lot of those when I maintained <a rel="external" href="https://tuist.io">Tuist</a>, and it had a positive on the community we were able to build around the tool.</p>
<p>I <strong>embraced chaos</strong> as one of my traits to mitigate the bits of anxiety that structuring the chaos brought me. Moreover, I adopted a tool like Logseq that allows me to capture the chaos in a raw state and defer giving some shape later. I usually do the latter if it’s essential to be able to get back to in the future or if it’s something that I plan to share with others.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Mitigating &#x27;delete node_modules&#x27;</title>
      <link>https://pepicrft.me/blog/mitigating-delete-node-modules/</link>
      <guid>https://pepicrft.me/blog/mitigating-delete-node-modules/</guid>
      <pubDate>Fri, 06 May 2022 12:00:00 +0000</pubDate>
      <description>If you&#x27;ve worked in the Javascript ecosystem, you might already be familiar with the &amp;quot;delete node_modules&amp;quot; solution commonly suggested on StackOverflow and GitHub Issues. People make fun of it, but it&#x27;s a frustrating scenario that…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If you've worked in the Javascript ecosystem, you might already be familiar with the <em>"delete node_modules"</em> solution commonly suggested on <a rel="external" href="https://stackoverflow.com/">StackOverflow</a> and GitHub Issues. People make fun of it, but it's a frustrating scenario that ruins the developer's experience using a tool or a framework.</p>
<p>After immersed me in the Javascript ecosystem as part of my work at <a rel="external" href="https://shopify.com/">Shopify</a> and on <a rel="external" href="https://gestaltjs.org/">Gestalt</a>, I understood better what leads to this scenario. It's the combination of an ecosystem favoring <strong>many small packages over fewer but larger ones</strong> and the reliance on humans to follow <a rel="external" href="https://semver.org/">semantic versioning</a> from their packages. When one out of thousand packages introduces breaking changes that are not reflected by the version of the package, that causes the contract with other nodes in the graph to break, and the broken contract often surfaces as a broken workflow for the user.</p>
<p>A <strong>solution</strong> to this problem would come down to having smaller dependency graphs and having more acceptance tests in packages that can manifest breaking changes on CI, but that's unfortunately not an overnight change considering the size of the ecosystem. Because of that, in Gestalt, we decided to defend ourselves against sources of non-determinism like that one. We did so by leveraging the bundling process through Rollup. I know this sounds weird if you are used to using bundlers to optimize the artifact that's served to the user, but believe me, it plays a crucial role in improving the experience for Gestalt users.</p>
<p>Our packages have their external dependencies as <strong>devDependencies</strong>. The versions are pinned through <a rel="external" href="https://github.com/gestaltjs/gestalt/blob/main/pnpm-lock.yaml">Gestalt's lock file</a>. They are <a rel="external" href="https://webpack.js.org/guides/tree-shaking/">tree-shaked</a> and bundled as part of the bundle of the package, and that's the bundle that we use for running our e2e tests, including in the NPM package that users install. If the bundle passes our e2e tests, it'll work as expected on the user side. We make exceptions for mature dependencies and have solid test suites because we have a higher trust in their usage of semantic versioning.</p>
<p>We've been using <a rel="external" href="https://rollupjs.org/">Rollup</a> for bundling, and we couldn't be happier with it. It also helps transform CJS dependencies that we can't interoperate with because they don't follow the Node conventions. <a rel="external" href="https://github.com/gestaltjs/gestalt/blob/main/packages/core/rollup.config.js">Here's</a> an example of the configuration used for bundling the <em>@gestaltjs/core</em> package.</p>
<p>Every tiny detail can have a significant impact on the developers' experience. Therefore we can't embrace "delete node_modules" as it is what it is when there are strategies we can adopt to minimize it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>But they are developers too</title>
      <link>https://pepicrft.me/blog/they-are-developers-too/</link>
      <guid>https://pepicrft.me/blog/they-are-developers-too/</guid>
      <pubDate>Thu, 05 May 2022 12:00:00 +0000</pubDate>
      <description>I often hear a statement when justifying decisions in building developer tools: but they are developers too. It bugs me a ton because it throws all the developers into the same bag and assumes that they know what you know. If we want to bui…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I often hear a statement when justifying decisions in building developer tools: but they are developers too. It bugs me a ton because it throws all the developers into the same bag and assumes that they know what you know.</p>
<p>If we want to build great developer tools, we need to <strong>start by acknowledging that the developer community is diverse in terms of backgrounds, skills, and levels</strong>. Our lazy side would prefer a single persona because we can design the tools using us as a reference, and without researching much. But fortunately, the world is heterogeneous.</p>
<p>Acknowledging diversity is necessary but not sufficient. We need to have the <strong>empathy</strong> to connect with the various personas that will use the tools. Here are some examples:</p>
<ul>
<li>A developer that doesn't want to make many decisions. - A developer that has strong opinions and wants to customize their setup. - A developer is new to programming and is getting familiar with some concepts.</li>
</ul>
<p>Once connected with those profiles we are building for, we can design a tool that either infers the experience based on the identified persona or provides an interface to indicate it. Alternatively, you can guide everyone through the same initial experience and give them opportunities to diverge and design their own journey. We can also embrace DHH's <a rel="external" href="https://m.signalvnoise.com/conceptual-compression-means-beginners-dont-need-to-know-sql-hallelujah/">conceptual compression</a> idea to make the experience feel like you are peeling layers of concepts as needed.</p>
<p>If you are building developer tools, remember. <strong>Not everyone is like you</strong>. Embrace diversity and build for it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>CLIs are products too</title>
      <link>https://pepicrft.me/blog/clis-product/</link>
      <guid>https://pepicrft.me/blog/clis-product/</guid>
      <pubDate>Wed, 04 May 2022 12:00:00 +0000</pubDate>
      <description>Over the years of working on command-line interface tools I observed that they are not often perceived as products. Consequently, organizations don&#x27;t embrace the same principles as UI-oriented products, which leads to complex tools designed…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Over the years of working on <a rel="external" href="https://en.wikipedia.org/wiki/Command-line_interface">command-line interface tools</a> I observed that they are not often perceived as products. Consequently, organizations don't embrace the same principles as UI-oriented products, which leads to complex tools designed by developers for developers.  <strong>The few projects that adopt a product mindset make a difference.</strong></p>
<p>A manifestation of the above is seeing ideas that are not ported over to CLIs. For example, <strong><a rel="external" href="https://en.wikipedia.org/wiki/Design_system">design systems</a></strong> are popularized across UI-oriented products. They play a crucial role in ensuring a consistent experience across features and products. The need for design systems grew organically when large organizations realized that it was becoming impossible to collaborate without a common foundation of blocks and principles. That manifested as inconsistently-styled experiences, which tightly connect with the user experience (UX). Design systems can play a similar role in CLIs, but few organizations spend some time devising and laying out a foundation to build upon. The ideas are the same, but they map to a different set of building blocks in the domain of terminal interfaces.</p>
<p>Adopting a product mindset requires looking at <strong>CLI commands as UI</strong>. Limited compared to browser-based products, but UI nonetheless that developers can experience. A command is a dialog between a person and a different domain through a terminal. Unless we put the attention to detail it deserves, we might end up designing conversations that feel like the person on the other side of the screen is a robot. They might serve their purpose, but they won't be as enjoyable as if it felt like talking to another human.</p>
<p>Pay attention to how you <strong>name</strong> commands, arguments, and flags. A terminal is limiting, but remember, <strong>constraints foster creativity.</strong> An intent well captured with the command's name and flags that become indirect complements of a sentence can yield a very expressive interface.</p>
<p>When you send output through the <a rel="external" href="https://en.wikipedia.org/wiki/Standard_streams">standard streams</a> it resembles receiving a response in a conversation. Be <strong>clear and direct</strong>, and when doing something that takes time, make sure the person knows about it. If you couldn't do what the user asked the CLI to do, tell them why, and provide the next steps that they can take to overcome the issue. Errors are also disregarded in CLIs primarily due to, in my experience, developers' laziness. It's quicker to just <em>throw</em> than go to the roots of the error to fix it or provide a better error experience.</p>
<p>If you build a CLI, remember, <strong>the how is as important as the what</strong>. The <strong>what</strong> makes a command satisfy the developers' intent. The <strong>how</strong> is what can make the experience more enjoyable to use. Some smartphones had been designed before Apple introduced the iPhone. They all served a similar purpose, but one put attention to the how and created an experience that made the product a successful piece of technology. Resist the urge of being lazy and not consider scenarios other than the <em>happy path</em>. You'll move slower, but remember, this is a long-term investment that pays off and you'r users will be thankful for it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Javascript, ESM, and tools</title>
      <link>https://pepicrft.me/blog/javascript-esm-and-tools/</link>
      <guid>https://pepicrft.me/blog/javascript-esm-and-tools/</guid>
      <pubDate>Wed, 04 May 2022 12:00:00 +0000</pubDate>
      <description>I&#x27;m using Javascript, Typescript, and Node a lot these days as part of my work at Shopify and Gestalt and I&#x27;m really loving it. In particular, its module system because it allows extensibility in ways it&#x27;d be more challenging with compiled…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I'm using Javascript, Typescript, and Node a lot these days as part of my work at <a rel="external" href="https://shopify.com/">Shopify</a> and <a rel="external" href="https://gestaltjs.org/">Gestalt</a> and I'm really loving it. In particular, its <strong><a rel="external" href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/">module system</a></strong> because it allows extensibility in ways it'd be more challenging with compiled languages or interpreted languages like Ruby that have a shared namespace where the code is loaded into. <a rel="external" href="https://vitejs.dev/">Vite</a> is an excellent example.</p>
<p>It hints that <strong>there might be a future where additional tooling and the indirection that comes with it its not necessary</strong>, but if you dig into that idea a bit, you realize it'll never be possible. At least in the years to come. Tooling will remain necessary to polyfill the code to adapt it to various runtimes (e.g <a rel="external" href="https://deno.land/">Deno</a>). It'll also be needed for UI frameworks that have built their template solutions upon Javascript (e.g JSX), remove type annotations from Typescript code, and accommodate NPM packages that don't comply with CommonJS conventions to ensure interoperability with ESM. g This is not unique to the Javascript ecosystem. Compilers also transform and optimize code into binary to be able to run it in the target platform. When building for Apple platforms, there's an artifact akin to sourcemaps, dSYMs, to be able to link stacktraces with the source code. The difference is that <strong>other ecosystems make it a core element of the programming language and that allows a more integrated experience</strong>. Achieving a similar level of cohesiveness in the Javascript world feels like juggling. You can integrate various tools under a framework to achieve a well-integrated experience, but you end up with a brittle setup that falls apart easily. This explains the well-known "delete <em>node</em>modules"_ and install dependencies again in the hope that the package manager will restore the state.</p>
<p>Despite how much I'd love to see a broader adoption of ES modules in the NPM ecosystem, and more conventions and standards pushed down to the Javascript foundation, I'll doubt that'll happen in the near future, and this influences how we build <a rel="external" href="https://gestaltjs.org/">Gestalt</a>. <strong>We'll do what's in our hands to minimize tooling indirection manifesting as bugs or breaking project setups.</strong> <a rel="external" href="https://rubyonrails.org/">Rails</a> is better positioned there thanks to the Ruby, but we can leverage some Javascript capabilities to approximate the Rails experience. For example, we can provide a foundational set of utilities that are automatically polyfilled by the framework depending on the deployment targets. This is something can't be done easily if frameworks encourage projects to import Node APIs directly.</p>
<p><strong>Instead of dreaming with a future where tools are not necessary, we are embracing tooling and leveraging it to provide Gestalt users with a reliable and integrated developer experience.</strong> I think Gestalt will blow your mind like not many frameworks have been able to do.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Users don&#x27;t care about your web app&#x27;s portable binary</title>
      <link>https://pepicrft.me/blog/users-dont-give-a-shit/</link>
      <guid>https://pepicrft.me/blog/users-dont-give-a-shit/</guid>
      <pubDate>Tue, 22 Mar 2022 12:00:00 +0000</pubDate>
      <description>We, software crafters, naturally tend to distance ourselves from users led by excitement for technological cycles and innovation. Our industry is full of examples. For instance, the crypto trend is an excellent example of that. No one can o…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>We, software crafters, naturally tend to <strong>distance ourselves from users</strong> led by excitement for technological cycles and innovation. Our industry is full of examples. For instance, the crypto trend is an excellent example of that. No one can obviate the fact that there's innovation in <a rel="external" href="https://en.wikipedia.org/wiki/Blockchain">blockchain</a>. Yet, it's not solving people's problems. It's doing more harm than good, but this is a topic for another blog post. The one distancing that got my attention recently is this idea of building a web app as a portable binary. <a rel="external" href="https://go.dev/">Go</a> started the trend with its ability to inline resources in the output binary. <a rel="external" href="https://deno.land/">Deno</a> has jumped on it with its <code>deno compile</code> command that many web developers are getting excited about.</p>
<p>Distributing software as a portable binary is an excellent idea for CLIs because you don't want to require users to install additional dependencies in their environment. But in the context of web apps, <strong>users don't give a shit about your web app being a binary.</strong> They care about the app's usability, reliability, and performance more than anything else. How an app runs in a server is an implementation detail. In pre-<a rel="external" href="https://kubernetes.io/">Kubernetes</a> and <a rel="external" href="https://www.docker.com/">Docker</a> times, there'd have been a strong argument in favor of binaries to ease deployments. But times have changed, and that's not a problem anymore. Platforms like <a rel="external" href="https://heroku.com">Heroku</a> or <a rel="external" href="https://fly.io">Fly</a> can infer your app's project deployment.</p>
<p>I'm writing this down and sharing it to remind myself and others that might come across the same argument that <strong>we build ultimately for users</strong>. If you get excited about a technological cycle or innovation, ask yourself whether you are playing with a new technology or building for users. And in the case of the latter, wonder if users care about the technological decision you are pondering. <a rel="external" href="https://shopify.com">Shopify</a> was criticized back when they chose <a rel="external" href="https://reactnative.dev/">React Native</a> for the mobile apps, but it was a decision that has had a positive impact on users' experience, which really matters.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>OSS and extrinsic motivators</title>
      <link>https://pepicrft.me/blog/oss-and-extrinsic-motivators/</link>
      <guid>https://pepicrft.me/blog/oss-and-extrinsic-motivators/</guid>
      <pubDate>Sat, 12 Mar 2022 12:00:00 +0000</pubDate>
      <description>More and more, we see open-source projects being backed by investment rounds . It&#x27;s positive for the projects because they can innovate faster and sustain themselves by paying people to work on it full-time, making money one of the main dri…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>More and more, we see <strong>open-source projects being backed by investment rounds</strong>. It's positive for the projects because they can innovate faster and sustain themselves by paying people to work on it full-time, making money one of the main drivers, and investors’ interests the wheel that steers the boat. <em>Is that something good or bad?</em> It depends.</p>
<p>When the motivations of the people contributing to a project are <a rel="external" href="https://en.wikipedia.org/wiki/Motivation#Incentive_theories:_intrinsic_and_extrinsic_motivation">extrinsic</a>, then the chances are that when money is gone, so are the motivations to contribute to the project. When the project is more community-driven, intrinsic motivations take preference, which helps the project sustain long-term. Note that community involvement and governance are not the same, even though they are often used interchangeably.</p>
<p>There’s a <strong>high correlation between projects that use money as an extrinsic motivator and the amount of marketing effort they’ve poured into them</strong>. They usually have marketing copies along the lines of <em>“we are making the web faster”</em> that reassemble the missions from Silicon Valley companies. I refrain from building anything upon those tools and frameworks no matter how good their marketing is. When I build software, I want it to sustain in time, and to achieve that, it’s important that the blocks I build it upon can sustain too.</p>
<p>Note that there’ll always be economic interests when developing open-source projects. Companies contribute to open-source projects because they benefit their business. However, <strong>money here is a secondary player</strong>. The community has a substantial role in steering the project than the companies that support the project through contributions. An excellent example of this is Rails. A company like <a rel="external" href="https://shopify.com">Shopify</a> has teams dedicated to contributing to <a rel="external" href="https://www.ruby-lang.org/en/">Ruby</a> and <a rel="external" href="https://rubyonrails.org/">Rails</a>. Shopify has interests, but it can't drive the framework in a direction that only benefits Shopify.</p>
<p>I think this is beautiful about the Ruby community, and recently in Javascript through projects like <a rel="external" href="https://vuejs.org/">Vue</a>, <a rel="external" href="https://vitejs.dev/">Vite</a>, <a rel="external" href="https://rollupjs.org/">Rollup</a>, and <a rel="external" href="https://svelte.dev/">Svelte</a>. You can sense a community behind it that connects all the different pieces in harmony and builds a strong community around it. This is the type of OSS that aligns with my principles and upon which I build the software that I craft.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Platform-dependent CLIs</title>
      <link>https://pepicrft.me/blog/platform-dependent-clis/</link>
      <guid>https://pepicrft.me/blog/platform-dependent-clis/</guid>
      <pubDate>Tue, 14 Dec 2021 12:00:00 +0000</pubDate>
      <description>I&#x27;m a firm believer that shaping products as developer platforms is an amazing idea to let developers from all over the world make your product diverse . Otherwise, you have products like Facebook and Apple &#x27;s that work great in California…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I'm a firm believer that <strong>shaping products as developer platforms is an amazing idea to let developers from all over the world make your product diverse</strong>. Otherwise, you have products like <a rel="external" href="https://facebook.com">Facebook</a> and <a rel="external" href="https://apple.com">Apple</a>'s that work great in California but conflict with the rest of the world, and what's worse, end up imposing a model that often becomes the source of serious problems. For example, the idea that people need to be connected and feel part of the community (the what) is accurate, but doing it through addictive technology (the how) has led to terrible consequences for people's mental health. Instead, <strong>they could have provided building blocks</strong> to model social interactions and communities and let developers use them to model how communities and social interactions work in their countries. Wouldn't that have been awesome?</p>
<p><a rel="external" href="https://shopify.com">Shopify</a> is a platform. They acknowledged <strong>the definition of e-commerce changes across countries</strong>. They can't build as many e-commerce versions as countries that exist in the world. But they can build the LEGO pieces and the core business logic and provide APIs for developers to build upon. The more I contribute to this platform from the inside, the more I realize how brilliant the idea is. It seems a simple idea, but I'm sure <a rel="external" href="https://twitter.com/tobi">Tobi</a> has put a lot of thought into this.</p>
<p>I have the opportunity to work on the <a rel="external" href="https://github.com/shopify/shopify-cli">CLI</a> that first and third-party developers use to build and deploy to the platform. As part of this work, one of the challenges we came across is <strong>breaking or abstracting away the dependency that projects have with the platform.</strong> If you've used CLIs to build for other platforms, you might have noticed that most of them don't require the platform in the development phase. If you create an iOS app, you only need the platform when you upload the app. Until then, you can use Xcode and the simulators to develop and test the app locally. If you create a web app with a framework like <a rel="external" href="https://nextjs.org/">NextJS</a>, you can run the app locally and only interact with <a rel="external" href="https://vercel.com/">Vercel</a> when you need to deploy the app. There's only a moment in time when the user has to navigate from the CLI and the local environment to the server-side platform.</p>
<p>But that's not the case at Shopify. <strong><a rel="external" href="https://shopify.dev/themes">Theme development</a></strong> depends on the production storefront renderer to preview the themes during development. The same is true for <strong><a rel="external" href="https://shopify.dev/apps/tools/cli/extension-commands">Extensions</a></strong>. An extension only makes sense when it's loaded within the context of the Shopify platform. For example, if the extension represents a checkout extension, you want to see it loaded in an actual checkout flow.</p>
<p><strong>During development, the dependency on the platform makes it extremely challenging to provide a great DX.</strong> It's not impossible, but something I've been thinking about ever since I came to that realization. I don’t have solutions yet, only ideas for improving the DX. For example, imagine Shopify providing a server-side <a rel="external" href="https://storybook.js.org/">Storybook-like</a> functionality that acts as a disposable sandbox environment. The dependency with the platform remains, but there's a platform-side dedicated tool to ensure the preview experience is the best. Storybook's stories concept would map so nicely. For example, we could provide different checkout scenarios that you can easily switch between without going through the checkout process.</p>
<p>Another approach could be <strong>taking platform functionality down to the client to simulate locally.</strong> However, that requires first designing those pieces to be modular enough so that the preview piece can be pulled locally. Second, write them in a compiled language such that you hide implementation details of the business domain. If you are familiar with iOS development, it'd be the same as providing a simulator for the Shopify platform.</p>
<p><strong>Improving the current state would shorten the development cycles, and developers would have more focus and motivation when building for the platform.</strong> I remember my days of iOS development when I could not preview my changes because of signing issues. It felt so frustrating that I don't want Shopify developers to feel the same way.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>On evolving opinions</title>
      <link>https://pepicrft.me/blog/on-evolving-opinions/</link>
      <guid>https://pepicrft.me/blog/on-evolving-opinions/</guid>
      <pubDate>Wed, 08 Dec 2021 12:00:00 +0000</pubDate>
      <description>I recently came across a tweet that suggested me to undo my blog post on Web3 after sharing some bad things I&#x27;d uncovered in the technology. I couldn&#x27;t understand why an undo and not a follow-up . I see opinions as alive entities that evolv…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I recently came across a tweet that suggested me to undo my blog post on <a href="https://pepicrft.me/blog/on-evolving-opinions/__GHOST_URL__/2021/11/29/exploring-web3">Web3</a> after sharing some bad things I'd uncovered in the technology. I couldn't understand why an <strong>undo</strong> and not a <strong>follow-up</strong>. I see opinions as alive entities that evolve and change. The initial opinion that I had when I started reading about Web3 evolved as I dove into communities and solutions build upon it. I went from having a high level of excitement with a vaguely-defined mental model to lose a bit of excitement as I defined the model further. I find the journey of evolving thrilling.</p>
<p>However, that doesn't seem to align with what some people expect: <strong>polarized and somewhat religious opinions.</strong> They expect you either be a <a rel="external" href="https://reactnative.dev/">React Native</a> lover or hater, a <a rel="external" href="https://en.wikipedia.org/wiki/Web_2.0">Web2</a> believer or a <a rel="external" href="https://web3.foundation/">Web3</a> geek, or a monolith vs a micro-services advocate. Liking Web3 but disliking parts of it is inconceivable for them. You either like it or hate it.</p>
<p>Because I <strong>don't want to be biased by my own static opinions</strong>, I avoid engaging in these discussions and keep and open mindset. Moreover, since I <a href="https://pepicrft.me/blog/on-evolving-opinions/__GHOST_URL__/about">value openness</a> and I enjoy sharing my learnings and opinions, that sometimes means seeing seemingly contradictory opinions at different points in time. And that's completely fine.</p>
<p><strong>My opinions</strong> about Javascript development have been a roller coaster. There are things that I like about it, for example the beautiful abstractions developers are building with it, and things that I hate about it, like the convoluted setup and dependency graph that you find in some projects. Similarly, I gave up a while ago on being religious about Swift. That gave me a unique perspective on where the programming language shines, what are the limitations, and how Apple's interests drive the direction of the project.</p>
<p>I'm currently forming opinions around the nature of the technologies and tools they use. <em>Do I want to continue using and supporting open-source technologies with business interests baked into it? Is my relationship with open-source sustainable long-term? Do I see myself doing the same thing for the next 10 years? 20 years?</em></p>
<p><strong>My days are filled with questions</strong>, and the answers to those lead to opinions and more questions. Expect my opinions to change. Expect me to share those opinions, and also expect my opinions to move along a spectrum. "The only constant in life is change" <a rel="external" href="https://arapahoelibraries.org/blogs/post/the-only-constant-in-life-is-change-heraclitus/#:~:text=One%20constant%20since%20the%20beginning,change%20is%20also%20a%20constant.&amp;text=When%20that%20fear%20of%20change,becomes%20a%20phobia%2C%20particularly%20Metathesiophobia.">they said</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Migrated to SvelteKit</title>
      <link>https://pepicrft.me/blog/migrated-to-sveltekit/</link>
      <guid>https://pepicrft.me/blog/migrated-to-sveltekit/</guid>
      <pubDate>Tue, 07 Dec 2021 12:00:00 +0000</pubDate>
      <description>I migrated this blog to SvelteKit . I did it to consolidate everything I had learned about the framework, and be able to SSR static pages with dynamic content. For example, I&#x27;ll be able to collect data from external sources like GitHub and…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I migrated this blog to <a rel="external" href="https://kit.svelte.dev/">SvelteKit</a>. I did it to consolidate everything I had learned about the framework, and be able to SSR static pages with dynamic content. For example, I'll be able to collect data from external sources like GitHub and include it in the <a href="https://pepicrft.me/blog/migrated-to-sveltekit/__GHOST_URL__/about">about</a> page.</p>
<p>I ported over the same boring design I had in the previous <a rel="external" href="https://jekyllrb.com/">Jekyll-based</a> website. I love it because it reminds us the origins of the web as a tool to share documents. The focus is in the content and not that much on the continent.</p>
<p>Expect some follow-up blog posts from me talking about the things that I like and don't like about Svelte and SvelteKit, and how it compares to other frameworks like Vue and React.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Adapting to a platform</title>
      <link>https://pepicrft.me/blog/adapting-to-the-platform/</link>
      <guid>https://pepicrft.me/blog/adapting-to-the-platform/</guid>
      <pubDate>Mon, 08 Nov 2021 12:00:00 +0000</pubDate>
      <description>In a simplistic way, we can see web frameworks as convenient functions that take your app as input and return deployable artifacts. GatsbyJS generates static HTML, CSS, and Javascript that platforms like Netlify know how to deploy. Rails ge…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>In a simplistic way, we can see web frameworks as convenient <strong>functions</strong> that take your app as input and return deployable artifacts. <a rel="external" href="https://www.gatsbyjs.com/">GatsbyJS</a> generates static HTML, CSS, and Javascript that platforms like <a rel="external" href="https://netlify.com">Netlify</a> know how to deploy. <a rel="external" href="https://rubyonrails.org/">Rails</a> generates static assets and provides an entry point to run a process on a platform like <a rel="external" href="https://heroku.com">Heroku</a>. Note that the artifacts need to be <strong>adapted</strong> to the deployment target. Heroku does it through <a rel="external" href="https://devcenter.heroku.com/articles/buildpacks">buildpacks</a> and <a rel="external" href="https://devcenter.heroku.com/articles/procfile">Procfiles</a> that instruct the platform on building and running a server. Netlify achieves the same through a <a rel="external" href="https://docs.netlify.com/configure-builds/file-based-configuration/">configuration file</a> where developers describe how to build and deploy their websites. Traditionally, the adaptation process has either fallen on the platform or developers’ sides (e.g. through a CI deployment pipeline)</p>
<p><strong>What if frameworks have adaptation as a built-in primitive?</strong> That's what SvelteKit provides through <a rel="external" href="https://kit.svelte.dev/docs#adapters">Adapters</a>. It's an API for third-party developers to define how to adapt a SvelteKit app to different hosting providers. For example, the <a rel="external" href="https://github.com/sveltejs/kit/tree/master/packages/adapter-netlify">netlify-adapter</a> adapts the output to Netlify and does things like turning endpoints and SSR pages into functions that run on-demand. Because the framework allows <a rel="external" href="https://developers.google.com/web/updates/2019/02/rendering-on-the-web#server-rendering">SSR</a>, <a rel="external" href="https://developers.google.com/web/updates/2019/02/rendering-on-the-web#csr">CSR</a>, and <a rel="external" href="https://developers.google.com/web/updates/2019/02/rendering-on-the-web#static-rendering">static rendering</a>, a SvelteKit project can contain the web app, documentation website, and marketing and landing pages. Cool? Isn't it. Adapters decouple the deployment platform from the framework to prevent <a href="https://pepicrft.me/blog/adapting-to-the-platform/__GHOST_URL__/2021/11/08/open-source-vendor-locking">vendor-locking</a>.</p>
<p>I’m still new to the framework, but I think its concepts are powerful, and adapters are an excellent example of that.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>I want to be rich</title>
      <link>https://pepicrft.me/blog/i-want-to-be-rich/</link>
      <guid>https://pepicrft.me/blog/i-want-to-be-rich/</guid>
      <pubDate>Mon, 25 Oct 2021 12:00:00 +0000</pubDate>
      <description>It&#x27;s been a while since I started reading more about personal finances and investments. My primary motivation was to escape the tempting treadmill of scaling up costs as the income increases. It&#x27;s never late to learn about it, but the earli…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It's been a while since I started reading more about personal finances and investments. My primary motivation was to escape the tempting treadmill of scaling up costs as the income increases. It's never late to learn about it, but the earlier, the better, so I'm glad it clicked in my head when I was 28.</p>
<p>As a <strong>software engineer</strong>, a fortunately well-paid job, it's easy to fall into the treadmill trap. You earn above the average (prompter), immersed in a planned obsolescence culture (temptation). You want to have the latest iPhone, a new Macbook, a large TV, an Apple watch... We become friends of <a rel="external" href="https://amazon.com">Amazon</a> and spend without thinking about our financial future.</p>
<p>The first thing that I learned is that it's important to have <strong>insights into your cash flow</strong> for two reasons. First, you can see whether you are spending too much money on things that bring no value. Second, you can see your family's net worth and know <strong>how much money you can invest</strong>.</p>
<p>This leads to the following question: <strong>what's my investment strategy?</strong> We first invested in a property in Berlin. That's what people do in Spain, so we had a strong bias towards this move. Is it the most brilliant move to start with? I don't think so. Was it a good idea in hindsight? I think it was by looking at the market and considering the interest rate of the mortgage. Then I read further and learned that it's wiser to defer that type of investment and use the liquid money to increase the net worth through other investments.</p>
<p>The next move (and serious mistake) was seeking financial advice. We came across <a rel="external" href="https://www.dvag.de/dvag/index.html">DVAG</a>, a Deutsch corporation whose goal is to sell insurance. We naively fell into their trap of thinking that we needed all the insurances they offered us. The person who sold us those products was a Spaniard living in Berlin, so her selling strategy was to "teach" ex-pats how Germans do it. We got the following for my wife and me:</p>
<ul>
<li><a rel="external" href="https://schlemann.com/altersvorsorge/riester-rente/riester-pension-english/">Riester</a> and <a rel="external" href="https://www.bvi.de/en/about-funds/savings-and-provision-for-retirement/ruerup-pension/#:~:text=The%20&#x27;R%C3%BCrup&#x27;%2D%20pension%20is,with%20a%20fund%20savings%20plan.">Rürup</a> pension plans - An income protection insurances, - A lawyers insurance, - A <a rel="external" href="https://de.wikipedia.org/wiki/Bausparvertrag">bausparvertrag</a> for our mortgage - An investment product (that invests in funds) - Private health insurance for me.</li>
</ul>
<p>In hindsight, we were too naive. Planning to move to Spain allowed us to see everything from a different angle:</p>
<ul>
<li>It is a company that follows a pyramid scheme earns commissions per sold product and from the products sold by the people under them. - We were sold products (the pensions) that were not designed for our profiles. They asked how much we earned and filled the costs as much as they could, ensuring there was a tiny bit of space for breathing. - They never shared the costs with us, and as you can imagine, they were pretty high (over 2% annually).</li>
</ul>
<p>We <strong>canceled</strong> everything except Rürup that cannot be canceled but paused. We lost some money, but it was nothing compared to what we'd have not earned if we stayed with them. This was something positive about considering moving back to Spain. When I told her I was canceling everything, her answer was: <em>Don't expect the same service from me anymore.</em> Of course, I later discovered that <a rel="external" href="https://www.generali.de/">Generali</a> would make them return all the commission they got for bringing me as a customer. Funny thing, she insisted a few times on getting my Germany deregistration confirmation (i.e. Abmeldung) to prove that I did it because I was leaving the country. If you ever come across this company, DVAG, watch out.</p>
<p>I learned a few lessons out of that experience, but the most important lesson is that <strong>no one will manage your finances better than you</strong>. Or in other words, investing money comes with the responsibility of learning how to invest it.</p>
<p>After that, I continued reading further. I started investing in ETFs (a mix of accumulative and distributing funds to take advantage of some tax benefits in Germany), individual stocks from companies that share dividends, and alternative investments such as microloans, whisky, and cryptocurrencies. As part of this effort, I created an additional spreadsheet to keep track of them. In particular, In particular, I'm interested in the diversification scheme and how investments are performing over time. If you are interested, the following two resources have been handy for me: <a rel="external" href="https://indexfundinvestor.eu/">Index Fund (European) Investor</a>, <a rel="external" href="https://www.elclubdeinversion.com/">El Club de Inversión (Spanish)</a>, and <a rel="external" href="https://www.bankeronwheels.com/">Banker on Wheels</a>.</p>
<p>Alright, Pedro, you save money, which you decide to invest, but what's your <strong>goal</strong>? My goal is to be <strong>rich</strong>. But not the definition of rich we are all used to. The definition by <a rel="external" href="https://en.wikipedia.org/wiki/Robert_Kiyosaki">Robert Kiyosaki</a>:</p>
<blockquote>
<p>If you stopped working, how long could you survive?</p>
</blockquote>
<p>I want to work less or even better, stop working, and not have to worry about money anymore. Right now, I have <strong>two dependencies</strong>. My employer, who is my primary source of income, and the future public pension from the Government, which we all know it's getting harder to sustain. Unless I do something, the default is to continue working as much as I do until I retire. But there's a better alternative to that, which I learned in the book <a rel="external" href="https://www.amazon.de/Cashflow-Quadrant-Rich-dad-poor/dp/3898798836">"The cashflow quadrant"</a>: I can be a mix of a business owner and an investor and leverage people and money to make money. Achieving that independence is also possible by being employed, but it often leads to working harder which is not healthy. It's not a matter of working harder, but being financially more intelligent.</p>
<p>I've always been in the employed quadrant and worked hard, which has allowed me to grow a lot professionally. But I feel I'm approaching an inflection point, and I'll have to take a leap. I might start using my spare time more wisely and gear it towards being the owner of my own business in the future. I think I have some necessary traits to get there, but there are some other areas I still need to work on.</p>
<p>I've you've followed me for a while, you might notice a shift in my relationship with open-source work and the content in this blog. If this intrigues you and you would like to chat about it further, don't be a stranger and send me an email. These topics are always taboo, but I'm open to talking about them.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The React chain</title>
      <link>https://pepicrft.me/blog/the-react-chain/</link>
      <guid>https://pepicrft.me/blog/the-react-chain/</guid>
      <pubDate>Wed, 13 Oct 2021 12:00:00 +0000</pubDate>
      <description>I’ve been thinking a lot lately about the role React plays when building a web app. Companies like GitHub and Shopify , both very successful software companies, introduced React recently in areas where it makes sense . This led me to the qu…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’ve been thinking a lot lately about the role <a rel="external" href="https://reactjs.org/">React</a> plays when building a web app. Companies like <a rel="external" href="https://github.com">GitHub</a> and <a rel="external" href="https://shopify.com">Shopify</a>, both very successful software companies, introduced React recently in areas where <strong>it makes sense</strong>. This led me to the question: Is React and everything that comes with it (e.g., abstractions, tools, libraries) an influential piece in generating value for users?</p>
<p>There are great things about the React stack. You can more easily <strong>unit-test</strong> the business logic of your frontend, <strong>share and use components</strong> that atomically encapsulate structure (HTML), behavior (JS), and style (CSS). Moreover, you have access to beautiful abstractions to do theme-based styling and even leverage the Typescript compiler to validate your styling object. React turns building a web app into a LEGO game where many blocks are already provided by the community.</p>
<p>However, with React, projects pull in a chain of drawbacks that wouldn’t exist if we didn’t add React in the first place. The first of them is having an API. Sure, if you plan to have more clients in the future, an API is a must. But what if that’s not the future plan, or it’s far ahead? You end up optimizing for a future that might never come.</p>
<p>In many cases, we end up going down the path of <a rel="external" href="https://graphql.org/">GraphQL</a> because libraries make it so convenient that we think we need it, but we don’t realize again that GraphQL was designed for a problem we are far from having. And as you probably know, but with an API, we introduce a new set of problems because we have two sources of truth for the data. Many Javascript libraries are trying to abstract that away through caching strategies. Some projects decide to go down the path of trying to model their state with yet another dependency, Redux, that ends up spreading like a virus and bringing more complexity to the frontend domain.</p>
<p>At this point, one might argue that it’s possible to solve that by doing <strong>server-side rendering (SSR)</strong>. True, but the moment you hydrate the app on the client, you want the routing experience to be on the client, leading to components having to fetch data through the API. We can’t move away from it. React and, more generally SPAs, force you to have two sources of truth for your data. And I forgot to mention that SSR requires your React libraries to be compatible with it, limiting the options from the exciting pool of component libraries one has access to.</p>
<p>Furthermore, React means JSX, and JSX means you need <strong>additional tooling and process changes</strong>. Babel or any other transpiler needs plugins to transform the JSX into a valid Javascript syntax, and some CSS-in-JS libraries might couple themselves to the underlying tooling through macros. Because the Javascript that you write is not the one that gets executed, and it’s just a declaration that is then loaded in a virtual DOM and persisted to the document, debugging requires additional browser extensions. Don’t get me wrong. Having to install tools is not a bad thing; having to mess around with these things when starting a project takes the focus from the important thing, generating value through technology.</p>
<p>We should not forget that we can make our styling themeable by simply leveraging CSS building blocks, generate HTML server-side without a framework like React and the chain of tools that come with it, and that small touches of Javascript are sufficient to add some interactivity where it makes sense.</p>
<p><strong>When does it make sense to follows the React approach then?</strong> I think it makes sense that the app will be very interactive, for example, if you are building a tool like <a rel="external" href="https://figma.com/">Figma</a>. It also makes sense if the value the abstraction brings outweighs the cost of maintaining and evolving a most likely convoluted set of Javascript libraries and NodeJS tools. You can also take the path of letting a framework do that for you, which is what <a rel="external" href="https://redwoodjs.com/">RedwoodJS</a> and <a rel="external" href="https://nextjs.org/">NextJS</a> are betting on. It also makes sense if supporting multiple clients is core to the product, and where developing an API and reusing mental models align closely with the product direction.</p>
<p>It <strong>does not make sense</strong> if your sole focus is to generate value through a web app. Throw a project with a <a rel="external" href="https://rubyonrails.org/">Rails</a> or similar framework and focus on the product and not the tools and the technology around it.</p>
<p>My <strong>sentiment</strong> with React and Javascript development is that it’s a bit like capitalism; it creates more problems that can be solved with more Javascript. Solutions are in rare cases evolving an existing foundation, but creating better versions of existing tools or creating new tools from scratch like Rome because everything that was built before is fundamentally wrong.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>On cutting off some dopamine dependency</title>
      <link>https://pepicrft.me/blog/on-cutting-off-dopamine/</link>
      <guid>https://pepicrft.me/blog/on-cutting-off-dopamine/</guid>
      <pubDate>Mon, 11 Oct 2021 12:00:00 +0000</pubDate>
      <description>Over time, my relationship with the Internet has turned me into a dopamine-dependent. I’ve reached a point when my body often has a physical presence in the offline world throughout the day, but my brain wanders in the online space. Should…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Over time, my relationship with the Internet has turned me into a dopamine-dependent. I’ve reached a point when my body often has a physical presence in the offline world throughout the day, but my brain wanders in the online space.</p>
<p><em>Should I tweet about this? What if I write a blog post about that? This is boring; let me check what people are talking about on Twitter. Look at that beautiful scene; I’ll take and share a photo on Instagram. This is hilarious; I’ll tweet what happened to me. I built this open-source project, I’ll share it broadly to gauge people’s reactions.</em></p>
<p>I was once gifted the Internet awesomeness, and now I gift my time and energy back to the Internet for free. In the meantime, life goes by, and I miss the opportunities to do fulfilling offline and social activities. <strong>Is this sustainable long-term?</strong> I don't think it is.</p>
<p>The more I run on the <strong>dopamine treadmill</strong>, the faster it goes, and the more I need to have a sense of fulfillment. I've got online friends that <em>I feel</em> I need to feed with photos and stories, some followers on Twitter <em>I feel</em> I need to share updates with, a handful of open-source projects <em>I feel</em> I need to maintain. There are also newsletters <em>I feel</em> I have to keep up with, Reddit discussions <em>I feel</em> might be relevant to me, and podcasts <em>I feel</em> it'd be great to listen to. I become <a rel="external" href="https://en.wikipedia.org/wiki/Blinkers_(horse_tack)">blinker</a>, and consequently, I miss out on the beauty of slowness, the present, and the beauty of the offline world. It's all me, my ego, the dopamine, and what I feel I need to do. It's all feelings.</p>
<p>What's worse is that it has a <strong>cascading effect</strong>. People see the facade, and if they feel inspired by a professional trajectory, they think they need to imitate what you do. The world then becomes a <strong>dopamine festival</strong>. Rockstars take the main stage, while the audience dream of becoming one in the future. I don't need to learn how to play an instrument, nor find a band or a manager; I need time and some tools that people are already addicted to <em>(e.g. Twitch, Twitter, TikTok)</em>. If I build my audience, I can play in the main stages too.</p>
<p><strong>The Internet has paved the way to achieve a dopamine-dependent life whose meaning come from other people worshipping you and your work.</strong></p>
<p>Seeking that life has some similarities with dreaming with becoming a millionaire. We pour a lot of energy, time, and sometimes health to finally realize you made your life more meaningless. We are on the treadmill, so we need <strong>recognition or money</strong> to sense a meaningful life.</p>
<p>The truth that many of us fail to realize is that we are <strong>social animals</strong>; thus long-lasting happiness and fulfillment often comes from social interactions in the offline world. If there's something positive out of the COVID19 pandemic, it's that it proved that we can't replace offline relationships with <a rel="external" href="https://zoom.us/">Zoom</a> calls or <a rel="external" href="https://www.joinclubhouse.com/">Clubhouse</a> discussions.</p>
<p>Alright, Pedro, I get you, but how are you going to remove your dependency? First, I'll limit the <strong>content consumption time</strong> to Friday mornings. If I find something interesting, I'll use a read-later and save it to read it on Fridays. Regarding my usage of <strong>social networks</strong>, I'll limit their usage to once per day. The list of social networks includes Twitter, Instagram, and Facebook. I like capturing my ideas and reflections in the open, and therefore, I'll continue sharing them. However, I'll use my personal website as a medium and not Twitter. The reason is that I don't want to contribute to the stream of tweets that might contribute to increasing people's anxiety. I'll <strong>increase the amount of social and offline activities</strong>. For example, learning how to design and assemble furniture, gardening, or learning German has been on my list for quite a long time, and I continue postponing to leave space for my online endeavors. And last, I'll <strong>remove any sense of obligation</strong> with anyone on the Internet. I'll do things that bring me <strong>joy</strong>.</p>
<p>Let's see how it goes.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Great solutions for the wrong problems</title>
      <link>https://pepicrft.me/blog/great-solutions/</link>
      <guid>https://pepicrft.me/blog/great-solutions/</guid>
      <pubDate>Tue, 28 Sep 2021 12:00:00 +0000</pubDate>
      <description>As you might know, I’m a curious person. That leads me to reading about challenges tech companies run into and the solutions that they come up with, and connecting them with similar problems with the aim of forming mental models. Why React…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As you might know, I’m a curious person. That leads me to reading about challenges tech companies run into and the solutions that they come up with, and connecting them with similar problems with the aim of forming mental models.</p>
<p>Why <a rel="external" href="https://reactjs.org/">React</a>? What’s the role of <a rel="external" href="https://graphql.org/">GraphQL</a>? Why was <a rel="external" href="https://www.rust-lang.org/">Rust</a> created? Where does it make sense to use it? How does it compare to <a rel="external" href="https://golang.org/">Go</a>? What are the drawbacks of building a CLI with interpreted languages? How does <a rel="external" href="https://svelte.dev/">SvelteJS</a> and <a rel="external" href="https://www.solidjs.com/">SolidJS</a> compare to <a rel="external" href="https://vuejs.org/">VueJS</a> and ReactJS? What is React Server Components trying to solve? Why does ES modules remove the need for intricate Javascript tooling? Why is "deleting node_modules" a thing in the Javascript ecosystem? Why is the trend in the Javascript community to build tooling in compiled languages?</p>
<p>Problems that are constantly arising push current solutions beyond their limits, and in less-opinionated environments like Javascript’s, new creative solutions emerge like flowers in a field. The result of that is a rich pool of solutions to choose from. The <strong>caveat</strong> is that solutions get so much attention that the problems they originally set out to solve remain background or get disregarded in the decision-making process. On top of that they present even more problems that get solved with more layers. In practice, this means simple projects with convoluted tech stacks that aim to solve problems they don’t really have.</p>
<p>Take React. It solved Facebook’s problems that are now becoming other companies’ problems too. GraphQL is a similar story and it’s now becoming the standard for the request-response model in web applications, even if there’s a single client consuming the API. Just today I came across a product that combines GraphQL with CDN to provide caching to GraphQL APIs. What will follow? Another product that solves synchronization issues between the source API and the caching layer.</p>
<p>We, developers, are usually solutions-oriented, and that makes the matter worse. We get tasked with solving something, and put too much focus on the solution. As a consequence, we end up proposing technologies and languages we are familiar with or that most people are talking about these days. This is very challenging for me. I need to make an effort to understand a problem well and consider multiple solutions before deciding for one. I have to tell my biases to shut up.</p>
<p>As the name of the post says, <em>we often end up with great solutions for the wrong problems.</em></p>
<p><strong>What should we do then?</strong> I think we have to embrace innovation and diversity of solutions. It’s something positive for the industry. However, I think we should <strong>mentor software developers</strong> to be more problem-oriented. They should be able to gain understanding of the problem that they have at hand, evaluate several solutions and understand the trade-offs of each of them, make the best unbiased decision, and document the rational behind the decision for future context and re-evaluation.</p>
<p>Moreover, I think it’d be great if open-source projects include in their READMEs the problem/s they are optimizing for, and some examples of projects for which the solution would and wouldn’t be suitable.</p>
<p>Mastering this is, in my opinion, what sets the difference between a junior and a senior developer. Towards the staff role, developers should be able to find problems to solve in domains with some uncertainty.</p>
<p>It’s not easy. As I mentioned earlier, I have to make an effort every time. However, once the decision is made and the solution executed, it feels extremely rewarding and puts you in the mood of hunting new problems.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Developer platforms and diversity</title>
      <link>https://pepicrft.me/blog/platforms-and-diversity/</link>
      <guid>https://pepicrft.me/blog/platforms-and-diversity/</guid>
      <pubDate>Thu, 16 Sep 2021 12:00:00 +0000</pubDate>
      <description>If we think about how tech companies build products these days, we&#x27;ll realize many present a single model that they push onto the world . Companies like Facebook and Twitter model for how social interactions happen on the Internet. Others l…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If we think about how tech companies build products these days, we'll realize many present a <strong>single model that they push onto the world</strong>. Companies like <a rel="external" href="https://facebook.com">Facebook</a> and <a rel="external" href="https://twitter.com">Twitter</a> model for how social interactions happen on the Internet. Others like <a rel="external" href="https://spotify.com">Spotify</a>, model how people produce and consume music and podcasts.</p>
<p>If we think about it further, we'll realize that the approach is incompatible with the <strong>diverse</strong> world we live in. Diverse problems require diverse solutions. But what we get instead are solutions designed for a western-centric simplified version of the world, and we expect everyone to embrace them.</p>
<p>Having a simplified version of the world is <strong>convenient for the business</strong>. Still, it might lead to severe problems like the <a rel="external" href="https://www.nytimes.com/2018/10/15/technology/myanmar-facebook-genocide.html">Myanmar</a> genocide incited on Facebook or the <a rel="external" href="https://www.berliner-zeitung.de/en/new-laws-could-end-e-scooter-chaos-li.116188">e-scooter chaos</a> in Berlin.</p>
<p>As someone who works in tech, this annoys me greatly, especially when the company prides itself upon its diversity efforts and building a product that rejects world diversity. <em>How crazy is that?</em></p>
<p>I understand building as many product versions as nuances exist in the world would be cumbersome. Still, companies could focus on the domain's core and provide a platform for <strong>developers to codify the diversity of the world</strong>. This is what <a rel="external" href="https://shopify.com">Shopify</a> does with its <a rel="external" href="https://apps.shopify.com/">apps ecosystem</a>. Shopify focuses on the business logic and primitives of e-commerce and provides developers with extension points on the platform to translate e-commerce to the meaning in their countries. I believe this is key to Shopify's success, and it's one of the reasons I like it working here.</p>
<p>Imagine Facebook doing something similar. They already have a platform with primitives, logic, and a complex graph of social interactions. Developers could build upon that to create social networks in their countries following their countries' social norms and cultural nuances. I believe <a rel="external" href="https://twitter.com/jack">Jack</a> aimed to do that with Twitter, but I can't find the link to it.</p>
<p>So the takeaway I'd like to leave you with is that shaping products as platforms and providing APIs for developers is an exciting model to embrace the world's diversity.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Spain, it&#x27;s not time to be reunited (yet)</title>
      <link>https://pepicrft.me/blog/spain-we-dont-meet-yet/</link>
      <guid>https://pepicrft.me/blog/spain-we-dont-meet-yet/</guid>
      <pubDate>Tue, 14 Sep 2021 12:00:00 +0000</pubDate>
      <description>As some of you might know, we’ve been in Barcelona looking for a flat to relocate from Berlin for the past few weeks. A few things happened during the COVID19 pandemic that prompted us to think about whether we wanted to stay in Berlin long…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As some of you might know, we’ve been in Barcelona looking for a flat to relocate from Berlin for the past few weeks. A few things happened during the COVID19 pandemic that prompted us to think about whether we wanted to stay in Berlin longer. In particular, Shopify became a distributed company and opened a legal entity in Spain. Furthermore, my wife got a job at Shopify. <em>What are we doing here?</em> The idea of moving to Spain sounded very appealing: <em>no language barrier, better weather, and more healthy food.</em> It felt the natural next step for us, and therefore we decided to spend weeks in Barcelona to see how it felt being back here.</p>
<p>It took weeks of many questions and answers to finally admit <strong>it was not the right time for us to be back</strong>.</p>
<p>What follows is a brain dump of what led us to make that decision. Note that this is based on my experience, and therefore it's subjective.</p>
<p>First, it's very <strong>comfortable</strong> living here. It's too comfortable that it makes us feel uncomfortable. We like the challenges and the learnings that come from them. We feel moving back would rush us into a more appropriate life for an older version of ourselves. Being abroad means being exposed to other <strong>cultures</strong>, and we love that a lot. When we left the country, we became more aware of what we didn't know and learned how nuanced and complex the world is.</p>
<p>Many people here say that "in Spain, we have a good life", but I realized that statement is subjective. <strong>What's good?</strong> If you reduce that to weather and food, sure, you'll have a good life here. But in other areas such as innovation and education, Spain is far distant from other countries in Europe, which also means good life to us.</p>
<p><strong>What are we doing then?</strong> For now, we'll go back to Berlin. We need to rest in what's our home. As weird as it sounds, we miss Berlin's weather. It's been too humid and hot these days in Barcelona <em>(we might have become Germans)</em>. The plans for later this year or early next are to visit <a rel="external" href="https://en.wikipedia.org/wiki/Amsterdam"><strong>Amsterdam</strong></a>, to assess it as our potential next home.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>A future note to self about Omniauth</title>
      <link>https://pepicrft.me/blog/a-future-note-to-self-about-omniauth/</link>
      <guid>https://pepicrft.me/blog/a-future-note-to-self-about-omniauth/</guid>
      <pubDate>Fri, 20 Aug 2021 12:00:00 +0000</pubDate>
      <description>Every time I try to set up Omniauth on a Rails codebase I run into the same issue: Not found. Authentication passthru And every time I have to spend a fair amount of time understanding what&#x27;s causing the error. Luckiy it won&#x27;t have anymore…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Every time I try to set up <a rel="external" href="https://github.com/omniauth/omniauth">Omniauth</a> on a Rails codebase I run into the same issue:</p>
<pre><code>Not found. Authentication passthru
</code></pre>
<p>And every time I have to spend a fair amount of time understanding what's causing the error.</p>
<p>Luckiy it won't have anymore after writing this note for my future self.</p>
<p>Besides the standard steps to set up Omniauth and <a rel="external" href="https://github.com/omniauth/omniauth-github">Omniauth GitHub</a>, we need to add <a rel="external" href="https://github.com/cookpad/omniauth-rails_csrf_protection">omniauth-rails_csrf_protection</a> to bring <a rel="external" href="https://owasp.org/www-community/attacks/csrf">CSRF Protection</a> to the requests that are sent from the authentication pages. After adding the dependency to the <code>Gemfile</code>, we need to add a new initializer, <code>omniauth.rb</code>, to allow sending <code>POST</code> requests from the Omniauth links:</p>
<pre><code>OmniAuth.config.allowed_request_methods = [:get, :post]
</code></pre>
<p>In that same initializer, we need to set the host to ensure Omniauth passes the right redirection URL when initiating the authentication flow. Otherwise the Omniauth provider might fail due to mismatching URLs:</p>
<pre><code>OmniAuth.config.full_host = &quot;https://myapp.com&quot;
</code></pre>
<p>If we generated the Devise views under our project's <code>app/views</code> directory, we can notice that the Omniauth links are already configure to be <code>POST</code> in the <code>_links.html.erb</code> file:</p>
<pre><code> &lt;%= link_to(&quot;Sign in with #{OmniAuth::Utils.camelize(provider)}&quot;,
 omniauth_authorize_path(resource_name, provider),
 { method: :post }) %&gt;
</code></pre>
<p>And last but not least, we need to instruct Omniauth on what to do once the authentication flow has finished. We do that by configuring a controller in the <code>routes.rb</code>:</p>
<pre><code>Rails.application.routes.draw do
 # Devise
 devise_for :users, controllers: { omniauth_callbacks: &quot;users/omniauth_callbacks&quot; }
end
</code></pre>
<p>In the controller each provider is represented by a method with the same name of the provider. Note that the request's <code>env</code> attribute provides all the user metadata that we need to find or create the user in our database and authenticate them using Devise's <code>sign_in_and_redirect</code> method:</p>
<pre><code>class Users::OmniauthCallbacksController &lt; Devise::OmniauthCallbacksController
 def github
 @user = ... # Create the user

 if @user.persisted?
 sign_in_and_redirect(@user, event: :authentication)
 else
 data = auth_data.except(&quot;extra&quot;)
 session[&quot;devise.oauth.data&quot;] = data
 redirect_to(new_user_registration_url)
 end
 end

 def failure
 redirect_to(root_path)
 end

 def auth_data
 request.env[&quot;omniauth.auth&quot;]
 end
end
</code></pre>
<p>And that should be it. I hope this is also useful for other users running into similar issues with the <a rel="external" href="https://rubygems.org/">Gem</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>.&#x2F;dev</title>
      <link>https://pepicrft.me/blog/dev/</link>
      <guid>https://pepicrft.me/blog/dev/</guid>
      <pubDate>Mon, 16 Aug 2021 12:00:00 +0000</pubDate>
      <description>One of the things that I appreciate as a developer is having a consistent experience across projects . As you probably know, this is often not the case when running a project locally. Some ask you to run yarn run ios . Others prefer an exec…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the things that I appreciate as a developer is having a <strong>consistent experience across projects</strong>. As you probably know, this is often not the case when running a project locally. Some ask you to run <code>yarn run ios</code>. Others prefer an executable like <code>bin/rails server</code> instead. This adds friction when changing when jumping between projects. <strong>Can we mitigate the friction?</strong></p>
<p>This is something I'm changing in my projects with an executable called <code>dev</code>. All my projects have it going forward. That's the only thing I have to remember.</p>
<p>Since I have Ruby in most of my projects, I leverage <a rel="external" href="https://github.com/ddollar/foreman">Foreman</a> and a <a rel="external" href="https://devcenter.heroku.com/articles/procfile">Procfile</a> to run concurrent processes. This is an example of the <code>Procfile.dev</code> of one of my Rails projects:</p>
<pre><code>rails: bin/rails server
vite: bin/vite dev
</code></pre>
<p>Then all I need in the <code>dev</code> executable is:</p>
<pre><code>#!/usr/bin/env bash

bundle exec foreman start -f Procfile.dev
</code></pre>
<p>It'd be great if I could have an <code>up</code> command too to configure the environment. However, and as you might know, configuring environments deterministically and reliably is hard. Many companies let that be a developer's responsibility. Others like Shopify have needed years to have a tool that does an incredibly good job at that. And companies like GitHub, prefer to take the development to <a rel="external" href="https://github.com/features/codespaces">the cloud</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Seabolt support for M1</title>
      <link>https://pepicrft.me/blog/seabolt-support-for-m1/</link>
      <guid>https://pepicrft.me/blog/seabolt-support-for-m1/</guid>
      <pubDate>Tue, 10 Aug 2021 12:00:00 +0000</pubDate>
      <description>As part of building Chimera , an AppleOS tool for capturing networked knowledge, thoughts, and ideas, I encountered an issue trying to set up Neo4j on an M1 laptop (i.e. arm64 architecture) . It turns out that Seabolt , the connector that n…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As part of building <strong>Chimera</strong>, an AppleOS tool for capturing networked knowledge, thoughts, and ideas, I encountered an issue trying to set up <a rel="external" href="https://neo4j.com/developer/ruby/">Neo4j</a> on an M1 laptop <em>(i.e. arm64 architecture)</em>. It turns out that <a rel="external" href="https://github.com/neo4j-drivers/seabolt">Seabolt</a>, the connector that <a rel="external" href="https://github.com/neo4jrb/neo4j-ruby-driver">neo4j-ruby-driver</a> uses to communicate with a running instance of Neo4j, doesn't have support for M1s. It was a bit of a bummer, but luckily I found <a rel="external" href="https://github.com/teomores/seabolt-M1">this fork</a> that someone created to add support.</p>
<p>If you run into this same issue in the future, you can either run the steps on that repository or download the <a href="https://pepicrft.me/blog/seabolt-support-for-m1/__GHOST_URL__/assets/tools/seabolt/seabolt-1.7.4-dev-Darwin.tar.gz">compiled version</a> that I built myself. <a href="https://pepicrft.me/blog/seabolt-support-for-m1/seabolt-1.7.4-dev-Darwin.tar.gz.sha256">Here</a> is the sha256 checksum to validate you downloaded the correct binary.</p>
<pre><code>shasum -a 256 seabolt-1.7.4-dev-Darwin.tar.gz
</code></pre>
<p>Once you verify the binary is correct, you can untar the content, and copy the dynamic library into the directory where the driver expects it:</p>
<pre><code>cd build/dist/lib
cp libseabolt17.dylib /usr/local/lib/libseabolt17.dylib
</code></pre>
<p>And that would be it. The Neo4j Ruby driver should be able to initialize successfully.</p>
<h3 id="a-note-on-chimera">A note on Chimera</h3>
<p>It's the first time I mention Chimera, so you might be wondering what's that tool. You are probably familiar with tools for capturing networked notes like <a rel="external" href="https://roamresearch.com/">Roam Research</a> and <a rel="external" href="https://obsidian.md/">Obsidian</a>. They are great because they remove the friction of giving your ideas, knowledge, and thoughts a structure other than the one they have in your brain. However, they are designed and optimized for the web. If you try to use them from your phone, the user experience is terrible. And because ideas can arise at any time, and you usually have your phone with you, I think having an app optimized for native will take the experience of capturing them to a whole new level. So that's what I set out to build; a tool for <strong>networked thoughts, ideas, and knowledge</strong>. I'll focus on Apple platforms first, following their <a rel="external" href="https://developer.apple.com/design/human-interface-guidelines/">human interface guidelines</a>. I'm very excited to use <a rel="external" href="https://tuist.io">Tuist</a> myself and learn about <a rel="external" href="https://developer.apple.com/xcode/swiftui/">SwiftUI</a> to make this happen.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Some Rust thoughts</title>
      <link>https://pepicrft.me/blog/rust-thoughts/</link>
      <guid>https://pepicrft.me/blog/rust-thoughts/</guid>
      <pubDate>Wed, 04 Aug 2021 12:00:00 +0000</pubDate>
      <description>A while ago, I started reading about the Rust programming language out of curiosity. Many things fascinated me about the language. It has a powerful dependency manager similar to the Swift Package Manager but more thoroughly designed. Unlik…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>A while ago, I started reading about the Rust programming language out of curiosity. Many things fascinated me about the language. It has a powerful dependency manager similar to the Swift Package Manager but more thoroughly designed. Unlike Swift, the compiled programming language I'm the most comfortable with, you can code Rust with your editor of choice and easily target several platforms because projects can be cross-compiled, and the standard library is available on all those platforms. This is not the case for Swift where leaving Xcode ruins your developer experience, and many utilities and primitives still live in macOS's <code>Foundation</code> framework.</p>
<p>Because I did not end up using it, I forgot most of the things that I learned. Therefore, I decided to get back to it, getting my hands dirty and applying the things I read about. This blog post is a braindump of some thoughts that I've got so far. Expect more of these to come in the future.</p>
<p>I like <strong>its module system</strong>. It reminds me of Ruby's but is more opinionated about the file structure. It encourages organizing the code in a modular fashion and ensures the file structure represents that structure. In Swift, for instance, namespaces can be created leveraging language's constructions, but the build system doesn't have any opinion on the file structure. As a result, it's common to see file structures not matching the code's.</p>
<p>The one thing that I haven't had the chance to work with yet is the <strong>ownership-based</strong> approach to memory management. I think I've got the idea, but it'll take some coding for the idea to click in my head and think in terms of <em>who owns what and for what</em>. It's exciting to read that it's one of the features that makes Rust so unique because it leverages the build system to catch what otherwise would be runtime issues.</p>
<p>The <strong>standard library</strong> looks pretty complete. Besides the basic types someone expects from a standard library, there are also handy utilities like <code>Path</code> that are handy when building apps that interact a lot with the file system. For instance, in <a rel="external" href="https://tuist.io">Tuist</a> we had to resort to a Swift Package to have such a model because <code>Foundation</code> does not provide it.</p>
<p>The collection of <strong>community Crates</strong> is enormous. It's not at the level of NPM or RubyGems, but I've found Crates for everything I needed so far. I find this crucial when choosing a programming language. You don't want to end up building something that someone else might have built before.</p>
<hr />
<p>And that's it for this this post. I'll continue playing with it and dumping my thoughts on this blog as I continue forming more mental models around the programming language and its tooling.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Planning open-source work</title>
      <link>https://pepicrft.me/blog/planning-open-source-work/</link>
      <guid>https://pepicrft.me/blog/planning-open-source-work/</guid>
      <pubDate>Fri, 30 Jul 2021 12:00:00 +0000</pubDate>
      <description>One of the things that I find the hardest when building open-source software is planning the work . On one side, there are all these new features and improvements that you&#x27;d like to build. On the other side, there are PRs to review, tickets…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the things that I find the hardest when building open-source software is <strong>planning the work</strong>. On one side, there are all these new features and improvements that you'd like to build. On the other side, there are PRs to review, tickets to triage and prioritize, and questions that come up. Leaning mostly on the former is not great because users and contributors feel ignored, but focusing solely on the latter isn't good either because the project doesn't evolve.</p>
<p><strong>What to do then?</strong> I don't know.</p>
<p>On <a rel="external" href="https://tuist.io">Tuist</a>, when I think about what to work on, many things come to my mind: <em>there's a new website design to implement</em>, <em>some caching issues that we need to tackle</em>, <em>documentation improvements that I'd like to add</em>, <em>functionality that I'd like to start building onto TuistLab</em>... It's too much. I'd like to do everything, and I end up doing nothing. The mental overhead causes paralysis. Working on one thing leaves you wondering if you should be working on something else instead. You feel bad because you are building something new instead of supporting existing users with the issues that they face. It's tricky, isn't it?</p>
<p>It's something I'm trying to get better at, but it's not easy. There are a few things that are clear to me though. There needs to be <strong>work on adding new features and improvements</strong>. I have a product mindset and I enjoy talking to users and turning that into solutions for them. The time that I invest into supporting users, I'll try to <strong>time-box</strong> it. For example, I can tackle an issue per week and no more than that. I'd make exceptions if there's a critical bug or regression in a new release. I have to say that in the area of support, we are lucky to have users, contributors, and maintainers helping there. Without their hands things would have gotten unsustainable.</p>
<p>So here's the thing I'm thinking about going forward. I'll focus on a project at a time and limit the support work per-week with exceptions. I'll decide the project based on my motivations and needs and what's important for users too. For example, I know caching of binaries is becoming and important feature for users. I'll use GitHub projects to organize the work on projects and have a sense of progress. It'll be helpful to involve others in a project I'm working on. And last and not least, I'll continue engaging with users on Slack, GitHub, and Twitter. We need to continue building trust with Xcode developers because every new person that joins brings new ideas and challenges for us to solve.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Contributors&#x27; first experience</title>
      <link>https://pepicrft.me/blog/contributors-experience/</link>
      <guid>https://pepicrft.me/blog/contributors-experience/</guid>
      <pubDate>Wed, 21 Jul 2021 12:00:00 +0000</pubDate>
      <description>When building open-source software, getting external contributions is usually one of the most difficult things. Most of the times developers are busy working on their projects, and they are hesitant to devote time to another project. That&#x27;s…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>When building open-source software, getting external contributions is usually one of the most difficult things. Most of the times developers are busy working on their projects, and they are hesitant to devote time to another project. That's understandable. Why would you? They usually do it when they have feedback or find an issue that they'd like to share with the maintainers of the project.</p>
<p>In rare scenarios, developers go further and contribute with code themselves. It's a huge effort because they need to get familiar with a new codebase <em>(architecture, guidelines, patterns, business logic, testing strategies...)</em>. This is where many contributors drop in the <strong>contribution funnel</strong>. They had an idea for something to contribute, but they felt overwhelmed by the project. Have you ever been in that situation? It's even worse when the project doesn't have documentation for contributors. The only thing they can do is to clone the repo and figure things out themselves. Unfortunately, this works when the project is small, but as you can imagine, it becomes indigestible in large projects.</p>
<p>Because <strong>external contributions bring diversity of ideas and new energies to the project</strong>, providng the <strong>best contribution experience</strong> is an important aspect in <a rel="external" href="https://tuist.io">Tuist</a>. There's still room for improvement, but I'm glad of what we've achieved so far. First of all, we have documentation for contributors. They can learn how to <a rel="external" href="https://docs.tuist.io/contributors/get-started/">get started</a>, <a rel="external" href="https://docs.tuist.io/contributors/testing-strategy">test</a> their changes, and <a rel="external" href="https://docs.tuist.io/contributors/reporting-bugs">report bugs</a>. Moreover, the project's modular architecture minimizes the surface of the things they need to learn before being able to contribute. For instance, if you want to optimize the generation of Xcode projects, you can focus on the <code>TuistGenerator</code> target and ignore the others. When everything is under <code>MyProjectKit</code> and the different components are strongly coupled, contributors have a hard time reasoning about the project's logic and forming mental models. <a rel="external" href="https://docs.tuist.io/contributors/architecture">Tuist's architecture</a> is documented too.</p>
<p>Furthermore, we include a Ruby CLI tool, <a rel="external" href="https://github.com/tuist/tuist/tree/main/projects/fourier">Fourier</a>, to automate all common tasks. It also ensures that everyone's interaction with the project is consistent. That makes it easy to debug reproducibility issues when they arise.</p>
<p>Contributors also have access to a <a rel="external" href="https://join.slack.com/t/tuistapp/shared_invite/zt-g38gajhj-D6LLakrPnVCy4sLm24KxaQ">Slack group</a> and <a rel="external" href="https://github.com/tuist/tuist/discussions">community forum</a> where they can seek advice and talk with other contributors and maintainers. We are luckyto have a very supportive group of contributors that are always open to give anyone a hand.</p>
<p>One of the things I'd like to improve <strong>next</strong> is the configuration of the environment to ensure everyone's environment is consistent. For example, ensure everyone is using the same Ruby, NodeJS, and Swift versions. We'll balance building for contributors and users. Both make Tuist the best tool of its class, and therefore both need the same level of attention and support.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>What I learned as a manager</title>
      <link>https://pepicrft.me/blog/what-i-learned-as-a-manager/</link>
      <guid>https://pepicrft.me/blog/what-i-learned-as-a-manager/</guid>
      <pubDate>Tue, 20 Jul 2021 12:00:00 +0000</pubDate>
      <description>As you might know, Shopify allowed me to try the people management track and become an engineering manager. I&#x27;ve been doing that for the past two years. Along the process I learned a lot and made so many mistakes and I don&#x27;t regret having g…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As you might know, <a rel="external" href="https://shopify.com">Shopify</a> allowed me to try the people management track and become an engineering manager. I've been doing that for the past two years. Along the process I learned a lot and made so many mistakes and I don't regret having given it a shot. In hindsight, I think the experience will help me be a better engineer.</p>
<p>This post is a <strong>list in no particular</strong> order of the things that I learned and experienced:</p>
<ul>
<li>People are unpredictable. - Management work is hard to measure. You can't count it and it's hard to reflect on it. - Achieving a balanced team state is an impossible task because of external factors that you don't control: <em>reorganizations, people leaving, priority shifts.</em> - A team larger than 5 people is not a good idea. Your management starts to suffer and your team notices it. - Exiting someone from the company is tough. - Being recognized for your work is unusual, but when it happens and it comes from your reports, it's very rewarding. - Sometimes you don't have answers for all the questions, and that's fine. You need to be comfortable being in that situation. - Seeing people leaving is sad. It's hard to to wonder if you could have done things better. - It's great seeing people progressing in their career and growing the impact of their contributions. - A road map you come up with today won't be valid in a few weeks from today. The world is dynamic, so is the company and its priorities. - Reorganizations are sometimes hard to digest. When they happen people move around, other people leave, and you have new objectives you have to accommodate to. - Context switching is an important skill to have. You mustn't let it make you a zombie at the end of the day. - The role of business partner is crucial to find answers to your questions and provide guidance when necessary. - Getting feedback from other managers when doing impact reviews is very useful.</li>
</ul>
<p>And at this point you might wonder what led me to go back to individual contributor. I enjoy <strong>building</strong>. I enjoy opening my laptop, putting my headphones on, and creating things with code. I do that with <a rel="external" href="https://tuist.io">Tuist</a> and I used to that before taking the manager role. I also like mentoring people through working together in problems. That's how I met <a rel="external" href="https://twitter.com/marekfort">Marek</a>, who recently joined the organization.</p>
<p>Shopify is a great place to grow as a manager. You have great tools and excellent managers you can learn from. There's even a framework to ensure management is consistent across the organization. However, and as I mentioned earlier, my path is on the technical track, and I'd like to continue solving problems with code.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Propose, prototype, and build</title>
      <link>https://pepicrft.me/blog/propose-build-release/</link>
      <guid>https://pepicrft.me/blog/propose-build-release/</guid>
      <pubDate>Thu, 15 Jul 2021 12:00:00 +0000</pubDate>
      <description>One of the things I like about Shopify is an internal tool called Vault . It&#x27;s the backbone of the organization. You can find people, navigate the report structure, find answers for your questions, follow projects and share updates with the…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the things I like about <a rel="external" href="https://shopify.com">Shopify</a> is an internal tool called <strong>Vault</strong>. It's the backbone of the organization. You can find people, navigate the report structure, find answers for your questions, follow projects and share updates with the rest of the organization, and praise someone. It's crucial for the <strong>organization's effectiveness</strong>.</p>
<p>When it comes to <strong>planning work</strong>, many organizations built their processes upon existing tools. As a result, they end up accommodating their organization to the tool and not the other way around. For example, they introduce a tool like <a rel="external" href="https://www.atlassian.com/software/jira">Jira</a> and all of a sudden everything is ticket-oriented. Teams have backlogs full of tickets. Some people get obsessed with cleaning backlogs and prioritizing tickets. Ticket gurus emerge and training are organized to use Jira the right way. That always annoyed me and I was glad to see that Shopify invested in doing the opposite: design a framework, GSD (Get Shit Done), to plan work and build tools around it.</p>
<p>The tool that you use to manage the project is an implementation detail of the developer or the team. You wanna use GitHub issues? Go ahead. Do you prefer Trello instead? That's fine too. The focus is shifted from the tool to the actual project and what's trying to solve. I think this is the trap many organizations fall into: they get too distracted with the tools.</p>
<p>A project is first <strong>proposed</strong>. Stakeholders ensure the problem or need is well defined, and that it's worth solving right now. This ensures people are working on the right things. If you can't relate your work to the organization's needs, then you need to take a step back and try to understand the thing you are tackling. Proposals can include a video, and go upwards in the hierarchy for approval.</p>
<p>Once approved, the project is <strong>prototyped</strong> to explore different potential solutions. Once stakeholders agreed on a solution, the project moves to <strong>build</strong> and the actual execution happens. Simple, yet powerful.</p>
<p>Along the process, Vault can be used to keep track of the project. The <strong>project champion</strong> is responsible for sharing updates with the stakeholders. A project has a feed where you can see a timeline of the project's evolution. It also has deadlines and checks that you can run with the project contributors assess the health of the project: <em>is it moving steadily?</em> <em>is the direction clear?</em> <em>are there any unexpected roadblocks?</em></p>
<p>And because the organization is large and there are many projects are being executed, <strong>you can follow the projects interest you</strong>. You can filter the signal from the noise and only get the updates from the projects that you are interested in.</p>
<p>One thing that I think it's also cool is that there's a <strong>champion role.</strong> A person ensures the project moves forward and that decisions are made. And yes, if it's a development project, that's the developer. Developers also feel empowered when driving projects.</p>
<p>As I've said a few times in the past, Shopify has done amazing work at having the best tools for their needs and this is yet another example of that. Product is important, but also the tools the people in the org use to build the product. There's so much inspiration to gain from Shopify that I can apply to the way the <a rel="external" href="https://tuist.io">Tuist</a> organization is managed.</p>
<p>If Shopify sounds an exciting place you'd like to work, let me know and we can talk about opportunities over here.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Back to Jekyll</title>
      <link>https://pepicrft.me/blog/back-to-jekyll/</link>
      <guid>https://pepicrft.me/blog/back-to-jekyll/</guid>
      <pubDate>Sat, 10 Jul 2021 12:00:00 +0000</pubDate>
      <description>I recently changed my stand in regards to the technologies that I use when building software. In particular, I decided to minimize the amount of Javascript that I use in my projects. In my experience, Javascript is usually synonym of indire…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I recently changed my stand in regards to the technologies that I use when building software. In particular, I decided to <strong>minimize the amount of Javascript</strong> that I use in my projects. In my experience, Javascript is usually synonym of indirection, complexities, and instability: <em>dependency updates that blow up your whole stack, cryptic build errors that are hard to debug, setup that is hard to reason about and unnecessarily complex.</em></p>
<p>On the other side, <a rel="external" href="https://www.ruby-lang.org/en/">Ruby</a> and its ecosystem is more harmonious and peaceful. If something works, it's very unlikely that it breaks. If there's already a Ruby gem that does something, people are more inclined to contribute to it instead of reinventing the wheel. No hype fatigue. The language that you ship is the language that you write. You don't need layers of transformations to accommodate your code to the environment in which it'll run.</p>
<p>Because of all of the above, I've migrated this blog back to <a rel="external" href="https://jekyllrb.com/">Jekyll</a> from <a rel="external" href="https://www.gatsbyjs.com/">GatsbyJS</a> and I've taken the opportunity to overhaul the design with something more boring and developerish. I want the focus to be on the content and not the aesthetics.</p>
<p>I've so decided to stay away from unnecessary abstractions upon standards like <a rel="external" href="https://en.wikipedia.org/wiki/HTML">HTML</a> and <a rel="external" href="https://en.wikipedia.org/wiki/CSS">CSS</a>. I got hyped into the <a rel="external" href="https://cssinjs.org/">CSS-in-JS</a> and <a rel="external" href="https://tailwindcss.com/">TailwindCSS</a> without realizing the value they provide is not really necessary in my projects. Moreover, the closer to the standards and the fewer abstractions the better for the long-term sustainability of the projects. If I write HTML and CSS today, I can open it in years from now, and it'll very likely work. If I to do the same with a <a rel="external" href="https://reactjs.org/">React</a>-based website that is processed by Gatsby through Babel, the chances are that it won't work in a few years.</p>
<p>It's been great to learn about those technologies and seeing companies pushing the web forward through them, but HTML and CSS and a bit of Javascript are enough to create value and share my ideas with everyone.</p>
<p>Stay safe!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Swinging the pendulum back to engineering</title>
      <link>https://pepicrft.me/blog/swinging-the-pendulum-back-to-ic/</link>
      <guid>https://pepicrft.me/blog/swinging-the-pendulum-back-to-ic/</guid>
      <pubDate>Tue, 01 Jun 2021 12:00:00 +0000</pubDate>
      <description>Over the past two years, I&#x27;ve been engineering manager at Shopify . I managed the Mobile Tooling and React Native Foundations teams over here. I&#x27;m grateful that Shopify allowed me to experience what being a manager is like. I learned that p…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Over the past two years, I've been engineering manager at <a rel="external" href="https://shopify.com">Shopify</a>. I managed the Mobile Tooling and React Native Foundations teams over here. I'm grateful that Shopify allowed me to experience what being a manager is like.</p>
<p>I learned that people are unpredictable and that sometimes there are behaviors you can't explain. I changed my mindset from creating impact myself to create impact through people. This required figuring out who to put together on which problems to create the most creative solutions. I teamed senior and junior people up to level up people through mentoring. I defined a vision for the team and learned that in large corporations priorities change so much that you can't stop iterating on them. I set up secondments for people in my team to have a first-hand experience with the products we build tools for, and keep our <a rel="external" href="https://fs.blog/knowledge-project/tobi-lutke/">trust battery</a> with them high. I put up promotion cases for people in my team and had to exit a person from my team because he was not meeting the expectations of the role. It's not a pleasant experience, but I stretched your emotional intelligence by going through it. I leveraged my community and open-source connections to bring talent to Shopify that I'd like to work with. I've done tiny code contributions trying not to step in the way of the people in the team but most of the time I did. I evangelized my passion for building great developer experiences that are easy to use. I fought complexity and indirection introduced by configurability. I recognized my team's work internally and externally and shared with the community how awesome it's that Shopify invests in their own tooling. I had weekly 1&amp;1s with the people in my team, provided feedback, and valued their impact through company-wide calibration sessions. I set up an on-call policy to provide support to the rest of the organization. And in all this journey I was extremely supported by the organization and its tools and resources.</p>
<p><strong>I learned a lot by being a manager but I miss coding so much</strong>. I miss getting my hands dirty by building new tools and improving the existing ones. I tried to squeeze coding time into my manager's responsibilities but ended up frustrated because doing deep coding was impossible due to the frequent context-switching my responsibilities required. For that reason, I'll soon swing the pendulum of my career back to be an individual contributor again. In hindsight, I think it was a great idea to go through the management experience because I've learned so many useful things that will make me a better engineer.</p>
<p>The change will happen in a few months when the new manager is up to speed and ready to take the team. I'll remain in the React Native Foundations team and work with the folks on the team to shape the experience of building React Native apps at the company. Exciting times ahead!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Focused Xcode projects</title>
      <link>https://pepicrft.me/blog/focused-xcode-projects/</link>
      <guid>https://pepicrft.me/blog/focused-xcode-projects/</guid>
      <pubDate>Mon, 24 May 2021 12:00:00 +0000</pubDate>
      <description>A while ago, and inspired by Facebook&#x27;s internal tooling, we added a new command to Tuist, tuist focus . As it names says, it&#x27;s intended to be used when you want to work on a given target. If you have a project of, let&#x27;s say 300 targets, yo…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>A while ago, and inspired by Facebook's internal tooling, we added a new command to Tuist, <code>tuist focus</code>. As it names says, it's intended to be used when you want to work on a given target. If you have a project of, let's say 300 targets, you don't want all of them when you open the project with Xcode. <em>The reason?</em> It makes Xcode slower. The more you open, the more needs to be indexed. You change a file, and Xcode needs to figure out how the change impacts the whole project.</p>
<p>Focus takes your project's dependency graph, and prunes the elements that are not necessary for you to work on target X. That includes references from schemes. Since there are times when you might want to focus on more than one target at once, you can pass the list of targets as arguments: <code>tuist focus MyApp Search</code>. But that's not all. We integrated this concept with the caching of target binaries. In a nutshell, the direct and transitive dependencies of your focused targets are replaced with their binary representation. The binary can come from a local cache, and soon, from a server-side counterpart, <a rel="external" href="https://github.com/tuist/lab">TuistLab</a>. Amazing, isn't it? This is what I've been hoping to see landing in Xcode, but instead, we've been told that the only solution is to replace Xcode's build system with <a rel="external" href="https://bazel.build/">Bazel</a>. I don't have anything against Bazel. I think it's damn amazing. But it's not compatible with Apple's way of building tools, and because the integration leads to a bad developer experience, or good but with a huge ongoing investment, I avoid it.</p>
<p>Surprisingly, and as the <a rel="external" href="https://stats.tuist.io">stats</a> show, <code>tuist focus</code> is not as used as <code>tuist generate</code>. It's hard to know the why, but my guess is that this is a workflow that developers are not that used to, and it requires some ongoing education and evangelization from our side. <em>Or maybe there's something not working as expected and we don't know?</em> If that's the case we'll soon find out because we are dog-fooding Tuist by building TuistLab.</p>
<p>As I mentioned in past blog posts, the opportunity to explore ideas with Tuist is what makes the project so exciting, and <code>tuist focus</code> is a good example of that. If you are using Tuist, I recommend you to give the command a shot. You won't get disappointed.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>On not having focus</title>
      <link>https://pepicrft.me/blog/on-not-having-focus/</link>
      <guid>https://pepicrft.me/blog/on-not-having-focus/</guid>
      <pubDate>Wed, 19 May 2021 12:00:00 +0000</pubDate>
      <description>One of the things that I struggle a lot with these days is focus . Because of that, I realized I cannot longer do deep and focused work. I spend my days context-switching all the time, and although I&#x27;ve got used to it, I don&#x27;t like it. Ther…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the things that I struggle a lot with these days is <strong>focus</strong>. Because of that, I realized I cannot longer do deep and focused work. I spend my days context-switching all the time, and although I've got used to it, I don't like it.</p>
<p>There are several reasons why that happens to me. The first, and well-known these days, are <strong>social networks</strong>. You've probably seen me talking about them in the past, so here I go again. I tend to spend my free time doing endless scrolling to keep up. I think that's one of the main contributors to feeling exhausted, yet I can't stop doing it. Moreover, at work there's a lot going on. Because of the size of the company, and all the context I've got over the past years, I spend my days helping here and there: <em>sharing context with other people, unblocking the users of our tools, digesting information that is floating in the organization.</em> Again, I think I've got better at this, but I miss having focus.</p>
<p>On top of all the above, I'm so curious that I can't stop <strong>exploring new ideas</strong> and problems to solve. As a result, my mental energy scatters across many different places, and I end up nor learning nor doing anything. I think the English saying for what happens to me is <em>"Biting off more than you can chew"</em> (thanks Google).</p>
<p>So here's what I'm going to try. First, I'll accept my time and energy boundaries and be mindful about them. I'll continue learning how to prioritize and say no to things. Both, at work and in open-source duties. Moreover, I'll center my open-source efforts around only two projects, <a rel="external" href="https://tuist.io">Tuist</a> and <a rel="external" href="https://buildify.com">Buildify</a>. As much as I can, I'll try to spend less time on social networks <em>(attempt number 125125)</em>.</p>
<p>Hope you are having a great week and stay safe!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Tuist 2.0 and next</title>
      <link>https://pepicrft.me/blog/tuist-2-and-next/</link>
      <guid>https://pepicrft.me/blog/tuist-2-and-next/</guid>
      <pubDate>Tue, 18 May 2021 12:00:00 +0000</pubDate>
      <description>As we are approaching the release of Tuist 2.0, I started thinking what&#x27;s next for the project. The focus until 1.0 was around project generation. We provided developers with a graph-based project generation that abstracts away Xcode&#x27;s intr…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As we are approaching the release of Tuist 2.0, I started thinking what's next for the project. The focus until 1.0 was around project generation. We provided developers with a graph-based project generation that abstracts away Xcode's intricacies. As we passed that milestone, we started thinking about building workflows and optimizations built upon project generation. The graph was a powerful project element that other tools lacked so we felt we needed to leverage it further. We added <code>tuist focus</code> to generate projects that are optimized for developers' intents. <code>tuist signing</code> made it easy to configure the environment and the generated projects for signing, and <code>tuist cache warm</code> allowed caching project targets as binaries for later usage when generating projects. We also started exploring the idea of standardizing and integration of third-party dependencies through a new manfiest file, <code>Dependencies.swift</code>, and we just released support for defining tasks defined in <code>.swift</code> file that get compiled and executed. Quite a ride, isn't it? Along the process we met many talented developers that joined on on this ride, and became the fuel that makes the project move forward.</p>
<p>After releasing tasks and overhauling our website to reflect the new brand, we'll start working towards 3.0. <strong>What does that mean for the project?</strong> Besides improving project generation, for example by making it faster and handling more project scenarios, I think we should focus on the following elements:</p>
<ul>
<li><strong>Thinning Tuist:</strong> We built many commands into Tuist that should be opt-in and extracted from Tuist. For example, the <code>tuist doc</code> command doesn't necessarily have to be implemented by Tuist. Our work on <a rel="external" href="https://docs.tuist.io/plugins/using-plugins">plugins</a> and tasks will allow that. Those commands will be distributed as plugins and live in different repositories. - <strong>Dependencies.swift:</strong> We should continue investing in this project and have great support for Pods, Packages, and Carthage frameworks. How to integrate third-party dependencies into Tuist project is a recurrent theme and therefore we should provide first-class support for it. - <strong>Cross-repository dependencies:</strong> At the moment, a <code>Project.swift</code> can't define a dependency with a <code>Project.swift</code> that lives in another repository. Because of that, teams end up creating a <code>Package.swift</code> alongside the <code>Project.swift</code> to be able to consume that dependency as a package. Although this works, it prevents developers from leveraging graph optimizations such as <code>tuist focus</code>. I think we could build a decentralized dependency resolution logic into Tuist inspired by the SPM and step into SPM's domain. Just a tiny bit 😁. - <strong>Lab:</strong> If graph is a cornerstone component in Tuist, a server would take Tuist to a whole new level. Lab would be that server. Developers would have the option to self-host it, or use our paid hosted instance, and therefore financially support the project. Lab would allow things like: - Reporting build insights on PRs - Define tripwires and alert teams on Slack or PRs when they hit them. - Cache your project's binaries remotely and share them across the teams. - Have an internal registry of frameworks and libraries that you can reference from your projects.</li>
</ul>
<p>I'm sure more ideas will pop up down the road, but the ones that I shared above will most likely be our focus as we enter this new chapter. We'll continue to listen developers, their challenges, needs, and collaborate to figure out how Tuist can help them the best way possible.</p>
<p>Thanks for reading.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Building mental models</title>
      <link>https://pepicrft.me/blog/building-mental-models/</link>
      <guid>https://pepicrft.me/blog/building-mental-models/</guid>
      <pubDate>Mon, 10 May 2021 12:00:00 +0000</pubDate>
      <description>As you probably know, I started building Buildify , an open-source and AGPL-3-based tool for deployments. Like I did with Tuist , I&#x27;m in the process of building mental models around the business domain. It&#x27;s one of the hardest steps, and th…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As you probably know, I started building <a rel="external" href="https://github.com/buildifydev">Buildify</a>, an open-source and AGPL-3-based tool for deployments. Like I did with <a rel="external" href="https://tuist.io">Tuist</a>, I'm in the process of building mental models around the business domain. It's one of the hardest steps, and the most important one for the viability of the project. If those models are not solid enough the application might become unusable, and if it's not flexible enough it might limit the development of future features.</p>
<p>As I keep thinking about the problem, some ideas are starting to emerge. For example, providers like <a rel="external" href="https://cloud.google.com">Google Cloud</a> and <a rel="external" href="https://aws.amazon.com">AWS</a>, offer a serverless solution for containarized apps. In other words, you can provide them with your Rails application in a Docker image and they'll take care of scaling the resources are needed. This simplifies things a lot on our side because we are mostly responsible for building deployable artifact that can then be handed over to the cloud provider. For long-running services those deployable artifacts will be Docker images. In the case of lambda functions and static websites it'll be a tar file containing the HTML, JS, and CSS following a conventional structure. And for mobile apps, it'll be the Android App Bundle or app archive without signing. The signing will be done server-side.</p>
<p>I'm also planning to abstract away the provider through an interface. That way contributors can add support for more cloud providers. Looking at Google Cloud and AWS, they both have similar offering, but with different names. The initial version will have the implementation for AWS. Since AWS offers Mac minis, we can use those to run certain tasks that can only run in macOS environments, like signing an iOS app.</p>
<p>A tool, <code>buildify-runner</code>, will take care of running deployment tasks. I'll write it in Rust so that it can be run in any hosts without requiring anything else to be installed in the system. It'll pull the build <a rel="external" href="https://en.wikipedia.org/wiki/Directed_acyclic_graph">DAG</a>, and execute it trying to parallelize as much as possible. For example, when deploying a <a rel="external" href="https://redwoodjs.com/">RedwoodJS</a>, the runner will install the NPM dependencies, and build the static files and the functions separately. For reproducibility reasons and stability, the runner will use <a rel="external" href="https://nixos.org/">Nix</a>. Thanks to that, we get caching of dependencies out-of-the-box. I believe using a tool like Nix for setting up the environment will be crucial for providing a great developer experience.</p>
<p>The concept of previews that got popularized by platforms like <a rel="external" href="https://netlify.com">Netlify</a> and <a rel="external" href="https://vercel.com">Vercel</a>, will be present in Buildify too but with some enhancements. It'll work with databases and mobile apps too. In a nutshell, we'll create disposable databases whose lifecycle is tied to the lifecycle of a repository branch. When the branch gets merged or becomes stale, the database will be dropped automatically.</p>
<p>The process of onboarding new apps must be as seamless as possible. People that have never deployed a project before should have a running app without having to familiarize themselves with infrastructure and deployment concepts. To achieve that, the runner will have a command for cloning a repo, parsing its content, and reporting to the backend all the projects found in the repository. For example, if it's a Rails app, Buildify will detect it and create the database and a Redis instance for being able to run background jobs.</p>
<p>And last but not least, because my background is mainly mobile development and tooling, I think this platform should work for mobile apps too. The release process will be a bit different though because continuous deployment cannot be extrapolated to mobile apps. In this case we'll use release branches where each commit will represent a releasable candidate that can be uploaded to the App Store and Google Play Store.</p>
<p>I'm very excited to kick off this project. I've been reading a lot lately about projects like <a rel="external" href="https://ghost.org/">Ghost</a> and <a rel="external" href="https://plausible.io/">Plausible</a>, whose revenue is re-invested in the project to make it better and continue to help their users. I feel we need to take back from VCs the problem of easing deploys, and build a community-driven and open-source project that goes hand in hand with those great open-source web frameworks that we've seen over the years.</p>
<p>As you can imagine, I'll be less active on <a rel="external" href="https://tuist.io">Tuist</a>, although I'll continue to provide advice and direction on the project.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>ViteJS and Rails</title>
      <link>https://pepicrft.me/blog/vite-and-rails/</link>
      <guid>https://pepicrft.me/blog/vite-and-rails/</guid>
      <pubDate>Thu, 22 Apr 2021 12:00:00 +0000</pubDate>
      <description>I recently had to set up a React frontend for a Rails app, and I decided to use ViteJS instead of Webpack . What&#x27;s interesting about ViteJS is that in development, it uses ES modules instead of smashing all your Javascript into a single fil…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I recently had to set up a React frontend for a Rails app, and I decided to use <a rel="external" href="https://github.com/vitejs/vite">ViteJS</a> instead of <a rel="external" href="https://webpack.js.org/">Webpack</a>. What's interesting about ViteJS is that in development, it uses <a rel="external" href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/">ES modules</a> instead of smashing all your Javascript into a single file because that's expensive and unnecessary during development. When building for production, it uses <a rel="external" href="https://github.com/evanw/esbuild">ESBuild</a> for generating a bundle. Unlike the traditional Webpack setup that uses <a rel="external" href="https://babeljs.io/">Babel</a>, ESBuild is significantly faster because it's implemented in Go.</p>
<p>I have to say the process of setting it up was pretty straightforward thanks to <a rel="external" href="https://github.com/ElMassimo/vite_ruby">vite_ruby</a>, a Ruby Gem that eases the process of integrating the tool into Rails's asset pipeline. Moreover, it provides <a rel="external" href="https://guides.rubyonrails.org/action_view_helpers.html">helpers</a> to add the necessary helpers to load the generated Javascript and CSS files. The resulting configuration is leaner than its <a rel="external" href="https://github.com/rails/webpacker">Webpacker</a> counterpart and easier to reason about. Vite is not as mature as Webpack, but it's already got a good community of <a rel="external" href="https://vitejs.dev/guide/api-plugin.html">plugins</a> around it. For example, the <a rel="external" href="https://www.npmjs.com/package/vite-plugin-legacy">legacy plugin</a> takes the role of <a rel="external" href="https://babeljs.io/docs/en/babel-preset-env">@babel/preset-env</a> to polyfill our Javascript to support old browsers. The <a rel="external" href="https://github.com/vitejs/vite-plugin-react">React plugin</a> can reload your component changes instantly to make your development experience smooth.</p>
<p>I really like the amount of utilities one gets when building for the web. You can choose the one that works best for your project, and accommodate it thanks to the numerous APIs that they expose.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Learning Rust</title>
      <link>https://pepicrft.me/blog/learning-rust/</link>
      <guid>https://pepicrft.me/blog/learning-rust/</guid>
      <pubDate>Sun, 18 Apr 2021 12:00:00 +0000</pubDate>
      <description>I became weirdly excited for Rust lately. It&#x27;s a programming language that I&#x27;ve been planning to learn for some time and I finally set out to learn it. It&#x27;s just the beginning of my learning process but I have to say I like the openness of…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I became weirdly excited for Rust lately. It's a programming language that I've been planning to learn for some time and I finally set out to learn it.</p>
<p>It's just the beginning of my learning process but I have to say I like the openness of its community and tooling, and the interesting concepts such as ownership that come with it. Swift feels authoritarian and constrained by Apple after getting immersed in Rust. I also like about it that you can easily do cross-platform compilation and use the editor of your choice. Let's see how it goes, but I think it'll become my go-to compiled programming language over Swift. Using it is so liberating and you can feel it's purely community driven.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Migrating documentation to Docusaurus</title>
      <link>https://pepicrft.me/blog/projects-documentation/</link>
      <guid>https://pepicrft.me/blog/projects-documentation/</guid>
      <pubDate>Mon, 12 Apr 2021 12:00:00 +0000</pubDate>
      <description>Writing a project&#x27;s documentation is not as exciting as coding, but over the years I got to understand the key role of documentation in the developer experience. Shopify for instance has a team dedicated to maintain our internal documentati…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Writing a project's documentation is not as exciting as coding, but over the years I got to understand the key role of documentation in the developer experience. Shopify for instance has a team dedicated to maintain our internal documentation ensuring it's well structured and navigatable.</p>
<p>Tuist's documentation website was built as part of Tuist's website, which is developed using <a rel="external" href="https://www.gatsbyjs.com/">Gatsby</a>, and it grew a lot since then. Because we haven't had a person dedicated to overview the evolution of the documentation, we ended up with a lack of cohesion and hard-to-navigate documentation. Developers have a hard time finding what they need, and getting started on the project.</p>
<p>For that reason, I set out to improve the documentation website. As a firm believer of choosing the right tool for the job, I took the opportunity to move the documentation to <a rel="external" href="https://docusaurus.io/">Docusaurus</a>, a <a rel="external" href="https://reactjs.org/">React</a>-based utility implemented by Facebook to create static documentation websites. It provides all the features that we need: <a rel="external" href="https://mdxjs.com/">MDX</a>, <a rel="external" href="https://docusaurus.io/docs/markdown-features/code-blocks">code snippets</a>, <a rel="external" href="https://docusaurus.io/docs/search">search</a>. For the past weeks, I've been working on moving the documentation over to the new website, which is available at <a rel="external" href="https://docs.tuist.io">https://docs.tuist.io</a>. As part of the process I set up redirects from <code>https://tuist.io/...</code> URLs to the new ones, and fixed a handful of broken links. It's looking great so far. I'm waiting for Algolia DocSearch's response to enable search on the website. Once everything is moved over, I'll work on adding a tutorial along the lines of what <a rel="external" href="https://learn.redwoodjs.com/docs/tutorial/welcome-to-redwood/">RedwoodJS</a> does. It'll be useful for developers that come across the project and decide to give it a shot. The tutorial will guide them through most important Tuist features that they should be aware of.</p>
<p>It's amazing everything React enables. Trying to achieve this with other static site generators would have taken way more work and the result wouldn't have been the same. If you have a project that needs documentation, you should definitively consider Docusaurus, even if you have no prior experience on React.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>TailwindCSS or Theme-UI</title>
      <link>https://pepicrft.me/blog/theme-ui-and-tailwind/</link>
      <guid>https://pepicrft.me/blog/theme-ui-and-tailwind/</guid>
      <pubDate>Mon, 12 Apr 2021 12:00:00 +0000</pubDate>
      <description>I’ve been using TailwindCSS a lot lately. I like the fact that styles are contained within the HTML elements through classes. You can copy and paste an element styled with Tailwind and you can be certain it’ll look the same. Unlike other st…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’ve been using TailwindCSS a lot lately. I like the fact that styles are contained within the HTML elements through classes. You can copy and paste an element styled with Tailwind and you can be certain it’ll look the same. Unlike other styling solutions, Tailwind doesn’t require the UI to be JS-based so that you can leverage CSS-in-JS and Babel transformations. But like any solution to a problem, it comes with caveats. In the case of Tailwind is the steep learning curve to learn the semantics of the classes. I find myself doing frequent back and forths between VSCode and the documentation.</p>
<p><a rel="external" href="https://theme-ui.com/getting-started">Theme-UI</a> solves the steep learning curve issue well. It introduces the notion of theming and responsive values without having to abandon the CSS language. Moreover, it’s built upon a theming specification defined by the same author. The downside though is that you need a JS-based UI and you can’t copy and paste styled HTML elements as you’d do with Tailwid.</p>
<p>My preferred option these days? My preference has been swinging, between the two, but these days I’m more inclined towards Theme-UI. The reason being is that I’d like to familiarize myself further with the CSS semantics and learn how to build great web UI experiences using as raw building blocks as possible. Copying and pasting styled components feel pretty much like solving code problems by pasting snippets from StackOverflow. You can create and solve things, without understanding the fundamentals of the solution.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Community-driven and organization-driven open source</title>
      <link>https://pepicrft.me/blog/organization-and-community-driven-oss-projects/</link>
      <guid>https://pepicrft.me/blog/organization-and-community-driven-oss-projects/</guid>
      <pubDate>Tue, 06 Apr 2021 12:00:00 +0000</pubDate>
      <description>Yesterday, while reading about Rust and its package manager, Cargo , I realized how diverse the list of Crates (packages) for building CLIs is compared to Swift, and made me think about the connection between that and how Rust and Swift are…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Yesterday, while reading about <a rel="external" href="https://www.rust-lang.org/">Rust</a> and its package manager, <a rel="external" href="https://crates.io/">Cargo</a>, I realized how diverse the list of Crates <em>(packages)</em> for building CLIs is compared to Swift, and made me think about the connection between that and how Rust and Swift are driven.</p>
<p>On one side there's <strong>Apple</strong>, a large business whose final goal is to sell hardware. They announced Swift and everyone got excited not only because it was a new and more modern programming language, but because it was open source. Since then, we've seen more open source work coming from Apple: <em><a rel="external" href="https://github.com/apple/swift-log">swift-log</a>, <a rel="external" href="https://github.com/apple/swift-metrics">swift-metrics</a>, <a rel="external" href="https://github.com/apple/swift-nio">swift-nio</a>, and <a rel="external" href="https://github.com/apple/swift-collections">swit-collections</a>.</em> It's great to see work being done in the open, the community gets excited about it, but the one who steers the boat is Apple, and the ultimate decision on what goes into Swift is made by Apple and not the community. There's nothing wrong with it. It's just another approach to open source where there's a business that needs a strong ownership to ensure the open source work supports the business. The caveat though is that the community around it doesn't flourish as much as it'd do in community-driven projects like Rust. Everyone is hoping for that next thing that will solve their problems and help them with their needs. Reactive programming is not new in Swift, yet they made everyone think <a rel="external" href="https://developer.apple.com/documentation/combine">Combine</a> is the way. Nowadays, no one thinks about exploring new reactive programming approaches. Similarly, no one thinks about exploring new solutions to package management. In fact, we are neglecting community work done in the past. This inevitably leads to a slightly authoritarian open source environment where diversity can't find its space.</p>
<p>On the other side, Rust is entirely <a rel="external" href="https://www.rust-lang.org/governance">community-driven</a>. Even though it was born within Mozilla, it became a community project. Because of that, there are plenty of utilities, packages, and resources to build great software upon it. One might see such large list of options as something negative, but I'm getting to appreciate after having done years of Swift and iOS development. It's easy to find a community utility that suits your needs best, or explore new alternatives because the project welcomes those.</p>
<p>I think both are valid approaches with understandable motivations behind them. Personally, I'm enjoying a lot the freedom more community-driven projects like Rust, Javascript, and Ruby provide.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The role of flexibility in scaling up Xcode projects</title>
      <link>https://pepicrft.me/blog/flexibility-to-scale-up-xcode-projects/</link>
      <guid>https://pepicrft.me/blog/flexibility-to-scale-up-xcode-projects/</guid>
      <pubDate>Sun, 21 Mar 2021 12:00:00 +0000</pubDate>
      <description>I often wonder why Apple continues to build features that are closed into Xcode, for example Swift Package Manager&#x27;s integration. While some developers might see that as something positive, because that means it can be seamlessly integrated…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I often wonder why Apple continues to build features that are closed into Xcode, for example Swift Package Manager's integration. While some developers might see that as something positive, because that means it can be seamlessly integrated into Xcode's UI and workflows, I see it as a <strong>complication for scaling up Xcode projects.</strong> Let me unfold this last thought in this post.</p>
<p><strong>You can't build a tool that satifies every team's needs.</strong> You can't design Xcode to work for the tiny startup that is building a simple app, as well as for a company like Facebook that has a complex project with many inter-dependent targets. Apple optimizes for one type of app, the one that is the most common across all the projects: a mono-target app that might have extensions and support for multiple platforms. In that setup, Xcode works fine. You create your project using Xcode's menus, add a new target when needed to <em>extend</em> your app, and add third-party dependencies through the Swift Package Manager integration. Xcode, the project format, its build system, Swift, and all the surrounding tools are designed for that. There's nothing wrong with that, except that those developers that need more are left out of the equation. Their projects take a long time to compile, tiny changes cause the build to break, and Xcode is not as responsive as it used to be. Companies like Uber <a rel="external" href="https://twitter.com/StanTwinB/status/1336890442768547845">have suffered a lot from this</a>. Others have adopted <a rel="external" href="https://bazel.build/">Bazel</a> as a build system to escape the problem, and need dedicated resources to keep it working with every Xcode/Swift update.</p>
<p><em>There must be a better way to scale</em>. Finding an answer to this question is what fuels me to build <a rel="external" href="https://tuist.io">Tuist</a>. I think the answer to this comes down to <strong>flexibility</strong>. The flexibility to extend, optimize and even replace the build process without having to leave Xcode. The flexibility to declare my project's graph, optimize it and validate it early to prevent errors down the road that cause developers' frustration. That flexibility could be achieved with Xcode opening more APIs instead of building inside itself and treating it as a black box. However, that's not the direction Apple is taking, and we are seeing that with Swift Package Manager's integration into Xcode. One of the reasons why other programming languages are used over Swift when building software at scale is the flexibility of their tooling. In <a rel="external" href="https://www.ruby-lang.org/en/">Ruby</a>, you can customize your test-running logic andd add <a rel="external" href="https://sorbet.org/">types</a> to the language. In Javascript, you can <a rel="external" href="https://esbuild.github.io/plugins/">implement plugins</a> that extend your build process and that add new <a rel="external" href="https://eslint.org/docs/developer-guide/working-with-plugins">linting rules</a> that integrate seamlessly with the editor. Having a <a rel="external" href="https://nshipster.com/vscode/">Language Server Protocol (LSP)</a> is a good step forward, but it's not enough.</p>
<p>Because Apple doesn't open those APIs, Tuist is taking the role of opening them for developers. We are doing that by leveraging Xcode project generation. We abstract the <code>project.pbxproj</code> format with a more declarative format that can be extended easily. Developers love that, and the fact that Apple doesn't change their mindset is positive for Tuist because they create a room for the project to thrive.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Open source, people, and happiness</title>
      <link>https://pepicrft.me/blog/open-source-people-happiness/</link>
      <guid>https://pepicrft.me/blog/open-source-people-happiness/</guid>
      <pubDate>Sat, 20 Mar 2021 12:00:00 +0000</pubDate>
      <description>When looked from the consumer standpoint, open source often reads as software publicly available that I can check out, use, and improve. However, there’s more than that. In a world where everyone seems to be obsessed with building the next…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>When looked from the consumer standpoint, open source often reads as software publicly available that I can check out, use, and improve. However, there’s more than that. In a world where everyone seems to be obsessed with building the next TikTok and making the world a better place, open source takes you, a software crafter, to what this pandemic has proved is the key ingredient for happiness, <strong>human connections</strong>.</p>
<p>I started building <a rel="external" href="https://tuist.io">Tuist</a> motivated by some challenges that I wanted to overcome, and over time, we turned it into a group of aligned people collaborating towards the same goal; extremely talented software crafters from different locations building upon a foundation that I helped build. <em>How did it happen?</em></p>
<p>First, Tuist is the reflection of the education that I received from my family. They taught me that happiness means spending time with people. That unlike capitalism tries to prove us, happiness is not about climbing ladders, getting a higher salary, or working for your dream company. For that reason, I <strong>made people a cornerstone in Tuist</strong>.</p>
<p>Since the moment people show up in Tuist, we spend time connecting with them and empathizing with the motivations that led them to adopt the tool. They feel heard by other humans beings, and that’s a great feeling in an industry that is trending towards dehumanizing technology with solutions like bots. Moreover, we invite them to contribute to the codebase. We give them the necessary pointers and even pair with them on nailing the first contribution. They go from I don’t know how to take the first steps in this project to nailing their first contribution and getting inspired to ship more.</p>
<p>We trust the people that join and let them prove us wrong. This is something that I learned at <a rel="external" href="https://shopify.com">Shopify</a>. Assume good intentions from the people around you, and work on having a charged trust battery with them. That has a tremendous effect on people. They feel inspired to contribute further, build their own tools, and do the same with other people joining the community. It cascades rapidly, and because doing great things for people can get very far, it has the side effect of bringing more diversity of ideas to the table from people that otherwise wouldn’t have contributed.</p>
<p>When I tell people that I do that without getting money in return they think I’m crazy. They think I’m wasting my time that I could otherwise spend becoming richer. What they don’t realize is how happy I am helping other developers overcome challenges that I had to go through, and seeing community members spreading goodness across other developers. It’s not about money, it’s about people.</p>
<p>When I was young, I used to work over the weekends in my family's cafe. What I remember from those days, and I can still see it in my parents, is how happy they are earning an average salary but having the opportunity to interact with people all the time. Open source is my modern cafe where "cafe con leches" became code.</p>
<p>I have to say though that I’m privileged of having a paid job that allows me to spend spare time on Tuist. Money is a component that we can’t remove because we need it for living, but it can be a secondary one.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Data-driven open source</title>
      <link>https://pepicrft.me/blog/data-driven-open-source/</link>
      <guid>https://pepicrft.me/blog/data-driven-open-source/</guid>
      <pubDate>Tue, 16 Mar 2021 12:00:00 +0000</pubDate>
      <description>Yesterday, we announced that Tuist has now stats that allows us to understand how users use the tool and therefore, invest our time working on Tuist more wisely. As expected, there were some negative reactions to this: Oh! I’m glad that I c…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Yesterday, we announced that Tuist has now <a rel="external" href="https://stats.tuist.io">stats</a> that allows us to understand how users use the tool and therefore, invest our time working on Tuist more wisely.</p>
<p>As expected, there were some negative reactions to this:</p>
<ul>
<li>Oh! I’m glad that I can opt out. - And yet another tool that succumbs to the data-driven method...</li>
</ul>
<p>If I put myself on their shoes and after seen what large corporations have done with the data I’d react the same way.</p>
<p>However, there’s a subtle difference. We are an open-source project, and such, the time can we can devote to the project is limited. It’s people working outside of their usual working hours to make the tool better. If we don't know how the tool is being used, we don't know if the limited time that we have is well-invested. It's not about us using the data to sell them something, <strong>it's about us using the data to make the tool better</strong>.</p>
<p>Interestingly, there are more tools out there that they might be using without realizing that they are also collecting data for the same purposes: <a rel="external" href="https://brew.sh">Homebrew</a> and <a rel="external" href="https://cocoapods.org/">CocoaPods</a>. Every <code>pod install</code> they've run, has sent data to CocoaPods to better understand how frequently Pods are used. Every <code>brew install X</code> has sent data to Google Analytics to know what formulas are used the most. And yes, <a rel="external" href="https://github.com/fastlane/fastlane/blob/48151291f2c4949c3b1b9919ba2cc81a7cc33293/fastlane_core/lib/fastlane_core/analytics/analytics_session.rb#L7">Fastlane</a> does it too.</p>
<p>Because we know this is concerning, we have taken the approach of not only having all the code for collecting and sending events public, but we've built our own <a rel="external" href="https://github.com/tuist/stats">Rails app</a> with its own database on Heroku to store the data. Tuist's data is our data, not Google's. It stays within our domain. And because we own it, we'll apply the same values to it that we've already applied to the code that users are already using.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Building Tuist as a platform</title>
      <link>https://pepicrft.me/blog/building-tuist-as-a-platform/</link>
      <guid>https://pepicrft.me/blog/building-tuist-as-a-platform/</guid>
      <pubDate>Fri, 12 Mar 2021 12:00:00 +0000</pubDate>
      <description>Having seen Shopify acting as an e-commerce platform that developers can extend made me think whether the same idea would be applicable to Tuist. What if instead of us trying to codify all different workflows and configurations, we gave dev…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Having seen Shopify acting as an e-commerce platform that developers can extend made me think whether the same idea would be applicable to Tuist. What if instead of us trying to codify all different workflows and configurations, we gave developers an API to do it? Damn, it's so good. I started thinking about it thoroughly, and I think I have a good idea around how that could be.</p>
<p>First, I think <strong>Tuist's focus should be on the project graph, the generation of projects, and the build and test commands</strong>. We've invested four years into building a solid graph that we can optimize and turn into Xcode projects. Developers love that! They no longer have to think about linking or embedding build phases. Tuist makes them an implementation detail and knows what changes can be applied to the resulting Xcode project to be fast to index and compile.</p>
<p><strong>What APIs can we expose?</strong> The two that I think would be very valuable are <code>Setup.swift</code> and <code>Tasks.swift</code>. The first already exists. Developers can define how to configure an environment before interacting with the project. However, I'd change the approach to be imperative instead of declarative. Basically, instead of Tuist parsing the file and then translating the steps into system commands, we'd run the <code>Setup.swift</code> file directly as if it was a command line tool. <code>Tasks.swift</code> is not yet implemented but it'd allow developers describe their workflows in the same way they currently do with Fastlane. The difference is that Tuist'd provide them with information about their projects, like the dependency graph. How cool is that? Let me dump some pseudo-code below:</p>
<pre><code>import TuistAutomation

let tasks = [
 .task(name: &quot;swifltint&quot;) { tuist in
 let graph = tuist.graph()
 let sources = graph.sources()
 tuist.system(&quot;swiftlint&quot;, ....)
 }
]
</code></pre>
<p>And this would align with the work that we are doing with <a rel="external" href="https://tuist.io/docs/plugins/using-plugins/">plugins</a>. Developers would be able to extract their tasks and up commands and wrap them in a plugin that they share across projects and with the community. Same as if they were sharing Fastlane lanes ❤️.</p>
<p>It's exciting seeing everything that project generation enables. As I've said a few times, project generation is a means in Tuist to help developers with the challenges at scale. Using project generation for only getting rid of git conflicts will not help you with a plenty of problems that you'll see down the road.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Tuist and JS bundlers</title>
      <link>https://pepicrft.me/blog/tuist-and-js-bundlers/</link>
      <guid>https://pepicrft.me/blog/tuist-and-js-bundlers/</guid>
      <pubDate>Wed, 10 Mar 2021 12:00:00 +0000</pubDate>
      <description>I think there are a lot of similarities between Tuist and JS bundlers. First, they both are functions that take input and return an output. In the case of a JS bundler, it takes Javascript or any variation of it, and converts it into Javasc…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I think there are a lot of similarities between Tuist and JS bundlers. First, they both are functions that take input and return an output. In the case of a JS bundler, it takes Javascript or any variation of it, and converts it into Javascript that is compatible with the target platform (e.g. browser). In the case of Tuist, it takes your project definitions, and generates an Xcode project that you can use to build your apps. What's beautiful about putting a function in between, is that it opens the door for optimizations and transformations that otherwise wouldn't be possible. Javascript bundlers use it to transform code, for example JSX syntax into plain Javascript, or minifying the output Javascript so that it can be downloaded faster when users open a website. What's great about those Javascript bundlers is that they all have the concept of plugins. They allow developers participate in that transformation process with their own functions. Tuist is no different. We take you definition of projects and figure out what optimizations we can apply to ensure that the resulting Xcode project is fast in Xcode and compiles fast. One of the transformations that we apply is caching. We transform some of the targets into their binary representation.</p>
<p>The difference between the Javascript bundlers and us is that we don't allow developers to define their custom transformations. Fortunately, that's going to change soon thanks to <a rel="external" href="https://tuist.io/docs/plugins/using-plugins/">plugins</a>. Developers will be able to encapsulate their transformations into a plugin that they'll be able to distribute to Tuist users. How cool is that? We took a very closed and monolith project format, <code>.pbxproj</code> files. And we are turning it into a more open format that developers can extend and optimize.</p>
<p>This is the beauty of Tuist.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Owning your workflows</title>
      <link>https://pepicrft.me/blog/owning-your-workflows/</link>
      <guid>https://pepicrft.me/blog/owning-your-workflows/</guid>
      <pubDate>Tue, 16 Feb 2021 12:00:00 +0000</pubDate>
      <description>The more I work with Javascript and Ruby, the more I realize how empowering it is to design your workflows. Having worked with Xcode and Swift for many years, I was used to Apple dictating your working style. You need to debug an issue? Thi…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>The more I work with Javascript and Ruby, the more I realize how empowering it is to design your workflows. Having worked with Xcode and Swift for many years, I was used to Apple dictating your working style. <em>You need to debug an issue?</em> This is how you do it. <em>Is your app is not performing?</em> Here's instruments to trace your app performance. <em>Need to do something custom at build time?</em> Here's a script build phase to extend the build process.</p>
<p>Sure, by doing that, Apple has stronger control over the ecosystem, and therefore, over the developers' apps. However, there are situations when the proposed method doesn't work for your scale. Then you need to come up with creative ways to accommodate Apple's processes to your needs. An excellent example of that is replacing Xcode's build system with Bazel and figuring out how to get Xcode to compile with Bazel instead of using its build system. The result of that setup looks more than a hack. It's brittle. One day it works; the day after, it doesn't. And because Apple is so distant from many real challenges developers face, they continue building around their utopian vision of app development. That one where apps are small, a few targets, and dependencies are seamlessly distributed via Swift Package Manager.</p>
<p>The reality is far from that. The day-to-day is way more convoluted than what Apple thinks. And because Apple doesn't embrace that and provides more flexibility to customize processes, teams have no choice other than to wait for the next WWDC to see if Apple decides to tackle the issues they are facing.</p>
<p>In Javascript, you can choose your build tool. You feel like using <a rel="external" href="https://webpack.js.org/">Webpack</a>? Go for it. Is it too slow? You can use alternatives like <a rel="external" href="https://github.com/evanw/esbuild">esbuild</a>. You need to lint some code? There's <a rel="external" href="https://eslint.org/">eslint</a>. Don't you have the rule that you need? You can implement <a rel="external" href="https://www.kenneth-truyers.net/2016/05/27/writing-custom-eslint-rules">your custom rules</a>. You need to generate code at build time? You can use Babel and <a rel="external" href="https://github.com/kentcdodds/babel-plugin-macros">implement your own macros</a>. Would you love to extend VSCode's interface to show useful debugging information? You can use the <a rel="external" href="https://code.visualstudio.com/api">Extension API</a>.</p>
<p>And because of all of that, Ruby and Javascript are excellent as general-purpose programming languages, while Swift remains that language for building apps for Apple's ecosystem that dreams of becoming something more than that.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Focusing on the problems</title>
      <link>https://pepicrft.me/blog/focusing-on-the-problems/</link>
      <guid>https://pepicrft.me/blog/focusing-on-the-problems/</guid>
      <pubDate>Tue, 09 Feb 2021 12:00:00 +0000</pubDate>
      <description>One of the things that I noticed when building tools for developers, either through Tuist or my work at Shopify, is that we developers tend to get incredibly excited about what our new idea would enable, and put the need or problem aside. I…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the things that I noticed when building tools for developers, either through Tuist or my work at Shopify, is that we developers tend to get incredibly excited about what our new idea would enable, and put the need or problem aside. I believe that’s the source the complexity and the configuration over convention that we see in many tools.</p>
<p>While working on <a rel="external" href="https://tuist.io">Tuist</a>, it’s common to see users creating issues saying they need something without giving context on why they need it. And it’s also common to see other contributors and maintainers moving the discussion along without figuring out the reason that prompted them to create the issue in the first place. <strong>We can’t design great solutions if we don’t understand the needs very well.</strong></p>
<p>My role as lead at Shopify and core maintainer at Tuist often comes down to reminding people about the importance of understanding the need or problem. In the case of Tuist, this is done through discussions on GitHub issues, and at Shopify we often do it through user interviews. It sometimes requires a few whys until the developer surfaces their motivation. In some odd cases, it leads to the realization that they don't know the need or that there's already a solution for it.</p>
<p>Once identified, I nudge people to find the simplest solution that solves the problem. Still during this phase developers think far ahead and imagine how developers would use the feature and why that usage justifies the level of configuration they want to introduce into the feature. <strong>But do they need it?</strong> Most of the times the answer is <strong>not now</strong>.</p>
<p>In the space of Xcode project generators, this mindset is a key and highly-appreciated differenciator compared to other alternatives. Although they turn the <code>.pbxproj</code> into a more readable and shorter version of it in a YAML file, it's still the same complex concepts and configuration that makes the process of evolving Xcode projects a difficult task. With Tuist, every request to port an Xcode feature into Tuist's APIs is looked from the angle of <strong>what are you trying to achieve with it</strong>. I like how DHH calls it on <a rel="external" href="https://www.youtube.com/watch?v=zKyv-IGvgGE">his keynote talk from RailsConf 2018</a>, <strong>conceptual compression</strong>. If we, crafters of tools, own complexity to provide simplicity, the resulting tools will noticeably spark more joy when using them.</p>
<p>And last but not least, I the process of turning a problem into a solution requires a thorough thinking. We should let the idea sit in our mind for days, explore different solutions, and very importantly, understand how they fit into the project and aligns with its direction. That sometimes means saying no to the idea. I think taking <strong>this process as a marathon and not a sprint</strong> can make a huge difference in developer experience. If you treat your GitHub issues as an inbox where you goal is to get down to zero and implement everything you've been asked for, there'll be plenty of interesting ideas, but that they don't know how to talk to each other.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Tuist and the Swift Package Manager</title>
      <link>https://pepicrft.me/blog/tuist-and-spm/</link>
      <guid>https://pepicrft.me/blog/tuist-and-spm/</guid>
      <pubDate>Fri, 05 Feb 2021 12:00:00 +0000</pubDate>
      <description>It&#x27;s common to see developers wondering why they should use Tuist instead of the Swift Package Manager (SPM) for modeling their projects. I think it&#x27;s normal. It happened to me a few times too. Some of them even made me wonder if I should c…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It's common to see developers wondering why they should use <a rel="external" href="https://tuist.io">Tuist</a> instead of the Swift Package Manager (SPM) for modeling their projects. I think it's normal. It happened to me a few times too. Some of them even made me wonder if I should continue investing time into Tuist. There are some ideas and principles that are common to both tools. One can use Tuist to define a CLI tool like you'd do with SPM in the same way SPM could be used to to define the targets of your project. However, there's a fundamental difference that is worth bringing up in this tiny blog post.</p>
<p><strong>The Swift Package Manager is dependencies-oriented while Tuist is projects-oriented.</strong> SPM does a good job resolving and pulling dependencies, and providing a standard CLI to build and test your packages. The developer experience integrating it with Xcode is questionable good, but it works in most cases. I say it's questionably good because when used at scale, like it's the case in Tuist's codebase, it's a bit frustrating seeing Xcode very often invalidating the dependency graph, or failing to resolve it and having a project that can't compile. Because SPM is dependencies-oriented, the workflows are designed around that. This might change depending on the direction that Apple takes with the tool, but if that doesn't change, I doubt we'll improvements that projects need at scale.</p>
<p>On the other side, Tuist is designed as a tool to <strong>make the experience of maintaining, interacting and scaling up your projects the best</strong>. Because the people behind Tuist maintains large-scale projects, we are building features that can make a huge difference in developers productivity: <em>project description helpers</em>, <em>focused projects</em>, <em>caching</em>, and <em>standard interface for third-party dependencies (not only packages)</em>. If Apple is that giant corporation that come up with utopian visions of developer experience towards which many teams are biased <em>(i.e. authoritative bias)</em>, we are the tiny startup that stays close to the developers and their pains and solves the problems that they bring up. And because we don't have to align our ideas with any business's direction, it's easier to explore and execute ideas.</p>
<p>That being said, it's possible that Apple changes the direction of the Swift Package Manager and turns it into a project manager. However, and as we've seen in the past, I think they'll continue distant from the real problems that developers face. The future of developer tooling around managing your Xcode projects is exciting.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Tackling technical debt in Tuist</title>
      <link>https://pepicrft.me/blog/tackling-technical-debt/</link>
      <guid>https://pepicrft.me/blog/tackling-technical-debt/</guid>
      <pubDate>Thu, 04 Feb 2021 12:00:00 +0000</pubDate>
      <description>I&#x27;ve recently spent a lot of time in Tuist tackling technical debt. It&#x27;d been a while since the last time I have to pause some other work for weeks to do something that would be beneficial for the long-term of the project. This time the wor…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've recently spent a lot of time in <a rel="external" href="https://tuist.io">Tuist</a> tackling technical debt. It'd been a while since the last time I have to pause some other work for weeks to do something that would be beneficial for the long-term of the project.</p>
<p>This time the work was replacing models that are very core to Tuist's domain: the graph and all the models associated to it. When I built the first graph structure, I didn't put too much thought into how it should be. I was led by intuition. I added a reference here, a subclass there, and everything seemed to work. It worked so well that we have built the majority of the features on top of it.</p>
<p>We could have continued building upon that graph, but the further we moved, the clearer it was that we needed more flexibility, safety, and an easier to reason about graph. Unlike the old graph that used in-memory references to represent dependencies, we implemented the new one as a <code>struct</code>.</p>
<p>The edges of the graph are represented by dictionary key-value relantionships, and the nodes by enums. Everything is defined in a model so at a glance you can see its format. Moreover, we built a traverser that wraps it and provides efficient methods to traverse it. Those are useful when generating the projects because the logic needs to traverse the graph a few times to obtain information like what linking build phases should be added.</p>
<p>The new graph is already used by many components, but there are still some left. Doing this work made me realize how core this model is and why it makes Tuist's project generation so unique. It's certainly not as interesting work as building new features, but I'm motivated by the fact that this refactor will enable so many future improvements and new features.</p>
<p>If you see me not talking too much about new Tuist features is because I'm spending most of my time making this possible.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Decision records</title>
      <link>https://pepicrft.me/blog/decision-records/</link>
      <guid>https://pepicrft.me/blog/decision-records/</guid>
      <pubDate>Wed, 03 Feb 2021 12:00:00 +0000</pubDate>
      <description>One of the things I&#x27;ve been terrible at is at keeping decisions records in projects . It happens often working on Tuist that I come across something that I need to know why it was done in a particular way and I can&#x27;t remember. It also happe…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the things I've been terrible at is at <strong>keeping decisions records in projects</strong>. It happens often working on Tuist that I come across something that I need to know why it was done in a particular way and I can't remember. It also happens that users ask about something and I have to repeat the same thing over an over. Because of that, I'm considering adding a decision record to the Tuist repository where we can keep track of these things, as well to the repos at Shopify that my team is responsible for maintaining.</p>
<p>As a developers <strong>we have to make many decisions along the day</strong>, and the result of those decisions is most of the times code. However, if the code doesn't speak for itself, it's extremely useful to add a companion narrative that adds the context necessary to understand the story of the code. It takes practice to build this habit, but I think it's an important one to build as you become a more senior engineer. Piling up undocumented decisions in a project is the perfect recipe for misunderstandings and frustration.</p>
<p>I'm working on building that habit and making decision records a core piece of every repository that I'm responsible for maintaining.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Scaling up an open-source project</title>
      <link>https://pepicrft.me/blog/scaling-up-an-open-source-project/</link>
      <guid>https://pepicrft.me/blog/scaling-up-an-open-source-project/</guid>
      <pubDate>Thu, 28 Jan 2021 12:00:00 +0000</pubDate>
      <description>One thing that I&#x27;ve been struggling a lot with lately is the amount of distractions that come with the growth of an open-source project. In the case of Tuist , those distractions have come in the shape of notifications on GitHub, mentions o…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One thing that I've been struggling a lot with lately is the amount of distractions that come with the growth of an open-source project. In the case of <a rel="external" href="https://tuist.io">Tuist</a>, those distractions have come in the shape of notifications on GitHub, mentions on PRs, direct messages on Slack, and interesting conversations happening on Slack channels. Working on Tuist lately has felt more like running on a treadmill. I don't like it. I like being able to craft new features and improvements with no distractions. Just me and Xcode.</p>
<p>To regain the focus that I used to have then the project was small and only a few people I started taking action. First I'm <strong>time-boxing</strong> the time I use checking notifications, Slack messages, and pings on PRs. I think spending between 15' and 30' minutes per day is enough. If something comes up after that daily time it has to wait until the next day. Moreover, I'm trying to document and automate as much as I can. I introudced a <strong>new tool</strong> into the project, <code>fourier</code>, that will become the place for all utilities necessary to work on the project. Most of the answers on how to do things will be in either the tool or the documentation so people shouldn't need me to answer "how do I do X"? Also, I'm encouraging people to use asynchronous discussion channels like GitHub PRs and issues. Unlike Slack where people feel the freedom to catch your attention, it's you who decides when is the time to read the discussion on GitHub. You are the one controlling your attention.</p>
<p>Let's see how that goes. One of the reasons why some maintainers give up on open-source projects is because they can't cope with the maintenance burden. I don't want the same to happen in Tuist and I'll work towards that.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The beauty of a standard command line interface</title>
      <link>https://pepicrft.me/blog/standard-automation/</link>
      <guid>https://pepicrft.me/blog/standard-automation/</guid>
      <pubDate>Mon, 18 Jan 2021 12:00:00 +0000</pubDate>
      <description>There&#x27;s something beautiful in entering a directory that contains a project and knowing how to interact with it. It&#x27;s like being part of a communication where the terminal is the channel and you both know the language. You know that build w…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There's something beautiful in entering a directory that contains a project and knowing how to interact with it. It's like being part of a communication where the terminal is the channel and you both know the language. You know that <strong>build</strong> will turn your code into binary, that <strong>test</strong> will validate that your code does what's supposed to do, and <strong>run</strong> will show you what the code does. Since all the projects speak the same language, you can move between projects freely and being able to interact with them seamlessly.</p>
<p>Unfortunately, such beauty hasn't existed for years in the Swift community. <a rel="external" href="https://fastlane.tools">Fastlane</a> gives you the tools to define the lanuage; you get words, but you are the one coming up with the language. The reality has proved that defining a coherent language while building an app it's not easy. Teams end up with complex and hard to optimize logic that is a nightmare to maintain. It's not Fastlane, their building blocks are great, but their approach naturally leads to this.</p>
<p>When people ask me why <a rel="external" href="https://tuist.io">Tuist</a> provides now commands like <strong>build</strong> and <strong>test</strong>, my answer is simply that there's the need in the Swift community for a different approach to interact with projects. An approach where we write the language, we make it simple and enjoyable to use, and you focus on building great apps.</p>
<p>You describe us the projects, and we do the rest.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Reflecting on 3 years at Shopify</title>
      <link>https://pepicrft.me/blog/what-i-have-learned-at-shopify/</link>
      <guid>https://pepicrft.me/blog/what-i-have-learned-at-shopify/</guid>
      <pubDate>Mon, 18 Jan 2021 12:00:00 +0000</pubDate>
      <description>A few days ago, it was my 3rd anniversary at Shopify, and I&#x27;ve got the idea of sharing in a short blog post what are the things that I like from Shopify and that allowed me to grow: Great mission: The company has a clear and realistic missi…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>A few days ago, it was my 3rd anniversary at Shopify, and I've got the idea of sharing in a short blog post what are the things that I like from Shopify and that allowed me to grow:</p>
<ul>
<li><strong>Great mission:</strong> The company has a clear and realistic mission that they go after, and most importantly, leadership believes in it. I'm noticing more and more companies emerging with CEOs with a utopian view of the world and throw many investors' money into the problem with the dream that the world will be shaped as they want it to be. - <strong>Leadership understands technology:</strong> And, therefore, can make informed decisions. When we decided to adopt React Native, it was a meditated decision that the CEO could see aligning with the company's direction. - <strong>They trust you:</strong> All that friction you see in other companies where you have to escalate the "can you give me access to" ladder doesn't exist at Shopify. They trust people, and people trust each other. We have a concept called "trust battery", and it's essential to have it fully charged with the people around us. - <strong>Technology is a means and not an end:</strong> Shopify is often criticized for being old-school with their Rails monolith, and very recently, for adopting React Native as the default technology for building mobile apps. However, I learned to appreciate that any technology in the right hands can get you to achieve great things. I've seen companies writing native Swift apps or complex micro-services backends whose business and user experience is broken. What's the point of being on the latest if you can't provide excellent value to your users? - <strong>You have a path for growth:</strong> Since I expressed my interest in leading a team, my manager trusted me to give it a shot and start taking steps towards it. Since then, they've provided me with resources, guidance, and support to help me grow every day. Similarly, I've seen other folks changing teams and paths to explore new areas. - <strong>Not afraid of black boxes:</strong> Unlike many companies that are afraid of change when they find their comfort zone, Shopify likes and embraces change because they accept the world is continually changing, and we need to evolve with it. A couple of examples of that are the adoption of React Native and becoming digital by default. As soon as the pandemic started, the CEO accepted that the new normal wouldn't be the same and that we should be the first to figure out what it'll be like and not the last. The whole company is learning how to be remote, and it's fantastic to see everything they are doing to support this transition. - <strong>Extremely talented people:</strong> Shopify is full of crafters that are passionate about what they do and from which you can learn a lot. I've had the opportunity to learn a lot about people management, design developer experiences, and manage projects. - <strong>A great developer experience can make a difference:</strong> The opportunity to work on tooling full time is one of those things that got me into Shopify. It's a company that doesn't see tooling as an after-thought. A great tool can save you time and bring you the focus you need to build the product. We have teams dedicated to tooling for different development areas: local environments, cloud environments, test infrastructure, mobile, web...</li>
</ul>
<p>Overall, I feel valued. I get the space that I need to be creative. I'm surrounded by a fast and inspiring environment that motivates me to challenge my static visions of the things around me continually.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>My first RFC in the React Native project</title>
      <link>https://pepicrft.me/blog/first-rfc-in-rn/</link>
      <guid>https://pepicrft.me/blog/first-rfc-in-rn/</guid>
      <pubDate>Thu, 07 Jan 2021 12:00:00 +0000</pubDate>
      <description>Today I created an RFC for the first time in the repository. I&#x27;ve pondering a bunch of ideas for a long time regarding how the experience building React Native apps could be improved and I finally gave them a structure and formalized them.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Today I created an <a rel="external" href="https://github.com/react-native-community/discussions-and-proposals/issues/318">RFC</a> for the first time in the repository 🥳. I've pondering a bunch of ideas for a long time regarding how the experience building React Native apps could be improved and I finally gave them a structure and formalized them in a RFC.</p>
<p>I'm not sure if the community will be willing to embrace that direction, but I'm convinced the developer experience can improve significantly. It reminds me to the moment I had the realization that <a rel="external" href="https://tuist.io">Tuist</a> was necessary and I set out to build it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>My tech stack in 2020</title>
      <link>https://pepicrft.me/blog/my-tech-stack-2020/</link>
      <guid>https://pepicrft.me/blog/my-tech-stack-2020/</guid>
      <pubDate>Mon, 28 Dec 2020 12:00:00 +0000</pubDate>
      <description>I&#x27;m a bit reflective today; I guess because we are approaching the end of this so-odd year. Therefore, I&#x27;d like to share what has been my preferred tech stack in 2020 and what most likely continue to be in 2021. React for building web front…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I'm a bit reflective today; I guess because we are approaching the end of this so-odd year. Therefore, I'd like to share what has been my preferred tech stack in 2020 and what most likely continue to be in 2021.</p>
<h2 id="react-for-building-web-frontends"><a rel="external" href="https://reactjs.org">React</a> for building web frontends</h2>
<p>I like React's approach to building declarative UIs. The React's movement led to an explosion of community components that make building UIs feel like LEGO, and great tools and processes like CSS-in-JS that save you a lot of time and improve the developer experience. I haven't tried <a rel="external" href="https://vuejs.org">Vue</a> myself; therefore, I can't say much about it. I'm not a huge fan of Facebook steering the framework, but I'm optimistic it'll become <em>(if it hasn't been done already)</em> a community-driven project.</p>
<h2 id="gatsby-for-building-static-websites"><a rel="external" href="https://www.gatsbyjs.com">Gatsby</a> for building static websites</h2>
<p>After embracing React, using <a rel="external" href="https://jekyllrb.com">Jekyll</a> and its partials felt old-school. The introduction of dynamic behaviors resulted in writing imperative Javascript that calls DOM APIs. I wanted to use React's declarative approach, and GatsbyJS allowed that. When I came across GatsbyJS, were a bunch of concepts that I had to learn. For example, its method to decouple the UI from the data sources using a GraphQL API. The learning curve was a bit steep, but after passing it over, using Gatsby is a pleasure. And because it's built upon React, I can reuse components and utilities built for React. When I see frameworks like <a rel="external" href="https://github.com/JohnSundell/Publish">Publish</a> in Swift, a programming language that I'm emotionally attached to, I always think there's no way I give up on React's awesomeness and convenience.</p>
<h2 id="netlify-for-deploying-static-websites"><a rel="external" href="https://netlify.com">Netlify</a> for deploying static websites</h2>
<p>Netlify is an excellent example of an abstraction that improves the experience of putting a static website on production. They provide an environment where my Gatsby websites can be built, and placing the resulting HTML artifacts in a CDN network that I can point my domains to. One of its breakthrough features is <a rel="external" href="https://www.netlify.com/tags/deploy-previews/">deploy previews</a>. They deploy PRs to temporary environments so that people reviewing your PRs can check out the changes live. They provide many other features, but I haven't used them yet.</p>
<h2 id="rails-for-building-web-services"><a rel="external" href="https://rubyonrails.org">Rails</a> for building web services</h2>
<p>I might be biased here because I work at <a rel="external" href="https://shopify.com">Shopify</a>, but I enjoy building web services with Ruby on Rails. I can confirm both the programming language and the framework spark joy when using it. I'm not an expert in any of both, but I reached a point where I feel fluent, and I can't have something up and running quickly. What I also like about Rails and Ruby is that there's less fatigue compared to Javascript. Suppose you need a database ORM; <a rel="external" href="https://guides.rubyonrails.org/active_record_basics.html">ActiveRecord</a> is there to help. If you need to expose a GraphQL API, you can use <a rel="external" href="https://graphql-ruby.org">GraphQL Ruby</a>.</p>
<p>These are the Gems that I usually add to projects: <a rel="external" href="https://github.com/heartcombo/devise">Devise</a> for authentication, <a rel="external" href="https://github.com/varvet/pundit">Pundit</a> for authorization, <a rel="external" href="https://sidekiq.org">Sidekiq</a> for running background jobs, <a rel="external" href="https://graphql-ruby.org">GraphQL Ruby</a> for defining a GraphQL API, <a rel="external" href="https://github.com/rails/webpacker">Webpacker</a> for using React as a frontend that interacts with a GraphQL API, and <a rel="external" href="https://github.com/rubocop-hq/rubocop">Rubocop</a> for code linting.</p>
<h2 id="heroku-for-deploying-web-services"><a rel="external" href="https://heroku.com">Heroku</a> for deploying web services</h2>
<p>I'm not an infrastructure person, so I appreciate services that put my code into production. Netlify is that service for statically-generated websites, and Heroku is its counterpart for long-running services like Rails applications. I can create a new project, link it to a repository that contains a Rails app, and in a matter of minutes, I have a Rails app up and running on production. I can add a <a rel="external" href="https://postgresql.org">PostgreSQL</a> database and a Redis instance that I can point Sidekiq to through add-ons.</p>
<p>As a side note, I have to say I like the <code>run</code> feature, which allows me to open a Rails console with the production instance and debug issues in production:</p>
<pre><code>heroku run rails console
</code></pre>
<h2 id="github-actions-for-continuous-integration"><a rel="external" href="https://github.com/features/actions">GitHub Actions</a> for continuous integration</h2>
<p>Since GitHub introduced it, GitHub actions became the go-to continuous integration service. I like it because it's integrated into GitHub's UI. The user interface is fluid compared to other services that I've used in the past, and it's straightforward to reuse CI logic across projects by defining actions. It took a long for GitHub to step into the business, but I have to say they beat the market with an extremely high-quality product.</p>
<h2 id="tailwindcss-for-styling-web-interfaces"><a rel="external" href="https://tailwindcss.com">TailwindCSS</a> for styling web interfaces</h2>
<p>TailwindCSS is probably the discovery of the year. The framework introduced me to the concept of utility classes in CSS; after learning a set of semantic HTML classes that match to CSS styles, you can easily style your HTML without having to jump back and forth between HTML and CSS files. Moreover, classes delimit properties such as color and margin to a pre-defined set of values. As a result, UIs look more consistent and harmonious.</p>
<p>After coming across the framework, I followed the authors of it, x and y, and I've been a massive fan of the work that they've been doing. Another masterpiece from them is the <a rel="external" href="http://tailwindcss.com">RefactoringUI</a> book, which teaches you ideas to build beautiful and clean UIs. I also paid for a license for <a rel="external" href="https://tailwindui.com/components">TailwindUI</a>, their set of pre-defined layouts implemented with TailwindCSS.</p>
<h2 id="ruby-for-command-line-tools"><a rel="external" href="https://www.ruby-lang.org/en/">Ruby</a> for command line tools</h2>
<p>Even though I'm building <a rel="external" href="https://tuist.io">Tuist</a> in Swift to make it easier for users to contribute, Ruby is my programming language for building CLI tools. It comes with the system, I'm incredibly familiar with it, and there are many useful Gems from the community that I can reuse. Moreover, its dynamism makes it very suitable for experimenting with ideas and workflows. Doing something like that in Swift would require going through Xcode and its compilation cycles, which takes the focus away from prototyping and hacking.</p>
<h2 id="vscode-for-editing-code"><a rel="external" href="https://code.visualstudio.com">VSCode</a> for editing code</h2>
<p>I love VSCode. It's a masterpiece from Microsoft. I can use it with multiple programming languages like Ruby and Typescript, extend it through community-built extensions, and configure it through workspace settings. Even though it's built with <a rel="external" href="https://electronjs.org">Electron</a>, which inevitably means using more computer resources than other editors built natively, I haven't tried any other editor that is as close to as significant as VSCode is. Between developer experience and efficient computer resource usage, I lean more towards the former in this domain.</p>
<h2 id="react-native-for-building-apps"><a rel="external" href="https://reactnative.dev">React Native</a> for building apps</h2>
<p>I like Swift and Apple's direction with <a rel="external" href="https://developer.apple.com/xcode/swiftui/">SwiftUI</a>, but I can't reuse the work that I do for Apple platforms in other platforms like Android and Windows. <a rel="external" href="https://shopify.engineering/react-native-future-mobile-shopify">Shopify's adoption of React Native</a> has taught me that you can build great products in React Native; you need to make the technology an implementation detail and focus on the product. In recent years I've shifted from treating technology as a goal to using it as a means to build tools that solve users' problems. To achieve this, I think React Native is the most suitable option, and I can apply all the concepts and learnings from building web UIs with React.</p>
<p>...and this is my preferred stack. What about yours? If you write a blog post about it and share it on Twitter, don't forget to tag me (<a rel="external" href="https://twitter.com/pepicrft">@pepibumur</a>); I'm curious to see what other folks in the industry are using.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Sparking joy working with Xcode</title>
      <link>https://pepicrft.me/blog/sparking-joy/</link>
      <guid>https://pepicrft.me/blog/sparking-joy/</guid>
      <pubDate>Thu, 10 Dec 2020 12:00:00 +0000</pubDate>
      <description>I learned by working with Ruby and Ruby on Rails during my time at Shopify that using tools and programming languages that spark joy is crucial for developers&#x27; motivation. Even though we developers love to understand complexities, we enjoy…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I learned by working with Ruby and Ruby on Rails during my time at Shopify that using tools and programming languages that spark joy is crucial for developers' motivation. Even though we developers love to understand complexities, <strong>we enjoy working with simplicities and conveniences day-to-day</strong>.</p>
<p>In the Swift community, we've seen a proliferation of tools to help developers with different needs <em>(e.g. generation of Swift interfaces from resources, code linting, dependency management)</em> that inevitably led to a non-cohesive and complex developer experience where <a rel="external" href="https://github.com/fastlane">Fastlane</a> acted as the glue. On top of that, the authority bias is nudging teams to have more than one dependency manager in their projects to stick to Apple's recommendations.</p>
<p>Below there's a common Xcode project setup with all the elements that are part of it and how they depend on each other. Note the estensive list of elements that you need to work on the project. There are a lot of caveats in such setup:</p>
<ul>
<li><strong>Reproducibility</strong> is harder that might result in developers spending their time debugging inconsistent results across environments. This can happen for instance if <a rel="external" href="https://brew.sh">Homebrew</a> decides to install a new version of a tool on CI that introduces breaking changes. - The setup is <strong>difficult to reason about</strong> for a new person joining the project. Only the people that have been part of the design can have such an overview. It results in a terrible <a rel="external" href="https://en.wikipedia.org/wiki/Bus_factor">bus factor</a>, which in large companies translates to the infra team or the go-to person that knows everything about the project setup. - <strong>Optimizations</strong> are not easy. Different pieces are so coupled to each other that introducing optimizations that have a significantly affect on developers' workflows is a challenging task. - Because there are many potential points of failure, when errors arise, they are harder to <strong>debug</strong>. <em>Is this failing because of my CocoaPods version? Is it because of this pod lane that I'm using? Might it be related to the version of Ruby I'm using?</em></li>
</ul>
<p><img src="https://pepicrft.me/blog/sparking-joy/__GHOST_URL__/images/posts/complex-setup.png" alt="The diagram shows an example of a complex Xcode project setup" /></p>
<p>That's a setup prone to errors and stress for developers with which I'd never want to work. We've spent most of our time building great tools but not that much thinking about providing a <strong>cohesive experience when bringing them together</strong>.</p>
<p>For this reason, we continue investing in <a rel="external" href="https://tuist.io">Tuist</a>. We believe there's an opportunity for providing a Rails-like experience for developers building apps with Xcode. An experience that combines primitives from Apple like <code>xcodebuild</code> and tools from the community.</p>
<p><strong>Anyone can and should be a project architect</strong>. To make this possible, developers need simple setups and APIs to describe their projects. Having an infrastructure team is useful to steward the project's growth, but there shouldn't be any strong dependency between feature teams and them. The trap many companies fall into is building this strong dependency where every time you need to do something that touches the architecture, you have to do it through the infra team. The setup must be <strong>simple</strong>. Embracing complexity is the formula for creating an environment in which developers don't want to work. Tuist owns complexity and the optimization of workflows to provide a simple and efficient workflows through the CLI. A more straightforward setup will make the environments more <strong>reproducible</strong>, and thus developers will have to spend less time debugging issues when they arise. To work with Tuist, teams only need to install Tuist, and that's it. No dependency on Ruby, Homebrew, nor Fastlane. It's you, Xcode, your project, and Tuist.</p>
<p>Developers might see this setup as rigid like many companies saw and continue to see Rails. But look at companies like <a rel="external" href="https://github.com">GitHub</a> and <a rel="external" href="https://shopify.com">Shopify</a> that were able to build excellent products in part thanks to the fact that developers could focus on building the product and not fighting the underlying tooling and frameworks. As apps become larger, the need for a Rails-like foundation becomes more important, and that's the place I think Tuist can take in the community.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Tree-shaking Xcode projects</title>
      <link>https://pepicrft.me/blog/tree-shaking-xcode-projects/</link>
      <guid>https://pepicrft.me/blog/tree-shaking-xcode-projects/</guid>
      <pubDate>Wed, 11 Nov 2020 12:00:00 +0000</pubDate>
      <description>Tree-shaking is a concept inspired by Javascript and used by Tuist to generate lean Xcode projects that are processed and compile faster.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>You might have seen me talking about Xcode projects' tree-shaking with no idea of what I'm talking about. This is a concept inspired by the same concept in the Javascript land. Over there, it refers to the process of stripping away from the resulting Javascript bundle those bits that are not necessary because there are no execution paths that go through them. The goal is to minimize the size of the file that is served that the website opens faster. I liked the idea and made me wonder if something like that would be useful in Xcode projects. It turned out it is.</p>
<p>What's tree-shaking an Xcode project Have you tried to open a large project in Xcode? Indexing is not immediate, the list of schemes is probably large and hard to navigate through, Xcode's features like searching are slower than usual. This is something we are, in fact, experiencing in Tuist's codebase, and it's very annoying. What if the generated project had a focus on a given target and removed everything that is not necessary to work on that target? In a modular codebase, that's a common thing to do. You work on the Search team, and most of your work is done in Search.framework. There'll be scenarios when you need to work on core frameworks, but most of the time, it's not the case. Well... that's what Tuist does when you run the following command:</p>
<pre><code>tuist focus Search
</code></pre>
<p>We traverse your project's dependency graph and remove the elements you don't need to work on Search. Let's look at the example below:</p>
<p><img src="https://pepicrft.me/blog/tree-shaking-xcode-projects/__GHOST_URL__/images/posts/tree-shake.png" alt="An image that shows how the tree-shaking of projects works with Tuist" /></p>
<p>We have a simple modular app with a layer of feature frameworks and another layer of utility frameworks. When we focus on Search we get that target and its dependant targets (e.g. SearchExample, SearchTests, SearchUITests) as sources, and its dependencies as binaries (if they exist in the cache). This means Xcode doesn't have to index anything related to App, Settings, and Home, and clean builds of the framework will only have to compile Search. For the user, that also means that they can safely clean their environment (i.e. deleting DerivedData) without feeling concerned about leading to a slow build.</p>
<p>As part of the tree-shaking process, we also delete from the workspace the projects that have no targets after deleting the unnecessary targets, and update the schemes to remove the references to no-longer-existing targets.</p>
<p>What if I wanted to modify something in Core? We thought about that too, tuist focus supports a list of targets you'd like to focus on. You can run the following command, and you'll get the sources of Core too:</p>
<p>tuist focus Search Core Neat! Isn't it? I think tree-shaking is a powerful idea that will boost developers' productivity working with large Xcode projects. I can't stress enough how much value this brings to Tuist's project generation functionality compared to other solutions out there whose main focus is having a new language for .pbxproj files that is not prone to Git conflicts. Tuist goes beyond that and puts itself in the shoes of teams that need a tool to optimize these optimizations to make their developers productive and focus on building features.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Module caching in Xcode projects</title>
      <link>https://pepicrft.me/blog/module-caching-in-xcode-projects/</link>
      <guid>https://pepicrft.me/blog/module-caching-in-xcode-projects/</guid>
      <pubDate>Tue, 10 Nov 2020 12:00:00 +0000</pubDate>
      <description>Bazel and Buck is the solution large companies have adopted to make Xcode build fast. However, it&#x27;s complex and not accessible to medium and small companies. In this blog post, I share the approach Tuist is taking and how it&#x27;s inspired by tools the community is already using.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As you might know, we've been working on a new feature for <a rel="external" href="https://tuist.io/">Tuist</a>, caching, to speed up build times of Xcode projects.</p>
<p>Large companies usually resort to build systems like <a rel="external" href="https://buck.build/">Buck</a> or <a rel="external" href="https://bazel.build/">Bazel</a> to introduce remote caching into their projects. Those are great build-systems. Apple is bringing talent that has previously worked with them to improve the Xcode and <a rel="external" href="https://swift.org/package-manager/">Swift Package Manager</a>'s build-system. However, the build system is not accessible for small and medium-sized companies because they can't afford to have a tooling or infrastructure team to migrate from Xcode's build system. Moreover, using another build system has proven to have significant costs for the infra team and inconveniences for the users. Since Xcode doesn't support replacing its build system, companies have to resort to project-generation in combination with some hacks to get Xcode to compile using Bazel or Buck. Moreover, with every new Xcode update, they have to do some work to ensure their setup doesn't break and that developers can always be in the latest Xcode version. Not ideal, is it?</p>
<p>With Tuist, we have taken a simpler approach to caching that is inspired by solutions that we have already seen in the community. Here's how our implementation relates to tools that you might already be familiar with:</p>
<ul>
<li><a rel="external" href="https://github.com/carthage/carthage">Carthage</a>: Carthage takes a different approach to dependencies. Rather than integrating the source code through a project and a workspace, it uses dynamic frameworks that can be easily dragged and dropped into a target and Xcode will automatically set the linking build phases. The clear advantage here over CocoaPods is that your clean builds don't compile the source code of those dependencies. However, it requires developers to understand their project's dependency graph, to ensure that the frameworks are copied into the right products. A badly configured project might lead to apps crashing at launch time, or Apple rejecting your bundles because you have copied a framework into another framework. From Carthage, Tuist gets the idea of turning your project targets into binaries. - <a rel="external" href="https://github.com/tmspzz/Rome">Rome</a>: Takes Carthage frameworks and store them in a remote storage. Thanks to this, Carthage frameworks are only built once and shared across all the developers in the team. Nothing changes regarding how those frameworks are integrated into the project. From Rome, Tuist gets the idea of reusing binaries by storing them on a remote storage. - Swift Package Manager: SPM's approach to dependencies is similar to CocoaPods. The main difference is that since it's developed and maintained by Apple, the integration in Xcode projects is more seamlessly. Xcode has built-in workflows for resolving Swift Packages at launch time, and the build system knows how to build and link those dependencies into your app. From the Swift Package Manager Tuist gets the idea of defining your projects using manifest files that are written in Swift.</li>
</ul>
<p>So how does Tuist combine all the above elements to provide caching?</p>
<p>It generates Xcode projects <em>(like CocoaPods)</em>, where the targets that you don't plan to work on are replaced by binaries <em>(like Carthage)</em>, that are stored in a remote storage *(like Rome) *that gets populated from CI. All of that happens at project generation time when developers run the following command:</p>
<pre><code>tuist focus MyFramework
</code></pre>
<p>It reads as: I'd like to work on <code>MyFramework</code>, please, replace direct and transitive dependencies with binaries, and tree-shake my project to remove elements that are not necessary to work on that target <em>(e.g. other targets, their schemes)</em>.</p>
<p>Because what you get in the end is a standard Xcode project, you don't have to worry about future Xcode versions breaking your setup, or using hacks on the Xcode side to make the developers' experience seamlessly.</p>
<p>The image below represents the layers of indirection that are introduced when using alternative build systems. Note that build files have to be translated into another representation that is then passed to a project generator to get an Xcode project. Moreover, the final Xcode projects need to need to trick Xcode into using Bazel or Buck as a build system.</p>
<p><img src="https://pepicrft.me/blog/module-caching-in-xcode-projects/__GHOST_URL__/images/posts/module-caching-1.png" alt="An image that shows the setup that companies adopt when using Buck or Bazel" /></p>
<p>The diagram represents the common setup when using alternative build systems.</p>
<p>In the case of Tuist, there are no layers of indirection. It takes your project definition and generates an Xcode  project ready to be used with Xcode's build system. Because of its simplicity, the setup is easier to reason about, optimize, and debug. Moreover, it makes caching accessible to more users:</p>
<p><img src="https://pepicrft.me/blog/module-caching-in-xcode-projects/__GHOST_URL__/images/posts/module-caching-2.png" alt="An image that shows how caching works with Tuist" /></p>
<p>The diagram represents how the caching works in Tuist.</p>
<h2 id="some-final-words">Some final words</h2>
<p>We'll never be able to build a solution like Bazel and Buck because we are not experts in build systems, nor we think it makes sense to take people away from Xcode's build system. We believe though, that some of the ideas from Bazel and Buck can inspire future improvements in Xcode.</p>
<p>Apple seems to be betting on evolving its build system to be something closer to what Google offers with Bazel. However, it'll be challenging to enable it in existing projects that might have deviated a lot from a standard Xcode project. One of my guesses on how Apple is going to proceed is that they'll first evolve the monolith <code>.pbxproj</code> format for projects into a new format that abstracts some of the intricacies that we have been traditionally exposed to *(e.g. linking build phases, build settings) *and is less prone to git conflicts. With a more limited format, it'll be easier for them to reliably enable build caching because they'll have a well-defined set of project flavors that they'd need to optimize for.</p>
<p>I'm very excited to bring this feature to Tuist and democratize caching for medium and small companies. There's a lot we need to improve, and project scenarios to handle gracefully, but it's looking promising, and can't wait to see more projects using it and making their developers productive through Tuist.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Growing Tuist&#x27;s community</title>
      <link>https://pepicrft.me/blog/growing-tuist-community/</link>
      <guid>https://pepicrft.me/blog/growing-tuist-community/</guid>
      <pubDate>Sat, 31 Oct 2020 12:00:00 +0000</pubDate>
      <description>In this blog post, I share my experience building the Tuist community. I talked about the things that have worked well, and the areas where there&#x27;s still some room for improvement.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As you might already know, I devised and started working on <a rel="external" href="https://tuist.io/">Tuist</a> a few years ago. I was motivated by the fact that modular Xcode projects were a nightmare to maintain and that existing project generation solutions were taking a direction that would lead them to surface the same intricacies and complexities present in Xcode projects. I envisioned Tuist as more than just a project generation. I wanted it to be a platform that makes development convenient and removes indirection layers introduced by tools written in different programming languages. Rails was my most massive inspiration. The framework places convention over configuration to provide a great user experience. Rather than installing a handful of tools, like it happens when developing apps with Xcode <em>(CocoaPods, Carthage, SwiftLint, <a rel="external" href="https://github.com/krzysztofzablocki/Sourcery">Sourcery</a>, <a rel="external" href="https://github.com/SwiftGen/SwiftGen">SwiftGen</a>)</em>, you install one, and it works. I was thrilled to bring the same idea to the Swift community.</p>
<p>When I embarked on that journey, it was clear that the community would play an important role. That's one of the things that makes <a rel="external" href="https://rubyonrails.org/">Rails</a> so unique too. It's made by people that have a lasting commitment to the project. This is rarely seen in the Swift land, where it's more common to see people come and go often. Many clickbait-type projects reach a spike of hype and stars on GitHub, and then they are abandoned or barely maintained. Tuist would be different. It'd have a mission, it'd place UX in the first place, and people would be encouraged to show a lasting commitment to the project. It'd help developers with the challenges they face when scaling up projects. Users would be invited to share their challenges to help shape the direction of Tuist.</p>
<p>In this blog post, I'll share what had worked well in building the community and the things that still have room for improvement.</p>
<h2 id="what-has-worked">What has worked</h2>
<h3 id="documentation-for-contributors">Documentation for contributors</h3>
<p>Joining a community as a contributor might feel intimidating. *Where do I start? *Projects usually place a <code>CONTRIBUTING.md</code> file in the repository with some basic guidelines, but that's not enough - people need a walkthrough that explains how the project is architected and how they can clone it and be able to run it locally. We did that on <a rel="external" href="https://tuist.io/docs/contribution/getting-started/">Tuist's documentation</a>. We realized new contributors appreciate that a lot because they have an exact starting point.</p>
<p>When we see new contributors joining the community, we take the opportunity to engage with them and get some feedback from them to improve the documentation. We don't treat it as a static piece of the project but rather as a dynamic one that needs to evolve alongside the project and the growth of the community.</p>
<p>We'd like to invest more in it and add a tutorial that guides the user through all the features they have access to with Tuist.</p>
<h3 id="pairing-with-newcomers">Pairing with newcomers</h3>
<p>I learned that introducing people into the project by pairing with them is the most effective way to bring a diversity of ideas to the project and empower them to contribute further to the project. It's hard to explain how energizing it is seeing people contributing for the first time to a project and shipping their first feature after one or a few pairing sessions.</p>
<h3 id="build-a-modularized-architecture">Build a modularized architecture</h3>
<p>If you build the project as a monolith, familiarising yourself with the project means familiarizing yourself with the entire monolith. However, if you split that up into smaller feature domains, it's easy for new contributors to familiarise themselves with a particular area of the project and contribute to it. In the case of Tuist, we invested a lot in that from the very beginning, and it's paying off. Most of our features are modeled following a functional paradigm. Projects are loaded and then passed through a series of mappers representing different features to eventually reach the components that turn them into the Xcode project. Thanks to that, we've been able to introduce mappers that bring support for caching, generate type-safe APIs for accessing resources, or turn your project into a visual graph.</p>
<p>In the case of Tuist, we followed the <a rel="external" href="https://tuist.io/docs/building-at-scale/microfeatures/">uFeatures</a> architecture that is detailed here, and it has worked very well.</p>
<h3 id="monorepo">Monorepo</h3>
<p>One of the areas of projects that is often disregarded is documentation. Getting the documentation out of sync with the project can have a very negative impact on the experience users have with the project. To prevent that from happening in Tuist, documentation (developed as part of a <a rel="external" href="https://www.gatsbyjs.com/">Gatsby</a> website) lives alongside the source code of Tuist in the same repository. Developers are required to update it as part of their work on improvements and new features. Moreover, their changes are automatically built by <a rel="external" href="https://www.netlify.com/">Netlify</a>, which offers a preview automatically.</p>
<p>If we were not using a monorepo, building a new feature would consist of more than one PR with references between them. That leads to *"I'll open a follow-up PR with the documentation update" *which, in the end, it doesn't happen. Thanks to GitHub Actions API, it's straightforward to define which workflows should be triggered based on the file changes.</p>
<p>Every improvement new feature on Tuist must have code changes, unit tests, acceptance tests (if needed), <code>CHANGELOG</code> update, and documentation. If any of those elements is missing, the PR is not merged until it has it.</p>
<h3 id="having-a-slack-group">Having a Slack group</h3>
<p>Even though I'm trying to avoid synchronous communication lately because it makes people believe that the answers should be synchronous too, I have to say Slack played an important role in the growth of Tuist's community. Once in a while, people are joining and engaging with other users and contributors. I always take the opportunity to engage with them and ask them what brought them to Tuist. It's fantastic to hear first-hand what features from Tuist motivated them to decide to use it. Interestingly, many users like the idea that they can use Tuist to define workspaces and have excellent documentation that they can follow through.</p>
<h3 id="engage-through-twitter">Engage through Twitter</h3>
<p>Since the inception of the project, we've had a Twitter account that we use to share updates with users and people interested in the project. We share all kinds of Tuist, from new releases to tips. Having the account also allows contributors to tag Tuist whenever they proudly share their contributions to the project. Most of the community of developers that work with Xcode are on Twitter, so it's the place to be if we want them to know about Tuist and give it a try.</p>
<h3 id="believe-in-our-ideas">Believe in our ideas</h3>
<p>The Xcode community is settled on solidified ideas that have either been established by Apple or the community. This is great because you don't have the fatigue you'd have in Javascript trying to find the solution among many that work best for you, but has the downside that constrains new ideas. We've experienced that from the very beginning when people started comparing Tuist with <a rel="external" href="https://github.com/yonaskolb/xcodegen">XcodeGen</a> and <a rel="external" href="https://github.com/fastlane/fastlane">Fastlane</a>. Yes, we leverage project generation and provide commands that developers would usually define in <code>Fastfile</code>. Still, we take a different approach with different goals. It's easy to get distracted by the community opinions, but it hasn't been the case here.\ Tuist's community is not afraid of throwing new ideas and exploring them further. Thanks to that, we have features like project description helpers, module caching, and auto-generation of documentation that wouldn't otherwise be in Tuist.</p>
<h3 id="trust-people">Trust people</h3>
<p>Shopify has taught me this. One of the best values that you can have in your project/company is trust. It's a value ingrained in Shopify's culture, and wanted it to be part of Tuist's too. Since the beginning, we trusted people to do all sorts of things in the project: <em>propose and own the implementation of new features, publish new releases, provide support yo the community...</em> When you do something like that, they feel part of the project and are empowered to contribute further.</p>
<p>This has the downside of trusting people that might end up proving that they are not trustworthy. However, we are lucky that hasn't been the case in Tuist yet. If we happen to have this scenario, we'll handle it.</p>
<h3 id="recognize-people-s-work">Recognize people's work</h3>
<p>We take the time to recognize the work that people do, both privately on Slack and through mentions on Twitter. I've noticed some communities have automated through bots on Slack, but honestly, it saddens me that we have reached a point where we need to say thanks through a bot. In some cases, I've gone as far as to send the person a little gift <em>(e.g., stickers with a hand-written card and a book about open source)</em>.</p>
<h2 id="what-hasn-t-work-so-well">What hasn't work so well</h2>
<h3 id="delegating">Delegating</h3>
<p>Although there are a few maintainers and contributors, there's still a lot of that falls over me, and that sometimes results in a bottleneck when there's a lot of work in the backlog, and I don't have enough attention after work that I can devote to it.</p>
<p>I'm currently seeking domain owners, but it's hard because Tuist is a side project. They sporadically contribute to the project but can't commit to a role in the project. This is the classic issue with open source projects that we don't know how to approach either. And it concerns me because it can lead some of us to burnout and give up.</p>
<p>I recently started building a companion web app that integrates with GitHub, Discourse, and Slack and provides utilities to make this easier. For instance, one of the ideas that I have in mind is having tweet requests (TR), a way for contributors to propose tweets shared from Tuist's main account. I called this app <a rel="external" href="https://github.com/tuist/backbone">Backbone</a>. It's in a very early phase, but you can check out the project on this repository.</p>
<h3 id="vision">Vision</h3>
<p>I haven't done a good job sharing what's the vision of the project. I've been hinting it through Slack messages and posts in the community forum. Still, it's hard for someone new to the community to imagine the future of Tuist and how the current projects align with it. I guess it's normal when the project is young. There are many things yet to be defined, but as things start to mature, having a vision makes it easier for teams to align with the upcoming features.</p>
<h2 id="final-thoughts">Final thoughts</h2>
<p>Tuist is my baby 👶 - I like working on it a lot. We've built a community of users, contributors, and maintainers that make the project so unique. We have gone from merely being a project generator to a platform that provides streamlined workflows to focus on the most critical tasks. Since I started building Tuist, I was disappointed that only the big companies in the industry could access those features that most projects need to scale up <em>(e.g., easy modularization, caching)</em>. I tasked ourselves with democratizing that and making it accessible to anyone.</p>
<p>It's been three years, and the project keeps moving forward, fueled with great minds and creative people. I don't know what'll come next, but I'll indeed say that it'll help projects of any size with the challenges they face or are about to face.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The exciting adventure of building a web app</title>
      <link>https://pepicrft.me/blog/the-exciting-adventure-of-building-a-web-app/</link>
      <guid>https://pepicrft.me/blog/the-exciting-adventure-of-building-a-web-app/</guid>
      <pubDate>Fri, 02 Oct 2020 12:00:00 +0000</pubDate>
      <description>I’ve been playing lately with building a web app that complements Tuist with some features that require storing state in a server. Since I have a mobile development background, being familiar with Swift, iOS, and very recently React Native,…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’ve been playing lately with building a web app that complements <a rel="external" href="https://tuist.io">Tuist</a> with some features that require storing state in a server. Since I have a mobile development background, being familiar with Swift, iOS, and very recently React Native, I’m learning a lot along developing both a web app and a backend that exposes a GraphQL API. This blog post is me reflecting on what I’ve learned so far from the technology choices we’ve made.</p>
<p>For the backend, I chose <a rel="external" href="https://rubyonrails.org/">Rails</a>. It’s easily deployable to <a rel="external" href="https://heroku.com">Heroku</a> by simply doing a <code>git push</code>. Moreover, I can use a programming language that I love a lot, Ruby, and save a lot of time by adding dependencies that bring functionality that otherwise I’d have to implement myself - we use <a rel="external" href="https://github.com/heartcombo/devise">Devise</a> for authentication, <a rel="external" href="https://github.com/RolifyCommunity/rolify">Rolify</a> for defining roles, and <a rel="external" href="https://github.com/CanCanCommunity/cancancan">CanCanCan</a> to codify permissions when accessing models.</p>
<p>The API is GraphQL. We use the <a rel="external" href="https://github.com/rmosolgo/graphql-ruby">Ruby GraphQL gem</a> that makes it so easy to define a schema and translate it to internal business logic. Unlike standard Ruby applications that tend to put the logic in models or controllers, we are using the <a rel="external" href="https://www.toptal.com/ruby-on-rails/rails-service-objects-tutorial">service pattern</a> heavily. Every unit of business logic is defined in a service that takes the necessary input, performs the operation, and either returns a value or raises an error. That makes those units easy to reuse from other components like controllers. As a result, our models are very lean; they only contain validations and a few callbacks to automatically populate some fields.</p>
<p>I like this setup because I’m learning a lot about GraphQL. I have to say I can’t imagine myself doing REST APIs anymore. There’s one thing that I’d like to read more about, and that’s how to solve the N+1 issue when running queries because, with the GraphQL approach, it’s more likely to happen. However, it’s not an issue right now if we consider that the amount of data we are sending is minimal and the queries relatively easy.</p>
<p>We only use Rails server-side rendering solution, <a rel="external" href="https://guides.rubyonrails.org/layouts_and_rendering.html">ERB</a>, for the authentication workflow because it’s provided by Devise out of the box. For everything else, we moved the rendering to the client-side by using <a rel="external" href="https://reactjs.org/">React</a> for describing the views and <a rel="external" href="https://www.apollographql.com/">Apollo</a> to interact with the GraphQL API and cache the responses. It provides a lovely hooks-based interface that makes interacting with the API a pleasure. Moreover, with use a code generation tool that turns our GraphQL queries and mutations into Typescript code, so we don’t have to write network code at all. Thanks to that, our focus on the frontend is on what data to fetch and how to represent it.</p>
<p>Last but not least, we are styling the UI using <a rel="external" href="https://tailwindcss.com/">TailwindCSS</a>. Ever since I came across it for the first time, I’ve been using it in every project that involves styling HTML. Styles are applied through classes with semantic meaning, limiting each attribute to a limited set to value. Thanks to it, it’s easier to achieve visual consistency that otherwise wouldn’t be possible if we had to pick values for every new HTML element. And that goes without mentioning the relief of not having to think about naming classes. I got a license for <a rel="external" href="https://tailwindui.com">TailwindUI</a>, which provides a set of beautiful components built upon TailwindCSS.</p>
<p>I'm enjoying and learning a lot during the process of building this web app, and I'm taking the opportunity to learn about <strong>designing for the web</strong>: patterns, semantic hierarchies, how to create components that look clean and modern.</p>
<p>Do you have experience building web apps? If you don't mind sharing your stack, I'd love to hear about it on <a rel="external" href="https://twitter.com/pepicrft">Twitter</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Generating Typescript code from a GraphQL schema</title>
      <link>https://pepicrft.me/blog/graphql-codegen/</link>
      <guid>https://pepicrft.me/blog/graphql-codegen/</guid>
      <pubDate>Wed, 30 Sep 2020 12:00:00 +0000</pubDate>
      <description>Today, I learned about a tool called GraphQL Code Generator turns a GraphQL schema into typed models and utilities for interacting with a GraphQL API. In my case, I&#x27;m using it in a React application where I&#x27;m using Apollo as the client. Usi…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Today, I learned about a tool called <a rel="external" href="https://graphql-code-generator.com/">GraphQL Code Generator</a> turns a GraphQL schema into typed models and utilities for interacting with a GraphQL API. In my case, I'm using it in a React application where I'm using <a rel="external" href="https://www.apollographql.com/">Apollo</a> as the client. Using the tool is as simple as adding a configuration YAML at the root of the project:</p>
<pre><code>schema: schema.graphql
generates:
 app/javascript/graphql/types.ts:
 documents: &#39;app/javascript/**/*.graphql&#39;
 plugins:
 - typescript
 - typescript-operations
 - typescript-react-apollo
 config:
 reactApolloVersion: 3
</code></pre>
<p>And then running <code>yarn graphql-codegen</code>. The tools outputs a <code>.ts</code> that contains all the necessary code for interacting with the API. For example, the snippet below shows how to fetch the current user by using the generated code:</p>
<pre><code>import { useMeQuery } from &#39;graphql/types&#39;;

const MyComponent = () =&gt; {
	const { data, loading, error } = useMeQuery();
	return

{data}

;
};
</code></pre>
<p>In the past are those days with Objective-C and Swift when I had to write the client-side models manually using the API documentation. Who wants to do that again after seeing such a powerful workflow? By the way, Shopify has a similar tool that generates models in Swift &amp; Kotlin - it's called <a rel="external" href="https://github.com/shopify/syrup">Syrup</a> and it's open source.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>What I like from Ruby and Rails</title>
      <link>https://pepicrft.me/blog/what-i-like-from-ruby/</link>
      <guid>https://pepicrft.me/blog/what-i-like-from-ruby/</guid>
      <pubDate>Wed, 30 Sep 2020 12:00:00 +0000</pubDate>
      <description>The more I use Ruby and Rails, the more I like it. I’ve played with Typescript lately, and it continues to feel heavy: parenthesis and brackets everywhere, layers on indirection through tools to accommodate the Javascript to the browser or…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>The more I use Ruby and Rails, the more I like it. I’ve played with <a rel="external" href="https://www.typescriptlang.org/">Typescript</a> lately, and it continues to feel heavy: <em>parenthesis and brackets everywhere, layers on indirection through tools to accommodate the Javascript to the browser or to your preferred way of writing it.</em> It's a powerful programming language but it doesn't spark the same joy that Ruby does.</p>
<p><a rel="external" href="https://www.ruby-lang.org/">Ruby</a> is lean. There’s an interpreter in your system that you pass your code to. <a rel="external" href="https://bundler.io/">Bundler</a> ensures that the directories of your dependencies are loadable and that’s it. No <a rel="external" href="https://babeljs.io/">Babel</a>, <a rel="external" href="https://webpack.js.org/">Webpack</a>, Typescript.... It simply works. That’s what you want at the end of the day, not spending time figuring out issues or how to configure underlying tools.</p>
<p>The only reason why I’d use Javascript is to be able to describe a website using <a rel="external" href="https://reactjs.org/">React</a>’s approach to represent states and encapsulate dynamic behaviors through <a rel="external" href="https://reactjs.org/docs/hooks-intro.html">hooks</a>. That’s why I use <a rel="external" href="https://www.gatsbyjs.com/">Gatsby</a> for creating statically generated sites over alternatives like <a rel="external" href="https://jekyllrb.com/">Jekyll</a>, or the so-talked-about in the Swift community, <a rel="external" href="https://github.com/JohnSundell/Publish">Publish</a>, that would lock myself to Xcode.</p>
<p>Going back to Ruby and Rails, <strong>what do I like about it?:</strong></p>
<ul>
<li>I only need the interpreter and the dependency manager to run a project. - I can write tests in plain Ruby classes and using the language’s standard library. - Bundler’s approach to structure dependencies is more sensible and prevents the “delete node_modules” issues. - There’s less library fatigue. There are fewer options that are better tested, and that makes deciding for a dependency easier. - Being able to open a Rails console in a remote server with ActiveRecord models loaded is damn amazing. - Thanks to its dynamism, you can build plugin systems that otherwise wouldn’t be possible with statically compiled languages like Swift. - Companies like Shopify are using it at scale, and IT WORKS. Some internal tooling to support the scale leverages the dynamism of the language. - The language and its ecosystem feels more harmonious. Working with Javascript is sometimes stressful because sometimes you need to go deep into an endless rabbit hole of patches over patches.</li>
</ul>
<p>This is my preferred stack when building software these days:</p>
<ul>
<li><strong>Static websites:</strong> GatsbyJS with Typescript - <strong>CLI tools:</strong> Swift if it's for macOS environments, and Ruby otherwise. - <strong>Apps for Apple platforms:</strong> Swift (I'm planning to learn SwiftUI at some point). - <strong>Web APIs:</strong> Ruby on Rails.</li>
</ul>
<p>And you? What language/technology do you like the most and why? Let me know on Twitter <a rel="external" href="https://twitter.com/pepicrft">Twitter</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Modularization in open source projects</title>
      <link>https://pepicrft.me/blog/modularization-in-open-source/</link>
      <guid>https://pepicrft.me/blog/modularization-in-open-source/</guid>
      <pubDate>Tue, 29 Sep 2020 12:00:00 +0000</pubDate>
      <description>I recently came across a blog post from Shopify where they share how they are componentize the main Rails application into smaller pieces with clearly defined boundaries and loose coupling between them. This made me think about the uFeature…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I recently came across a blog post from Shopify where they share how they are componentize the main Rails application into smaller pieces with clearly defined boundaries and loose coupling between them. This made me think about the uFeatures architecture that I proposed back when I was iOS engineer at SoundCloud, and that I naturally inherited in Tuist.</p>
<p>Typically open source Swift CLIs are organized in two targets, one that represents the executable (i.e. <code>main.swift</code>), and another one, typically named with <code>Kit</code>, that contains all the business logic of the tool. The main motivation for doing is being able to implement tests for the business logic. However, since everything lives within the same boundaries, there’s a huge risk of the business logic growing into large group of components strongly coupled, and an architecture that is hard to reason about, maintain, and evolve. It’s a good starting point, but not a good idea long-term because it’ll compromise developers’ efficiency contributing to the codebase, and complicate onboarding new contributors to the project.</p>
<p>As I mentioned earlier, Tuist follows the uFeatures architecture. There are Tuist-agnostic targets like <code>TuistSupport</code> (inspired by Rails’ ActiveSupport) and <code>TuistTesting</code> that contain utilities that transversal to all features and core utilities: abstractions built upon foundational APIs and extensions. There’s a <code>TuistCore</code> target that contain models and business logic that is core to Tuist; for example the dependency graph and the models that represent the projects. This target also acts as a dependency inversion layer so that feature targets don’t have dependencies among them. Thanks to this, we can build a feature without having to build the others. This makes iterations cycles faster when working on individual features. Then features are organized horizontally. Most of them represent the different command namespaces that are exposes by the CLI. In some cases like automation commands, they are grouped under <code>TuistAutomation</code>. Cloud-related utilities live in <code>TuistCloud</code>. This is great for new contributors because if they want to fix or improve something in the <code>tuist build</code> command, they only need to onboard on the <code>TuistAutomation</code> target. Isn’t it great?</p>
<p>Last but not least, we have the <code>TuistKit</code> that glues all the features together into a command line interface that is hooked from the entry <code>main.swift</code> file. Commands are classes responsible for parsing the CLI arguments and throwing errors when they are incorrectly used, and delegate the business logic to <code>Service</code>. For example, there’s a <code>GenerateCommand</code> and a <code>GenerateService</code>.</p>
<p>One might think that this is over-engineering a project, but I’d certainly disagree. Defining clear boundaries in a codebase by leveraging Swift’s access levels will lead to a better architecture, which in turn, eases contributions and the addition of new features. Starting the modularization way after creating the project will be a hard challenge to undertake because the code will most likely be strongly coupled. We tried to do that at SoundCloud and, from what I know, there’s still a lot of code that lives in the main app that is hard to extract.</p>
<p>I can’t imagine Tuist being a monolith codebase these days.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Finding focus</title>
      <link>https://pepicrft.me/blog/focus/</link>
      <guid>https://pepicrft.me/blog/focus/</guid>
      <pubDate>Mon, 07 Sep 2020 12:00:00 +0000</pubDate>
      <description>One of the things that I struggle a lot with these days is having focus. Despite my several attempts to mitigate distractions, they always find their way to make it into my attention span. The result of that is that I feel stressed, and whe…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the things that I struggle a lot with these days is <strong>having focus.</strong> Despite my several attempts to mitigate distractions, they always find their way to make it into my attention span. The result of that is that I feel stressed, and when I'm stressed I can't think clearly. I feel like I'm jumping from one thing to the other without being able to do deep work in any of them.</p>
<p>One side of me thinks that the solution to this is removing those distractions. For example, applying some ideas from the minimalism movement: <em>be only in the strictly necessary Slack channels, don't spend so much time in social networks, tidy up the desktop and phone setup and remove any apps clutter</em>. That has helped, but it's not enough, I still feel distracted and often stressed.</p>
<p><strong>What else can I do?</strong> I think I have to learn to accept that distractions will always be there and that I have to become better at saying yes and no to things. I struggle with saying yes, this is important and therefore requires my attention, and no this is not relevant right now and therefore I should let it go.</p>
<p>I'm also trying to get comfortable with <strong>not reading Twitter often</strong>. I got used to being a passive consumer of everything that it's going on in the world, and that's not sustainable. My brain is exhausted with keeping up with everything that is happening. Instead, I'm teaching myself to be more offline than online, and more active than passive. For example, I'm trying to read more paper books and newspapers, or write more often in my blog or in random pieces of paper. It's very tough because my brain somehow got used to being distracted all the time, but when I get it into the mood of being offline I quite like it.</p>
<p>It'll be a long and tough re-education process but this is what I'm up to these days: <em>trying to be less stressed to have more focus and be able to do deep work again.</em></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Pairing sessions to introduce people to Tuist and open-source</title>
      <link>https://pepicrft.me/blog/pairing-tuist/</link>
      <guid>https://pepicrft.me/blog/pairing-tuist/</guid>
      <pubDate>Sat, 22 Aug 2020 12:00:00 +0000</pubDate>
      <description>I recently started having pairing sessions with developers interested in contributing to open-source; it’s something that usually intimidates people, but that becomes easier if someone guides you through the first contribution. You have a p…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I recently started having pairing sessions with developers interested in contributing to open-source; it’s something that usually intimidates people, but that becomes easier if someone guides you through the first contribution. You have a person that can answer any question you might have and that can give you an overview of the projects ad the decisions made in the past.</p>
<p>I’ve had two of them and I love it. Getting new people to contribute to Tuist brings new and more diverse ideas to the table. Moreover, they bring more energy which is the fuel for the project to move forward.</p>
<p>To make the first-time experience great, I pick a feature that I know is implementable end-to-end in one session. For example, in the session we worked on a <code>tuist lint code</code> command to lint projects’ code using SwiftLint, and in the second one we implemented a <code>tuis doc</code> to auto-generate documentation from targets.</p>
<p>Doing these sessions made me realize how great idea it was following the uFeatures architecture in Tuist. It’s very easy to add a new feature alongside the others, and build its business logic by composing existing pieces of business logic. Moreover, it’s easy to compare the existing architecture, with what they know from building iOS apps. For example, I tell them that the CLI is the App Delegate, that commands are like views, and since views should not have logic, we extract the business logic into services.</p>
<p>If you maintain an open-source project I’d strongly recommend doing something like this.</p>
<p>If you are reading this and would like to pair on the project too you can let me know and I’ll be happy to schedule a session and do a bit of hacking together.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Thinking in terms of problems</title>
      <link>https://pepicrft.me/blog/thinking-in-terms-of-problems/</link>
      <guid>https://pepicrft.me/blog/thinking-in-terms-of-problems/</guid>
      <pubDate>Mon, 03 Aug 2020 12:00:00 +0000</pubDate>
      <description>One of the things that I find the most challenging these days when building tools for developers is thinking in terms of problems . Very often Tuist&#x27;s users ask for features that they have seen in Xcode and that they&#x27;d like to see in Tuist…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the things that I find the most challenging these days when building tools for developers is <strong>thinking in terms of problems</strong>.</p>
<p>Very often Tuist's users ask for features that they have seen in Xcode and that they'd like to see in Tuist too: <em>is there support for script build phases?</em> or <em>can I run a command right after generating the project?</em> It's temptin to say that we don't support it, but that we can add support for it. However we'd end up with the same concepts and complexities that motivated them to use Tuist.</p>
<p>The approach that I take instead is aking them <strong>whys:</strong> <em>why do you need a script build phase</em> or <em>why do you need to add this build setting?</em> Thanks to this, we have been able to simplify some of Xcode's complexities like defining dependencies. If we understand what are users' motivations, we can provide them with simpler and more optimized solutions. And this is something that excites me a lot about the way we are building Tuist. It's all about helping teams with the challenges that the face. The <strong>how</strong> is up to us to figure out.</p>
<p>For example, I know that one of the challenges that teams face is <strong>slow builds.</strong> Some teams went straight into adopting build systems like Bazel or Buck because they saw that's something that worked for other companies. However, they might have not realized that the fact that it worked for them doesn't mean that it'll work for them too. This often leads to teams going too deep into rabbit holes, or what's worse, introducing layers of complexities that make projects hard to maintain and work with. If you have seen projects using CocoaPods, Carthage, and the Swift Package Manager for managing dependencies, you probably know what I'm talking about.</p>
<p>As one of the maintainers of Tuist, one of the roles that I set for myself is evangelizing this idea on how to build tools. <strong>I'd love them to think of Tuist as a product</strong>; a product that solves concrete problems that we understand well. If we want to build something that developers love to use, we need to understand why we are building it in the first place.</p>
<ul>
<li><strong>We built updates into Tuist</strong> because the existing solution for managing the installation of system dependencies <em>(e.g. Homebrew)</em> might yield non-deterministic results that cause frustrations to developers. - <strong>We built project generation</strong> because Xcode difficults defining a modular project consistently, which is crucial for sharing code and keeping build times low with architectures like uFeatures. - <strong>We are adding cache</strong> because developers use ⌘+K often and end up wasting a lot of time doing clean builds with Xcode. - <strong>We are adding automation</strong> because Fastlane's approach in practice result in large and complex <code>Fastfiles</code> that are hard to maintain. - <strong>We are synthesizing interfaces for resources</strong> to prevent runtime errors when accessing non-existing resources.</li>
</ul>
<p>If you are also working on tools for developers, I'd recommend adopting this mindset. Listen to your users, understand their needs, and build the best solution for them. Resist the temptation of building just what they ask for.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The beauty of not expecting something in return</title>
      <link>https://pepicrft.me/blog/the-beauty-of-doing-things-for-people/</link>
      <guid>https://pepicrft.me/blog/the-beauty-of-doing-things-for-people/</guid>
      <pubDate>Sat, 01 Aug 2020 12:00:00 +0000</pubDate>
      <description>Yesterday I had a thought-provoking chat with an acquaintance. He thinks that when we connect with someone is because they are a means to achieve goals - for example a business partnership. He was, in fact, trying to do that with me, and I…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Yesterday I had a thought-provoking chat with an acquaintance. He thinks that <strong>when we connect with someone is because they are a means to achieve goals</strong> - for example a business partnership. He was, in fact, trying to do that with me, and I felt really disappointed. I was invited to a casual lunch, then spent a nice afternoon with them having coffee and some drinks, until at some point he realize that I was too naive to get the game that he was trying to play.</p>
<p>I feel very uncomfortable with this attitude and the more time I spend in Germany, the more I realize that this is a cultural thing from Spain. It’s not the first time I’ve noticed this pattern: people playing the game of being your friend, but in reality treating you as a tool. It’s ok if you play the same game, but not so cool if you are out of the game.</p>
<p>After that chat, I couldn’t avoid reflecting on myself, and whether I behave the same way. I think in my case I’m more driven by the beauty of building connections with people. I think that’s the reason I’m so engaged devoting my free time to Tuist. Some people would perceive it as a waste of time, but I see it as a fulfilling thing because I get to know and talk with people that otherwise I wouldn’t have been able to. In fact, the other day I met Marek, also core contributor of Tuist, and had breakfast together in Berlin. For me, that has more value than money, success, likes, follows, stars, and any other kind of interest that people might have these days.</p>
<p>This is something that I learned from my parents and that I’ll never forget. Happiness is not about success and money, is about being healthy, and being friend of your friends.</p>
<p>What I’m learning to do though is how to distance myself from those people that either treat me or other people as means. I’ve been there. I’ve suffered a lot from it, and it’s consumed a lot of my energy. It’s easy to fall into the trap of only seeking success and feed your narcissistic desires.</p>
<p>And my random thought about people ends here while I’m somewhere in the countryside of a small town in the south of Spain called Murcia.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>A shift towards product development</title>
      <link>https://pepicrft.me/blog/shifting-towards-product/</link>
      <guid>https://pepicrft.me/blog/shifting-towards-product/</guid>
      <pubDate>Mon, 13 Jul 2020 12:00:00 +0000</pubDate>
      <description>Working on building tools for developers has helped me realize that what I like even more than coding is going through the product thinking process. That&#x27;s why I&#x27;m so engaged building Tuist , and recently Galaxy . I used to be excited by pl…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Working on building tools for developers has helped me realize that what I like even more than coding is going through the product thinking process. That's why I'm so engaged building <a rel="external" href="https://tuist.io">Tuist</a>, and recently <a rel="external" href="https://building.appgalaxy.io">Galaxy</a>.</p>
<p>I used to be excited by playing with technology itself. <em>SwiftUI?</em> Oh! I want to test that out and see how it feels. <em>A new reactive framework?</em> I want to add it to my app and see how it compares to RxSwift. However, that's no longer the case. I see technology as a mean provide something to the users and tackle problems/needs they might have. And the side effect of this shift is that I don't worry anymore about having to keep up with the latest with the latest. Instead, my focus is on users, <strong>what do they need?</strong></p>
<p>I enjoy seeing how developers work at <a rel="external" href="https://shopify.com">Shopify</a> and wondering what kind of tools we could build to help them. I also enjoy seeing developers joining <a rel="external" href="https://slack.tuist.io">Tuist's Slack group</a> and bring new interesting challenges I didn't think about before.</p>
<p>These are questions that I often ask myself:</p>
<ul>
<li>How can I make convenient inconvenient steps of developing apps with Xcode? - How should Tuist's website design be to convey the ideas behind the project? - What can I do to build a healthy and engaging community of users? - What can I do to reach those developers that still struggle to scale up their Xcode projects? - How can I solve challenging problems like reliable team signing of apps or faster builds? - How can I make sure we don't disregard little details that make the user experience using Tuist great?</li>
</ul>
<p>In a recent interview at Shopify, someone asked me what I like from my job. I did not expect that question, but I could answer it without thinking twice: <strong>I like to make complex things simple.</strong></p>
<p>That's what I've enjoyed doing at Shopify and with Tuist, and that I'll continue exploring further in the next few years.</p>
<p>By the way, I just got a book on <a rel="external" href="https://abookapart.com/products/on-web-typography">Web Typography</a> because I want to understand how different typographies influence the way a design is perceived.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Transitive React Native dependencies</title>
      <link>https://pepicrft.me/blog/react-native-transitive-dependencies/</link>
      <guid>https://pepicrft.me/blog/react-native-transitive-dependencies/</guid>
      <pubDate>Wed, 01 Jul 2020 12:00:00 +0000</pubDate>
      <description>Today I learned about how dependencies are organized by NPM and Yarn. Let&#x27;s say we have the following scenario of dependencies: A -&amp;gt; B -&amp;gt; C (3.2.1) - A -&amp;gt; C (1.2.3) Javascript dependency managers will structure the dependencies fol…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Today I learned about how dependencies are organized by NPM and Yarn. Let's say we have the following scenario of dependencies:</p>
<ul>
<li><code>A -&gt; B -&gt; C (3.2.1)</code> - <code>A -&gt; C (1.2.3)</code></li>
</ul>
<p>Javascript dependency managers will structure the dependencies following the structure below:</p>
<pre><code>node_modules/
 a/
 b/
 node_modules/
 c/ #3.2.1
 c/ # 1.2.3
</code></pre>
<p>With this scenario package managers like <a rel="external" href="https://bundler.io/">Bundler</a> or <a rel="external" href="https://swift.org/package-manager/">Swift Package Manager</a> would error, but NPM and Yarn do not. Javascript bundlers like Webpack and Metro might be able to resolve those and generate a valid Javascript code that runs successfully <em>(perhaps with a larger size than expected)</em>.</p>
<p>The problem comes when the <code>C</code> dependency is a React Native dependency that includes native code. The <a rel="external" href="https://github.com/react-native-community/cli">React Native CLI</a> uses CocoaPods and Gradle to link the native code that is distributed as part of the NPM package. In the above scenario, we can't link both versions of the <code>C</code> dependency so the CLI decides to link only the direct dependencies.</p>
<p>That means that adding <code>B</code> as a dependency of my React Native app also means that I have to add <code>C</code>. Otherwise, the app will crash when it tries to access the non-existing native code from <code>C</code>.</p>
<p>I find it very weird that the app needs to know about transitive dependencies as well, but I can't think of a better way for the CLI to solve it. I guess one thing that it could do is to extend its logic to lookup transitive dependencies as well, detect conflicts, and fail if it finds any.</p>
<p>This is just me and another misterious quirk of React Native development.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Streamlining app development</title>
      <link>https://pepicrft.me/blog/streamlining-app-development/</link>
      <guid>https://pepicrft.me/blog/streamlining-app-development/</guid>
      <pubDate>Wed, 01 Jul 2020 12:00:00 +0000</pubDate>
      <description>One thing that I noticed after Shopify &#x27;s commitment to React Native is that it foster a culture of turning ideas into mobile apps. Doing app development is no longer a thing that only mobile developers do. In hindshight, it was a good comp…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One thing that I noticed after <a rel="external" href="https://shopify.com">Shopify</a>'s commitment to <a rel="external" href="https://reactnative.dev/">React Native</a> is that it foster a culture of turning ideas into mobile apps. Doing app development is no longer a thing that only mobile developers do. In hindshight, it was a good company decision, but it presents another set of challenges that my team, React Native Foundations, will have to figure out how to overcome. Those challenges have to do with steps further down the process that are not obvious if you are not a mobile developer per-se: <em>How do I share my app with another person?</em> <em>How do I run the app on my device?</em> <em>How can I upload my app to Google Play Store and App Store?</em></p>
<p>Yesterday, while thinking about all of this, I came up with the idea of grouping phases along the process of developing apps in 4 categories:</p>
<ul>
<li><strong>Start:</strong> Starting a project happens when a team has an idea and they want to make it tangigle. Traditionally they used the <a rel="external" href="https://github.com/react-native-community/cli">React Native CLI</a>, but unfortunately, that's not enough. Creating a new project also involves setting up continuous integration and signing. What we are doing here, and we'll share more about it on the company's engineering blog, is moving the creating of projects to a web-app. Developers give their app a name, select what functionality they'd like to opt-into, and the service takes care of the rest. <em>Cool, isn't it?</em> - <strong>Develop:</strong> Once the project is created, developers need to interact with it from the terminal and their editor; they need to build, test, run, and lint their code. This is something that the React Native CLI provides, but that we are wrapping inside an internal CLI tool that minimizes the amount of configuration required by providing a more opinionated development experience. The plan is also to integrate the tool with our internal infrastructure to provide useful workflows. - <strong>Share:</strong> Once the app is in a usable state, developers usually want to share it with other people. In concrete terms, it would be something like uploading the app to Google Play Store and Testflight. However, at Shopify we have Shipit Mobile and a tophat which makes the sharing process very convenient without having to depend on a third-party provider. - <strong>Release:</strong> Last but not least, once teams feel the app is ready to be rolled out to the final users, they need to sing and upload it to Google Play Store and Apple Store Connect. This is something for which they can use our internal Shipit Mobile platform.</li>
</ul>
<p>It's exciting being able to translate the above user intents into workflows that developers can follow. In the past few years we have been building individual tools that we are slowly bringing together to provide a more cohesive experience that developers enjoy.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>WWDC&#x27;s FOMO</title>
      <link>https://pepicrft.me/blog/wwdc-fomo/</link>
      <guid>https://pepicrft.me/blog/wwdc-fomo/</guid>
      <pubDate>Thu, 25 Jun 2020 12:00:00 +0000</pubDate>
      <description>I&#x27;m avoiding opening Twitter these days. It makes me a bit anxious receiving WWDC news through people racing to be the first one to publish the clickbait-type of tweet. I used to have energy to be part of that race and not suffering from FO…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I'm avoiding opening Twitter these days. It makes me a bit anxious receiving <a rel="external" href="https://developer.apple.com/wwdc20/">WWDC</a> news through people racing to be the first one to publish the clickbait-type of tweet. I used to have energy to be part of that race and not suffering from <a rel="external" href="https://en.wikipedia.org/wiki/Fear_of_missing_out">FOMO</a>, but it's become unsustainable for me － it's not just anxiety, I feel that I'm wasting my time watching or reading about <em>"the new things"</em>, even if I don't really need them.</p>
<p>In the past few months, I've worked on turning things around in the way I consume tech. Rather than letting my excitement decide where to spend my time, I consume the content as I need it for my day-to-day tasks. For example, reading about people talking about <a rel="external" href="https://developer.apple.com/xcode/swiftui/">SwiftUI</a>, especially now around WWDC, made me feel that I should read and talk about it too. However, a more thorough thinking stopped me from doing it. I used that time to learn things that I might need for improving <a rel="external" href="https://tuist.io">Tuist</a>, which is what I enjoy working on these days.</p>
<p>It's a uncomfortable stance at first, but I believe in its long-term benefits in my mental health. Being ok with not knowing about what was presented during WWDC allows me to use my time more wisely and have a mental space that otherwise I wouldn't have.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>First thoughts on Sorbet</title>
      <link>https://pepicrft.me/blog/first-thoughts-on-sorbet/</link>
      <guid>https://pepicrft.me/blog/first-thoughts-on-sorbet/</guid>
      <pubDate>Wed, 03 Jun 2020 12:00:00 +0000</pubDate>
      <description>We started using Sorbet to add types to Galaxy&#x27;s codebase . Types are great to catch type-related issues statically, and prevent them from blowing up on production. This tiny blog-post contains my impressions using it for the first time: So…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>We started using <a rel="external" href="https://sorbet.org/">Sorbet</a> to add types to <a rel="external" href="https://twitter.com/appgalaxyio">Galaxy's codebase</a>. Types are great to catch type-related issues statically, and prevent them from blowing up on production. This tiny blog-post contains my impressions using it for the first time:</p>
<ul>
<li>Sorbet has a great adoption process. It can load your codebase, analyze it, and add <a rel="external" href="https://sorbet.org/docs/static">sigil annotations</a> to the files. - After adopting it, I was able to run <code>srb tc</code> successfully. Sorbet flags some of the files as ignored, and lets you gradually change the granularity of the type checks. That means you can adopt types at your own pace. - The typecheck (<code>srb tc</code>) command runs incredibly fast and that makes it a good candidate to be part of your local development workflows. - I don't like the syntax for adding type annotations, but I don't dislike it either. It feels a bit detached from the implementation code. For example, for annotating a method, I'd expect something along the lines of:</li>
</ul>
<pre><code>def my_method(x: String): String
end
</code></pre>
<ul>
<li>It can use runtime reflection to generate <a rel="external" href="https://sorbet.org/docs/rbi">Ruby Interface files</a> for third-party gems.</li>
</ul>
<p>Overall, the impression has been quite possitive. I don't many Ruby projects, but if I had to, I'd definitively set them up with Sorbet. If you are a Ruby developer and you haven't checked it out yet, I'd recommend you to give it a try in one of your projects.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Working on new features or tackling technical debt</title>
      <link>https://pepicrft.me/blog/new-features-technical-debt/</link>
      <guid>https://pepicrft.me/blog/new-features-technical-debt/</guid>
      <pubDate>Mon, 18 May 2020 12:00:00 +0000</pubDate>
      <description>One of the things that I find the hardest when working on Tuist these days is finding a good balance between adding new features and tackling technical debt. The most exciting part is always building new things. Indeed, yesterday I came acr…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the things that I find the hardest when working on <a rel="external" href="https://tuist.io">Tuist</a> these days is finding a good balance between adding new features and tackling technical debt. The most exciting part is always building new things. Indeed, yesterday I came across a piece of code to authenticate users with Apple Developer Portal using the internal API that <a rel="external" href="https://fastlane.tools">Fastlane</a> has always used. Part of me was eager to add that logic to Tuist for future ideas that we have in the backlog. The other part of me was thinking that I should rather spend time fixing issues and working on some technical debt tickets that are necessary before continuing the work on some features like cache. <strong>What should I do?</strong></p>
<p>I'm not sure. Most of the times I lean towards the former because I'm devoting my free time to the project and I want to work on exciting things. However, I do it thinking that developers are getting a bad impression of Tuist due to tiny flaws that shouldn't be there. I like building great user experiences, and flaws defeat any great worked we might have put into building Tuist.</p>
<p>I don't have a perfect framework on how to do this yet, so I'll continue exploring and finding a more sustainable relationship with open-source.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Add and remove footer using NSBox</title>
      <link>https://pepicrft.me/blog/adding-an-add-remove-bar/</link>
      <guid>https://pepicrft.me/blog/adding-an-add-remove-bar/</guid>
      <pubDate>Sun, 10 May 2020 12:00:00 +0000</pubDate>
      <description>If you use macOS, you have probably realized many apps have the following UI component on their settings: I had to add one of those to the settings view of Angle , and then I realized that it&#x27;s not a pre-defined component that you can drag…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If you use macOS, you have probably realized many apps have the following UI component on their settings:</p>
<p><img src="https://pepicrft.me/blog/adding-an-add-remove-bar/__GHOST_URL__/images/posts/add-remove-nsbox.png" alt="Screenshots that shows the UI controller that many apps use to add or remove items from a list" /></p>
<p>I had to add one of those to the settings view of <a rel="external" href="https://angle.dev">Angle</a>, and then I realized that it's not a pre-defined component that you can drag &amp; drop and use. <em>Does that mean we have to implement a custom view for it?</em> You are right! And that's what I ended up doing.</p>
<p>It took me several iterations until I got it right. Since I'm sure I'm not the first one coming across this need, I'll leave the code snippet here:</p>
<pre><code>import Foundation
import AppKit

class AddRemoveFooter: NSBox {

 // MARK: - Attributes

 fileprivate var addButton: NSButton!
 fileprivate var removeButton: NSButton!

 // MARK: - Init

 override init(frame frameRect: NSRect) {
 super.init(frame: frameRect)
 setup()
 }

 required init?(coder: NSCoder) {
 super.init(coder: coder)
 setup()
 }

 // MARK: - Internal

 func setAddAction(_ action: Selector?, target: AnyObject?) {
 addButton.action = action
 addButton.target = target
 }

 func setRemoveAction(_ action: Selector?, target: AnyObject?) {
 removeButton.action = action
 removeButton.target = target
 }

 // MARK: - Fileprivate

 fileprivate func setup() {
 setupStyle()
 setupButtons()
 }

 fileprivate func setupButtons() {
 contentView = NSView()
 contentView!.translatesAutoresizingMaskIntoConstraints = false
 NSLayoutConstraint.activate([
 contentView!.leadingAnchor.constraint(equalTo: self.leadingAnchor),
 contentView!.topAnchor.constraint(equalTo: self.topAnchor),
 contentView!.bottomAnchor.constraint(equalTo: self.bottomAnchor),
 contentView!.trailingAnchor.constraint(equalTo: self.trailingAnchor),
 ])

 addButton = NSButton(title: &quot;+&quot;, target: nil, action: nil)
 addButton.bezelStyle = .shadowlessSquare
 addButton.translatesAutoresizingMaskIntoConstraints = false

 removeButton = NSButton(title: &quot;﹣&quot;, target: nil, action: nil)
 removeButton.bezelStyle = .shadowlessSquare
 removeButton.translatesAutoresizingMaskIntoConstraints = false

 contentView!.addSubview(addButton)
 contentView!.addSubview(removeButton)

 NSLayoutConstraint.activate([
 addButton.leadingAnchor.constraint(equalTo: contentView!.leadingAnchor, constant: 0),
 addButton.topAnchor.constraint(equalTo: contentView!.topAnchor, constant: 0),
 addButton.bottomAnchor.constraint(equalTo: contentView!.bottomAnchor, constant: 0),
 addButton.widthAnchor.constraint(equalToConstant: 30)
 ])

 NSLayoutConstraint.activate([
 removeButton.leadingAnchor.constraint(equalTo: addButton.trailingAnchor, constant: -1),
 removeButton.topAnchor.constraint(equalTo: contentView!.topAnchor, constant: 0),
 removeButton.bottomAnchor.constraint(equalTo: contentView!.bottomAnchor, constant: 0),
 removeButton.widthAnchor.constraint(equalToConstant: 30)
 ])
 }

 fileprivate func setupStyle() {
 self.boxType = .custom
 self.alphaValue = 1
 self.borderColor = NSColor.gridColor
 self.borderType = .lineBorder
 self.borderWidth = 1
 }

}
</code></pre>
]]></content:encoded>
    </item>
    
    <item>
      <title>My first coding video on Youtube</title>
      <link>https://pepicrft.me/blog/my-first-coding-youtube/</link>
      <guid>https://pepicrft.me/blog/my-first-coding-youtube/</guid>
      <pubDate>Thu, 07 May 2020 12:00:00 +0000</pubDate>
      <description>I never thought I&#x27;d end up doing this, but today I just recorded an uploaded a video to Youtube that is meant to be the first of a series about Tuist . I recorded myself with Photo Booth, the screen and the voice using Quicktime, and edited…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I never thought I'd end up doing this, but today I just recorded an uploaded a video to Youtube that is meant to be the first of a series about <a rel="external" href="https://tuist.io">Tuist</a>. I recorded myself with Photo Booth, the screen and the voice using Quicktime, and edited it with Final Cut.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>To build, or not to build</title>
      <link>https://pepicrft.me/blog/to-build-or-not-to-build/</link>
      <guid>https://pepicrft.me/blog/to-build-or-not-to-build/</guid>
      <pubDate>Wed, 06 May 2020 12:00:00 +0000</pubDate>
      <description>These days I&#x27;m a rollercoaster of emotions ― I guess as a result of COVID19 and spending so much time at home. In particular, these days I&#x27;m thinking a lot about Tuist and my devotion for it. I really like building it, working on building s…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>These days I'm a rollercoaster of emotions ― I guess as a result of COVID19 and spending so much time at home. In particular, these days I'm thinking a lot about <a rel="external" href="https://tuist.io">Tuist</a> and my devotion for it. I really like building it, working on building something valuable for the users ― building something that is simple and more intuitive than what they'd get exposed to in Xcode. However, there's also another version of myself telling me that I'm wasting my time building something while Apple is building the Swift Package Manager and everyone is waiting for the <em>"official"</em> thing to meet everyone's needs.</p>
<p>Another negative thought that I've had lately is: <em>what if I end up wasting my time replacing feature after feature what Xcode provides?</em> That has never been the goal for Tuist, but the more I work on it, the more I realize people want to see in their projects what they see in Xcode. I don't think Tuist should do that because that'll bring the same accidental complexity Xcode ended up with. But that means a lot of energy conveying Tuist's ideas and convincing people to go down a different path. I don't like pushing ideas onto people, or at least feeling that I'm doing it. I tend to have a lot of ideas, which I codify into tools that I build, or guidelines that I publish, like the <a rel="external" href="https://tuist.io/docs/architectures/microfeatures/">microfeatures</a> one. If people like them fine ― if they don't like them, that's fine too. However, once they are onboard with some original ideas, doing shifts or doing gentle pushbacks is an uncomfortable thing for me to do. I guess it's something I'll have to learn to do, considering I've been envisioning a handful of Tuist's core ideas.</p>
<p>What I'm doing a lot these days, which helps a lot, is <strong>looking at the project from an angle of positivisim</strong>:</p>
<ul>
<li>The opportunity the project gave me to connect with very talented people with great values. - The opportunity to re-imagine existing workflows that people have accepted for years and challenge myself with simplifying them. - Building simple things in a world of complexity gives me a huge sense of accomplishment. - By building this project I'm impacting people's lives through the companies that have already adopted the project. - Having the opportunity to work on building a community and a product that people can talk about and enage with.</li>
</ul>
<p>And well, those are my thoughts about my relationship with Tuist in the morning of May 6th 2020. I love this project and I'll continue building great stuff into it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Cognitive overhead</title>
      <link>https://pepicrft.me/blog/cognitive-overhead/</link>
      <guid>https://pepicrft.me/blog/cognitive-overhead/</guid>
      <pubDate>Sat, 02 May 2020 12:00:00 +0000</pubDate>
      <description>Bootstrapping and publishing an app to the App Store is not a straightforward process. I tried to do it myself yesterday and a lazy me got stuck when I had to create signing artifacts, write automation scripts, and set up things on the App…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Bootstrapping and publishing an app to the App Store is not a straightforward process. I tried to do it myself yesterday and a lazy me got stuck when I had to create signing artifacts, write automation scripts, and set up things on the App Store Connect side.</p>
<p>It made me think that Apple is imposing, perhaps without being aware, a barrier for newcomers to iOS development. As a newcomer, you want to code a few views, and get the app on Testflight so that you and others can try it out. This is what they need to do beforehand:</p>
<ul>
<li>Understand how signing works and what are certificates and provisioning profiles. - Know how to set up the app’s build settings to sign the app successfully. - Figure out the difference between build, archive, and export an app.</li>
</ul>
<p>Many iOS developers nowadays don’t have a good grasp of how those things work because they are typically hidden behind an abstraction automation layer. Or in other words, some Fastlane files.</p>
<p>In the aim of streamlining this process making it possible to sign and upload the app without the cognitive overhead that the current process requires, I’ll try to leverage Tuist’s foundation to provide a very easy workflow:</p>
<ul>
<li>tuist init - tuist connect setup - tuist release</li>
</ul>
<p>That’s how I imagine the process to be for the users, so I’ll start designing everything from there. If you are into tools and frameworks development, I’d recommend start designing them from the experience that you’d like to provide to your developers. Otherwise, you might end up with something that is not user-friendly.</p>
<p>I’ll keep you posted on the progress that I’m making towards this.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Graphed knowledge</title>
      <link>https://pepicrft.me/blog/graphed-knowledge/</link>
      <guid>https://pepicrft.me/blog/graphed-knowledge/</guid>
      <pubDate>Sat, 02 May 2020 12:00:00 +0000</pubDate>
      <description>Most of the note-taking apps that we can find out there are designed around the same organization principle: notes are linearly organized and grouped into higher-lever abstractions that are folders. Unfortunately, our knowledge is not linea…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Most of the note-taking apps that we can find out there are designed around the same organization principle: <em>notes are linearly organized and grouped into higher-lever abstractions that are folders.</em></p>
<p>Unfortunately, our knowledge is not linear, hence using those apps to dump our brain into the cloud requires a pre-conversion, which takes you away from your root thought and perhaps the opportunity to connect it with other thoughts and ideas.</p>
<p>Some people might not find this annoying, but I certainly do. The way I think is pretty much like Internet and many things in this planet work: <em>as a network of interconnected thoughts where the close ones have something in common</em>.</p>
<p>What I would expect from an app where I can dump my thoughts an ideas is therefore a <strong>simple interface to build a graph where the nodes are units of knowledge or ideas.</strong></p>
<p>There are apps like <a rel="external" href="https://notion.so">Notion</a> that make that possible with the use of hyperlinks but the interface is fairly overwhelming. Moreover, the experience in mobile is terrible as a consequence of using a webviews.</p>
<p>There are also apps around the concept of mind-mapping. They provide a visual interface to modify the graph. Although that might be handy for short-term graphs, I don’t think it’s the most suitable interface for quick brain-dumps. I think the graph must exist, but <strong>it should be an implementation detail.</strong></p>
<p><strong>How do I imagine the app then?</strong> I imagine a native mobile app, meaning by native that it uses native primitives and patterns. Most of the time I’ll be in brain-dump mode, so as soon as I open it, I get a form. Moreover, I’d get a default list of labels and other ideas to connect them with.</p>
<p>The other mode the app would have is journey. I could get lost in the graph and revisit those notes that I left for my future self. Pretty much like Pinterest but most knowledge and ideas oriented. <em>Isn’t it beautiful?</em></p>
<p>I started building it with my wife and sister-in-law. My wife will focus on envisioning and designing the product. My sister-in-law and I will do the coding part. All the projects will be open source in the GitHub organization <a rel="external" href="https://github.com/logosapp">logosapp</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Catching crashes at launch time on Android React Native apps</title>
      <link>https://pepicrft.me/blog/catching-react-native-launch-crashes-on-android/</link>
      <guid>https://pepicrft.me/blog/catching-react-native-launch-crashes-on-android/</guid>
      <pubDate>Mon, 20 Apr 2020 12:00:00 +0000</pubDate>
      <description>One thing that I noticed about React Native is that with the setup that most teams have on CI launch-time crashes can go unnoticed . Those crashes often happen when the contract between React Native and native is not met. That scenario is n…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One thing that I noticed about React Native is that with the setup that most teams have on CI <strong>launch-time crashes can go unnoticed</strong>. Those crashes often happen when the contract between React Native and native is not met. That scenario is not caught when transpiling the Javascript or running tests on either the Javascript or the native side.</p>
<p><em>What's the consequence of that?</em> Crashes landing on master, developers frustrated because the app don't launch after rebasing changes from master, or even worse, users getting an app that doesn't launch.</p>
<p>At Shopify, I tasked myself to put a system in place to catch those errors on <strong>CI</strong>. In this short blog post, I'll share what we ended up doing.</p>
<p>Since we use the <a rel="external" href="https://firebase.google.com/docs/test-lab">Firebase test lab</a>, the contract with whatever we build needs to build a test. After a bit of reading because I'm not very familiar with Android as a platform, and in particular how testing works in it, I managed to implement the following test:</p>
<pre><code>@RunWith(AndroidJUnit4::class)
class LaunchTest {
 @get:Rule var rule = ActivityTestRule(MainActivity::class.java, true, true)
 @Test
 fun default() {
 Thread.sleep(20000)
 }
}
</code></pre>
<p>As you can see, it does nothing but just launching the main app activity and wait for 20 seconds. I first tried to subscribe to the React Native loading events but I couldn't find a public interface for that. 20 seconds should be enough time for an app to boot on an Android emulator. If the test fails because it takes more than 20 seconds to boot, there's probably something else to be looked at because that's a terrible experience for the user.</p>
<p>The test passed for an app that launched successfully, but it also passed for an app that was supposed to crash. <em>Why was that?</em></p>
<h2 id="disabling-the-developer-support-mode">Disabling the developer support mode</h2>
<p>As you might know, React Native has a developer support mode that is enabled when the app is compiled for debug. That mode prevents the app from crashing and shows a red error screen instead. Because of that, the activity was not crashing causing the test to throw a false positive. The 2 first options that I ended up discarding where the following:</p>
<ul>
<li><strong>Use the release variant:</strong> Although that could have probably worked, it's not common to run tests using a release configuration. Moreover, we'd have had to sign the app before sending it to the test lab, which is something that we didn't want to do. - <strong>Add a debugTesting variant:</strong> That extended from debug, and set a build config variable that we can read from the Application to disable the developer support mode. However, that resulted in compilation issues that bubbled up from React Native dependencies.</li>
</ul>
<p>What I did in the end was defining a custom test runner that leverages <a rel="external" href="https://developer.android.com/training/data-storage/shared-preferences">shared preferences</a> to pass some variables to the application when it's being run from the test:</p>
<pre><code>class LaunchTestRunner : AndroidJUnitRunner() {
 override fun callApplicationOnCreate(app: Application?) {
 val preferences = InstrumentationRegistry.getInstrumentation().targetContext.getSharedPreferences(&quot;TESTING&quot;, 0)
 val editor = preferences.edit()
 editor.putBoolean(&quot;IS_LAUNCH_TEST&quot;, true)
 editor.commit()
 super.callApplicationOnCreate(app)
 }
}
</code></pre>
<p>Thanks to that, we could adjust the logic in the application class, to read the value and adjust the developer mode accordingly:</p>
<pre><code>override fun getUseDeveloperSupport() = BuildConfig.DEBUG &amp;&amp; !applicationContext.getSharedPreferences(&quot;TESTING&quot;, 0).getBoolean(&quot;IS_LAUNCH_TEST&quot;, false)
</code></pre>
<p>Moreover, we had to change the testing configuration to use our custom test runner:</p>
<pre><code>testInstrumentationRunner &#39;com.shopify.app.LaunchTestRunner&#39;
</code></pre>
<p>After that, the test was passing when the app launched successfully, and failed when the application crashed.</p>
<blockquote>
<p>By default, when building a React Native app for debug it doesn't bundle the Javascript and the resources because it reads them from a local HTTP server that runs alongside the application. Since that's not what we want, before building the app, we run the following command: <code>react-native bundle --platform android --dev false --entry-file index.js --bundle-output app/android/app/src/main/assets/index.android.bundle --assets-dest app/android/app/src/main/res --config metro.config.js</code></p>
</blockquote>
<p>In a follow-up blog post I'll talk about how we achieve a similar thing on iOS. In that case, we didn't have to implement an XCTest test; instead, we added a Rake task that built the app and attempted to launch it on an iOS simulator using the <code>simctl</code> tool.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Control and innovation</title>
      <link>https://pepicrft.me/blog/control-innovation/</link>
      <guid>https://pepicrft.me/blog/control-innovation/</guid>
      <pubDate>Fri, 17 Apr 2020 12:00:00 +0000</pubDate>
      <description>I saw a tweet this morning where the author was hoping for Apple to announce a new product in the domain of CI. Apple acquired BuddyBuild two years ago and since then, they seem to have working on something secret that they&#x27;ll release at so…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I saw a <a rel="external" href="https://twitter.com/kikeenrique/status/1250897617686614016?s=20">tweet</a> this morning where the author was hoping for Apple to announce a new product in the domain of CI. Apple acquired <a rel="external" href="https://www.buddybuild.com/">BuddyBuild</a> two years ago and since then, they seem to have working on something secret that they'll release at some point ― perhaps a CI platform that integrates with Xcode.</p>
<p>I'm not sure why, but that made me think about Apple's <strong>obsession for control and limitation</strong> of the environment and its tools. Unlike more open ecosystems and communities like Javascript or Ruby, where developers don't feel constrained to innovate and buid solutions for the problems and challenges that they encounter, in Apple's, many people dream with that innovation only coming from Apple.</p>
<p>People might critize communities like Javascript or Ruby's and find them overwhelming, but they are so open that the innovation comes in any shape: <em>tooling, libraries, paradigms...</em> React is a good example. With all the support from the community we have seen its ecosystem maturing very quickly. Building stating sites with <a rel="external" href="https://www.gatsbyjs.org/">Gatsby</a>, or building web apps that follow the JAMstack philosophy with <a rel="external" href="https://redwoodjs.com/">RedwoodJS</a> is mind-blowing. On the Apple land, we just saw <a rel="external" href="https://developer.apple.com/xcode/swiftui/">SwiftUI</a> last year. I haven't tried myself, but it seems that it's still not mature enough, and since the framework is close-sourced, radars is the only contribution that you can do to it. That, and doing a bit of evangelization in the shape of talks, posts, and books.</p>
<p>Until Apple relaxes its closeness and obsession for control, I doubt we'll see <a rel="external" href="https://vapor.codes/">Vapor</a> taking off, more companies adopting <a rel="external" href="https://bazel.build/">Bazel</a> because it integrates seamlessly into Xcode, or Swift being used more broadly, not just for writing apps or tools for those apps.</p>
<p>I'll continue using Swift and building things for the Apple ecosystem because I have a emotional connection to it, but I sometimes wish building Tuist didn't feel like fighting the ecosystem, and rather like building an extension for it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Anxiety-free working</title>
      <link>https://pepicrft.me/blog/anxiety-free-working/</link>
      <guid>https://pepicrft.me/blog/anxiety-free-working/</guid>
      <pubDate>Wed, 15 Apr 2020 12:00:00 +0000</pubDate>
      <description>I feel it really hard to work these days without feeling anxious. A Slack ping here, an interesting tweet there, some emails to answer, articles to read that are piling up... With that set up, not only I can&#x27;t concentrate, but I deliver poo…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I feel it really hard to work these days without feeling anxious. A Slack ping here, an interesting tweet there, some emails to answer, articles to read that are piling up... With that set up, not only I can't concentrate, but I deliver poorly. All my mental energy is disseminated and I look like a zombie at the end of the day.</p>
<p>To fix that, I've done the following adjustments to the way I approach spending time with computers:</p>
<ul>
<li>I only check social networks when I'm mentally exhausted <em>(i.e. at the end of the day).</em> - If I think there's something worth sharing, I use <a rel="external" href="https://buffer.com">Buffer</a> instead of openning Twitter and be trapped by the unceasing stream of new things. - I use to asynchronous communications over real-time ones like Slack. I'm moving Tuist's discussions to GitHub issues and a <a rel="external" href="https://community.tuist.io">community</a> forum. At work, we are trying to use GitHub issues and documents more. - I reduced the Slack groups I'm part of, especially the community ones. I'm already doing my part of helping the community by building <a rel="external" href="https://tuist.io">Tuist</a>. - I time-box the time that I dedicate to certain tasks like reading email, answering messages on Slack, or doing open source. - I minimize my go-to programming languages and tools and be ok with not keeping up with updates. I became a goal-oriented engineer rather than technology-enthusiastic. Swift and Ruby are just technologies that enable me to achieve certain goals.</li>
</ul>
<p>From all of the above, the ones that have helped me the most are <strong>being ok with not keeping up with things</strong>, and <strong>moving away from quick and unceassing communications</strong> that happen on platforms like Twitter, or Slack.</p>
<p>I'm way more relieved now, and I feel I can deliver much better things without feeling anxious at all.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Keeping it simple</title>
      <link>https://pepicrft.me/blog/keeping-it-simple/</link>
      <guid>https://pepicrft.me/blog/keeping-it-simple/</guid>
      <pubDate>Sat, 11 Apr 2020 12:00:00 +0000</pubDate>
      <description>If there&#x27;s something that characterizes my approach to problem solving these days is simplicity. Working on acquiring a product mind-set in the last 2 years has helped me realize how obsessed we, developers, are with configurability. Why is…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If there's something that characterizes my approach to problem solving these days is <strong>simplicity.</strong> Working on acquiring a product mind-set in the last 2 years has helped me realize how obsessed we, developers, are with configurability. <em>Why is that?</em> I think it has to do with trying to model the world as it is with software ― and the world is complex. We want to have flags, arguments, and options to model all possible scenarios we might encounter; we want every single detail of our software to be configurable. I've seen developers anticipating to those scenarios too: <em>what if teams want to do X</em>, <em>what if we want this feature to behave differently</em>,...</p>
<p>This is a constant when working on <a rel="external" href="https://tuist.io">Tuist</a>. In this case, developers often ask for features that mimic <strong>Xcode's complexity</strong>, and that's precisely the reason why we are providing Tuist as an abstraction: <em>to conceptually compress Xcode's complexities and initriciacies.</em> My first thought is often: <em>if we add X, Y, and Z, which is what Xcode provides, we'll end up with the same thing, but in a different language.</em> Teams might need that, and that's fine, but unfortunately, that's not what Tuist is amining for. We aim to <strong>challenge projects' complexity and nudge them to be simpler.</strong> The adoption of Tuist might require simplification on the user side, but believe me, both your team and Xcode will be so thankful for that.</p>
<p>Something that works for me to challenge developers' requests is asking them <strong>whys</strong> until I reach their core motivation or root problem. They typically come with a solution in mind, without really understanding what they need that for ― they haven't spent time going through those whys themselves.</p>
<p>I'm aware that this mind-set when developing a product like Tuist might suppose not pleasing everyone ― but it's fine because that's not our goal. The goal is to remain small and close to our gist of keeping things simple. That's what makes users of Tuist love it, and most importantly, enjoy scaling up their projects.</p>
<p>If you are a developer working close to product, whether a product is a tool for developers, or a user-facing app, I'd encurage you to work on having this mindset of understanding the motivations behind features, and striving to keep them simple.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Diving into Nix</title>
      <link>https://pepicrft.me/blog/nix/</link>
      <guid>https://pepicrft.me/blog/nix/</guid>
      <pubDate>Thu, 09 Apr 2020 12:00:00 +0000</pubDate>
      <description>At Shopify , the dev-infra team has been working on using Nix from one of our internal tools, dev . The tool is responsible for setting up the developers&#x27; environment, as well as providing a standard CLI for automation for projects like Rai…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>At <a rel="external" href="https://shopify.com">Shopify</a>, the dev-infra team has been working on using <a rel="external" href="https://nixos.org/nix/">Nix</a> from one of our internal tools, <code>dev</code>. The tool is responsible for setting up the developers' environment, as well as providing a standard CLI for automation for projects like Rails, iOS, or Android apps. As you probably know, setting things up in a developer's environment is wild — you don't know what to expect. It's hard to set things up deterministically, and reproduce one environment into another. <a rel="external" href="https://brew.sh">Homebrew</a> for instance, tries to do as best as it can, but since it treats the environment as a global space in which dumping things, alike a singleton class that <em>anyone</em> can modify, that often results in hard-to-debug errors.</p>
<p>The first time that I heard about Nix was on <a rel="external" href="https://medium.com/pinterest-engineering/continuous-integration-for-ios-with-nix-and-buildkite-ef5b36c5292d">this blog post</a> from Pinterest, but it didn't catch my attention until now. I started reading about it and watching some internal videos that <a rel="external" href="https://twitter.com/burkelibbey">Burke</a> is creating to evangelize the idea. The more I read about it, the more amazed I am with the idea. These are the ideas that struck me:</p>
<ul>
<li>Environments are defined in directories with symlinks to other directories that represent nodes of a dependency graph. Each node has a unique hash based on its content, the input, and the output. - Every modification of your environment is tracked and can be rolled-back akin to how <a rel="external" href="https://git-scm.com/">Git</a> works. - If one of those nodes needs to be built locally, the output artifacts can be shared remotely and pulled from other environments to speed things up. - The dependency graph extends to components that are very core to the system. That prevents, among others, that macOS upgrades break the user environment. - You can pull and run a package without polluting the environment. - Nix provides its own expressive language that prevents developers from doing operations that might introduce side effects.</li>
</ul>
<p>I'll keep reading about it. I think <a rel="external" href="https://tuist.io">Tuist</a> could benefit from some of its ideas. For example, the idea of minimizing the IO and side effects, as well as the way it models the dependency graph.</p>
<p>I hope everyone is safe in these difficult times. Stay at home!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>We need more crafters</title>
      <link>https://pepicrft.me/blog/we-need-more-crafters/</link>
      <guid>https://pepicrft.me/blog/we-need-more-crafters/</guid>
      <pubDate>Sat, 28 Mar 2020 12:00:00 +0000</pubDate>
      <description>I think the technology industry needs more crafters. People that have a genuine and lasting love for what they do . Our industry is filling with people that are constantly trying to catch the latest trend, or create the newest product&#x2F;proje…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I think the technology industry needs more crafters. People that have a <strong>genuine and lasting love for what they do</strong>.</p>
<p>Our industry is filling with people that are constantly trying to catch the latest trend, or create the newest product/project so that people have something to talk about. In most cases, they don't have a genuine interest in the domain, they are just feeding their narcisistic needs. There's a positive thing on that — we are constantly exploring new territories that otherwise would remain unexplored. However, there are important drawbacks:</p>
<ul>
<li>Since we don't have interest in the problems' domain, we never engage with our craft because we are constantly thinking about what's next. - It creates anxiety — The anxiety of figuring out how to stay relevant and catching up with everything. - It distances us from the recepients of our craft, who just become a mean to feed our egos.</li>
</ul>
<p>It's easy to follow that path. I've done that myself, and I don't like it. I prefer to keep my feet on the ground, and nurture the love for my craft. Outside the context of of Shopify, my craft is <a rel="external" href="https://tuist.io"><strong>Tuist</strong></a>.</p>
<p>There are a handful of people in the community that I admire for their lasting and deep love for the craft that they do. Off the top of my head, I really admire's <a rel="external" href="https://twitter.com/brentsimmons">Brent Simmons's</a> ingrained passion for RSS readers and <a rel="external" href="https://ranchero.com/netnewswire/">NetNewsWire</a>, and <a rel="external" href="https://twitter.com/dhh">DHH</a> <em>(and <a rel="external" href="https://basecamp.com">Basecamp</a>)</em> and their passion for building Rails and helping teams collaborate. There are probably more, but those are the ones that popped in my mind. They have seen lots of shiny RSS readers being created, and many better-than-Rails frameworks, but there they are. After many years in the industry, they continue doing what they like the most.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>A better signing experience in Xcode</title>
      <link>https://pepicrft.me/blog/signing-tuist/</link>
      <guid>https://pepicrft.me/blog/signing-tuist/</guid>
      <pubDate>Sun, 08 Mar 2020 12:00:00 +0000</pubDate>
      <description>A few days ago, Marek decided to take on a proposal that I made for Tuist a while ago, management of certificates and provisioning profiles . As it happened with the definition of dependencies, dealing with certificates and provisioning pro…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>A few days ago, <a rel="external" href="https://twitter.com/marekfort">Marek</a> decided to take on a proposal that I made for Tuist a while ago, <strong>management of certificates and provisioning profiles</strong>.</p>
<p>As it happened with the definition of dependencies, dealing with certificates and provisioning profiles is something that annoyed me a lot. It takes time to understand all the concepts and get it right right, and it can take even longer to understand issues when they arise. In my experience, there's usually a go-to person in each team to help debug and solve signing issues when they arise. That's pretty bad. Configuring signing should be straightforward and issues should be easier to debug and fix.</p>
<p><a rel="external" href="https://docs.fastlane.tools/actions/match">Fastlane</a> helped with automating the generation of the certificates and the profiles but doesn't prevent developers from setting the wrong settings to their projects.</p>
<p><strong>How can Tuist do things better?</strong> It can make certificates and profiles an implementation detail of signing; like we did with linking build phases being an implementation detail of dependencies. Those are part of the repository and encrypted using a team's key that will need to be present in the local and CI environments.</p>
<p>At <strong>project generation time</strong>, Tuist will decrypt and validate them, and configure both, the environment and the project, for the signing to work. If something is missing or invalid, we'll fail early to prevent developers from facing signing issues in Xcode.</p>
<p>Moreover, to eliminate the need to configure anything on the user end, we'll establish the following naming convention:</p>
<ul>
<li><strong>Certificates:</strong> Configuration.p12 <em>(e.g Debug.p12)</em> - <strong>Profiles:</strong> Target.Configuration.mobileprovision <em>(e.g MyApp.Debug.mobileprovision)</em></li>
</ul>
<p>Thanks to that convention, the configuration will be zero, and Tuist will know which certificates and profiles to take from <code>Tuist/Signing</code>, for each of the targets that are part of the dependency graph.</p>
<p>Project generation is a powerful tool to help teams with their scaling issues yet we are just starting to see its real benefits. Check out <a rel="external" href="https://tuist.io/docs/usage/getting-started/">the docs</a> to know how to adopt it in your projects.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>From iOS engineer to a T-profiled techie</title>
      <link>https://pepicrft.me/blog/t-profile/</link>
      <guid>https://pepicrft.me/blog/t-profile/</guid>
      <pubDate>Fri, 06 Mar 2020 12:00:00 +0000</pubDate>
      <description>One of the things that excited me the most about the opportunity to join Shopify back in 2018 was the opportunity to grow and learn from the challenges and the talent of the company. When I joined, my background was mainly iOS development w…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the things that excited me the most about the opportunity to join <a rel="external" href="https://shopify.com">Shopify</a> back in 2018 was the opportunity to grow and learn from the challenges and the talent of the company. When I joined, my background was mainly iOS development with a bit of excitement for tooling. I was very comfortable doing Swift; I knew the common SDKs, kept up with the latest updates, and read every trendy article that came out. I loved the platform <em>(and I still do)</em>, but there was a ingrained curiosity in me that was pushing me for exploring unknown.</p>
<p>Even though curiosity was knocking the door, something was holding me back. I had to answer the question of whether I wanted to be a Swift specialist, or broaden my skills, not just to include other programming languages, but also to areas like design, product, or even people management. I ended up pursuing the latter: <em>adventuring myself into trying new things.</em></p>
<p>At work I learned Ruby and Ruby on Rails. I learned how to work in large and distributed organizations and support them with tooling. I learned how to communicate better and how to build a trust battery with other people. I’m also learning how to manage people and how to help them grow and have impact in their careers. In my spare time, I learned React and Typescript and played with Gatsby and theme-ui, which by the way, I fell in love with them both. I learned how to use Swift to implement a command line tool and how to build a great product that cares about the user experience. I learned about design by designing the brand and the website of Tuist. Also with Tuist, I learned how to build a healthy community of users and contributors that engage with challenging problems and that are thrilled to help others.</p>
<p>In hindsight, moving on from the label "iOS Developer" is one of the best things I could have done in my career. These days I’m not the best in any of those areas, nor I want to be. However, I know them well enough that I can explore challenges and ideas from many angles by myself. I feel empowered to build things, and I guess that’s where my motivation for building <a rel="external" href="https://tuist.io">Tuist</a> comes from. It’s not just about the challenge, which motivates me a lot, but having the opportunity to think of Tuist as a product, as a community, as a philosophy of working. It’s incredibly exciting!</p>
<p>Another advantage of moving on is being able to come up with better and more creative solutions as a result of being more resourceful. If I had remained as an iOS developer, I’d probably tried to push Swift to places where the language is not the most suitable option. For example, I’d have tried to use it to build my website, or implement a web service with it. You can definitively do it, but after learning about other options, I can choose the ones that I think are a a better fit for what I’m trying to do. For instance, I have to build a website, I’d use something like <a rel="external" href="https://www.gatsbyjs.org">GatsbyJS</a> or <a rel="external" href="https://nextjs.org">NextJS</a> and if I had to build a web service, I’d use Rails. Swift was a good option for Tuist to encourage contributions, and I’d continue to use it for building apps.</p>
<p>Being a T-profiled techie <em>(I originally wrote it as engineer but I that’s a constraining label that I’m trying not to use anymore)</em> might feel exhausting because you are constantly pushing yourself outside your comfort zone, but it’s definitively worth it. It’s the same as learning a new language; it helps you consolidate the languages that you know, and find interesting connections from which you can learn a lot.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Generation of Swift interfaces to access resources</title>
      <link>https://pepicrft.me/blog/generate-swift-interfaces/</link>
      <guid>https://pepicrft.me/blog/generate-swift-interfaces/</guid>
      <pubDate>Tue, 25 Feb 2020 12:00:00 +0000</pubDate>
      <description>Many of you might already be familiar with SwiftGen ; a tool that generates Swift code to access resources in a type-safe manner. Having a type-safe API is something that Android developers have had for a long time, and that Apple has never…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Many of you might already be familiar with <a rel="external" href="https://github.com/SwiftGen/SwiftGen">SwiftGen</a>; a tool that generates Swift code to access resources in a type-safe manner. Having a type-safe API is something that Android developers have had for a long time, and that Apple has never added to Xcode.</p>
<p>I think it’s a wonderful idea because we delegate to the compiler the task of checking whether a resource exists or not. It prevents apps from crashing at runtime, and thus improves the stability of the apps.</p>
<p><em>Why am I bringing this up?</em> Because I like the idea so much that I’m pondering integrating SwiftGen into <a rel="external" href="https://tuist.io">Tuist</a>. SwiftGen suggests adding a new build phase to every target for which we’d like to generate the interfaces. However, I’m planning to do it differently. If users of Tuist enable this feature, the interfaces will be generated at the project generation time. The generated project will already contain the resources and their interfaces ready to be bundled and compiled.</p>
<p>I might give this a shot later this week. I had a look at the SwiftGen project and it exports a target that we can link against to use its API. Moreover, the license is compatible with Tuist’s so there shouldn’t be any issue. I’m planning to set up this first integration defaulting to a conventional format for the interfaces and maybe revisit this in the future to add a certain level of configurability.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>A standard CLI for Xcode projects</title>
      <link>https://pepicrft.me/blog/standard-cli-for-xcode-projects/</link>
      <guid>https://pepicrft.me/blog/standard-cli-for-xcode-projects/</guid>
      <pubDate>Wed, 19 Feb 2020 12:00:00 +0000</pubDate>
      <description>There’s an idea that I’d love Tuist to move towards: provide a CLI that is standard across all the projects defined using Tuist. This is not a new idea; we can see it in frameworks like Rails that thanks to being opinionated about the struc…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There’s an idea that I’d love <a rel="external" href="https://tuist.io">Tuist</a> to move towards: provide a CLI that is standard across all the projects defined using Tuist. This is not a new idea; we can see it in frameworks like <a rel="external" href="https://rubyonrails.org">Rails</a> that thanks to being opinionated about the structure of the projects they can be opinionated about the CLI that users interact with most of the time. We can also see it in the <a rel="external" href="https://swift.org/package-manager/">Swift Package Managers</a>, which is also opinionated about the structure of the packages.</p>
<p>What I find beautiful about this idea are <strong>2 things</strong>:</p>
<ul>
<li>Developers don’t need to maintain a translation layer like Fastlane that maps intents to calls to Apple tools. This often becomes a common source of issues and complexity in projects. - They can learn a concise list of commands that they can use to interact with any project defined with Tuist.</li>
</ul>
<p>My motivation for building new features into Tuist usually comes from trying to iron out some inconveniences, or creating new workflows as I'd like them to be. For instance, implementing project generation in Tuist embracing Swift as an interface language and abstracting the definition of dependencies was motivated by the fact that having more Xcode projects at <a rel="external" href="https://soundcloud.com">SoundCloud</a> was becoming painful and error-prone. I implemented an API for describing dependencies that was simple and understandable by anyone.</p>
<p>It's a similar scenario when it comes to automation. The industry accepted <a rel="external" href="https://fastlane.tools">Fastlane</a> as the go-to solution to define a CLI for projects. It does a really good job, and we owe a lot to it, but I used at scale results in a lot of duplication and complexity spread across Fastfiles that no one wants to maintain. For that reason, I think Tuist could go one step further and make things simpler leveraging project generation and the foundation that we have built. The way I picture myself as developer working in a large project is the following:</p>
<blockquote>
<p>I'd cd into the directory that contains the project that I plan to work on. <code>tuist focus</code> would give me an Xcode project that I can use to edit the code, and I can use <code>tuist build</code>, <code>tuist test</code>, and <code>tuist lint</code> to make sure that the code does what's supposed to do and that it follows the styling conventions.</p>
</blockquote>
<p>As simple as that. I can go to any directory that contains a <code>Project.swift</code> file, and run any of those commands knowing that Tuist will know how to proceed.</p>
<p>I'm so excited for this that today I put the <a rel="external" href="https://github.com/tuist/tuist/pull/1019">first stone</a> towards this vision.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Evolving Tuist&#x27;s architecture</title>
      <link>https://pepicrft.me/blog/evolving-tuists-architecture/</link>
      <guid>https://pepicrft.me/blog/evolving-tuists-architecture/</guid>
      <pubDate>Mon, 10 Feb 2020 12:00:00 +0000</pubDate>
      <description>I&#x27;m flying back from Tokyo and took the opportunity to code a bit on Tuist. Since I don&#x27;t have Internet connection to get distracted with, I decided to work on something that doesn&#x27;t require Internet connection: improving the project archit…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I'm flying back from Tokyo and took the opportunity to code a bit on Tuist. Since I don't have Internet connection to get distracted with, I decided to work on something that doesn't require Internet connection: <strong>improving the project architecture</strong>.</p>
<p>I'm quite happy with how the project has evolved so far with the help of everyone involved in the project. The slow yet steady pace of adoption in the community made it easy to keep en eye on the project's architecture while introducing new features. Doing so is crucial to have a <strong>healthy codebase that has little technical debt and allows adding new features easily.</strong></p>
<p>Over the project's lifetime, we moved from a single-target project to a modularized one. Perhaps because I was heavily influenced by my work at <a rel="external" href="https://soundcloud.com">SoundCloud</a>, where I introduced the idea of <a rel="external" href="https://github.com/tuist/microfeatures-guidelines">Microfeatures</a>. Although the main goal of modularizing the codebase was to improve developers' productivity, it allowed identifying and defining different areas of responsibility that were represented as frameworks. Teams worked independently but highly aligned thanks to shared utilities that were core to SoundCloud business domain.</p>
<p>I believe the benefits of having a modularized architecture for Tuist are the following:</p>
<ul>
<li><strong>Have owners and experts in different domains</strong> of the code base. For instance, there can be an owner of the generation of Xcode projects. They'll make sure that manifests are properly translated into Xcode projects, and that the generation of Xcode projects is fast. - <strong>Ease first-time contributions</strong> because new contributors don't have to get familiar with the whole codebase, just the domain that they are interested in contributing to. - <strong>Better design</strong> because adding a new feature is not just adding a internal class that I can depend on from other classes. It requires defining where the feature should be implemented <em>(i.e. target)</em>, how the feature interacts with others, and what will be its public interface. At least to me, doing this type of engineering work is beautiful.</li>
</ul>
<p>So far the areas of responsibilities, and therefore frameworks, that we have identified in the project are the following:</p>
<ul>
<li><strong>Support:</strong> Contains Tuist-agnostic utilities. For example, there's a utility for interacting with the file system, <code>FileHandler</code>, or another one to output information to the user, <code>Printer</code>. - <strong>Support testing:</strong> Contains Tuist-agnostic utilities for testing purposes. It also includes XCTest extensions for tests to use. - <strong>Core:</strong> It contains utilities and models that are core to the business logic of Tuist. For example, the <code>Project</code> model is ubiqutuous to all the features of the project and therefore needs to be defined here. - <strong>Loader:</strong> Contains the logic responsible for reading the manifest files and generating an in-memory dependency graph that is used latere on to generate the Xcode projects. - <strong>Generator:</strong> Contains the logic that translates the in-memory graph into valid Xcode projects that developers can use to work on their features.</li>
</ul>
<p>All targets have an associated <code>-Testing</code> targets, which provide <strong>test data</strong> and <strong>mocks</strong> to the targets that depend on them. This is another idea that I <em>"stole"</em> from my time at SoundCloud and that I really like because you are facilitating future testing work. Writing a test and realizing there are mocks for our test subject dependencies already defined is priceless. Some people prefer to use tools like Sourcery for this type of work, but I'm a bit old-school here.</p>
<p>There'll soon be another domain with its own target, <strong>Linting</strong>, whose logic is currently implemented as part of Loader. Linters make sure that the project is in a valid state. Otherwise, they output errors and warnings to the users, and depending of the severity, they fail the project generation. The goal here is to save developers some time debugging issues in their projects.</p>
<p>In a <strong>nutshell</strong>, we can summarize Tuist's project generation as a sequence of <strong>4 steps:</strong></p>
<ol>
<li>Loading 2. Linting 3. Transformation 4. Generation</li>
</ol>
<p>If we translate that to code, we might be</p>
<pre><code>func generarte(load: (AbsolutePath) throws -&gt; Graph,
 lint: (Graph) throws -&gt; [LintingIssue],
 transform: [(Graph) throws -&gt; Graph] = [],
 generate: (Graph) throws -&gt; Void)
</code></pre>
<p>Beautiful, isn't it? We are not there yet but that's the idea. Once we get there, I'd love to explore the idea of allowing developers to define their own transformations, either locally, or imported from third-party packages defined as Swift packages.</p>
<p>There could be a transformation that adds a <a rel="external" href="https://github.com/realm/SwiftLint">Swiftlint</a> to all the targets:</p>
<pre><code>final class SwiftLintTransformer: TuistTransformer {
 func transform(graph: Graph) throws -&gt; Graph {
 // Traverse projects&#39; targets and add the build phase
 }
}
</code></pre>
<p>Architecting code and projects is a pleasing exercise, and I love it!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Seeking inmutability</title>
      <link>https://pepicrft.me/blog/path-to-inmutability/</link>
      <guid>https://pepicrft.me/blog/path-to-inmutability/</guid>
      <pubDate>Tue, 07 Jan 2020 12:00:00 +0000</pubDate>
      <description>I recently opened up this PR on Tuist that turns models that represent the projects into structs. For some reason, which I don&#x27;t remember, I had the not-so-brilliant idea of defining them as classes. While that has been working fine, they d…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I recently opened up <a rel="external" href="https://github.com/tuist/tuist/pull/870">this PR</a> on Tuist that turns models that represent the projects into structs. For some reason, which I don't remember, I had the not-so-brilliant idea of defining them as classes. While that has been working fine, they don't really need to be classes and moreover, they'll cause troubles as we start optimizing things by introducing parallelization.</p>
<p>Classes <strong>don't prevent mutation</strong>, so as soon as we add threads to the mix, we might start seeing some race conditions of crashes derived from the mutation of instances from different threads.</p>
<p>Interestingly, as part of this work I found out that we were <a rel="external" href="https://github.com/tuist/tuist/pull/870/files#diff-4aba63b3478b390c4fe138b58e4d4b67L111">mutating</a> an instance of <code>Target</code> to change its <code>infoPlist</code> attribute to point to an <code>Info.plist</code> generated by Tuist. After turning the models into structs, Xcode complained about that not being possible. What I ended up doing was changing the code implementation to rather create a copy of the target with that attribute mutated.</p>
<p>Next week we <a rel="external" href="https://github.com/tuist/tuist/issues/869">are meeting</a> to sync up on the state of the project, and optimization is one of the topics. I can't wait to see this area being explored further. Since the inception of the project this is an area that we have disregarded. Perhaps to avoid the introduction of <a rel="external" href="http://wiki.c2.com/?PrematureOptimization"><em>premature optimization</em></a>.</p>
<p>Two years later, and after some large projects started to use Tuist, we realized there's a lot to improve so feel it's now the right time to tackle that problem.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Social anxiety</title>
      <link>https://pepicrft.me/blog/social-anxiety/</link>
      <guid>https://pepicrft.me/blog/social-anxiety/</guid>
      <pubDate>Thu, 02 Jan 2020 12:00:00 +0000</pubDate>
      <description>I keep falling into the same trap over and over: believing that I should be active in social media to be connected to others and have a prosper professional future. My relationship with them is a rollercoaster. There are times when I neglec…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I keep falling into the same trap over and over: believing that I should be active in social media to be connected to others and have a prosper professional future. My relationship with them is a rollercoaster. There are times when I neglect using them, and there are other times when I’m very active on them.</p>
<p>Not using them feels great; I am more present and sleep better. I don’t have to think about what creative bits to share next on Twitter, what photo to take to amaze people around me, or what project to work on to create some hype and make developers think that I do cool stuff too. I have the mental space to listen to myself, to know what I want, how I feel, and to look after important things such as the health and the family, which I tend to disregard when I’m on social media.</p>
<p>When I’m on social media, I feel anxious. I feel anxious when I see people traveling and having fun when I’m just “enjoying” a rainy day in Berlin. I also feel anxious when I see developers on Twitter talking and sharing things that I don’t have the bandwidth to play with. I feel all those things happening so fast, waste the scarce of attention and energy that is left for me after 8 hours at work. I don’t sleep well. I go to sleep with the phone and wake up with it too. Every moment of boredom is filled with infinite scrolling in timelines that bring me more anxiety.</p>
<p>I’ve tried to have a healthy relationship with social networks, but I can’t. I have a personality that doesn’t make that easy, and social networks, whose business models rely on exploiting our vulnerabilities and using our attention, doesn’t help.</p>
<p>For that reason, I’m starting 2020 by taking another break. Hopefully, an I-don’t-know-the-end type of break. I have my personal website where I can share my thoughts, collect the stuff that I find useful on the Internet, and write down the books that I read. It’s my own space on the Internet where I don’t feel the itch of social validation. It won’t be easy, mainly because of the sense of loneliness that the break creates. Still, I’m hopeful that this time I’ll overcome the difficulties and have a healthier life without social networks.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Wrapping up 2019</title>
      <link>https://pepicrft.me/blog/wrapping-up-2019/</link>
      <guid>https://pepicrft.me/blog/wrapping-up-2019/</guid>
      <pubDate>Mon, 30 Dec 2019 12:00:00 +0000</pubDate>
      <description>Following every year&#x27;s tradition, I&#x27;m writing a wrap-up post for this year, 2019. 2019 has been the year when María José and I got married . I proposed to her in January and celebrated the wedding in September. I have no words to describe h…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Following every year's tradition, I'm writing a wrap-up post for this year, 2019.</p>
<p>2019 has been the year when María José and I <strong>got married</strong>. I proposed to her in January and celebrated the wedding in September. I have no words to describe how happy we were that day. I won't forget the moment I was standing waiting for María José to come and seeing both families and friends from Spain and Berlin celebrating such a beautiful moment with us.</p>
<p>2019 was also the year that María José and I decided to <strong>invest in a property</strong> in Berlin. Since we had some savings to spend, and the real state market is growing fast in Berlin, we thought it'd be a good idea. I was a bit hesitant at the beginning because I pictured ourselves being tied to a bank forever. Still, we were quite optimistic that things would turn out well, and that it would become our source of income when we get retired <em>(we don't know if there'll be public pension by the time that happens)</em>. We haven't got the keys yet, but we have already started working with an interior designer that helps us materialize our ideas for the apartment. We'll move in between June and July next year. That means we'll stay in Berlin a bit longer, and we are excited about that because these days, Berlin feels like home.</p>
<p>At the beginning of the year, we <strong>traveled</strong> to Thailand, Laos, Cambodia, and Malaysia. It was the first time María José traveled outside Europe and the first time for me visiting Laos and Malaysia. It was such an adventure where we went from the chaos of Bangkok to the beautiful nature in Laos, getting amazed by the cocktail of religions in Kuala Lumpur. It was perhaps a bit long because we spent 4 weeks traveling, and the last 2 were a bit of <em>"I miss my routine a bit."</em></p>
<p>The professional side of things has been hectic too. At <a rel="external" href="https://www.shopify.com">Shopify</a>, I changed my career path and became <strong>engineering manager</strong> of the team that I was part of as an individual contributor, mobile tooling. I'm so grateful that my manager and the company supported me and that they allowed me to give it a try and manage the team. I've yet many things to learn, but it's exciting and can't wait to keep learning next year. I also have the opportunity to do a bit of project and product management, which I realized I like a lot.</p>
<p>In my spare time, I kept pushing some <strong>side projects</strong>. We took <a rel="external" href="https://tuist.io"><strong>Tuist</strong></a> to its first major version, 1.0, and got companies like <a rel="external" href="https://bloomberg.com">Bloomberg</a>, <a rel="external" href="https://es.mytaxi.com/taxistas.html">mytaxi</a>, <a rel="external" href="https://www.sky.es/">Sky</a>, and <a rel="external" href="https://soundcloud.com">SoundCloud</a> to use the tool to scale up their Xcode projects. <em>(you can read more about it <a rel="external" href="https://tuist.io/blog/2019/12/18/version-1.0.0/">here</a>)</em>. Next year I'd like my team to spend some time assessing and hopefully introducing it to Shopify, where mobile teams started facing some scaling challenges.</p>
<p>I also worked on <a rel="external" href="https://angle.dev"><strong>Angle</strong></a> with two good friends of mine. Angle is a macOS app to streamline the process of testing software projects. The first version is focusing on iOS and Android apps, but the idea is to extend it to web apps and backend services. It integrates with GitHub and takes care of setting up the local environment for running builds. We plan to release it publicly in Q1 next year.</p>
<p>And last on side projects, but not least, I started working on <a rel="external" href="https://github.com/indiesocial"><strong>Indie Social</strong></a>. It's a specification for the format and structure of social publications on statically generated websites. After several attempts to give up on social networks that are built upon surveillance capitalism, I realized that one of the reasons why I ended up going back is because I don't have a convenient to publish content. Having a specification allows developers to build plugins for static website generators like <a rel="external" href="https://jekyllrb.com/">Jekyll</a> or <a rel="external" href="https://www.gatsbyjs.org/">Gatsby</a>, and clients to publish content <em>(e.g. an iOS app)</em>. Moreover, I want to put my grain of salt to help people to be owners of their content on the Internet.</p>
<h3 id="what-s-coming-in-2020">What's coming in 2020?</h3>
<p>I plan to keep working on <strong>balancing my personal and professional</strong> life. That's something that I still struggle with. As I mentioned earlier, we'll get the keys of the apartment in July, so I'll work with María José on building the interiors and creating the cozy space where we see ourselves living in.</p>
<p>On the <strong>health</strong> side, I plan to work out more regularly. In fact, I started running more frequently because I have two marathons planned for next year, <a rel="external" href="https://www.runczech.com/en/events/volkswagen-marathon-weekend-2019/races/volkswagen-prague-marathon/index.shtml">Prague</a> and <a rel="external" href="https://www.getkidsgoing.com/berlin_marathon.htm?gclid=EAIaIQobChMIm8zdwu3d5gIVS1XTCh1QKw8pEAAYASAAEgJzYvD_BwE">Berlin</a>. I want to build the habit that I had back in 2015, where I ran 4 times a week.</p>
<p>I'll keep <strong>traveling</strong>, starting with a trip to <a rel="external" href="https://en.wikipedia.org/wiki/Japan">Japan</a> in February with María José, my sister, and her boyfriend. India and Chile might be next, but it's still early to know what we'll do further next year.</p>
<p>I want to <strong>learn</strong> more about product design and illustration. Before I took the logical and engineering path in my life, I used to draw a lot. These days, when I open Sketch or take the iPad, I can spend hours quietly drawing and come up with a decent piece of art. I want to take the hobby further and learn skills and tools from creative people.</p>
<p>At work, I'll keep <strong>learning to be a manager</strong>. One of my first tasks for next year is growing the team, which I've never done before. Moreover, the entire team needs to figure out what developing using <a rel="external" href="https://facebook.github.io/react-native/">React Native</a> means, and leverage that to build first-class tools and services for supporting the development with that technology. In that regard, I might attend some React &amp; React Native conferences next year to get familiar with the technology and the community.</p>
<p>As for the <strong>side projects</strong>, I'll start working on Tuist 2.0, whose primary focus will be automation and productivity. My main goal will be building Galaxy, a service to speed up Xcode builds by providing caching. We started doing some groundwork, and it looks promising. I also plan to release the first version of Angle and the Indie Social specification.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Signing with Xcode on CI</title>
      <link>https://pepicrft.me/blog/signing-xcode-app-on-ci/</link>
      <guid>https://pepicrft.me/blog/signing-xcode-app-on-ci/</guid>
      <pubDate>Fri, 27 Dec 2019 12:00:00 +0000</pubDate>
      <description>Today, I worked on automating the release process of Angle on CI. At first, I thought it&#x27;d be a straightforward task, but it turned out not to be so. Most Xcode projects don&#x27;t have to deal with this because they use Match , which abstracts…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Today, I worked on automating the release process of <a rel="external" href="https://angle.dev">Angle</a> on CI. At first, I thought it'd be a straightforward task, but it turned out not to be so. Most Xcode projects don't have to deal with this because they use <a rel="external" href="https://fastlane.tools">Match</a>, which abstracts us from all those intricacies, but Angle doesn't use Match to keep the tooling stack as lean as possible.</p>
<p>For those of you who run into this need in the future, this is the TL;DR; version of what needs to be done:</p>
<ol>
<li>Create an <strong>unlocked</strong> keychain where signing certificates will be imported. If we use the system one, the OS will prompt the user to confirm the access, and since there's no user interface on CI, the build will get stuck. 2. <strong>Import the certificates</strong> and their private keys into the Keychain created in the previous step. 3. Allow <code>codesign</code>, the signing tool from Xcode, to access the certificates without prompting the user for the password. 4. <strong>Copy the provisioning profiles</strong> into the directory where Xcode reads them from. 5. Run <strong>xcodebuild</strong> using the <code>OTHER_CODE_SIGN_FLAGS</code> build setting to indicate the certificate that should be used to read the certificates from.</li>
</ol>
<p>Since we are using <a rel="external" href="https://www.ruby-lang.org/en/">Ruby</a> and <a rel="external" href="https://github.com/ruby/rake">Rake</a> for automation in the project, in the following sections I include some Ruby snippets that I extracted from the project.</p>
<h4 id="executing-commands-in-the-system">Executing commands in the system</h4>
<p>The method below wraps the execution of system commands using Ruby's <code>system</code> method and adding support for printing the command that is executed:</p>
<pre><code>def execute(print_command: false)
 puts(&quot;Running: #{args.join(&quot; &quot;)}&quot;) if print_command
 system(*args) || abort
end
</code></pre>
<h4 id="creating-the-keychain">Creating the Keychain</h4>
<p>The snippet below includes a method to initialize a temporary keychain where we'll import the signing certificates. Note that that after creating the Keychain, we use <code>set-keychain-settings</code> to set the timeout until which the keychain will remain unlocked; 1 hour in our case. Moreover, we unlock the keychain so that processes can access it without the os prompting the user for the password. The <code>set_key_partition_list</code> function configures the keychain to give Apple's tools access to the keychain:</p>
<pre><code>def with_keychain
 keychain_name = &quot;ci.keychain&quot;
 keychain_password = &quot;ci&quot;

 puts(&quot;Creating Keychain for signing&quot;)
 execute(&quot;security&quot;, &quot;create-keychain&quot;, &quot;-p&quot;, keychain_password, keychain_name)
 execute(&quot;security&quot;, &quot;list-keychains&quot;, &quot;-s&quot;, keychain_name)
 execute(&quot;security&quot;, &quot;set-keychain-settings&quot;, &quot;-t&quot;, &quot;3600&quot;, &quot;-u&quot;, keychain_name)
 execute(&quot;security&quot;, &quot;unlock-keychain&quot;, &quot;-p&quot;, keychain_password, keychain_name)

 set_key_partition_list = -&gt;() {
 execute(&quot;security&quot;, &quot;set-key-partition-list&quot;, &quot;-S&quot;, &quot;apple-tool:,apple:,codesign:&quot;, &quot;-s&quot;, &quot;-k&quot;, keychain_password, keychain_name)
 }

 yield(keychain, set_key_partition_list)
ensure
 execute(&quot;security&quot;, &quot;delete-keychain&quot;, keychain_name)
end
</code></pre>
<blockquote>
<p>Note that we <strong>ensure</strong> that the temporary keychain is deleted once the given block finishes executing.</p>
</blockquote>
<h4 id="installing-certificates-and-profiles">Installing certificates and profiles</h4>
<p>Once we have the keychain created, we can proceed with installing the certificates. We can do that by using the <code>security import</code> command. As we can note in the code snippet below, we need to use the <code>-T</code> argument to indicate which executables will have access to the certificate.</p>
<p>In the case of provisioning profiles, we need to copy them to <code>~/Library/MobileDevice/Provisioning Profies</code>, the directory where Xcode reads them from.</p>
<p>The snippet below iterates through all the certificates and profiles under the <code>certificates/</code> directories, installing and copying the certificates and provisioning profiles respectively:</p>
<pre><code>def install_certificates(keychain: nil)
 puts(&quot;🔑 Installing certificates and copying provisioning profiles&quot;)
 files = Dir.glob(File.join(__dir__, &quot;certificates/*&quot;))
 files.each do |file|
 if file.include?(&quot;.p12&quot;) || file.include?(&quot;.cer&quot;)
 security_import_command = [
 &quot;security&quot;, &quot;import&quot;,
 file,
 &quot;-P&quot;, &quot;&quot;,
 &quot;-T&quot;, &quot;/usr/bin/codesign&quot;,
 &quot;-T&quot;, &quot;/usr/bin/security&quot;,
 ]
 security_import_command.concat([&quot;-k&quot;, keychain]) unless keychain.nil?
 execute(*security_import_command)
 elsif file.include?(&quot;.provisionprofile&quot;)
 profiles_path = File.expand_path(&quot;~/Library/MobileDevice/Provisioning\ Profiles&quot;)
 copy_to_path = File.join(profiles_path, File.basename(file))
 FileUtils.mkdir_p(File.dirname(copy_to_path))
 FileUtils.cp(file, copy_to_path)
 end
 end
end
</code></pre>
<h4 id="archiving-exporting-the-app">Archiving &amp; exporting the app</h4>
<p>Once we have the temporary keychain with the right content in it, it's time to archive and export the app. Remember, archive generates a <code>.xcarchive</code> file that we need to export and sign obtaining a <code>.app</code> as a result.</p>
<p>For <strong>archiving</strong> the app we run <code>xcodebuild</code> passing the configuration, the path where we'd like to export the <code>.xcarchive</code> file, as well as the <code>OTHER_CODE_SIGN_FLAGS</code> build setting with the value <code>--keychain keychain_name</code>. That way we can indicate Xcode to use a keychain other than the default one.</p>
<p><strong>Exporting</strong> is very similar, with the difference that we need to pass the <code>-exportPath</code> to indicate the path where the app should be exported, as well as <code>-exportOptionsPlist</code> pointing to a <code>.plist</code> file with options to export the app.</p>
<pre><code>def archive_and_export(keychain: nil)
 puts(&quot;📦 Archiving app&quot;)
 archive(keychain: keychain) do |archive_path|

 puts(&quot;👩‍💻 Exporting app&quot;)
 export(archive_path: archive_path, keychain: keychain) do |app_path|
 yield(app_path)
 end
 end
end

def archive(keychain: nil)
 Dir.mktmpdir do |dir|
 archive_path = File.join(dir, &quot;Project.xcarchive&quot;)
 arguments = [
 &quot;-configuration&quot;, &quot;Release&quot;,
 &quot;-archivePath&quot;, archive_path,
 &quot;clean&quot;,
 &quot;archive&quot;
 ]
 arguments &lt;&lt; &quot;OTHER_CODE_SIGN_FLAGS=&#39;--keychain #{keychain}&#39;&quot; unless keychain.nil?
 xcodebuild(*arguments)
 yield(archive_path)
 end
end

def export(archive_path:, keychain: nil)
 Dir.mktmpdir do |dir|
 export_options_path = File.join(dir, &quot;options.plist&quot;)
 File.write(export_options_path, export_options)

 arguments = [
 &quot;-exportArchive&quot;,
 &quot;-exportOptionsPlist&quot;, export_options_path,
 &quot;-archivePath&quot;, archive_path,
 &quot;-exportPath&quot;, dir,
 &quot;MACOSX_DEPLOYMENT_TARGET=#{MACOSX_DEPLOYMENT_TARGET}&quot;,
 ]
 arguments &lt;&lt; &quot;OTHER_CODE_SIGN_FLAGS=&#39;--keychain #{keychain}&#39;&quot; unless keychain.nil?

 xcodebuild(
 *arguments,
 project: nil,
 scheme: nil
 )

 app_path = Dir.glob(File.join(dir, &quot;*.app&quot;)).first
 yield(app_path)
 end
end
</code></pre>
<h2 id="putting-it-all-together">Putting it all together</h2>
<p>And combining all the previous snippets, the resulting code looks like the snippet below. Beautiful, <em>isn't it?</em></p>
<pre><code>with_keychain do |keychain|
 install_certificates(keychain: keychain) do
 set_key_partition_list.call

 archive_and_export(keychain: keychain)
 end
end
</code></pre>
<h2 id="some-final-notes">Some final notes</h2>
<p>The part that took me the most time to figure out was giving <code>xcodebuild</code> and <a rel="external" href="https://sparkle-project.org/">Sparkle</a> access to the keychain without the os prompting for the password. Initially, I thought it was enough with unlocking the keychain, but I was wrong in that assumption. When adding items to the keychain, we need to use the <code>-T</code> argument to indicate the applications that have access to the item. Moreover, we also need to use <code>set-key-partition-list</code> command from <code>security</code>, which sets the <code>PartitionIDs</code> for keys that can sign <em>(-s)</em> for a specific keychain.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Moving Pods to Packages</title>
      <link>https://pepicrft.me/blog/moving-pods-to-packages/</link>
      <guid>https://pepicrft.me/blog/moving-pods-to-packages/</guid>
      <pubDate>Tue, 24 Dec 2019 12:00:00 +0000</pubDate>
      <description>Today, I decided to move all Angle &#x27;s dependencies that were defined as CocoaPods Pods to Swift Packages. It was my first-hand experience with Xcode&#x27;s integration with the Swift Package Manager so here are my thoughts: I had no issues. I we…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Today, I decided to move all <a rel="external" href="https://angle.dev">Angle</a>'s dependencies that were defined as <a rel="external" href="https://cocoapods.org">CocoaPods</a> Pods to Swift Packages. It was my first-hand experience with Xcode's integration with the Swift Package Manager so here are my thoughts:</p>
<ul>
<li>I had no issues. I went through all the dependencies, got their URL, and added the dependency from the linking frameworks build phase. Xcode was able to resolve the dependencies, list the linkable targets, and configure the project seamlessly. I barely had to touch anything on the project. - Some Pods had not <code>Package.swift</code> file so I ended up using <a rel="external" href="https://github.com/carthage">Carthage</a> for those. I compiled a <code>.framework</code> file and then dragged and drop the framework to the project. - After moving all the dependencies, I deleted the workspace generated by CocoaPods and all the references from the project. The project built successfully, and ran without any issues.</li>
</ul>
<p><a rel="external" href="https://apple.com">Apple</a> did a really good job here.</p>
<p>By the way, I'm very excited to continue working on Angle, another side project in which I'm involved and to which I couldn't contribute much because I was mainly focused on <a rel="external" href="https://tuist.io">Tuist</a>. Last weekend I worked on creating the <a rel="external" href="https://angle.dev/documentation">documentation website</a> in Gatsby. It already contains the getting started steps in case you want to give it a try.</p>
<p><img src="https://pepicrft.me/blog/moving-pods-to-packages/__GHOST_URL__/images/posts/xcode-swift-packages.png" alt="Image that shows how dependencies are defined as packages in Angle" /></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Adding bits of reactive programming to Tuist</title>
      <link>https://pepicrft.me/blog/reactive-tuist/</link>
      <guid>https://pepicrft.me/blog/reactive-tuist/</guid>
      <pubDate>Sun, 08 Dec 2019 12:00:00 +0000</pubDate>
      <description>In this blog post I talk about a recent decision that we made to start using reactive programming to model asynchronous tasks in Tuist.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Until now, most of the code in Tuist followed an imperative approach, the logic executes as part of the process’s main thread. There were some exceptions, like the execution of other system tools that ran in their process, blocking Tuist’s main process.</p>
<p>As we add more features, doing everything in the main thread is no longer a good idea for performance reasons. A piece of business logic that doesn’t make sense to run sequentially in a single thread is the upload of cached xcframeworks for Galaxy. Let’s say our project has in total 20 frameworks that can be cached, <em>why not upload them in parallel?</em></p>
<p>It seems a straightforward task, yet there’s a little detail that might go unnoticed if you are not familiar with writing CLIs: we need to block the main thread until all the asynchronous tasks complete to continue the execution. Otherwise, the process will exit, and the tasks get canceled.</p>
<p>Foundation provides APIs for synchronizing asynchronous work such as dispatch <a rel="external" href="https://developer.apple.com/documentation/dispatch/dispatchsemaphore">semaphores</a> and <a rel="external" href="https://developer.apple.com/documentation/dispatch/dispatchgroup">groups</a>. However, it might not be evident from the resulting code to read how the execution of the asynchronous takes place. Conversely, reactive frameworks make that easy thanks to operators than can be chained, and that describes how asynchronous units of work are combined. Let me include some pseudocode to represent that:</p>
<pre><code>let result = combineLatest([a, b, c]).wait()
</code></pre>
<p>Right for that particular reason, we are starting to introduce some bits of reactive programming in Tuist using <a rel="external" href="https://github.com/ReactiveX/RxSwift">RxSwift</a>. It's not a binary decision, or in other words, it doesn’t mean that we go from an entirely imperative codebase to a fully reactive one. Reactive programming makes sense in areas where asynchronous work is required, and where that asynchronous work might need to synchronize with other asynchronous work.</p>
<p>At this point, you might wonder why not <a rel="external" href="https://developer.apple.com/documentation/combine">Combine</a>? Well, Combine is a macOS 10.15.x framework, and we might have users in older versions of macOS. A migration to Combine will definitively happen gradually as soon as we deprecate macOS 10.14. Until then, I think it’s fine starting with RxSwift.</p>
<p>This decision reminds me of SoundCloud, where we took a binary approach, and Reactive ended up all over the place. I aim to do things differently here and have the usage of reactive programming scoped to only the areas where it makes sense.</p>
<p>I hope you all have a great week. I just arrived in Ottawa, and it’s cold over here. On Wednesday, I plan to experiment with porting Shopify’s native Xcode projects to Tuist. Wish me luck!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Working on a new website for Tuist</title>
      <link>https://pepicrft.me/blog/new-tuist-website/</link>
      <guid>https://pepicrft.me/blog/new-tuist-website/</guid>
      <pubDate>Fri, 06 Dec 2019 12:00:00 +0000</pubDate>
      <description>An update on what I&#x27;m up to these days with Tuist. In particular, I talk about the new website that I&#x27;m designing and implementing for the project.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Over the past few weeks I've been working on a new website for Tuist's. This is the third iteration of the website and I'm never tired of going through them; it takes learning some design tricks and some inspiration from other websites to see the current website as old and not representative.</p>
<p>For someone like me with little experience in creating products, a task like this one isn't straightforward, yet challenging. I have to think about the message that I'd like to convey, the content that I'd like to present, the combination of fonts, colors, and sizes that represent best the tool. The website and the GitHub repository is most of the times what users first see when they come across your projects. If its style and content is not appealing, developers will probably not give the project a try.</p>
<p>What most developers do is using markdown files in their repositories. I've seen many creative and well organized markdown files that convey the message of the project well. In case of Tuist, we started with something like that but at some point, we realized markdown was not enough. I can describe in paragraphs how life-changing Tuist can be projects, but without a more visual and dynamic explanation, users won't probably get the idea. That's where having your own website comes handy. You are in full control, not only of the message, but of the way the message is represented. You can summarize a bunch of paragraphs in a beautiful animation that lets developers eager to try the tool.</p>
<p>Anyway, that's where I'm mostly spending my time these days. For this new iteration I used <a rel="external" href="https://figma.com">Figma</a> for the design. It really feels like GitHub but for design. I can define my shared components and colors that I can reuse from all the designs, share them with other people and get their input through comments, and all of that in the cloud. If all of that was enough, I just came across <a rel="external" href="https://www.figma.com/blog/announcing-auto-layout/">this new feature</a> that they just launched 🤯. In case you are interested in giving feedback on the design, <a rel="external" href="https://www.figma.com/file/NjaC1IooavnI82mxRY6T6C/Website-2.0?node-id=1%3A4">here</a> is the link.</p>
<p>Moreover, we are moving away from <a rel="external" href="https://www.docz.site/">Docz</a> for generating the documentation. We'll merge the documentation into the website built with <a rel="external" href="https://www.gatsbyjs.org/">Gatsby</a> The reason why we are doing this is because it gives us the control to design the website, and make sure that complies with the search engines' algorithsm. My goal is that each documentation page has the right metadata headers and HTML semantics for the content to be well indexed by search engines like Google.</p>
<p>That's what I'm pretty much up to! On Sunday I'm flying to Canada to spend some days with the team to come up with a roadmap for next year ✈️.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Creating experiences</title>
      <link>https://pepicrft.me/blog/creating-experiences/</link>
      <guid>https://pepicrft.me/blog/creating-experiences/</guid>
      <pubDate>Tue, 03 Dec 2019 12:00:00 +0000</pubDate>
      <description>Picked up my phone and dumped some thoughts on why I&#x27;m so engaged and excited to build Tuist.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There's something in Tuist that keeps me very engaged with the project. Never before I had had that experience with other projects; I think it has something to do with the fact that with Tuist I'm creating new experiences and workflows that would otherwise be unimaginable.</p>
<p>After years of iOS development, I feel we have been accommodating our workflows and tools to what we were given by Apple. With Tuist I'm taking down those constraints. <strong>I imagine how I'd like the experience to be and then craft it as such.</strong></p>
<p>If I would like to describe dependencies as <code>.target("Core")</code> I codify it. If build times are slow, I think of ways of making them fast and add them to Tuist. I can push myself outside my comfort zone of just developing and work on designing a brand, a website. The same goes for writing documentation and building a community of enthusiastic developers that share the vision of the projects. That's damn exciting and can't stop doing it.</p>
<p>It's also exciting thinking of solutions for problems that I experienced myself. For instance, project generation is a solution to a problem: Xcode projects exposing too many complexities that difficult its maintenance and growth. Nowadays I look at Tuist's API and keep thinking further through ideas to make the API simpler and nicer. I'm not building a project generator, I'm building a tool to improve developers' experience using Xcode.</p>
<p>And I do all of this in the open because I'd like anyone to be part on helping others. I worked on a solid foundation to make this possible and now I'm starting to see the results.</p>
<p>Creating experiences in the open is awesome.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>I am X</title>
      <link>https://pepicrft.me/blog/i-am-x/</link>
      <guid>https://pepicrft.me/blog/i-am-x/</guid>
      <pubDate>Sun, 24 Nov 2019 12:00:00 +0000</pubDate>
      <description>This is a short reflection around something that it&#x27;s common in our industry, professionals labelling themselves and limiting their area of influence.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><a rel="external" href="https://en.wikipedia.org/wiki/Leonardo_da_Vinci">Leonardo di ser Piero da Vinci</a> was an Italian polymath interested in invention, drawing, painting, sculpture, architecture, science, music, mathematics, engineering, literature, anatomy, geology, astronomy, botany, paleontology, and cartography. Like him, many other geniuses of the Renaissance had interest in so many areas of knowledge. None of them put a label on themselves constraining their area of expertise. If they just found geology interesting, they grabbed a bunch of books to read and learn about it.</p>
<p>Fast forward to today, and talking about our industry, things have changed a lot. Developers of a given programming language, let's say Swift, are just Swift developers. Commonly, when things arise in other domains they refuse to step outside their comfort zone. I think we developers have found our comfort zone in which we feel experts and for which we get paid a lot compared to other industries. I believe that's one of the reasons why companies move slow. They have unnecessary friction coming from having too many technoly-X developers and very few Leonardo da Vincis. Those are developers that opt for opening tickets when they find issues in the tools that they use. Developers that do the same when there's some work that involves backend development. Those tickets can live in the backlog days and weeks until someone picks them up.</p>
<p>When it comes to cross-discipline work, things are even worse. Don't ask a developer to do a bit of design, or the other way around, ask a designer to do a bit of coding. It's true that those are completely opposite disciplines, but imagine how powerful it'd be if we trained our brain to know a bit of both. If we could express our ideas by combining bits of design and code. One of the people in our industry that I admired a lot because he's able to combine all disciplines to build great products is <a rel="external" href="https://tom.preston-werner.com/">Tom Preston</a>. <a rel="external" href="https://github.com">GitHub</a> &amp; <a rel="external" href="https://chatterbug.com">Chatterbug</a> founder, he does design, development, and product brilliantly. In collaboration with other folks, he created the platform in which most of us spend hours and hours. The platform that stood out for its simplicity and social ideas that were copied by other competitors later on. Imagine if in its early days, he'd have had to look around to find designers and product experts to materialize their ideas around how social software development should be. I bet GitHub wouldn't be what it is today.</p>
<p><strong>How does all of that relate to me?</strong> Since I joined Shopify, I pushed my boundaries to do more work with other programming languages and domains. These days you can find me doing Ruby, using Ruby on Rails to build web apps, Javascript to do a bit of automation, or even Ansible to do a bit of devops. I might not be an expert in all of those, but when a task that involves cross-domain work arises, I'm able to deliver it entirely. With Tuist, I'm going even further. I'm reading a lot about design and product to come up with an identity for the tool. I've re-designed the website a few times, changed the logo a few others, and worked on defining the culture of the organization to ensure it's healthy and collaborative. It's sometimes exhausting, but worth it because the resulting product becomes a <strong>accurate reflection of the vision</strong>.</p>
<p>I believe our industry needs more crafters with Leaonardo da Vinci's mindset. We need people that love the craft and whose main goal is not just making money. We need people that finds absorving knowledge exciting and that don't set boundaries to themselves. The world would have better and more human tools. Designers would go beyond placing pixels or defining colors to understand the moral implications of their designs. Developers would show more empathy for others and build for everyone instead of for the latest device in the market.</p>
<p>I think we can all start by turning <em>"I am X"</em> (where X can be replaced with Swift developer, frontend designer, product manager, CEO) into <em>"I can make X real"</em>. What we need to get there is up to us to figure out.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Static site generators</title>
      <link>https://pepicrft.me/blog/static-site-generators/</link>
      <guid>https://pepicrft.me/blog/static-site-generators/</guid>
      <pubDate>Mon, 04 Nov 2019 12:00:00 +0000</pubDate>
      <description>In this blog post I talk about what traits I expect a static site generator to have, and why I believe Gatsby is a more suitable option than other alternatives in the industry.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>The range of options that we find nowadays to create static sites is endless. I remember back when I started as a developer and set up my personal website and blog using <a rel="external" href="https://jekyllrb.com/">Jekyll</a>. I was not familiar with HTML &amp; CSS but the amount of themes out there was so large that I could pick my favorite, customize it, and get a beautiful website where I could dump my thoughts and learnings.</p>
<p>Things have have changed a lot since then. Every programming language has its own static site generator, <a rel="external" href="https://twitter.com/johnsundell/status/1190007933712633856">including Swift</a>. Each tries to take advantage of the programming language they are developed with. For instance, the Swift static site generator that people starts to talk about seem to have a strongly typed API. That's awesome! But like anything in software, <em>it's all tradeoffs.</em></p>
<p>In years iterating my website, which is now built using <a rel="external" href="https://www.gatsbyjs.org/">Gatsby</a> by the way, I have learned what are the most important traits that make the experience of developing web a joy: <em>instant feedback, composability and extendability</em>.</p>
<ul>
<li><strong>Instant feedback:</strong> This means getting the changes instantly reflected in the web browser without having to wait for a transpiler or compiler to do some heavy-lifting work. <code>CMD + S</code> and <code>CMD + Tab</code> are your best friends. This can make a huge difference in the productivity of a developer because the process laying out a web page, is very iterative. Gatsby is by far doing an excellent job here. It detects when certain files that impact the site have changed, and reloads the content automatically without losing the currently loaded context. - <strong>Composability:</strong> Large sites are broken down into smaller composable pieces, <em>components</em>. A component is a combination of a layout <em>(HTML)</em>, styles <em>(CSS)</em>, and some interactivity <em>(JS)</em>. Frameworks like <a rel="external" href="https://vuejs.org/">VueJS</a> or <a rel="external" href="https://reactjs.org/">React</a> make defining atomic components easy and they integrate seamlessly with bundling tools such as a <a rel="external" href="https://webpack.js.org/">Webpack</a>, which is one of the building blocks of Gatsby. The Javascript community is years away from any tool that is being built in not-so-web-oriented programming languages like <a rel="external" href="https://www.rust-lang.org/">Rust</a>, or Swift. <a rel="external" href="https://babeljs.io/">BabelJS</a>, <a rel="external" href="https://webpack.js.org/">WebpackJS</a>, or <a rel="external" href="https://github.com/emotion-js/emotion">Emotion</a> are good examples of tools and frameworks without which building web nowadays would be an inconvenient task. - <strong>Extendability:</strong> And last, and not for that least important, have different options for extending your website functionality easily. In case of Gatsby, there are many hooks you can subscribe to to override any step in the generation logic, <a rel="external" href="https://www.gatsbyjs.org/docs/themes/what-are-gatsby-themes/">themes</a> to include functionality that other developers have packaged and distributed as <a rel="external" href="https://www.npmjs.com/">NPM</a> packages, and React components and libraries that can be easily imported and used.</li>
</ul>
<p>I'm glad to have chosen Gatsby as a framework for my personal website because it provides the aforementioned traits and more. I can package a functionality that I've built for this website, like the journal section that I call <a rel="external" href="https://github.com/tuist/gatsby-theme-micro-blog">micro-blogging</a>, use a library like <a rel="external" href="https://theme-ui.com/getting-started">Theme-UI</a> to make the blog themable, use Gatsby plugins like <a rel="external" href="https://www.gatsbyjs.org/packages/gatsby-plugin-offline/">this one</a> that makes the website offline and more resistant to slow connections, or add React components to a markdown file using <a rel="external" href="https://mdxjs.com/getting-started/gatsby">MDX</a>.</p>
<p>It's great to see though that there are people pushing the boundaries of static site generators to other programming languages like Swift. And it's also great to have types and APIs that you are already familiar to. However, the value that it brings having a compiler that ensures that I wrote a <code>#</code> where it should be a , compared the value that you get when you use a framework like Gatsby that can leverage years of development for the web, is not worth it, at least for me.</p>
<p>Hope you have a wonderful week 👋! If you notice some oddness on the website, it's because I'm overhauling it a bit.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Better relative paths</title>
      <link>https://pepicrft.me/blog/better-relative-paths/</link>
      <guid>https://pepicrft.me/blog/better-relative-paths/</guid>
      <pubDate>Thu, 31 Oct 2019 12:00:00 +0000</pubDate>
      <description>We are providing a new API from Tuist to define relative paths and this blog post describes the motivation behind it and the solution that we are adopting.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of the best decisions that we made when we envisioned Tuist was using Swift as a language for describing projects. Its compiler can validate the syntax, users get documentation right in the code editor, Xcode, and very soon, it’ll allow defining paths that are relative to Tuist-specific directories.</p>
<p>One of the concerns that surfaced when we proposed introducing project description helpers was being able to define paths relative to those helpers, or why not, relative to the root directory of the project. The good thing is that with some tricks, and some Swift interface, we found a solution for that. Let’s say there’s a helper that generates a standardized feature framework project:</p>
<pre><code>// FrameworkHelper.swift

func framework(name: String) -&gt; Project {
 // Your initialization logic here
}
</code></pre>
<p>With some rare exceptions, the Info.plist files the framework targets usually point to have the same content. It’s clearly a good candidate to be reduced to a single file that we can place in the root directory of our project to be reused by all the targets. With the current Tuist API, developers would have to write something along the lines of:</p>
<pre><code>// FrameworkHelper.swift

let path = &quot;&quot;../../Shared/Framework.plist&quot;
</code></pre>
<p>It’s a bit ugly, and the helper is making an assumptions on the directory where the manifest using the helper is located.</p>
<p>Thanks to some work that we are doing, developers will be able to do something along the lines of:</p>
<pre><code>// FrameworkHelper.swift

let path = Path.from(root: &quot;Shared/Framework.plist&quot;)
</code></pre>
<p>The definition is shorter, and there are no assumptions, it can be used from anywhere because the root directory of the project will remain the same.</p>
<p>The feature work is still progress but you can check out the <a rel="external" href="https://github.com/tuist/tuist/pull/617">pull request</a> and give us feedback.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Project description helpers</title>
      <link>https://pepicrft.me/blog/manifest-helpers/</link>
      <guid>https://pepicrft.me/blog/manifest-helpers/</guid>
      <pubDate>Thu, 10 Oct 2019 12:00:00 +0000</pubDate>
      <description>In this blog post I talk about a beautiful abstraction which Alex and I came up with to push Tuist&#x27;s awesomeness even further.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Yesterday I had a pairing session with a good friend of mine who started introducing Tuist to his company's project. He brought up an interesting need that had been in the backlog for quite some time but that no one embarked on building it: reusing code across manifests.</p>
<p>I was so eager to build that feature into Tuist that I immediately proposed him to pair on it. It was a very fruitful exercise that we couldn't finish but got a fully functional prototype. If was excited before building it, my excitement skyrocketed when I saw it working.</p>
<p>In a nutshell, the solution that we adopted was compiling all the files under the <code>Tuist/ProjectDescriptionHelpers</code> in a module, and then linking the manifest against it. I think it's a simple solution, yet powerful.</p>
<p>With this feature developers can not only reuse code across manifests, but leverage any language abstractions to codify their projects: struct, classes, functions, enums, generics...</p>
<p>Here are some things that the new feature enables:</p>
<ul>
<li>Have a factory of projects or targets that given the name and some basic attributes, it returns a standard project. - Define how build settings are generated and combined. If you never liked how xcconfigs or build settings are flattened, you can define your own merge logic. - Projects can be defined in one line of code. I can't stress enough how great this is to ease the maintenance and creation of new projects.</li>
</ul>
<p>Can't wait to finish it up and bring it to the users in the next version of Tuists. Until then, there are sone tests to add and documentation to write.</p>
<p>Happy coding!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Abstractions</title>
      <link>https://pepicrft.me/blog/abstractions/</link>
      <guid>https://pepicrft.me/blog/abstractions/</guid>
      <pubDate>Thu, 03 Oct 2019 12:00:00 +0000</pubDate>
      <description>In this blog post I talk about abstractions in the Xcode projects domain and how Tuist leverages the concept to conceptually compress intricacies of Xcode projects that developers are often confronted with.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Most developers are familiar with the concept of abstractions. They are often used to turn a domain language into another language that suits the problem or set of problems better. Moreover, they can be leveraged to simplify things, or extend the abstracted element’s functionality. We have seen that over the years in open source libraries that aimed to simplify system frameworks such as UIKit, Foundation, or CoreData. Almofire, MagicalRecord, and SnapKit are good examples of abstractions that turned intricate APIs into a beautiful experience for developers. Those libraries <strong>sparked joy</strong>, which is a key element be engaged and motivated when we craft software. Let’s be honest, no one wants to spend their time understanding complex interfaces, figuring out how to use them safely, or working on repetitive tasks.</p>
<p>When abstractions are validated, they end up inspiring the evolution of the abstracted layers. We’ve seen Apple evolving their frameworks taking abstraction ideas from the community and other programming languages. UIKit will eventually be a vintage framework because developers already have a simpler, more beautiful, and declarative alternative, <a rel="external" href="https://developer.apple.com/xcode/swiftui/">SwiftUI</a>.</p>
<p>Most of the abstractions that we see in the Apple ecosystem are code abstractions; there are plenty of libraries out there that you can use to improve the coding experience of the developers in your team. However, code is not the only element that requires abstraction. If you work on a large project, you probably know the domain that I’m talking about: Xcode projects.</p>
<p>Apps are no longer a single-target project in Xcode. Even apps that are not structured in modules (frameworks or libraries) have targets for dependencies, extensions, and apps for other platforms. Xcode projects evolved to support the unceasing growth of the Apple ecosystem, and that resulted in an interface to define your projects, Xcode projects, that exposes a lot of complexity. That complexity makes it a good candidate upon which build an abstraction. <strong>Tuist</strong> was conceived to provide that abstraction.</p>
<p>Tuist provides an abstraction that compresses Xcode complexities and allows developers to codify conventions. It does it by leveraging projects generation and Swift.</p>
<p>Working on Tuist, I came across many developers that compare Tuist to <a rel="external" href="https://github.com/yonaskolb/xcodegen">XcodeGen</a> and understandably end up concluding that Tuist is just another project generation tool. While it also generates projects, there are two subtle differences, that I think make Tuist a more suitable option for some projects.</p>
<p><strong>The first</strong> of the differences has to do with conceptual compression. Despite how tempting it might be translating concepts and ideas one-to-one from Xcode projects to Tuist abstractions, we know that it results in leaking complexities and therefore we make an effort to compress concepts and provide a simple interface that Tuist defaults to. XcodeGen has good abstractions too, but it’s closer to the Xcode project’s domain.</p>
<p>When I was iOS developer at SoundCloud, I remember being certainly annoyed because breaking down the app required being familiar with many Xcode-specific concepts, and a fair amount of manual work. Only a few people in the team knew how to add more targets, and when issues arose, the rest of the team couldn’t make a guess on what the issue could be. The bus factor was high, and the complexity of the project grew significantly.</p>
<p>Creating a new project or target meant having answers for the following questions:</p>
<ul>
<li>How do I name it? - Where do I place it? - Where do I place it in the dependencies graph? - What should be its configuration? - How do I make sure it’s consistent with other targets? - How do I make sure I’m not breaking anything? - How should I set up CI? - Should it be a framework or a library? - Can it be a library but with access to resources?</li>
</ul>
<p>What we did at SoundCloud, which I’ve seen in other teams, is having all of that documented. In practice that translates into teams having one or two people that know how to answer those questions right, and the rest of the team resorting to them. It might feel great if you are one of those people. I actually was. But as I mentioned earlier, that sets the bus factor high and adds dependencies that might slow down other people’s work.</p>
<p>For that reason, making things easier and opinions on the Xcode projects domain codifiable, was one of the motivations to build Tuist. For instance, one of the features that I put a lot of effort into simplifying was the definition of dependencies. With Tuist, defining a dependency is as simple as defining <strong>what depends on what</strong>. The build settings and phases that are required for that are an implementation detail. Moreover, and conversely to XcodeGen that uses YAML as a language to describe the projects, I decided to use Swift for a few simple reasons: it’d validate the syntax, users would get inline documentation while editing their projects, and most importantly, it’d make codifying opinions easy. For example, the targets that are part of a project can be defined by a function that acts as a factory of targets:</p>
<pre><code>func target(name: String) -&gt; Target {
 // Initialize and return the target
}
</code></pre>
<p>Doing that with YAML would require extending the specification to support it, which would end up leaking some complexity in the tool domain.</p>
<p>It might not be obvious from the code snippet above, but it’s a powerful idea that makes codifying opinions possible. Here are some ideas:</p>
<ul>
<li>All targets follow the same naming convention: <code>Prefix\(name)</code> - They have the same files structure: Sources under <code>Sources/</code> and tests under <code>Tests/</code>. - They run Swiftlint to lint the code. - They depend on a set of foundation frameworks.</li>
</ul>
<p>Being able to codify opinions makes being consistent easier, and as a result, scaling app your projects a pleasant experience.</p>
<p><strong>The second</strong> difference with XcodeGen is that Tuist is not just a project generator. Project generation is the first step to be able to provide an easy and standard command line interface to interact with projects. This hasn’t been built yet because we are focusing on the project generation, but we’ll start working on it afterward.</p>
<p>Since comparisons often help understand concepts, you can think of it as <a rel="external" href="https://github.com/fastlane">Fastlane</a>, but without having to write Fastfiles. The reason why Fastfiles exist is because the user needs to describe how their intents map to system commands. There are some important pitfalls of using that approach at scale:</p>
<ul>
<li>Not all lanes run on CI for every code change. As a consequence, lanes might break without no one noticing until they have to run the lane, for example when releasing the app. That’s very frustrated. - Ensuring a good and clean structured mapper (Fastfile) in large projects with many developers contributing to it has been proven to be an arduous task. Developers see those files as a canvas where they can dump code, hacks, and any snippet they find on the Internet. As long as they can do <code>fastlane my_lane</code>, that’s all most developers care about. Not only that, but it’s easy to end up with inconsistencies in the name of the lanes. Is it <code>build_release</code> or <code>release_build</code>? Or maybe just <code>release</code>?</li>
</ul>
<p>SoundCloud’s Fastfiles were large and complex, so are Shopify’s. It just happens, and it’s really hard to prevent it if we don’t have conventions and a way to enforce them. If we think about Rails, which has been a huge source of inspiration to design Tuist, any developer working with the framework knows that databases can be migrated with <code>rails db:migrate</code>, or that the server can be initialized with <code>rails server</code>. On Xcode projects, we don’t have such a user-oriented interface that reflects user intents. One might argue that there are tools like <code>xcodebuild</code>, or <code>simctl</code>, but they are closer to the system than to the user, they are not pleasant to use. Imagine we could just do <code>tuist keys setup</code> and we’d get the environment set up with the right certificates in the keychain to sign the app.</p>
<p>Tuist will provide an standard and user-friendly CLI with the most common tasks. It’s possible to do it reliably and with bare input from the user because they describe us the project and therefore, we know how to interact with it <em>(the contract)</em>. These are some commands that are good candidates to be implemented first:</p>
<ul>
<li><strong>Build:</strong> Builds your app. - <strong>Test:</strong> Runs tests - <strong>Run:</strong> Builds and runs the app in the destination platform (e.g Simulator). - <strong>Release:</strong> Archives, exports apps uploads apps. For frameworks, it’d build and export a distributable framework.</li>
</ul>
<p>Graph is a command that has already been built in to export the dependencies graph representation. That’s something that surprisingly Xcode doesn’t provide, and that I believe is crucial to make informed decisions on the project structure.</p>
<hr />
<p>This is where we are heading, and I’m very excited about the journey. Tuist gave me the opportunity to meet very talented developers who share the same vision and that are bringing a lot of illusion and ideas for the project. I applied one of Shopify’s main principles, trust, and that resulted in a very healthy and collaborative space which I’m very proud of. It’s a pleasure working with Kassem, Olliver, Marcin, Marek and so many other contributors and users that gave Tuist a try.</p>
<p>I had a few downs with the project, mainly because this is a long-term bet in a space where things move fast and Apple’s tooling have always more trust from the community. What makes me stay on track and motivated is having the opportunity to explore new ideas, being able to build them into Tuist, and help companies and projects to scale up.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Keeping up with dependencies updates</title>
      <link>https://pepicrft.me/blog/auto-updating-dependencies/</link>
      <guid>https://pepicrft.me/blog/auto-updating-dependencies/</guid>
      <pubDate>Tue, 10 Sep 2019 12:00:00 +0000</pubDate>
      <description>A brief reflection on Dependabot, a tool that was recently acquired by GitHub and that helps automate the process of updating dependencies on your GitHub repositories.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Keeping dependencies up to date is and important task that we shouldn't disregard because updates sometimes bring <strong>security patches and improvements</strong> that we might want to benefit from in our projects. Unfortunately, most teams don't pay enough attention to this, and just focus on developing the product on top of a specific version of frameworks and libraries.</p>
<p>The good thing is that keeping up with the upstream changes has never been so easy. In my projects, I configure <a rel="external" href="https://dependabot.com/">Dependabot</a>, a tool that GitHub acquired recently and whose role is automating the process of updating dependencies and letting you make the final decision of testing &amp; merging the PR.</p>
<p>I set up Dependabot in all my open and private source repositories. It requires no configuration to start working, which is great, and allows you to customize things like the frequency at which dependencies are updated.</p>
<p>One feature that I requested on Twitter and that they mentioned they are working on is support for updating Swift Package dependencies. The Swift community will be so grateful of seeing Swift Packages been supported. I can't wait to use it to update <a rel="external" href="https://tuist.io">Tuist</a>'s dependencies.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>What&#x27;s coming to Tuist</title>
      <link>https://pepicrft.me/blog/whats-coming-to-tuist/</link>
      <guid>https://pepicrft.me/blog/whats-coming-to-tuist/</guid>
      <pubDate>Mon, 09 Sep 2019 12:00:00 +0000</pubDate>
      <description>A Monday blog post with some reflections about the current state of Tuist and its future.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I continue to be excited about Tuist. It's one of those things that brings me a lot of joy when I work on it. What makes me the most exciting is the challenge of abstracting Xcode intricacies that arise when Xcode projects grow. I relate Tuist to Rails, a framework that I had the experience to learn and fall in love with very recently. Rails provides beautiful and simple abstractions for most of the features that are required nowadays to build web apps. <strong>What Tuist's abstractions will look like</strong> is still to be defined, but I'm glad that we are on the right track to define them.</p>
<p>One of the things that we plan to work on, and that <a rel="external" href="https://twitter.com/kwridan">Kas</a> is leading, is morph the architecture of the project into a more modular approach. That'll make the code safer, easier to understand, and will increase the extendibility of the projects generation. He pushed the idea that we are pondering to the <a rel="external" href="https://github.com/tuist/tuist-labs">tuist-labs</a> tha we created to explore ideas outside the main repository.</p>
<p>In regards to features, these are the ones that I've been pondering lately and that I'd like to see in Tuist:</p>
<ul>
<li><strong>Swift interface for accessing resources:</strong> I think Tuist could leverage <a rel="external" href="https://github.com/SwiftGen/SwiftGen">SwiftGen</a> to generate type-safe Swift code to access resources. The generated Swift code would be added automatically to the target the resources belong to. - <strong>Support for resources in libraries:</strong> Libraries can't contain libraries, but we could enable that by generating a resources bundle and providing a Swift interface to access the resources from the right directory within the product bundle. I've seen projects workarounding this by having a build phase that copies the resources into the right directory. That's not easy to maintain though. - <strong>Shared manifest files:</strong> One of the advantages of writing the manifests in Swift vs defining them in a Yaml is that we can leverage the Swift compiler to make things like reusing pieces of the manifest possible. Imagine adding more modules to your project is all about calling a function, <code>module(name: "Settings", dependencies: ["DesignKit"])</code> that is defined in a <code>Shared.swift</code>. That'd remove one of the biggest barriers when it comes to growing the number of modules of a project.</li>
</ul>
<p>Stay tuned because those and more features will land soon in Tuist. If you would like to use Tuist in your projects or even contribute, you are welcome to do so. I'd gladly walk you through the project to have a solid understanding to start using it in your projects or contributing.</p>
<p>Have a great week!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>A period of changes</title>
      <link>https://pepicrft.me/blog/a-period-of-changes/</link>
      <guid>https://pepicrft.me/blog/a-period-of-changes/</guid>
      <pubDate>Thu, 29 Aug 2019 12:00:00 +0000</pubDate>
      <description>Dumping some thoughts on what the last month have been for me in my personal and professional life.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It's been a while since I wrote my last blog post here. During this time there's been some important changes in my life and my professional career and I felt like writing them down in an unstructured blog post.</p>
<p>The first of those changes is that I was giving the opportunity to give management a try. Changing paths in my career is something that I've always wanted to try and my team, and specially Mark, gave me the opportunity to do so. It's been a few weeks learning a lot and getting used to it. I'm starting to feel how my ability and time to code is decreasing and I'm doing a little bit of everything. The part that I find the most exciting about this job is that I'll have the opportunity to enable my peers to achieve their goals.</p>
<p>The change didn't came alone. A person that I worked with was moved to another team <em>temporarily</em> to help tackle a company-wide pressing issue. That means our team went back to 2 people, being one of them a new individual contributor <em>(IC)</em> that just joined our team. We had to asses our resources and the projects that we where championing, and cut down some workload to help the team accommodate all the changes.</p>
<p>On the personal side of things, I've been dealing with some bureaucratic paperwork in regards to the apartment that María José and I bought in Berlin. We are very excited to be in this journey together and very looking forward to having the keys in March next year. Luckily, the amount of paperwork has reduced significantly and these days, we just get letters from Deutsche Bank with the recent movements in our bank accounts. Also, in the vein of organizing stuff, our wedding is in less than a month, so we've been working hard to make sure that everything is ready for it.</p>
<p>On another topic, I've been pondering again the idea of quitting social networks. I keep thinking they are not doing any good to my brain and that they put something on me which I don't like: <strong>constantly seeking recognition and approval</strong>. For some people it might just be ok, but I don't want my brain to only be ok when it has doses of those. I closed, <strong>again</strong>, my Facebook account, and reduced my usage of Twitter. The time that I used to spend on those places, I spend it drawing or just not doing anything. This re-education process won't be easy, but I think my brain will be so thankful for it.</p>
<p>An last but not least, damm, I'm having a lot of fun playing with <a rel="external" href="https://www.gatsbyjs.org/">Gatsby</a> and <a rel="external" href="https://theme-ui.com/">theme-UI</a>. It reminds me to the early days of learning iOS or Swift when everything was new and joyful. I'm playing with them to polish <a rel="external" href="https://tuist.io">Tuist's website</a> and I'm even considering drawing the illustrations of the website. <em>Why not?</em> I like to develop but also shape other areas of the project that have nothing to do with development.</p>
<p>Hope you are all having a lovely week.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Project generation</title>
      <link>https://pepicrft.me/blog/project-generation/</link>
      <guid>https://pepicrft.me/blog/project-generation/</guid>
      <pubDate>Mon, 22 Jul 2019 12:00:00 +0000</pubDate>
      <description>This blog post describes the advantages of dynamic over static Xcode projects, and how Tuist leverages project generation to help teams overcome the challenges associated to scaling up projects.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Last week I published a <a rel="external" href="https://twitter.com/pepicrft/status/1153252000685072384">thread</a> on Twitter in which I shared what I think is the value of generated Xcode projects. I've been a huge advocate of generated Xcode projects since I worked at SoundCloud, where I realized the maintenance cost that modular Xcode projects bring.</p>
<p>In this blog post, I'd like to extend each of the advantages that were mentioned in the thread, and relate them with the features that we are building into <a rel="external" href="https://tuist.io">Tuist</a>.</p>
<h2 id="1-focus">1 - Focus</h2>
<p>Large apps often resort to modularization to scale up. Codebases are broken down into smaller modules with clear boundaries and responsibilities. In my experience seeing modular Xcode codebases, they are usually organized in multiple directories and Xcode projects. Each them is <strong>manually maintained</strong>.</p>
<p>The more Xcode projects you have, the more time you will need to spend <strong>maintaining</strong> them and <strong>figuring out issues</strong> that might arise as a result of the accidental complexity.</p>
<p>Tuist abstracts the low-level intricacies and handles them for you. For example, the dependencies are described semantically and not in terms of build phases or build settings:</p>
<pre><code>let app = Target(name: &quot;App&quot;, product: .application, dependencies: [
 .target(&quot;Profile&quot;)
])
let profile = Target(name: &quot;Profile&quot;, product: .framework, dependencies: [
 .target(&quot;Utilities&quot;)
])
let utilities = Target(name: &quot;Utilities&quot;, product: .staticLibrary)
</code></pre>
<p>Furthermore, it generates Xcode projects with just the pieces that the developer needs to do their work. The distractions are taken away to help developers have more <strong>focus</strong> and bring joy scaling their project up.</p>
<h2 id="2-environment">2 - Environment</h2>
<p><em>How often have you tried to compile an app, and after some time, it fails because a necessary certificate is not present in your Keychain?</em> The more dependencies the project has with the environment, the more likely that scenario is to happen. Using <a rel="external" href="https://github.com/SwiftGen/SwiftGen">SwiftGen</a> to generate code from our resources, or <a rel="external" href="https://github.com/Carthage/Carthage">Carthage</a> to embed dynamic frameworks, is an implicit dependency. If they don't exist, the compilation might fail.</p>
<p>Teams overcome this problem by including in the project <code>README.md</code> a list of steps that they need to execute before opening the project in Xcode. There are two caveats with this approach: it's hard to ensure that developer environments are configured consistently <em>(e.g. the same version of a tool)</em> and notify them when one of the dependencies requires an update <em>(e.g. a new certificate to be installed in the Keychain)</em>.</p>
<p>Tuist provides a command, <code>tuist up</code>, to verify and configure the environment. Teams just need to describe the configuration in a <code>Setup.swift</code> file:</p>
<pre><code>import ProjectDescription

let setup = Setup([
 .homebrew(packages: [&quot;swiftlint&quot;, &quot;SwiftGen&quot;, &quot;Carthage&quot;]),
 .carthage(platforms: [.iOS])
])
</code></pre>
<p>Moreover, and this is not implemented yet, it'll provide an interface to describe the signing. It'll use that description to install the right certificates in the Keychain, place the provisioning profiles in the right directory, and configure the Xcode during the project generation.</p>
<p>Tuist is more strict than Xcode with the validation of the projects and the environment. <strong>If it knows that the project won't compile, it fails immediately.</strong> Developers time is precious and shouldn't be wasted.</p>
<h2 id="3-misconfigurations">3 - Misconfigurations</h2>
<p>The growth of Xcode projects come with complexity, and when things become complex, it's easier to make mistakes. A wrong build settings flag or a missing argument in a script build phase can be the source of compilation and App Store validation errors.</p>
<p>Xcode runs weak validations on projects. It assumes the developers know what they are doing, and heavily relies on components like the build system or the app uploader to catch issues. There are two drawbacks with that approach:</p>
<ul>
<li>It might take some time. For example, if a dynamic framework is being copied into another framework. The error will show up when the app is being uploaded to the store. - Most of the times, the errors say nothing about the source of the error. For instance, if you try to link a iOS framework against a macOS's <em>(something that Xcode allows)</em>, the compilation will fail with a <code>framework not found</code> error message.</li>
</ul>
<p>Tuist is more strict in this regards and runs validations during the project generation. If it knows something won't compile, it'll fail and tell developers why. We understand configuring a large project can be a hard task, and we want developers to do it right <strong>at any scale.</strong></p>
<h2 id="4-consistency">4 - Consistency</h2>
<p>Consistency is crucial to scale up apps. Without it, the work across multiple projects becomes more difficult. Jumps between projects require an extra effort to understand how projects differ from each other. Moreover, inconsistent projects are more error prone.</p>
<p>Although ensuring consistency is easier when all the Xcode projects are part of the same repository, Xcode doesn't help much with it. The only feature that helps with consistency by reusing build settings across projects are the <code>.xcconfig</code> files.</p>
<p>Consistency can also manifest in:</p>
<ul>
<li>The list of targets of each of the projects. - The list of target build phases and their names. - The list of project schemes and their configuration.</li>
</ul>
<p>The way Tuist helps making the projects more consistent is by having a programmable interface where developers can leverage Swift features like functions. The definition of a project can be the result of calling a function:</p>
<pre><code>func frameworkProject(name: String) -&gt; Project {
 // Targets
 let framework = Target(name: name, product: .framework)
 let unitTests = Target(name: &quot;\(name)Tests&quot;, product: .unitTests)
 let uiTests = Target(name: &quot;\(name)UITests&quot;, product: .uiTests)
 let targets = [framework, unitTests, uiTests]

 return Project(name: name, targets: targets)
}

let searchFramework = frameworkProject(name: &quot;Search&quot;)
let coreFramework = frameworkProject(name: &quot;Core&quot;)
</code></pre>
<p><em>How beautiful is that?</em> Using Swift over declarative formats like YAML makes it possible without having to re-invent the well.</p>
<h2 id="5-complexities">5 - Complexities</h2>
<p>One of the most important lessons that a developer can learn for coding is KISS <em>(keep it simple and stupid)</em>. I believe the same applies to Xcode projects. In this case, the complexity is hard to avoid because it's Xcode the one exposing it.</p>
<p>After the creation of projects, Xcode leaves the developers with the responsibility of maintaining and keeping them up to date. That's proven not to be an easy job. For instance, with the recent introduction of support for Swift Packages in Xcode, many developers are still <a href="https://pepicrft.me/blog/project-generation/__GHOST_URL__/2019/06/23/the-tale-xcode-projects-complexity/">figuring out how the new Tetris piece fits their overly complex projects</a>, that are perhaps already using CocoaPods or Carthage.</p>
<p>Tuist has taken a stance similar to the one Rails has in the web ecosystem: <em>complex tasks are abstracted and made easier, and only if necessary, developers can manage intricacies by themselves.</em> It defaults to simplicity and prevents the complexity of the projects' structure from growing proportionally with the number and size of the projects.</p>
<p>Believe me, seeing how easy it is to describe the structure of a large project also makes scaling apps a enjoyable task.</p>
<h2 id="6-workflows">6 - Workflows</h2>
<p>Many projects depend on tools like <a rel="external" href="https://cocoapods.org">CocoaPods</a>, <a rel="external" href="https://github.com/SwiftGen/SwiftGen">SwiftGen</a>, or <a rel="external" href="https://github.com/krzysztofzablocki/Sourcery">Sourcery</a> to be run before opening the project. If developers forget to run them, they might end up getting errors. They are sometimes obvious errors, like your <code>Podfile.lock</code> is out of sync, but other times they are not. Some teams decide to automate all these tasks using Fastlane lanes, which calls underlying system commands:</p>
<pre><code>lane :bootstrap do
 cocoapods
 swiftgen
 sourcery
end
</code></pre>
<p>Installing the team's certificates and provisioning profiles is another example. Many teams in the industry decided to use Fastlane for that, but again, we are putting the developer in the position of having to remember running <code>fastlane match</code>, and knowing which certificates/provisioning profiles they need for the job at hand.</p>
<p><em>What if if all those tasks where beautifully integrated into the process of generating a project?</em> That's what Tuist aims for. It determines which tasks need to be executed, and executes them as part of the project generation. The idea is the developer doesn't have to think about all of that. They can just remember one and easy to remember command:</p>
<pre><code>tuist generate
</code></pre>
<h2 id="7-conflicts">7 - Conflicts</h2>
<p>Having many Git conflicts is perhaps one of the most annoying things of working on large Xcode projects. The likeliness of having conflicts is proportional to the amount of people contributing to the project, and in the case of Xcode, to the size of the project. Xcode projects have a monolithic structure; most of their content lives in a file, the <code>project.pbxproj</code>. Any change to the project through Xcode gets reflected in that file.</p>
<p>If there are many branches being merged in your project, having to rebase often to solve git conflicts can be very annoying, even more if the CI takes long every time we rebase and push the changes to remote.</p>
<p>Tuist diminishes the conflicts because Xcode projects don't need to be part of the repository.</p>
<h2 id="8-file-patterns">8 - File patterns</h2>
<p>Xcode projects have references to the files and folders that are part of it. Because of that, it was very common to end up with a project files and folders hierarchy that was inconsistent with the structure in the filesystem. This has improved with the recent Xcode versions, but it's still certainly annoying having to drag &amp; drop files to the Xcode projects to use them from targets.</p>
<p>Tuist makes that way easier by using glob patterns. Rather than individually referencing files, we can define a glob pattern, for example <code>Sources/**/*.swift</code>, and Tuist will unfold the pattern and add the resolved paths to the project. This makes it easier to define conventions in regards to the folders structure. For example, the example below is a function that ensures that all the targets, regardless of the project they belong to, have the sources in the same directory.</p>
<pre><code>func target(name: String) -&gt; Target {
 return Target(name: name,
 sources: &quot;Sources/**/*.swift&quot;)
}
</code></pre>
<h2 id="9-cli">9 - CLI</h2>
<p>Xcode provides <code>xcodebuild</code>, a command line tool to interact with the project. Both, its input and and output are so verbose that most developers wrap them with tools like <a rel="external" href="https://docs.fastlane.tools/actions/gym/">Gym</a> or <a rel="external" href="https://github.com/xcpretty/xcpretty">xcpretty</a>. Moreover, there are common use cases like building, signing, and publishing the app to the App Store, that require the interaction with other CLIs besides <code>xcodebuild</code>. Most projects solve this issue by using <a rel="external" href="https://fastlane.tools/">Fastlane</a>, but that creates a new contract between the <code>Fastfiles</code> and your projects that can break easily, and as a consequence, present developers with failing lanes that they need to debug and fix. <em>Have you ever experienced trying to release an app, and running into issues because someone changed something in the signing settings of the project and forgot to update that lane that configures the environment for signing?</em></p>
<p>Tuist knows your projects and will leverage that information to offer a simple set of commands. Being positioned in a directory where there's a project defined, I could execute something like:</p>
<pre><code>tuist build
</code></pre>
<p>And that'd build all the targets from the project in the current directory. If building requires installing CocoaPods dependencies, or generating code for your resources using SwiftGen, Tuist will do it as part of the command execution. The idea here is removing the need of having to use a tool like Fastlane, which in my experience, results in complex Fastiles that grow proportionally with the number of Xcode projects. Tuist embraces <a rel="external" href="https://en.wikipedia.org/wiki/KISS_principle">KISS</a>.</p>
<h2 id="10-caching">10 - Caching</h2>
<p>At some point in the growth of a projects, build times start affecting developers' productivity. They push code to GitHub and it takes over 20 minutes to compile. We consider using <a rel="external" href="https://github.com/Carthage/Carthage">Carthage</a> to precompile the dependencies, and that gives us a bit of breath that is insignificant compared to the compilation time of the project. We heard that <a rel="external" href="https://github.com/facebook/buck">Buck</a> and <a rel="external" href="https://bazel.build/">Bazel</a> help mitigate the issue, but our team is so small that we can't invest time and resources into replacing our build system entirely. We hope for Apple to release new versions of the Swift compiler and magic flags that speed up our builds, but that's being too hopeful; they optimize for the majority of their userbase, and that's small-medium sized apps.</p>
<p>One of Tuist's goals is to help with this need projects have when they scale. The idea is very simple. All the modules, being a module a framework or a library, are hashed, compiled, and uploaded to a cloud storage. That's done for every commit that is built on CI. When developers want to work with the project locally, Tuist generates the dependency graph, and generates the project by using pre-compiled modules for those targets that we don't plan to work on. For instance, let's say we have an App that depends on a dynamic framework <code>Search</code>, which depends on another framework called <code>Core</code>. Since we only plan to work on the app at the moment, Tuist will give us a project hat contains a target with the source code of the app, which links against <code>Search</code>, and copies both <code>Search</code> and <code>Core</code> into the product directory.</p>
<hr />
<p>All of that makes me very excited when I work on Tuist. I believe working on a large Xcode project has to be as fun as working on small ones. Over the years, I've seen tools like Fastlane helping small/medium projects, and tools like Buck and Bazel helping large ones, but there's space in the middle of that spectrum where projects end up hacking their way through to scale. I dream with the Rails for the development of apps using Xcode. A tool that provides simple abstractions and makes it easier to enforce practices at any level of the project.</p>
<p>If that sounds exciting, and would like to take part on this journey, you can start by joining our <a rel="external" href="http://slack.tuist.io/">Slack channel</a> and reading <a rel="external" href="https://docs.tuist.io">the documentation</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Adding error tracking to a CLI written in Swift</title>
      <link>https://pepicrft.me/blog/adding-error-tracking-to-a-swift-cli/</link>
      <guid>https://pepicrft.me/blog/adding-error-tracking-to-a-swift-cli/</guid>
      <pubDate>Tue, 16 Jul 2019 12:00:00 +0000</pubDate>
      <description>Trying to add error tracking to Tuist, I realized how the process is not very straightforward. This blog post describes the process that I followed to help other Swift developers add error tracking to their CLI tools.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Software is written by imperfect creatures, humans, and as a consequence the imperfection manifests in the software in the shape of bugs. Languages like Swift can help us write free-of-bugs software, but they'll never be able to help us get rid of them entirely.</p>
<p>When bugs happen, it's crucial to be notified automatically with the right information that helps us debug and fix the bug quickly. That's why platforms like <a rel="external" href="https://try.crashlytics.com/">Crashlytics</a> or <a rel="external" href="https://sentry.io">Sentry</a> exist. They provide an SDK to add to your projects that collect handled and unhandled errors and report them to a web service. If you are an iOS developer, you are most likely familiar with them.</p>
<p><a rel="external" href="https://tuist.io">Tuist</a> didn't have error reporting, making it hard to know when errors happened and why. Moreover, we were relying on users to know about bugs. If they didn't create GitHub issues, we had no way to know that they were facing bugs while using the tool.</p>
<p>I recently worked on adding error reporting to Tuist, which turned out not to be an straightforward task. This blog post is a summary of all the steps that I followed. Developers building command line tools using the <a rel="external" href="https://swift.org/package-manager/">Swift Package Manager</a> might find this blog post useful.</p>
<h2 id="download-the-dynamic-framework">Download the dynamic framework</h2>
<p>The first thing that we need to do is pull the dynamic framework of your error tracking platform. Most services provide a dynamic framework, if not, you can ask them for it. <a rel="external" href="https://github.com/getsentry/sentry-cocoa/releases">Here's</a> for instance the list of Sentry releases, which contain the dynamic framework attached to it.</p>
<blockquote>
<p>Setting up error tracking with a static framework it's also possible, but in this post I'll focus on the dynamic approach.</p>
</blockquote>
<p>Place the framework under <code>./Frameworks/</code> <em>(e.g. <code>./Frameworks/Sentry.framework</code>)</em>.</p>
<h2 id="generate-an-xcode-project-that-links-against-the-framework">Generate an Xcode project that links against the framework</h2>
<p>Once we have the framework, we need to tell the Swift Package Manager to set up the generated Xcode project to use it. Although there isn't a public API that we can use from our project's <code>Package.swift</code> file, there's an undocumented API that we can leverage. Create a file, <code>MyTool.xcconfig</code>, where <code>MyTool</code> is the name of your tool, and add the following content:</p>
<pre><code>LD_RUNPATH_SEARCH_PATHS = $(inherited) $(SRCROOT)/Frameworks
FRAMEWORK_SEARCH_PATHS=$(inherited) $(SRCROOT)/Frameworks
OTHER_LDFLAGS = $(inherited) -framework &quot;Sentry&quot;
</code></pre>
<ul>
<li><strong>LD_RUNPATH_SEARCH_PATHS</strong>: Defines a list of directories where the dynamic linker can look up the linked frameworks. We are adding <code>$(SRCROOT)/Frameworks</code>, which is the <code>Frameworks</code> directory relative to the path where the generated Xcode project is. - <strong>FRAMEWORK_SEARCH_PATHS</strong>: Defines the directories that contain the frameworks to be linked during the compilation process. - <strong>OTHER_LDFLAGS:</strong> With this setting we include the linker flag <code>-framework Sentry</code> to link against the Sentry framework. You'll need to replace Sentry with the name of your framework.</li>
</ul>
<p>With the file <code>MyTool.xcconfig</code> in the project directory, we can run the following command:</p>
<pre><code>swift package generate-xcodeproj --xcconfig-overrides MyTool.xcconfig
</code></pre>
<p>Notice the <code>---xcconfig-overrides</code> the argument that indicates the SwiftPM to use a different xcconfig file for the generated Xcode project.</p>
<p>Try to import your framework and use its API. The Xcode project should compile:</p>
<pre><code>// main.swift
import Sentry

// Your setup logic
</code></pre>
<h2 id="build-the-swift-package-from-the-terminal">Build the Swift package from the terminal</h2>
<p>If you try to run <code>swift build</code> at this point, it'll fail. Although the generated Xcode project includes the build settings to link against the framework, SwiftPM doesn't use the Xcode project to compile your tool and therefore, it doesn't know how to link the framework.</p>
<p>Fortunately, the <code>swift build</code> command accepts arguments to be passed to the compiler:</p>
<pre><code>swift build \
 --configuration Release \
 --Xswiftc -F -Xswiftc ./Frameworks/ \
 --Xswiftc -framework -Xswiftc Sentry
</code></pre>
<p>If we run that command, we should get the tool compiled and linked dynamically against the framework.</p>
<h2 id="add-the-runtime-path">Add the runtime path</h2>
<p>If we distribute the binary under <code>.build/release/MyTool</code>, users will get an error when they try to run it from the terminal. Since the framework is dynamically linked, the linker will try to link the framework at runtime and will fail because it won't be able to find it.</p>
<p>To fix the issue, you need to make sure of 2 things:</p>
<ul>
<li>The frameworks is copied as part of the installation. - The directory where the framework is placed is part of the binary runtime search paths.</li>
</ul>
<p>If we assume we'll copy the framework into the <code>/usr/local/Frameworks</code> directory, we can run the following command to add that directory to the runtime search paths.</p>
<pre><code>install_name_tool -add_rpath &quot;/usr/local/Frameworks&quot; &quot;/path/to/MyTool&quot;
</code></pre>
<p>After running that command, and having the error tracking framework in that directory, you should be able to run the tool successfully.</p>
<h2 id="conclusions">Conclusions</h2>
<p>As we have seen, the process is not as straightforward as it could be with other programming languages like Swift. The complexity comes from the fact that the SwiftPM doesn't provide an API to link against existing pre-compiled dynamic frameworks, nor a way to handle the installation of the tools and its dependencies in the user's environment.</p>
<p>I hope you found the blog post useful and that it encourages you to add error tracking to your command line tools written in Swift.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Derived Info.plist files</title>
      <link>https://pepicrft.me/blog/derived-info-plist/</link>
      <guid>https://pepicrft.me/blog/derived-info-plist/</guid>
      <pubDate>Fri, 12 Jul 2019 12:00:00 +0000</pubDate>
      <description>In this mini-post I talk about some recent work that I&#x27;ve done in Tuist to support defining Info.plist files in the manifest file.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Today I found some time to do some work on <a rel="external" href="https://github.com/tuist/tuist/pull/380">this PR</a>, which allows Tuist users to define the content of their <code>Info.plist</code> files in the project manifest. Although it doesn't add much value compared to having the content in a <code>Info.plist</code> file, it opens the door to a powerful abstraction: inheriting product-base values that developers can extend with their target-specific keys.</p>
<pre><code>let infoPlist = InfoPlist.default(extend:[
 &quot;CFBundleShortVersionString&quot;: &quot;1.0&quot;,
 &quot;CFBundleVersion&quot;: &quot;1&quot;
])
let target = Target(name: &quot;MyFramework&quot;, infoPlist: infoPlist)
</code></pre>
<p>As we can see, we just need to override the values that our target is interested in providing, the rest is provided by Tuist. As part of the project generation, Tuist creates the file at <code>/path/to/project/Derived/InfoPlists/MyFramework.plist</code>.</p>
<p>The <code>Derived</code> directory only contains the <code>Info.plist</code> files for now, but we may store more types of files in the future. For instance, I'm considering integrating <a rel="external" href="https://github.com/SwiftGen/SwiftGen">SwiftGen</a> into Tuist, storing the generated code under <code>Derived/SiftGen*</code>.</p>
<p>It's exciting seeing Tuist abstracting all the complexities and most importantly, seeing how the architectural decisions that we made are enabling this effort.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Running system tasks with Swift and Foundation</title>
      <link>https://pepicrft.me/blog/running-system-tasks-on-macos/</link>
      <guid>https://pepicrft.me/blog/running-system-tasks-on-macos/</guid>
      <pubDate>Wed, 10 Jul 2019 12:00:00 +0000</pubDate>
      <description>In this blog post, I talk about my experience using one of Foundation&#x27;s APIs, Process.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Have you ever tried to use Foundation's API on macOS to run system tasks? Perhaps you know the class <a rel="external" href="https://developer.apple.com/documentation/foundation/process"><code>Process</code></a>, which is provided exactly for that purpose. I tried to used it in <a rel="external" href="https://www.angle.dev">Angle</a>, a side project that I'm developing with some friends, and I'm struggling to use it properly. These are the issues that I ran into:</p>
<ul>
<li>When the application that triggers the process gets killed, the process remains running. After digging around, I <a rel="external" href="https://github.com/Carthage/ReactiveTask/blob/master/Sources/Task.swift#L408">found</a> that there's a private method, <code>setStartsNewProcessGroup:</code> to tell the process whether it should terminate when the process that triggers it finishes. Why is that method private? - It doesn't ensure that the standard output, error, and completion events are serialized in the same order. That may result in events coming in the wrong other, for example, a process that completes before the standard error message comes. Projects like <a rel="external" href="https://github.com/JohnSundell/ShellOut/blob/master/Sources/ShellOut.swift">ShellOut</a>, which wrap <code>Process</code> to provide a more convenient API, <a rel="external" href="https://github.com/JohnSundell/ShellOut/blob/master/Sources/ShellOut.swift#L357">have to use</a> to ensure the events come in the right order.</li>
</ul>
<p>The best implementation that I found so far to run tasks in the system is the one from the Swift Package Manager, which interestingly, doesn't use Process but its <a rel="external" href="https://github.com/apple/swift-package-manager/blob/master/Sources/Basic/Process.swift">own implementation</a> of it. Unfortunately, you can't/shouldn't copy-paste the class into your project.</p>
<p>It's unfortunate that those issues haven't been tackled. The API is not very user-friendly and there's a lot of room for improvement to make it more straightforward to use. If we look at Ruby's API, this is how we look like:</p>
<pre><code>require &#39;open3&#39;

# Launch the process and capture the standard output in a variable.
developer_path = `xcode-select -p`

# Launch the process and forward the standard output and error.
system(&quot;xcodebuild&quot;, &quot;build&quot;, &quot;-project&quot;, &quot;MyProject.xcodeproj&quot;) || abort

# Launch the process and capture the standard output and error
stdout_str, stderr_str, status = Open3.capture3(&quot;xcrun&quot;, &quot;simctl&quot;, &quot;list&quot;, &quot;devices&quot;, &quot;-j&quot;)

# Launch the process and call the block with the
Open3.popen3(&quot;xcodebuild&quot;, &quot;build&quot;, &quot;-project&quot;, &quot;MyProject.xcodeproj&quot;) {|stdin, stdout, stderr, wait_thr|
 pid = wait_thr.pid
 exit_status = wait_thr.value
}
</code></pre>
<p>As you can see, we have several options from which we can choose depending on what we'd like to do with the process:</p>
<ul>
<li>Fire and forget. - Fire and collect its output. - Fire and notify me when the an event <em>(e.g. standard output data)</em> has been sent.</li>
</ul>
<p>The most reliable abstraction that I've found is <a rel="external" href="https://github.com/Carthage/ReactiveTask">ReactiveTask</a>, which is developed by the Carthage team and used by Carthage. It provides a beautiful reactive API using <a rel="external" href="https://github.com/ReactiveCocoa/ReactiveSwift">ReactiveSwift</a>, with which you can use Reactive operators and subscribe to the events that you are most interested in. If there's a good use case for the usage of the reactive paradigm, this is to me one. A process is an operation that starts, sends a bunch of events, and then completes.</p>
<p>Unfortunately 😕, Angle has already <a rel="external" href="https://github.com/ReactiveX/RxSwift">RxSwift</a> as a dependency, and I doubt it's a good idea to add another reactive library to the stack. For that reason, I started developing internally an implementation similar to ReactiveTask's, but using RxSwift. It's still WIP, but if I'm happy with the result, we might open source it.</p>
<p>I wonder if I'm the only one having this experience with the <code>Process</code> class, or there are other developers that are struggling with the same issues. If you are one of those, I'm curious to know how you overcame them.</p>
<p>Have a wonderful week!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>All you need is tools (talk)</title>
      <link>https://pepicrft.me/blog/all-you-need-is-tools-talk/</link>
      <guid>https://pepicrft.me/blog/all-you-need-is-tools-talk/</guid>
      <pubDate>Tue, 09 Jul 2019 12:00:00 +0000</pubDate>
      <description>This post contains the video of the talk that I gave at AltConf about why I think it&#x27;s important investing into tooling and some tips to build great tools.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[]]></content:encoded>
    </item>
    
    <item>
      <title>How I feel working on Tuist</title>
      <link>https://pepicrft.me/blog/how-i-feel-working-on-tuist/</link>
      <guid>https://pepicrft.me/blog/how-i-feel-working-on-tuist/</guid>
      <pubDate>Wed, 03 Jul 2019 12:00:00 +0000</pubDate>
      <description>A random reflection about Tuist and why I&#x27;m so glad working on it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It’s been a long time working on Tuist, and despite some downs, I continue to be excited about the project. In hindsight, these are the facts that contribute to that:</p>
<ul>
<li>I had the opportunity to meet and work with enthusiastic people that bring a lot of ideas and good vibes for the project. They found a lot of value in the project and are giving a lot back. Seeing them contributing to the project is very inspiring. For instance, this week I sent them some Tuist stickers and a small letter thanking them for the contribution. - It’s an interesting challenge in a domain where most of the standards, frameworks and tools are given by Apple. It sometimes feel like rowing a small boat next to a cruise, but that’s fun too. The fact that we are a tiny project allows us to be closer to developers and have a more iterative process to help them scale. - Swift is relatively new in the command line tooling space. As a consequence there are APIS like <code>Process</code> that are not as friendly as they could be. Exploring that territory and pushing the language forward feels great. - We started building a new element to take Tuist and teams’ productivity to the next level, Tuist Galaxy. We aim to build a web platform that integrates with developers workflows and their tools (e.g Xcode, GitHub, Slack) and provides them with insights and useful information to ensure their projects are in a healthy state. Leveraging the web to make that possible is an interesting task. - We are no just building software, but a product. That means design, documentation, community, website, and so many other things from which I'm learning a lot.</li>
</ul>
<p>The only thing that I wish I could start doing is dog-fooding. It’s hard to get ideas, or build the ones that I have if I don’t use the project as part of my day to day job.</p>
<p>Anyway, I’m happy for what we achieved and looking forward for the months and years ahead.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The tale of Xcode projects&#x27; complexity</title>
      <link>https://pepicrft.me/blog/the-tale-xcode-projects-complexity/</link>
      <guid>https://pepicrft.me/blog/the-tale-xcode-projects-complexity/</guid>
      <pubDate>Sun, 23 Jun 2019 12:00:00 +0000</pubDate>
      <description>This is a short story of how Xcode projects can end up being very complex and hard to maintain.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>The CEO of our company wants the product to have an iOS app. We embark on building it, so we start by creating the project: we open Xcode, select new project, and then Xcode dumps the following into a local directory:</p>
<p><img src="https://pepicrft.me/blog/the-tale-xcode-projects-complexity/__GHOST_URL__/images/posts/project-tale-1.jpg" alt="Project tale 1s" /></p>
<p>What a beautiful greenfield. We click run and the simulator opens almost instantly with our app running in it. We probably don't know about many of those files that were created and the content in them but <em>who cares?</em> As long as we can compile it, it's all fine.</p>
<p>A few weeks later, the need of adding <strong>dependencies</strong> comes up. Someone in the team decides to introduce <a rel="external" href="https://cocoapods.org">CocoaPods</a>. By then the project has got a bit more complex; there were a few build flags added to speed up compilation, and some build phases to customize the build process a bit. CocoaPods tries to do its best to integrate the dependencies into the project but it fails at it. We blame CocoaPods because we believe it's CocoaPods fault. We don't realize that Xcode exposes so much complexity that CocoaPods can't define a contract between the Pods project and ours. Our project became complex, it's normal, and it's not our fault. After Stackoverflowing a bit, we find out the hack that will make the CocoaPods integration work. <em>Awesome!</em> Now we have external dependencies and we can add more if we need to.</p>
<p>Times goes by, the project continues to grow, and few months later, someone sees that <strong>modularizing</strong> the project helps with having clearly defined boundaries between features and better compilation times. The modularization requires creating a few frameworks, and therefore new targets with some files to configure them. It doesn't sound that hard. A few weeks later, the project is modularized. Some features have been moved into their own framework, others remain in the main app because their code is so tangled to the foundation of the project, that is impossible to extract them. Perhaps without realizing it, we end up with <em>similar projects and targets (build phases &amp; settings)</em> that barely reuse anything.</p>
<p>A year after we added the first line of code to the project, someone mentions the idea of replacing CocoaPods with <strong><a rel="external" href="https://github.com/carthage">Carthage</a></strong> because they heard its a better option. Someone said something about the source code being pre-compiled, and therefore faster builds. That sounds too good to be true, and it shouldn't be that much work according to the <code>README.md</code>. We add a few Carthage dependencies and our project doesn't compile; we added them as transitive dependencies of one of our frameworks and forgot to copy them into the app's bundle. Again, Stackoverflow has the solution to our problem: just a few tweaks and the project compiles. Since we want to be safe, we add the copy frameworks build phase that Carthage suggests to all the targets. Nothing can be wrong if I can compile the app and CI is green. Well... it is all fine until we try to release the app and Apple realizes that we are embedding frameworks that contain other frameworks. <em>What is this, inception?</em></p>
<p>The time to migrate the version of <strong>Swift</strong> comes. We want to try the latest and re-invented APIs that Apple presented in the last WWDC. We don't want to be that old-school project or company that ues Swift 3. Oh nice! Xcode suggests doing the migration for us. They must know what they are doing... We are too naive. Xcode assumes that our project is simple but it's not. After clicking the magic button our project not only doesn't compile, but leaves us with over hundred errors that are caused by who knows which flag. <em>What do we do?</em> Hopefully we use a version control system, so we revert the changes that Xcode introduced and do the migration manually. It turns out to be more painful than how Apple presented it during WWDC. Using the latest Swift version is worth the effort so we spend all the time that is necessary to do the migration. <em>Yay!</em> After a week, we can consider the migration complete.</p>
<p>It's 2019, the flying bird knows how to drop packages in projects. It flies over our project, but it's confused. It doesn't know where to drop them. <em>How did we end up in this situation?</em></p>
<p><img src="https://pepicrft.me/blog/the-tale-xcode-projects-complexity/__GHOST_URL__/images/posts/project-tale-2.jpg" alt="Project tale 2" /></p>
<h2 id="takeaways">Takeaways</h2>
<p><em>Is there any part of the story that resonates with you?</em> It's easy end up with a lot of accidental complexity if we are not aware of the implication of each of the changes that we are adding to our projects. Xcode projects are monoliths and barely allow reusing its pieces. Complexity makes the projects hard to maintain and migrate. We can see that when developers use Xcode's feature to migrate projects. <em>Hast it ever worked for you?</em> Perhaps if it's a single-target application. We all know that one-target project is how we start but we eventually end up with many of them <em>(libraries, extensions, apps for other platforms)</em>.</p>
<p><em>What can we do if we don't want to be there?</em> The first option would be to wait for Apple to rethink the format of the projects like they do with hardware. I had some hope for this year but nothing was presented. Instead, they keep extending the project format, this time with the support for Swift packages. You probably didn't realize, but they leveraged the closeness of Xcode, to make a seamless integration of dependencies possible. They did what CocoaPods tried for a long time, but they couldn't because Apple didn't allow them to do so.</p>
<ul>
<li><strong>Default to simplicity but open to configuration:</strong> Only expose details whose developers are interested in. Otherwise, default to default values. - <strong>Allow reusability of project elements:</strong> Being able to define elements like build phases or schemes in one place, and use them from multiple projects and targets.</li>
</ul>
<p>The second option would be using <a rel="external" href="https://tuist.io">Tuist</a>, an open source tool that I'm maintainer of. It makes the definition of the projects more declarative and abstracts developers from all the intricacies that are often the source of the aforementioned issues. <strong>Only if they need to</strong>, developers can have fine-control over the low-level projects configuration.</p>
<p>Until Apple decides to invest in developers experience scaling their projects, you can give Tuist a try. I'd love to help you set it up if you are interested in using it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>The urge to be the first</title>
      <link>https://pepicrft.me/blog/the-urge-to-be-the-first/</link>
      <guid>https://pepicrft.me/blog/the-urge-to-be-the-first/</guid>
      <pubDate>Thu, 20 Jun 2019 12:00:00 +0000</pubDate>
      <description>Just an observation of a trend that I&#x27;ve seen in our industry: developers rushing to be the gain the label of expert in a given technology.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I have the impression that there's a increasing urge to be the first in our industry. The first one to write a blog post about SwiftUI, a book, a podcast, a talk, an opinion to be pushed onto others. I'm honestly exhausted when I look at Twitter these days. I haven't had time to watch the talks or read the official documentation, but I feel I know a lot about SwiftUI. I know a lot through the lenses of those who are running the race to be the first one, to be assigned the label of expert on the technology. <em>God sake!</em></p>
<p>Good for them. They are responsible for their time and how they want to use it. What bothers me though, is that they are normalizing <em>"being exhausted"</em>. They don't understand that we are not running that race, but they somehow want us to feel part of it. No, that's the marathon they decided to run, not us. Some people praise that behavior; I'll never do so.</p>
<p><strong>There's beauty in going slowly, in learning things as we come across them.</strong> I'm learning to ignore all those unhealthy attitudes. I don't want to stress out because I can't participate in discussions about SwiftUI, nor have I an opinion about it. It's ok.</p>
<p>We often talk about burnout and how to overcome it, yet we barely talk about what leads us to it. Meditation is great, but in my opinion, the proliferation of meditation apps is a symptom of something not working in our industry. As much as I can, I'll reject and talk about unhealthy behaviors like this one that might lead to burnout. We, as a community, should not accept such things, and most importantly, reject them to help others not end up being exhausted in their lives.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Speaking at AltConf</title>
      <link>https://pepicrft.me/blog/altconf-2019/</link>
      <guid>https://pepicrft.me/blog/altconf-2019/</guid>
      <pubDate>Sat, 08 Jun 2019 12:00:00 +0000</pubDate>
      <description>A brief post talking about my experience speaking at AltConf 2019 in San Jose.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>A few days ago I gave a talk at AltConf in San Jose. Even though it’d been a while without giving a talk publicly, it went very well.</p>
<p>Seeing familiar faces in the crowd and talking about something that I’ve been working for a long time brought me a lot of confidence. I spoke relaxed, not feeling nervous at all, and I was even able to make some jokes and demo Tuist, the open source tool that I’m most proud of maintaining.</p>
<p>This reinforced something that I’m huge advocate of, sharing without having experienced is like teaching someone life lessons without having experienced them yourself. Learning is a long process. We can read many books on a topic but we’ll struggle to assimilate the knowledge if we don’t get our hands dirty.</p>
<p>I felt my hands were dirty, perhaps not as much as I could, but I believe enough to share some lessons and give the attendees some takeaways for their projects.</p>
<p>Moreover, it was great to meet people with whom I’d only talked over Slack or GitHub. It’s so much nicer to talk to people in person. That made me think that I should jump more into calls to see other developers’ faces and have spontaneous chat. I’m so grateful of having connected to those people thanks to open source projects.</p>
<p>I’m almost landing in Zurich after having flown from San Francisco. The WWDC break is over. I’m excited to seeing all the improvements that are landing to the Apple OS, although I’m not coding apps anymore. There’s been a fair amount of improvements that we’ll leverage at Shopify to make developers productive, and that’s exciting.</p>
<p>I wish you all a great weekend.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Abstracting Info.plist files</title>
      <link>https://pepicrft.me/blog/infoplists/</link>
      <guid>https://pepicrft.me/blog/infoplists/</guid>
      <pubDate>Wed, 08 May 2019 12:00:00 +0000</pubDate>
      <description>On this blog post I talk about an idea that I&#x27;m pondering for Tuist. In the aim of abstracting implementation details from Xcode projects, I think there&#x27;s an opportunity for Tuist to abstract `Info.plist` files which are barely modified by developers after they get created.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If you have worked with Xcode projects before, you might know what <code>Info.plist</code> files are. For those of you who are not familiar with them, they are plain xml files with key-value pairs that define app settings such as the icon or the build number. Below you find an example of the structure of the file:</p>
<pre><code>xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?



	CFBundleDevelopmentRegion
	$(DEVELOPMENT_LANGUAGE)
	CFBundleDisplayName
	MyApp
	CFBundleExecutable
	$(EXECUTABLE_NAME)
	...
	AppIdentifierPrefix
	$(AppIdentifierPrefix)
</code></pre>
<p><code>Info.plist</code> files are created when developers create a new target <em>(e.g. a new iOS application)</em>. Most of the entries in the file are necessary but they are barely modified after the file is created. The entries that developers change the most is the version and build numbers. For others like the main storyboard or the icon, Xcode provides a UI interface to change the value.</p>
<p>As you might know, one of the aims of <a rel="external" href="https://tuist.io">Tuist</a> is abstracting away the details that we believe developers shouldn't be exposed to. I think those <code>Info.plist</code> values that are barely touched are a perfect candidate for abstraction.</p>
<p>I've been thinking about how that abstraction would be, and this is the idea I came up with:</p>
<pre><code>enum InfoPlist {
 case file(Path)
 case dictionary([String: Any])
 static func productDefaults(extend: [String: Any]) -&gt; InfoPlist
}
</code></pre>
<ul>
<li><strong>file:</strong> If the user project has already an <code>Info.plist</code> file and they'd like to continue maintaining it themselves, this is the best option. The target will be generated accordingly to point to the local file. Notice that this is the only option that Tuist offers currently. - <strong>dictionary:</strong> If the wants to define the content of the file in the project manifest and let Tuist generate the <code>Info.plist</code> file this is the option. When Tuist generates the project, it'll also generate the file right next to the project in a directory that contains this and other generated files. - <strong>productDefaults:</strong> As I mentioned earlier, developers barely modify the values in that file. The one that they usually modify when they release a new version of the app is the build and version numbers. This option tells Tuist to use the default values of the target product, allowing the user to extend them as needed.</li>
</ul>
<p>Below you find some examples of how the definition of the target would look. Note that for simplicity of the examples, the targets don't take all the arguments that are required:</p>
<pre><code>// Existing Info.plist file
let watchApp = Target(name: &quot;MyWatchApp&quot;, infoPlist: .file(&quot;./WatchApp.plist&quot;))

// Generated Info.plist file with the given dictionary
let framework = Target(name: &quot;MyFramework&quot;, infoPlist: .dictionary([
 &quot;CFBundleExecutable&quot;: &quot;$(EXECUTABLE_NAME)&quot;,
 &quot;AppIdentifierPrefix&quot;: &quot;$(AppIdentifierPrefix)&quot;
]))

// Generated Info.plist file extending the platform default values.
let app = Target(name: &quot;MyApp&quot;, infoPlist: .productDefaults(extend: [
 &quot;CFBundleInfoDictionaryVersion&quot;: &quot;6.0&quot;,
 &quot;CFBundleVersion&quot;: &quot;1.0&quot;
]))
</code></pre>
<p>One of the most beautiful features of Tuist in my humble opinion is that manifests are written in Swift. That allows us to take benefit of extensions and <code>Foundation</code> protocols to simplify the interface:</p>
<pre><code>extension InfoPlist: ExpressibleByDictionaryLiteral {
 init(dictionaryLiteral elements: (String, Any)...) {
 self = .dictionary(Dictionary(uniqueKeysWithValues: elements))
 }
}

extension InfoPlist: ExpressibleByStringLiteral {
 init(stringLiteral value: String) {
 self = .file(value)
 }
}
</code></pre>
<p>Thanks to those extensions, we can turn the examples into:</p>
<pre><code>// Existing Info.plist file
let watchApp = Target(name: &quot;MyWatchApp&quot;, infoPlist: &quot;./WatchApp.plist&quot;)

// Generated Info.plist file with the given dictionary
let framework = Target(name: &quot;MyFramework&quot;, infoPlist: [
 &quot;CFBundleExecutable&quot;: &quot;$(EXECUTABLE_NAME)&quot;,
 &quot;AppIdentifierPrefix&quot;: &quot;$(AppIdentifierPrefix)&quot;
])
</code></pre>
<p>By giving Tuist more control over those files, we can <strong>run validations</strong> and verify that they contain the required attributes with the right values. As an example, watchOS extensions have a strict requirement when it comes to the bundle id of the extension. Since that's an attribute configured in the <code>Info.plist</code>, we could verify that the value is right according to the watch app they are associated to.</p>
<p>Although developers can git-ignore those files because they get generated automatically when they run Tuist, I'd encourage them to keep them in the repository so that developers can checkout any revision of the project and compile it with Xcode without having to install Tuist.</p>
<p>An idea that I'm still pondering is how to structure the directory that contains the generated files. <code>Info.plist</code> files will be the first ones living in this directory but I'm sure they won't be the only ones. Here's a rough idea that I just had:</p>
<pre><code>./Project.swift
./Generated
 InfoPlists/
 App.plist
 MyFramework.plist
</code></pre>
<p>I'll sleep over the idea experiment with it to see how it feels in practice. If you have an opinion on it and don't mind sharing, I'd appreciate it a lot. Don't hesitate to ping me on Twitter, send me an email, our join <a rel="external" href="https://slack.tuist.io">Tuist's Slack</a> where you can talk to other contributors and maintainers.</p>
<p>I wanted to start coding on my flight ✈️ to Alicante but unfortunately, I forgot to run <code>swift package generate-xcodeproj</code> and now I can't fetch the dependencies to do some coding 😕.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Xcode updates are fun</title>
      <link>https://pepicrft.me/blog/xcode-updates-are-fun/</link>
      <guid>https://pepicrft.me/blog/xcode-updates-are-fun/</guid>
      <pubDate>Fri, 12 Apr 2019 12:00:00 +0000</pubDate>
      <description>On this blog post I talk about Xcode updates and how painful they can sometimes be.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Last week we pushed the latest Xcode version to all the CI hosts. It's an exciting thing because you see the company projects keeping up with the tools, but updates are painful. There hasn't been any Xcode update that required any work other than installing it. We cross our fingers every time hoping for the update to be straightforward but we know that's being too optimistic. That never happens.</p>
<p>With Xcode 10.2, teams migrated their apps pretty quickly and we did our job installing Xcode on the CI hosts. Things seemed to be running smoothly until yesterday, when one of the teams tried to release a new version of the app to the store and the build failed. It's been two days of debugging and guess what, we haven't been able to figure it out yet. The app gets archived, but when we try to export it, the xcodebuild command gets killed by some other process that is out of our control.</p>
<p>We have tried many things but more we try, the more confused we are:</p>
<ul>
<li>It works locally but not on CI. - One project succeeds but the other fails. - The archive from CI can be successfully exported locally.</li>
</ul>
<p>At this point I wish I had access to xcodebuild to track down where issue is coming from but I know that won't be possible. xcodebuild is a black box whether we like it or not.</p>
<p>Right today, I attended a React conference in Amsterdam, and one of the things that I observed is how great it is that the Javascript industry have access to the source code of most of the tools that they use. The software that they use might be buggy, but at least they have the option to dive deep into the code and help solve the bugs.</p>
<p>We are not that lucky. Try and error is our best friend to understand the closed tooling that Apple provides. I remain optimistic though, and hope for a future where tools are open like Swift and that helps make our Xcode updates painless.</p>
<p>How has your Friday been?</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Reliably installing Xcode</title>
      <link>https://pepicrft.me/blog/reliably-install-xcode-versions/</link>
      <guid>https://pepicrft.me/blog/reliably-install-xcode-versions/</guid>
      <pubDate>Sat, 06 Apr 2019 12:00:00 +0000</pubDate>
      <description>I started developing a tool, install-xcode that aims to help developers to install and upgrade versions of Xcode easily. In this blog post I talk about the motivation behinds building it and some design principles that I&#x27;m embrazcing.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Apple hasn't traditionally done a good job at providing convenient channels for distributing their tools for development environments. A good example of that is Xcode. If you want to install it on your laptop and have an account on the App Store is fine. You just need to search for it, click download and voila 🎉! You can start coding straight away.</p>
<p>However, if the environment where you are trying to install Xcode doesn't have a GUI, the installation process is not straightforward. First of all, one needs to know the link where to download Xcode from. You can authenticate on the developer portal, go to the downloads section, and copy the link of the Xcode version that you wish to download. Not too much of a hassle, but it's one step that needs to be done manually. Optionally, you can depend on a third-party website like <a rel="external" href="https://xcodereleases.com/">xcodereleases</a>, which provides an up-to-date list of all the Xcode versions with their download link.</p>
<p>Compared to other apps that you can drag &amp; drop into the system <code>/Applications</code> directory and start using them, Xcode requires some additional steps to be executed:</p>
<ul>
<li>Agree with non-agreed or new licenses. - Install missing components.</li>
</ul>
<p><a rel="external" href="https://github.com/xcpretty/xcode-install">xcode-install</a>, a well-known Ruby tool from the community, has been the tool most teams resorted to, including Shopify. It drives the whole process asking the user for input if necessary <em>(like providing the 2 factor authentication code to authenticate the access to the download page)</em>. The tool makes the process more convenient, but in my experience, doesn't provide the level of reliability and convenience that one expects when upgrading Xcode versions. It's not something that we have to do every day, but when it has to be done, it's fairly frustrating seeing the tool dumping errors on the terminal. For that reason, I embarked on developing a new command line tool in Swift to help developers install and upgrade Xcode versions:</p>
<ul>
<li>The tool will be written in Swift. No more dependencies with Ruby or transitive native dependencies whose compilation might fail as stated on the <a rel="external" href="https://github.com/xcpretty/xcode-install#installation">xcode-install's README</a>. - It's distributed as a self-contained binary. Just install it anywhere on the system and run it. - No more authentication required from the installer. The list of versions will be synchronized periodically and placed on the repository as a json file, <code>downloads.json</code>. If all of a sudden Apple decides to introduce a 3 factor authentication with a short notice period, well, users of the tool won't have to change anything, we'll deal with that for them.</li>
</ul>
<p>It's still work in progress but you can look in to it <a rel="external" href="https://github.com/angledotdev/install-xcode">on this repository</a>.</p>
<p>I hope you are having a great weekend 🥘🌴</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>macOS development and being comfortable</title>
      <link>https://pepicrft.me/blog/macos-development/</link>
      <guid>https://pepicrft.me/blog/macos-development/</guid>
      <pubDate>Fri, 29 Mar 2019 12:00:00 +0000</pubDate>
      <description>I&#x27;ve been avoiding macOS development for no reason. This blog post is a short reflection on why I think I&#x27;ve been doing it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><em>How has your week been?</em> It's Friday, I'm having a sip of the first morning coffee, and I thought it'd be a good idea to write something down in my blog post. For years, I've been focusing on building iOS apps and tools around it. Developing macOS was always a far remote thing to me, and somehow postponed every time the idea of doing something for macOS came to my mind.</p>
<p><em>Have you ever procrastinated to not push yourself out of comfort zone?</em> That's exactly what happened to me with macOS. I felt comfortable with iOS and its frameworks, so the idea of confronting new frameworks and paradigms held me back from trying.</p>
<p>I recently started building an app with some friends, Angle, an app that will make it easier for software teams to collaborate when building features. This time I decided it was the time to get my hands dirty with macOS. To my surprise, it's not that different as I thought it would be. There's no reason of which being scared. I actually realized that I enjoy it a lot. It reminds me back 8 years ago when I was playing with iOS for the first time. Some APIs are different, some have some weird intricacies exposed and merely documented, but it's something one can easily learn with a bit of effort.</p>
<p><strong>How many things are we missing because our comfort zone is holding us back from experimenting new things?</strong> macOS was just one example but I think this happens to me in other areas of my life. When one grows, you and others put labels on you. You are the person <code>x</code>, that has personality <code>y</code>, that knows <code>z</code>, and that likes <code>w</code>. I have them. I also have prejudices about me. I know what I'm good at and areas where I'm not that good. I avoid them, no one ones to know that they are bad at something. I'd rather remain comfortable around the things in my domain.</p>
<p>Introducing myself into macOS has helped me realize that it's an stupid idea to get stuck in your comfort area. There are many things to explore and learn, and even though we have grown a personality, and with it a comfort zone, that does not mean that we cannot expand it. I'll work more and more on feeling uncomfortable.</p>
<p>Have a great weekend!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Interacting with Xcode projects in Swift</title>
      <link>https://pepicrft.me/blog/xcodeproj/</link>
      <guid>https://pepicrft.me/blog/xcodeproj/</guid>
      <pubDate>Fri, 15 Mar 2019 12:00:00 +0000</pubDate>
      <description>This blog post is an introduction to the format of Xcode projects and xcodeproj, a Swift library that helps read and update Xcode projects in Swift. The post contains a few hands-on examples for developers to experiment with the library.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There are some scenarios where it might be useful to do some automation on those files, for example, to detect references to files that don’t exist, or invalid build settings. Even though you could check those things by parsing the file yourself and traversing the structure, you can do it more conveniently with <code>xcodeproj</code>. It not only provides you with an API in Swift, but ensures that your changes in the project file are persisted with the format that Xcode.</p>
<p>In this blog post, I’ll talk about the project and its structure, and jump into some examples where you might consider introducing some automation in your projects with <code>xcodeproj</code>.</p>
<p><strong>Note that APIs might have changed since the I wrote this blog post. If the examples don't run as expected, I recommend checking out the documentation on the repository.</strong></p>
<h2 id="xcodeproj-a-monolithic-format">Xcodeproj, a monolithic format</h2>
<p>The Xcode project, which has an extension <code>xcodeproj</code> <em>(where the name of the library comes from)</em>, is a folder that contains several files that define different components of the project. One of the most interesting and complex files is the file <code>project.pbxproj</code>. You might be familiar with it if you have run into git conflicts on Xcode projects before. This is a <a href="https://pepicrft.me/blog/xcodeproj/TODO">property list file</a>, like the <code>Info.plist</code>, but with a subtle difference that made implementing <code>xcodeproj</code> a challenge. The file has some custom annotations that Xcode adds along the file to make the format more human-readable and <em>(I'm guessing)</em> facilitate resolving git conflicts. Since the format is not documented, the library required several iterations to approximate the format of Xcode accurately.</p>
<p>The <code>pbxproj</code> file contains a large list of objects, which in <code>xcodeproj</code> are modeled as <code>PBXObject</code> classes. They represent elements such as build phases <em>(<code>PBXBuildPhase</code>)</em>, targets <em>(<code>PBXNativeTarget</code>)</em> or files <em>(<code>PBXFileReference</code>)</em>. Those objects get a unique identifier <em>(UUID)</em> when Xcode creates them, and it’s used to declare references between objects. For example, a target has references to its build phases using their UUIDs as shown in the example below:</p>
<pre><code>buildPhases = (
OBJ*593 /* Sources _/,
OBJ_599 /_ Frameworks \_/,
);
</code></pre>
<blockquote>
<p>The example above is from a project generated by the SPM. SPM has its own convention for naming UUIDs, which doesn’t match Xcode’s default.</p>
</blockquote>
<p>For projects like the SwiftPM or Tuist, which leverage project generation, it’s crucial to <strong>generate the UUIDs deterministically</strong>. In other words, every time a project is generated, its objects always get the same UUIDs. Otherwise, Xcode and its build system would invalidate the cache and cause builds to start from a clean state. <code>xcodeproj</code> uses the object attributes and the attributes of its parents to make the generated id deterministic. Moreover, the format is better aligned with the one that Xcode uses.</p>
<h2 id="an-undocumented-format">An undocumented format</h2>
<p>Conversely to Android applications that are built using Gradle, a build system that is extensively documented, the format of Xcode projects lacks documentation. Apple expects Xcode to be the interface to the projects. Consequently, they barely put effort into documenting the project structure or making it more declarative and git-friendly.</p>
<p>So if the format is not documented, how were we able to develop a Swift library that works as an alternative interface to the projects? First and foremost, thanks to the pioneering work that the fantastic <a rel="external" href="https://cocoapods.org">CocoaPods</a> team did in that area. They developed the first ever library to read, update and write Xcode projects, <a rel="external" href="https://github.com/cocoapods/xcodeproj">xcodeproj</a>. The library is written in Ruby and is a core component of CocoaPods.</p>
<p>The work of understanding the project pretty much of reverse-engineering how Xcode maps actions to changes into the project files. To give you an example, let's say that we'd like to understand how the linking of a new library reflects on the project files.</p>
<ol>
<li>We commit the current state of the project so that we can use git to spot the diff. 2. Change the target settings to link the library. 3. Use <code>git diff</code> and see what changed.</li>
</ol>
<p>CocoaPods already did some of that work, but that did not prevent us from having to do it as well. For instance, we wanted to expose as optionals the attributes that are optionals in projects. <em>How did we know which attributes were optionals?</em> We removed them from the project and tried to open the project with Xcode. If Xcode was able to open the project, that indicated that the attribute was optional. If Xcode crashed, it meant that the attribute was required. <em>Do you imagine doing that with every attribute of each object?</em> It was a vast amount of work, but luckily something that we don't have to do often because new Xcode versions barely introduce new attributes.</p>
<h2 id="hands-on-examples">Hands-on examples</h2>
<p>I could write a blog post explaining each of the objects and get you weary with some theory, but I thought it'd be better to take you through some practical examples that you could write yourself to get familiar with the objects. Before we dive into them, we need to create a new Swift executable package where we'll add <code>xcodeproj</code> as a dependency. Let's create a folder and initialize a package:</p>
<pre><code>mkdir examples
cd examples
swift package init --type executable
</code></pre>
<p>The commands above will create a manifest file, <code>Package.swift</code>, and a <code>Sources/examples</code> directory with a <code>main.swift</code> file where we'll write our examples. Next up, we need to add <code>xcodeproj</code> as a dependency. Edit the <code>Package.swift</code> and add the following dependencies to the <code>dependencies</code> array:</p>
<pre><code>.package(url: &quot;https://github.com/tuist/xcodeproj.git&quot;, .upToNextMajor(from: &quot;6.5.0&quot;)),
</code></pre>
<blockquote>
<p>Replace <code>6.5.0</code> with the version of xcodeproj that you'd like to use.</p>
</blockquote>
<p>Alternatively, you can use <a rel="external" href="https://github.com/mxcl/swift-sh">swift-sh</a>, a handy tool that facilitates the definition of Swift scripts with external dependencies. The only thing you need to do is to install the tool, which can be done with Homebrew by running <code>brew install swift-sh</code> and create a Swift script where you'll code the examples:</p>
<pre><code>#!/usr/bin/swift sh

import Foundation
import xcodeproj // tuist/xcodeproj
import PathKit // kylef/PathKit
</code></pre>
<p>That's all we need to start playing with the examples.</p>
<h3 id="example-1-generate-an-empty-project">Example 1: Generate an empty project</h3>
<p>In this example, we'll write some Swift lines to create an empty Xcode project. <em>Exciting, isn't it?</em> If you ever wondered what Xcode does when you click <code>File &gt; New Project</code>, you'll learn it with this example. You'll realize that after all, creating an Xcode project is not as complicated as it might seem. <strong>You could write your own Xcode project generator</strong>. Let me dump some code here and navigate you through it right after:</p>
<pre><code>import Foundation
import PathKit
import xcodeproj

// 1 .pbxproj
let pbxproj = PBXProj()

// 2. Create groups
let mainGroup = PBXGroup(sourceTree: .group)
pbxproj.add(object: mainGroup)
let productsGroup = PBXGroup(children: [], sourceTree: .group, name: &quot;Products&quot;)
pbxproj.add(object: productsGroup)

// 3. Create configuration list
let configurationList = XCConfigurationList()
pbxproj.add(object: configurationList)
try configurationList.addDefaultConfigurations()

// 4. Create project
let project = PBXProject(name: &quot;MyProject&quot;,
buildConfigurationList: configurationList,
compatibilityVersion: Xcode.Default.compatibilityVersion,
mainGroup: mainGroup,
productsGroup: productsGroup)
pbxproj.add(object: project)
pbxproj.rootObject = project

// 5. Create xcodeproj
let workspaceData = XCWorkspaceData(children: [])
let workspace = XCWorkspace(data: workspaceData)
let xcodeproj = XcodeProj(workspace: workspace, pbxproj: pbxproj)

// 6. Save project
let projectPath = Path(&quot;/path/to/Project.xcodeproj&quot;)
try xcodeproj.write(path: projectPath)
</code></pre>
<p>Let's break that up analyze block by block:</p>
<ol>
<li>A <code>PBXProj</code> represents the <code>project.pbxproj</code> file contained in the project directory. The constructor initializes it with some default values expected by Xcode and an empty list of objects. 2. <code>PBXGroup</code> objects represent the groups that one can see in the project navigator. Projects required two groups to be defined, the <code>mainGroup</code> which represents the root of the project and where other will groups will be added as children, and the <code>productsGroup</code> which is the group where Xcode creates references for all your project products <em>(e.g. apps, frameworks, libraries)</em> 3. Projects and targets need what's called a configuration list, <code>XCConfigurationList</code>. A configuration list groups configurations like <code>Debug</code> and <code>Release</code> and ties them to a project or target. The call to the method <code>addDefaultConfigurations</code> creates the default build configurations, represented by the class <code>XCBuildConfiguration</code>. A <code>XCBuildConfiguration</code> object has a hash with build settings, and a reference to an <code>.xcconfig</code> file, both optional. 4. Next up, we need to initiate a <code>PBXProject</code> which contains project settings such as the configuration list, the name, the targets, and the groups. 5. Last but not least, we need to create an instance of a <code>XcodeProj</code> which represents the project that is written to the disk. If you explore the content of any project, you'll realize that it contains a workspace. Therefore the <code>XcodeProj</code> instance needs the workspace attribute to be set with an object of type <code>XCWorkspace</code>. 6. Changes need to be persisted into the disk by calling <code>write</code> on the project and passing the path where we'd like to write it.</li>
</ol>
<blockquote>
<p>Notice that the objects that are created to be part of the project need to be added to the <code>pbxproj</code>.</p>
</blockquote>
<p>If you run the code above, you'll get an Xcode project that works in Xcode. However, it does not contain any target or schemes that you can work with. The goal with this example was to give you a sense of what the xcodeproj API and Xcode projects look like. Using <code>xcodeproj</code> to generate your company's projects would require much work so unless there's a good reason for it, you can use tools like <a rel="external" href="https://github.com/yonaskolb/xcodegen">XcodeGen</a> or <a rel="external" href="https://github.com/tuist/tuist">Tuist</a> instead. Those tools allow you define your projects in a different format, for example, yaml or Swift, and they convert your definition into an Xcode project. The resulting definition file is much simpler and human-readable than Xcode's <code>.pbxproj</code></p>
<h3 id="example-2-add-a-target-to-an-existing-project">Example 2: Add a target to an existing project</h3>
<p>Continuing with examples that help you understand the project's structure, we'll add a target to an existing project. Like I did with the preceding example, I'll introduce you to the code first:</p>
<pre><code>import xcodeproj
import PathKit

// 1. Read the project
let path = Path(&quot;/path/to/Project.xcodeproj&quot;)
let project = try XcodeProj(path: path)
let pbxproj = project.pbxproj
let targetName = &quot;MyFramework&quot;
let pbxProject = pbxproj.projects.first!

// 2. Create configuration list
let configurationList = XCConfigurationList()
pbxproj.add(object: configurationList)
try configurationList.addDefaultConfigurations()

// 3. Create build phases
let sourcesBuildPhase = PBXSourcesBuildPhase()
pbxproj.add(object: sourcesBuildPhase)
let resourcesBuildPhase = PBXResourcesBuildPhase()
pbxproj.add(object: PBXResourcesBuildPhase())

// 4. Create the product reference
let productType = PBXProductType.framework
let productName = &quot;\(targetName).\(productType.fileExtension!)&quot;
let productReference = PBXFileReference(sourceTree: .buildProductsDir, name: productName)
pbxproj.add(object: productReference)
pbxProject.productsGroup?.children.append(productReference)

// 5. Create the target
let target = PBXNativeTarget(name: &quot;MyFramework&quot;,
buildConfigurationList: configurationList,
buildPhases: [sourcesBuildPhase, resourcesBuildPhase],
productName: productName,
product: productReference,
productType: productType)
pbxproj.add(object: target)
pbxProject.targets.append(target)

try project.write(path: path)
</code></pre>
<ol>
<li>The first thing that we need to do is read the project from disk. <code>XcodeProj</code> provides a constructor that takes a path to the project directory. <code>xcodeproj</code> decodes the project and its objects. Notice that we are assuming that the <code>pbxproj</code> contains at least a project. If nothing has been messed up with the project that's always the case. 2. Like we did when we generated the project, targets need configurations. We are not defining any build settings, but if you wish, I recommend you to explore the constructors of the classes. You'll get to see all the configurable attributes. 3. A target has build phases. <code>xcodeproj</code> provides classes representing each of the build phases supported by Xcode, all of them following the naming convention <code>PB---BuildPhase</code>. In our example, we are creating two build phases for the sources and the resources. 4. Targets need a reference to their output product. It's the file that you see under the <code>Products</code> directory when you create a new target with Xcode. It references the product in the derived data directory. Since we are creating the target manually, we need to create that reference ourselves. For that, we use an object of type <code>PBXFileReference</code>. The name is initialized with two attributes, the name, and the <code>sourceTree</code> which defines the parent directory or the association with its parent group. You can see all the possible values that <code>sourceTree</code> can take. In the case of the target product, the file must be relative to the build products directory. Don't forget to add the product as a child of the project products group.</li>
</ol>
<pre><code>public enum PBXSourceTree {
 case none
 case absolute // Absolute path.
 case group // Path relative to the parent group.
 case sourceRoot // Path relative to the project source root directory.
 case buildProductsDir // Path relative to the build products directory.
 case sdkRoot // Path relative to the SDK directory.
 case developerDir // Path relative to the developer directory.
 case custom(String) // Custom path.
}
</code></pre>
<p>With all the ingredients to bake the target, we can create the instance and add it to the project. Write the project back to disk and open the project. Voila 🎉! A new target shows up in your project.</p>
<blockquote>
<p>Note: A <code>pbxproj</code> can contain more than one project when an Xcode project is added as sub-project of a project. In that case Xcode adds the project as a file reference and then adds the reference to the <code>pbxproj.projects</code> attribute.</p>
</blockquote>
<h3 id="example-3-detect-missing-file-references">Example 3: Detect missing file references</h3>
<p>If you have solved git conflicts before in your Xcode projects, you might already know that sometimes, you end up with files in your build phases that reference files that don't exist. Most times, Xcode doesn't let you know about it, and you end up with a project in a project in a not-so-good state. What if we were able to detect that before Xcode even tries to compile your app?</p>
<pre><code>import xcodeproj
import PathKit

let path = Path(&quot;/path/to/project.xcodeproj&quot;)

let project = try XcodeProj(path: path)
let pbxproj = project.pbxproj
let pbxProject = pbxproj.projects.first!

/// 1. Get build phases files
let buildFiles = pbxproj.nativeTargets
 .flatMap({ $0.buildPhases })
 .flatMap({ $0.files })

try buildFiles.forEach { (buildFile) in
/// 2. Check if the reference exists
guard let fileReference = buildFile.file else {
fatalError(&quot;The build file \(buildFile.uuid) has a missing reference&quot;)
return
}

/// 3. Check if the references an existing file
let filePath = try fileReference.fullPath(sourceRoot: path.parent())
if filePath?.exists == false {
 fatalError(&quot;The file reference \(fileReference.uuid) references a file that doesn&#39;t exist&quot;)
}
</code></pre>
<ol>
<li>Projects have an attribute, <code>nativeTargets</code>, that returns all the targets of the project. From each target, we can get its list of build phases accessing the attribute <code>buildPhases</code>. Build phases are objects of the type <code>PBXBuildPhase</code> which expose an attribute, <code>files</code> with the files that are part of the build phase. Build phase files, build files, are represented by the class <code>PBXBuildFile</code>. 2. The first thing that we do is checking if the file reference exist. Notice that we are accessing the <code>file</code> attribute from the build file. That's because a build file is a type that works as a reference to a file from your project groups. The same file represented by its <code>PBXFileReference</code> object, can be referenced from multiple build phases resulting in multiple <code>PBXBuildFile</code>s but just one <code>PBXFileReference</code>. We check whether the file reference exists. If it doesn't, it probably means that we didn't solve the git conflict correctly and removed a reference that was being referenced by a build file. 3. After checking if the file reference exists, we check that the file reference points to an existing file. We can do that by obtaining the absolute path calling the method <code>fullPath</code> on the file reference. Notice that we need to pass a sourceRoot argument, which is the directory that contains the project.</li>
</ol>
<h3 id="example-4-detecting-if-a-info-plist-is-being-copied-as-a-resource">Example 4: Detecting if a Info.plist is being copied as a resource</h3>
<p>Another typical scenario when working with Xcode projects, is when we add a file to the copy resources build phase when it shouldn't be there. An excellent example of this one is copying the <code>Info.plist</code> file. Have you been there before? Fortunately, we can leverage <code>xcodeproj</code> to detect that as well.</p>
<pre><code>import xcodeproj
import PathKit

let path = Path(&quot;/pat/to/project.xcodeproj&quot;)

// Read the project
let project = try XcodeProj(path: path)
let pbxproj = project.pbxproj
let pbxProject = pbxproj.projects.first!

try pbxproj.nativeTargets.forEach { target in
// 1. Get the resources build phase
let resourcesBuildPhase = try target.resourcesBuildPhase()

resourcesBuildPhase?.files.forEach { buildFile in
guard let fileReference = buildFile.file else { return }

/// 2. Check if the path or name reference an Info.plist file
if fileReference.path?.contains(&quot;Info.plist&quot;) == true ||
 fileReference.name?.contains(&quot;Info.plist&quot;) == true {
 fatalError(&quot;The target \(target.name) resources build phase is copying an Info.plist file&quot;)
}
</code></pre>
<ol>
<li>We can obtain the resources build phase from a target calling the convenience method <code>resourcesBuildPhase()</code>. If the build phase doesn't exist, it'll return a <code>nil</code> value. 2. As we did in the previous example, we get the file reference of each build phase, and we check whether the name or the path contain <code>Info.plist</code>. If they do, we let the developer know.</li>
</ol>
<blockquote>
<p>Note that checking the name of the file being <code>Info.plist</code> is not enough cause it might be a file that is not the target <code>Info.plist</code>. If we want to be more precise, we'd need to check if it references the same file as the <code>INFOPLIST_FILE</code> build setting. For the sake of simplicity, we only check one thing in the example.</p>
</blockquote>
<h2 id="ensuring-a-healthy-state-in-your-projects">Ensuring a healthy state in your projects</h2>
<p>As we've seen, with a few lines of Swift, we can implement relatively simple checks that can be run as part of the local development or as a build step on CI to make sure that your projects are in a good state. Thanks to <a rel="external" href="https://github.com/tuist/xcode">xcodeproj</a> you can do it in a language that you are familiar with, Swift.</p>
<p>Having your projects in a good state is crucial to make your builds reproducible and avoid unexpected compilation issues that might arise later as a result of a bad merge that went unnoticed.</p>
<h2 id="projects-powered-by-xcodeproj">Projects powered by xcodeproj</h2>
<p>Before closing the blog post, I'd like to give you some examples of tools that leveraged <code>xcodeproj</code> to make your life easier as a developer.</p>
<ul>
<li><strong><a rel="external" href="https://github.com/tuist/tuist">Tuist</a>:</strong> Tuist is a tool that helps you define, maintain, and interact with your Xcode projects at any scale. It's the project that motivated the development of xcodeproj. - <strong><a rel="external" href="https://github.com/mxcl/cake">Cake</a>:</strong> A delicious, quality‑of‑life supplement for your app‑development toolbox. - <strong><a rel="external" href="https://github.com/yonaskolb/xcodegen">XcodeGen</a>:</strong> A Swift command line tool for generating your Xcode project - <strong><a rel="external" href="https://github.com/GirAppe/AutoEnvironment">AutoEnvironment</a>:</strong> Tool to automatically generate Environment.swift based on Xcode project. - <strong><a rel="external" href="https://github.com/kawoou/Deli">Deli</a>:</strong> Deli is an easy-to-use Dependency Injection(DI). - <strong><a rel="external" href="https://github.com/JamitLabs/Accio">Accio</a>:</strong> A dependency manager driven by SwiftPM that works for iOS/tvOS/watchOS/macOS projects. - <strong><a rel="external" href="https://github.com/werediver/xccheck">xccheck</a>:</strong> A diagnostic tool for Xcode projects. - <strong><a rel="external" href="https://github.com/krbarnes/expel">expel</a>:</strong> Automatically move your Xcode project build settings to xcconfig files. - <strong><a rel="external" href="https://github.com/jeffctown/xcodemissing">xcodemissing</a>:</strong> A tool to find and delete files that are missing from Xcode projects. - <strong><a rel="external" href="https://github.com/skagedal/xcodeproj-modify">xcodeproj-modify</a>:</strong> Adds a Run Script phase to an Xcode project. - <strong><a rel="external" href="https://github.com/SpectralDragon/Templar">Templar</a>:</strong> A template generator.</li>
</ul>
<p>I hope after reading this blog post you have a better sense of how Xcode projects are structured, and how even though Xcode doesn't expose any API for you to read/update your projects, you can leverage a tool like <a rel="external" href="https://github.com/tuist/xcodeproj">xcodeproj</a> to do so.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Open source and trust</title>
      <link>https://pepicrft.me/blog/open-source-and-trust/</link>
      <guid>https://pepicrft.me/blog/open-source-and-trust/</guid>
      <pubDate>Thu, 14 Mar 2019 12:00:00 +0000</pubDate>
      <description>Trust is key for open source projects to thrive. In this blog post I explain what trust has meant for Tuist.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As I wrote on <a href="https://pepicrft.me/blog/open-source-and-trust/__GHOST_URL__/2019/03/01/software-and-people">this blog post</a>, one of the facts that I value the most about writing software is being able to meet and collaborate with people. Coincidentally, I recently had the opportunity to meet like-minded developers that started getting involved in <a rel="external" href="https://tuist.io">Tuist</a>.</p>
<p>I'm a person that trusts other people by default and therefore, that's what I did since I could see they were really interested in the project, and would like to contribute to make it work for their projects. Seeing someone that you don't know trusting you might take you by surprise at first, but it gives you the necessary confidence to feel part of the project. One might think that I'm risking the project by doing that, however, that's a risk that I'm willing to take. <strong>The most fruitful collaboration, and thus contributions, happen when there's trust among the people involved in the project.</strong> If by any chance, the person turns out to be untrustworthy, we can take steps back. Luckily, I haven't had an experience like that <em>(yet)</em>.</p>
<p>I've personally tried to contribute to projects where maintainers didn't seem to be interested in receiving external contributions. I could feel that from the friction that they added and sometimes, a lack of empathy with a new contributor. They turned all the energy that I had for the project into a pure lack of interest. I experienced the same when I came across a project that is driven with a fair amount of ego and where recognizing each other's work was inconceivable.</p>
<p>With Tuist, I did things differently and I'm glad that I made that decision:</p>
<ul>
<li>Repositories are not under my GitHub user, but under a organization to which contributors and maintainers belong. - Anyone can join the Slack channel and talk to other users of the project. - Developers get push access after their first PR gets merged. - Praises and thanks have space in pull requests and issues. - We default to trust and let them prove wrong.</li>
</ul>
<p>Trusting by default has allowed me to work with <a rel="external" href="https://github.com/ollieatkinson">Oliver</a>, <a rel="external" href="https://github.com/marciniwanicki">Marcin</a>, and <a rel="external" href="https://github.com/kwridan">Kassem</a> and some other like-minded developers. We can brainstorm and overcome challenges together. Challenges that many developers are facing and for which unfortunately, Apple hasn't offered a solution yet.</p>
<p>If you maintain an open source project and would like it to thrive, I recommend you to default to trust when new contributions land in the project. It's a subtle thing but with a huge impact.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Automated tests for a Swift CLI tool with Cucumber</title>
      <link>https://pepicrft.me/blog/cucumber/</link>
      <guid>https://pepicrft.me/blog/cucumber/</guid>
      <pubDate>Wed, 13 Mar 2019 12:00:00 +0000</pubDate>
      <description>In this post, I explain how we are able introduce changes and release new versions of Tuist with the confidence of not introducing bugs or breaking things.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As you might already know, I'm devoting part of my free time to build <a rel="external" href="https://github.com/tuist/tuist">Tuist</a>, a command line tool that helps Swift developers maintain their Xcode projects regardless of their scale. Since we added the first Swift file to the project, having a good test suite has been one of our key design principles to ensure that features do what they are supposed to do, and that new versions are backward compatible <em>(unless it's impossible to achieve so)</em>. If companies and developers start using Tuist in a daily basis, the last thing that we want is disturbing their work as a consequence of a buggy or breaking update.</p>
<blockquote>
<p>There's nothing more annoying than not being able to do your work because the tool that you are using doesn't work as expected.</p>
</blockquote>
<p>The project initially contained a target with decent list of <strong>unit tests.</strong> This allowed us to test each piece of code in isolation but didn't bring enough confidence for us to release new versions of Tuist. <em>If unit tests were not enough, what else could we do?</em> We could have adopted an analogic approach. Before releasing a new version, we could have asked users to try the next version before going out into wild. Beta testing is a tedious process, requires an effort on the users side, and slows down the release due to all the back and forth that it entails.</p>
<p>The approach that we decided to take, and about which I'd like to talk, is based on the Ruby BDD testing framework <a rel="external" href="https://github.com/cucumber/cucumber-ruby">Cucumber</a>. Before I jump into details about why we made that choice, I want to show you an example of a test run output:</p>
<p><img src="https://pepicrft.me/blog/cucumber/__GHOST_URL__/images/posts/cucumber.gif" alt="Cucumber" /></p>
<p>As you can see in the example above, the steps of the scenario that we are testing can be read as if you were reading a story. At the end of the day, they are user stories. We describe the scenarios as a set of steps that are in fact sentences, and Cucumber maps those steps into Ruby code that gets executed. Cucumber offers the <strong>expressiveness</strong> that <a rel="external" href="https://developer.apple.com/documentation/xctest">XCTest</a> doesn't. The latter is, in my opinion, more suitable for unit tests where having a more verbose API and output makes more sense.</p>
<p>Before introducing Cucumber to the project, I was a big skeptical about adding Ruby code to the mix. I'm comfortable writing code Ruby but <em>what about contributors to the project?</em> It turns out that people can quickly understand how Cucumber works. Whenever we see a use case with potential to be tested with include a fixture project that we use to run the tests on. We keep track of all the fixtures <a rel="external" href="https://github.com/tuist/tuist/tree/master/fixtures">on this README</a> where each fixture includes a description of what the project is like.</p>
<p>Here are some examples of fixtures that we run automated tests on:</p>
<ul>
<li><strong>ios_app_with_static_libraries:</strong> This application provides a top level application with two static library dependencies. The first static library dependency has another static library dependency so that we are able to test how tuist handles the transitiveness of the static libraries in the linked frameworks of the main app. - <strong>app_with_frameworks:</strong> Slightly more complicated project consists of an iOS app and few frameworks.</li>
</ul>
<p>The automated tests see the Swift Package Manager as a tool that builds the object under testing, the Tuist binary. The only interactions that they can have with Tuist is through the CLI, the standard output and error, and the generated output artifacts. Something like this can also be achieved defining a tests target with the Swift Package Manager, but I find it odd that the test runners, SwiftPM or Xcode, run tests that depend on themselves. When we describe the tests, we put ourselves in someone elses shoes:</p>
<blockquote>
<p>I'm a user that have just installed Tuist and I'd like to initialize a project.</p>
</blockquote>
<p>I'd expect to be able initialize the project with Tuist and get an Xcode project with a target that I can build. We'd describe that scenario in Cucumber like this:</p>
<pre><code>Feature: Initialize a new project using Tuist

 Scenario: The project is a compilable macOS application
 Given that tuist is available
 And I have a working directory
 When I initialize a macos application named Test
 Then tuist generates the project
 Then I should be able to build the scheme Test
</code></pre>
<p>Imagine that we introduce a change in the project that doesn't break the project generation, for which we already have unit tests, but for some reason the generated Xcode project cannot be built. <em>Do you think it'd be a good experience for the user?</em> I doubt so. Luckily our automated test would fail immediately and raise a flag.</p>
<p>I believe being able to release new software versions with confidence is crucial to <strong>move fast without breaking things.</strong> When developers use your software, they trust the software and the people behind it. They use it because it brings value to them and they'd like to continue using it if it continues to work reliably. If we are not able to meet that expectation and release with confidence, we are putting ourself at the risk of breaking the trust between our users and us.</p>
<p>This is just an example of how we are bringing that confidence to Tuist, and it's certainly not the only one. The next time you merge a PR or release a new version ask yourself if you feel confident enough. If you don't, you'd better adjust things in your project.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Software and people</title>
      <link>https://pepicrft.me/blog/software-and-people/</link>
      <guid>https://pepicrft.me/blog/software-and-people/</guid>
      <pubDate>Fri, 01 Mar 2019 12:00:00 +0000</pubDate>
      <description>A reflection on what&#x27;s one of the most important things to me when building software, the people that make it possible.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I'm currently flying back to Berlin, somewhere over the Atlantic ocean. Perfect time <em>(without an Internet connection)</em> to make some reflections. The one that I made this time has to do with my motivations when it comes to writing software. <em>Guess what?</em> One of the things that motivate me the most about writing software is <strong>getting to know and meet people that I would not meet otherwise</strong>.</p>
<p>I've been in Ottawa for 2 weeks. It's the city where most of my team work from, so I try to visit them as much as I can. Most of my interactions with them happen over Slack or GitHub. You probably know what your colleagues are on those platforms, users. They have an avatar, a name, and write messages more elaborated than the ones a bot could ever write. Some people like to see their colleagues just like more intelligent bots. I don't. I spend many hours a day working with computers <em>(at the very least 8)</em> so I don't want to feel like talking to computer 8 hours a day.</p>
<p>That's why whenever I have the opportunity, I break the ice and try to make personal the impersonal. I propose activities to my colleagues that have nothing to do with work. If people are hesitant to it, I completely understand and I don't insist. People might want to keep some distance with the people that they work with, that's understandable.</p>
<p>This time in Ottawa I learned that people in my team love philosophy and skiing and that some love traveling the world. I know more about them, and therefore, I can have more casual conversations with them about the things that they love the most. <em>Isn't it great?</em></p>
<p>I experience the same on the open source space. Recently, I met wonderful people that happened to have an interest in an open source project that I gladly bootstrapped, <a rel="external" href="https://tuist.io">Tuist</a>. I invited <a rel="external" href="https://github.com/kwridan">Kassem</a>, <a rel="external" href="https://github.com/marciniwanicki">Marcin</a>, and <a rel="external" href="https://github.com/ollieatkinson">Oliver</a> to the organization and Slack. Since then, we've been collaborating, having ideas together, proposing improvements. <em>Isn't it a beautiful experience?</em> Software enabled that. I'm starting to appreciate more the opportunity to meet people thanks to software.</p>
<p>I don't imagine myself writing software without having any human component around it. I think I'd end up writing software that only machines would find useful, not humans. It'd be depressing, and that's why I guess I avoid when we treat each other in such impersonal manners. I think it also take initiatives to abstract myself and the people around me from seeing software and the people that make it possible as just bytes, patterns, paradigms, architectures, technologies...</p>
<p>I firmly believe that great software is a result of <strong>humans being humans</strong>. Machines and the code that we put on them allow it, but that's just the means.</p>
<p>I'm glad that software development gave me that opportunity and I'll do my best to keep it alive. Thanks to software, I worked with amazing people some of whom I consider great friends. I'm grateful to have the opportunity to work with lovely people at Shopify from whom I can learn a lot and build incredible things together. And last, and not for that less important, I'm glad that open source is connecting me with people with so many different backgrounds that are helping me grow personally and professionally.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Turning negativism into positivism</title>
      <link>https://pepicrft.me/blog/turning-negativism-into-positivism/</link>
      <guid>https://pepicrft.me/blog/turning-negativism-into-positivism/</guid>
      <pubDate>Thu, 21 Feb 2019 12:00:00 +0000</pubDate>
      <description>Short reflection on how beneficial it can be turning negativism into something positive.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Today, while I was having a chat with whom used to be my manager, he brought up an idea that resonated a lot in me: <em>try to always turn sources of negativity into opportunities to bring positivism into the team</em>. Let me give you an example.</p>
<p>My team at Shopify builds tools and infrastructure for mobile developers, and as part of our job we have to do some support work and respond requests which sometimes are out our area of the responsibilities. It's easy to feel annoyed by that and start complaining about your colleagues believing that your team is there to put out the fires and have answers for everything. However, you can take the opportunity, show empathy, put yourself in the other person's shoes, and think if within your domain, there's something you could do to make that person's life easier.</p>
<p>It helps you build trust between you, your team and the other person. Moreover, you are preventing you and your team from entering a negativism spiral that can drain your energy. I think it's an exercise easy to do, yet with beneficial results for you and for others.</p>
<p>It's a powerful idea that not only applies to work but life. In a world where there are inevitably negative things happening, it's a simple exercise that we should do as much as we can.</p>
<p>The next time I start feeling any annoyance and negativism around me, I'll stop and ask myself: <strong>What's the most positive thing I could take of of this?</strong></p>
<hr />
<p>I hope you are all having a wonderful week. I'm spending a couple of weeks in Canada 🇨🇦, catching up and working closely with my colleagues, whom I mostly see on Slack or GitHub most of the time.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Deep linking into macOS apps</title>
      <link>https://pepicrft.me/blog/deep-linking-into-macos-apps/</link>
      <guid>https://pepicrft.me/blog/deep-linking-into-macos-apps/</guid>
      <pubDate>Wed, 13 Feb 2019 12:00:00 +0000</pubDate>
      <description>Some comments on what&#x27;s the state of art of macOS handling deeplinks.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Today I happened to play with deep links on macOS. Having worked a lot on the iOS platform, I assumed things would be alike. To my surprise, it wasn't like that.</p>
<p>As you might know, websites can include a manifest file that associates a website with a given application on iOS. When the webview detects that the website is <em>deeplinkable</em>, it suggests the user to continue the navigation inside the app. <em>Seamless, isn't it?</em> There could arguably be more flexible and better ways of dealing with deeplinks on iOS, but I think the approach that iOS currently provides is enough for the needs of most projects. The example below shows the format of that <code>apple-app-site-association.json</code> manifest file:</p>
<pre><code>{
	&quot;applinks&quot;: {
		&quot;apps&quot;: [],
		&quot;details&quot;: [
			{
				&quot;appID&quot;: &quot;com.mycompany.App&quot;,
				&quot;paths&quot;: [&quot;*&quot;]
			}
		]
	}
}
</code></pre>
<p>Things are pretty different on macOS. First of all, macOS apps can't be associated to a website through a manifest. What they can do though is defining URL schemes that they support. When a webview tries to load a URL, whose scheme matches any of the schemes defined by the installed apps, it'll launch the app pasing the URL to it. <em>One might think that that's all needs right?</em> Let me refute that by giving you an example, proof of a bad user experience.</p>
<p>You navigate a website or a service that can deeplink into a macOS client. At some point of the user navigation, it triggers the deeplink and it turns out that the user doesn't have the app installed. The system errors because the request was not handled by anyone and the browser can't show an error because it doesn't know what happened after the link was fired off.</p>
<blockquote>
<p>The browser can just trigger the request hoping for the os to handle it gracefully. Unfortunately, the system interrupts the flow when there isn't an app to process the request.</p>
</blockquote>
<p>One solution to this problem could come from Apple. They could align macOS to iOS and allow defining associations between websites and desktop apps. Given that they are putting effort into aligning macOS to the other platforms, I would not be surprised if that happens any time soon.</p>
<p>Another solution, yet not perfect, could be implemented by using some Javascript and HTML. The first thing that I tried was changing the website location using Javascript and detect whether the browser was able to replace the location using a timeout. That solution worked for Chrome and Firefox but not for Safari. Regardless of the system being able to handle the request, Safari navigates to an invalid page, in which our Javascript session with the timeout gets wiped out.</p>
<p>After some reading, I found a little hack that also works in Safari. We can embed an `` </code> element in which we can load the deeplink. By doing that, we can trigger the processing of the deeplink by the system and prevent Safari from navigating to an invalid page. Not ideal, but works. If you are familiar with React, here is how I ended up wrapping everything into a component:</p></p>
<pre><code class="language-language-jsx">class RedirectShowPage extends React.Component {
render() {
let body = (
<p>
<b>Redirecting to the app...</b>
<br />
If you don't have the app installed, you can download it using the
following <a href="link_to_app">link</a>.
</p>
);
const path = this.props.path;
const location = `scheme://${path}`;
return (
<Page>
{body}
<iframe ref="iframe" style=\{\{ visibility: "hidden" \}\} src={location}/>
</Page>
);
}
}
</code></pre>
<p>I tried to figure out if it'd be possible to detect when the deeplink could not be handled but unfortunately, that's something neither the browser nor the system can help us with.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://developer.apple.com/ios/universal-links/">Universal links</a></li>
</ul>
<!--kg-card-end: markdown--> ``
]]></content:encoded>
    </item>
    
    <item>
      <title>The motivations behind building Tuist</title>
      <link>https://pepicrft.me/blog/tuist-motivations/</link>
      <guid>https://pepicrft.me/blog/tuist-motivations/</guid>
      <pubDate>Sat, 02 Feb 2019 12:00:00 +0000</pubDate>
      <description>Tuist is my most beloved open source project. In this blog post I touch on the motivations that led me to build it.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It's been a long time working on <a rel="external" href="https://github.com/tuist/xcodeproj">xcodeproj</a> and <a rel="external" href="https://github.com/tuist/tuist">Tuist</a>, two open source projects that I'm very proud of. Before I started working on xcodeproj, the library that Tuist depends on, I'd worked on other open source projects that were Swift libraries. They had a much smaller scope and were intended to be used as a helpers and time savers in iOS apps.</p>
<p>The motivation to build Tuist came to me when I was working at <a rel="external" href="https://soundcloud.com">SoundCloud</a>. We handled the growth of the project, which brought an increase in build times, by splitting up the project into smaller projects and frameworks. It was back then when I realized how hard and cumbersome maintaining Xcode projects can be. Before I moved on from the company, there were around 8 frameworks, each with 3 targets within a project. Most of them were very similar, but we could barely reuse anything between them, just the build settings. Not only it was cumbersome, but also an error-prone setup. From time to time, we got linking errors and compilation issues caused by small changes that seemingly had no relation with the errors raised. I then set out to build Tuist, with the goal of making it easier to work with Xcode projects at any scale and with any experience.</p>
<p>I wanted to build Tuist in Swift, but I needed a way to read, update and write Xcode projects, like CocoaPods had with <a rel="external" href="https://github.com/cocoapods/xcodeproj">xcodeproj</a>. Unfortunately, there wasn't such a thing on the Swift community, so I worked on the Swift brother of that library, <a rel="external" href="https://github.com/tuist/xcodeproj">xcodeproj</a>. It was while I was working on the library when <a rel="external" href="https://github.com/yonaskolb">Yonas</a> opened an PR on the repository. <em>How came someone was already using the library when it as not ready to be used yet?</em> After a quick chat where I asked him what led him to use the project, I realized that we was building a Xcode project generator, something that to some extent, overlapped with what I wanted to achieve with Tuist.</p>
<p>I had a sadness feeling. Someone had had a similar idea while I was doing some groundwork for that idea to become real. After sleeping over it a few nights, I decided to pause the idea of Tuist, and rather focus on releasing the first version of xcodeproj, which would support the generator that Yonas was building, <a rel="external" href="https://github.com/yonaskolb/xcodegen">XcodeGen</a>, as well as any other tools that the community decided to build. During that time I realized two things. The first one was that, even though XcodeGen had things in common with the ideas that I had for Tuist, the goals were completely different. The second realization was that by giving up on the idea of building Tuist I lost the motivation for building xcodeproj. I was building a library, with the plans of using it, but I had decided not to.</p>
<p>An inner voice told me to make Tuist real, but another pushed the idea back to not seem like a competition with XcodeGen. The evolution of XcodeGen continued to prove me that we were aiming for <strong>different goals</strong> and principles and that there was no reason to feel bad about building Tuist. On one side, XcodeGen was coming up with a declarative interface for defining projects and taking the opportunity to simplify and making the definition of projects easier. On the other side, Tuist aimed to abstract complexities of Xcode projects at any scale, and make it easier not only to generate projects but build, test and release them.</p>
<p>Another area in which both projects diverge is the <strong>design principles</strong>. XcodeGen prefers configuration over conventions. Most of the attributes that are supported by Xcode projects are also supported by XcodeGen. If you need a tool that helps you define and generate Xcode projects with no conventions imposed by the tool, XcodeGen is your tool. On the other side, Tuist compares to Rails. It comes with simple and strong conventions weakly held, which are aimed over configuration. These conventions abstract developers from common complexities, like linking dependencies, and encourage them to follow good practices.</p>
<p>As you might know, many people criticize Rails for being so opinionated. I've seen similar comments on issues and pull requests on the Tuist repository. They are understandable so I take the opportunity to introduce them to XcodeGen and encourage them to use it.</p>
<p>I've had a <strong>few downs</strong> while working on Tuist, times when I thought I'd rather stop working on it and work on a project that people would like to use. Seeing people neglecting the use of it, or considering the use of other tools can be demotivating. I took me some time to accept that as something normal and not let it impact my motivation for the project. I took me also time to accept that working on a long-term project, like Tuist is, means that you get a moment of hype when you first release and announce it, that's when your motivation goes to the highest pick, and then it fades away. I was too used to the excitement of publishing tiny libraries and framework fairly frequently, which helped fed my ego.</p>
<p>I'd love Tuist to be <strong>thoroughly designed and continue to stay firm in its conventions</strong>. I'm trying hard to get people involved with their project and make them feel part of it as I feel. I few days back, I felt glad when I checked my GitHub notifications on <a rel="external" href="https://octobox.io">Octobox</a>, and I saw that contributors had been working on new features for the project while I'd been on vacation. It's a moment when you see that all the work that you did bootstrapping the project, creating a website, writing documentation and some other tasks, pays off.</p>
<p>I'm very excited to see all the ideas and features that we are in the backlog for Tuist. To give you a sneak peak of what's coming, . is working on supporting <strong>static transitive dependencies</strong>. This will allow configuring dependencies and their dependencies as static libraries with resources that will get automatically bundled and copied into the right product directories. Changing between dynamic and static linking will be easier than ever after we merge this feature in.</p>
<p>Moreover, xx and xx are working on <strong>re-structuring the project targets</strong> to make the logic of projects generation reusable. They found it practical and they'd like to extend it with their own additions. The current generation logic is very coupled to the Tuist's API so they are making it more agnostic.</p>
<p>I'm working on adding <strong>two commands, build and test</strong> so that you can build and test your projects by just running <code>tuist build</code> and <code>tuist test</code> in the directory where the project is defined. Most of the <code>xcodebuild</code> arguments will be inferred for you. What excites me the most about this features is that developers won't have to maintain <code>Fastfiles</code> or depend on <a rel="external" href="https://github.com/fastlane">Fastlane</a> anymore. Another fact that I find exciting is that I'm porting the well-known <a rel="external" href="https://github.com/supermarin/xcpretty">xcpretty</a> into Swift. I'll most likely extract it into a separate repository so that developers can use it in their own projects.</p>
<p><strong>Slow but steadily, the baby is growing.</strong> We want to make sure that we are taking steps in the right direction and that we continue to be aligned with our values. Moreover, we keep improving our test suite, to which we recently added acceptance tests with Cucumber that test real scenarios. With projects and teams already depending on Tuist from their workflows, is crucial to make sure the tool works reliably and that minor versions don't break their projects.</p>
<p>It seems it was yesterday when I ran <code>swift package generate</code> to bootstrap the project. <strong>I can't wait to see all the features that we'll land on the project.</strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Wrapping up 2018</title>
      <link>https://pepicrft.me/blog/wrapping-up-2018/</link>
      <guid>https://pepicrft.me/blog/wrapping-up-2018/</guid>
      <pubDate>Sun, 23 Dec 2018 12:00:00 +0000</pubDate>
      <description>A retrospective on what 2018 has been</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It's been almost 365 days since I made a similar reflection on 2017. This time is the turn for 2018, a year with significant changes in my life, new countries that I visited for the first time, and some ups and downs that made me stronger and helped me grow as a person. In this blog post, I'd like to reflect on some remarkable things that happened to me this year.</p>
<h2 id="shopping-cart-shopify">🛒 Shopify</h2>
<p>I started the year by joining the mobile tooling team at <a rel="external" href="https://shopify.com">Shopify</a>. Having done iOS development for the last 4 years, this was a shift in my career, where developers became my users, and I'd write Rails and Ruby instead of Swift. During this year, I was part of the design and development of internal tools that are used across the mobile teams at the company. Moreover, my Ruby code, which initially looked pretty much like Swift, improved a lot. Also, I got to learn more about Rails, which we use to build an internal website that I'm looking forward to telling you more about soon.</p>
<p>I've also learned a lot about how to work with a remote team. Working remotely was an exciting thing that I had read a lot. However, I was not fully aware of all the challenges that it comes with. I feel I'm better at communicating and coordinating work with the rest of my team.</p>
<p>In retrospective, this was a great step in my career, and I can't wait to continue to learn and grow.</p>
<h2 id="brain-psychologist">🧠 Psychologist</h2>
<p>As I already wrote about on my <a href="https://pepicrft.me/blog/wrapping-up-2018/__GHOST_URL__/2018/10/06/what-psychologist-helped-me-realize">"What a psychologist helped me realize"</a> blog post, I went through some issues related to stress and anxiety. I was not balancing my time well, and I was putting too much time and energy onto work-related stuff. Besides my full-time job, I was doing open source, side projects, writing blog posts. I ended up losing motivation for things that I used to like a lot, like doing sport. Everything that I did outside work had to do with work in some way or another. I read books related to software engineering, I talked to my friends about stuff that I did at work...</p>
<p>I wasn't until I got some professional help when I realized how poorly I was managing my time. Moreover, I learned about the importance of being assertive, setting expectations, defining short-term goals and celebrating often.</p>
<p>Although I struggle a bit nowadays, it got much better. I'm more aware and present about my feelings and take more time to make more accurate decisions. Getting professional help is something that I'd recommend to anyone feeling mentally or emotionally unstable. Our brains are a mystery, and we'd better be taught about how they work.</p>
<h2 id="airplane-new-countries">✈️ New countries</h2>
<p>I had the opportunity to visit 3 countries for the first time:</p>
<ul>
<li><strong>Canada 🇨🇦:</strong> I flew there for the first time for the Shopify interviews. Since then, I've been in Canada several times along the year and visited cities like Ottawa, Montreal, and Toronto. - <strong>Latvia 🇱🇻:</strong> Despite being not that far from Berlin, I had never been in Latvia before. I visited it to attend the <a rel="external" href="https://devternity.com/">DevTernity conference</a> with some friends. - <strong>Macedonia 🇲🇰:</strong> I went on a 4-day trip with Maria José to celebrate my birthday. We rented a car and drove from Skopje to the beautiful Ohrid, and from there to Thessaloniki, northern Greece.</li>
</ul>
<h2 id="walking-male-sign-walked-el-camino">🚶‍♂️ Walked "El Camino"</h2>
<p>It had been in my list for a long time and I finally set out to do it this year. I'm glad that I made this decision. El Camino is an unique experience that is hard to describe. You pause your life for a few days, weeks or months to connect with the nature, with people you have never met before. You have time to think about yourself, about your concerns, your motivations, your life. You come across a lot hearted people willing to share stories and happiness with you.</p>
<p>I definitively plan to do it again in the near future. I took the photo below when I was around 40 Km from Santiago.</p>
<p><img src="https://pepicrft.me/blog/wrapping-up-2018/__GHOST_URL__/images/posts/camino.jpg" alt="" /></p>
<h2 id="mega-conferences">📣 Conferences</h2>
<p>In 2017, I took a break from attending and speaking at conferences. Moreover, with the other organizers of <a rel="external" href="https://addconf.com">ADDC</a>, we made the decision for me to step down as an organizer. It was a great experience during the two years that I was involved, and I'm glad the event ran successfully. I'm sure the event will continue to grow and be ahead of innovation.</p>
<p>After this year-long break, I feel with more energy and motivated to prepare a talk for a conference. We've built some internal tools at Shopify to overcome some scalability challenges so I might prepare the talk around that topic.</p>
<h2 id="de-german">🇩🇪 German</h2>
<p>I set learning German as a goal for 2018, and I think I miserably failed at it. First of all, I think it was a mistake to define <em>"learn German"</em> as a goal. What's learning German? Being proficient? Being able to have a casual conversation or make a phone call? Since learning languages is not something that I particularly like, I kept procrastinating and leaving my lessons for later. As a consequence, I kept running into awkward situations where I needed to talk to someone in German, and I didn't know how to say a word. One side of me things that I should speak the language because I don't know for how long I will be in the country, the other side of me says that I should instead put my energy into something that really motivates me.</p>
<p>I feel terrible because I think that as a person living in Germany, I should speak the language of the country. Living in a globalized world is excellent, but I shouldn't disregard the beauty of having different cultures and languages, and thus, I should strive to keep them.</p>
<h2 id="runner-male-sign-exercise">🏃‍♂️ Exercise</h2>
<p>I'm not very proud of how I've been exercising this year. The first half of the year I got a personal trainer to help me prepare the marathon in Berlin which, unfortunately, I had to abandon after some pain in my muscles. After that, I haven't trained regularly, barely one or twice a week. Moreover, I got some extra kilos which I'm struggling get off my body. I'd like to get back the motivation that I had two years ago when I was exercising 4 times a week, but I don't know how.</p>
<p>I've been thinking about this a lot, and I think that I just need to find a running buddy that can workout with. Two years ago I was mostly working out with my flat-mate. When I was not feeling motivated, he was the source of motivation. When he wasn't, I was the source. Moreover, I wasn't putting too much energy into work, so it was easier for me to stop thinking about work and enjoy the moment of going for a run.</p>
<h2 id="goal-net-goals-for-2019">🥅 Goals for 2019</h2>
<ul>
<li><strong>Nurture other areas of my life:</strong> I started doing it this year, and I'd like to continue doing it more next year. It's been 5 years with too much focus into software development while disregarding other areas that are equally important. - <strong>Completely abandon social networks:</strong> In my experience, they bring more negativism than positivism into my life. In particular, Twitter, the one that I use the most, I experience it as a bloated stream of information and a race to see who gets the most attention. I ended up doing the same, which caused some anxiety and valuable time of my life being spent scrolling on their infinite timeline. Moreover, I don't want to be part of a platform where users are used as a means or where the voice of assholes gets echoed. - <strong>Get the running routine back:</strong> I'd like to exercise around 3/4 times a week regularly, even when I'm traveling. Exercise makes me feel more energized and confident, so I should have no excuses to make an effort to bring the routine back. - <strong>Have a routine for learning German:</strong> I replace the ambitious "I want to learn German" with just I want to be constant at learning it regardless of how much it takes to be proficient. I've been procrastinating it too much, and I think it's time to settle down. - <strong>Devote more time to María José and grow the relationship:</strong> I feel I disregarded the relationship a bit by unbalancing my life's priorities. I think a relationship is like a flower if you don't put enough water and love into it gets down. While María José has been very supportive and hearted along the year, I think it's time for me to contribute.</li>
</ul>
<p>Can't wait to see what 2019 holds my life. I hope you are all having a wonderful Christmas time 🎄.</p>
<p>Give and share some love with your loved ones and never stop doing it. This world needs more love and more humanity than ever.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>All you need is tools</title>
      <link>https://pepicrft.me/blog/all-you-need-is-tools/</link>
      <guid>https://pepicrft.me/blog/all-you-need-is-tools/</guid>
      <pubDate>Sun, 25 Nov 2018 12:00:00 +0000</pubDate>
      <description>In this post I talk about why investing in good tooling is crucial for projects to move steadily.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Almost a year ago, I joined the team <em>Mobile Tooling</em> at Shopify. It’s a team that focuses on developing tools and infrastructure that mobile developers can leverage to build and release high-quality apps. It was the first time I had the opportunity to work full time on tooling, something that I’d had the opportunity to experiment with in some open source space.</p>
<blockquote>
<p>You can read <a rel="external" href="https://engineering.shopify.com/blogs/engineering/mobile-tophatting-at-shopify-1">Mobile Tophatting at Shopify</a> and <a rel="external" href="https://engineering.shopify.com/blogs/engineering/scaling-ios-ci-with-anka">Scaling iOS CI with Anka</a> to have an idea of the things that my team is building at Shopify.</p>
</blockquote>
<p>Tooling is an area that is often disregarded. Since it doesn’t contribute directly to the product, most companies would rather have developers building the app, instead of building the tools that are necessary for that. What many companies don’t know is that having great tooling and infrastructure is vital for the projects to move forward steadily. It has a <strong>significant impact on developers productivity, motivation, and the quality of the product</strong> that is delivered to the end user.</p>
<p>In this post, I’d like to talk about why I think investing in tooling is crucial, some recommendations based on my experience, and bad practices that you should avoid in your tools.</p>
<h2 id="why-do-we-need-tools">Why do we need tools?</h2>
<h3 id="car-more-automation">🚗 More automation</h3>
<p>When you work on a project, it’s common to end up doing a lot of manual and repetitive tasks. The first time you have to do something again, you don’t realize it’s the second time, but when you do it one more time, you notice there are a pattern and an opportunity for automation. <strong>Manual and repetitive work should be avoided because it is error-prone and computers are better than us at it.</strong> When those tasks are automated, not only they are more robust but save us a much time.</p>
<p>For instance, at Shopify developers used to spend a much time checking out PR branches and compiling the app to try out other developers changes. We spotted that and provided them with a command that they could use to download the app and launch it in a local emulator/simulator in a matter of seconds.</p>
<p>Like we do by abstracting code when it’s duplicated in several places, we should automate manual tasks that repeat over time. <strong>Developers’ time is a valuable asset that you do not want to waste in repetitive work.</strong></p>
<p>At Shopify, we use Ruby for most of that work, but one can choose the language they feel most comfortable with. <a rel="external" href="https://developer.apple.com/swift/">Swift</a>, <a rel="external" href="https://golang.org/">Go</a>, <a rel="external" href="https://www.rust-lang.org/en-US/">Rust</a>, or <a rel="external" href="https://kotlinlang.org/">Kotlin</a> are examples of languages that you could use as well. Shopify is a company that bet for Ruby and we have a lot of libraries and knowledge that we can leverage in our tools. Not to mention all the open source projects in Ruby, like <a rel="external" href="https://fastlane.tools/">Fastlane</a>.</p>
<h3 id="sparkles-reliability">✨Reliability</h3>
<p>Murphy <a rel="external" href="https://en.wikiquote.org/wiki/Murphy%27s_law">once said</a> that <em>if something can go wrong, will go wrong</em>. Things can fail at any time. Perhaps as a result of some flaws in the code or the environment where your app is running. When it happens, developers retry because most of the times it fixes the issue. <em>What if we could detect flaws or infrastructure failures and provide those retries automatically?</em> Luckily, that’s something one can do with tools. Commands in the system, and we can know at any time how the execution is going and the result when it completes. With that information, we can provide a mechanism that retries the failures automatically.</p>
<p>We recently implemented automatic tests retries for Android and iOS. We leveraged <code>gradle</code> and <code>xcodebuild</code> respectively, analyzed the output of those commands, and retried the tests that could potentially be flaky. As a consequence, the stability of the pipelines improved and we could surface flakiness issues for developers to tackle them.</p>
<blockquote>
<p>We discourage bad test practices that make tests flaky but admit that some testing scenarios bring a lot of value and come with some inherent flakiness.</p>
</blockquote>
<h3 id="calling-better-insights">📲 Better insights</h3>
<p>Tools are an excellent opportunity to surface insights about the project and the code. For example, if our tool abstracts the compilation of an iOS app and we have detected some warnings that can potentially become issues in the future, we can expose them on GitHub, and hint the developer how to fix them.</p>
<p>By having control on the tooling, we can also raise awareness when teams don’t follow good practices and conventions that are standard across the organization. We can raise an error if we come across an unacceptable practice, or output a warning if it’s not that critical. We can guide developers to improve the quality of their code and projects.</p>
<p>If your project is on GitHub, its <a rel="external" href="https://developer.github.com/v3/checks/">Checks API</a> is fantastic for this. You can report insights directly to GitHub, and they will show up on the developers PRs. You can add inline annotations and even send a markdown file as a report. We recently added integration with that API to our CI infrastructure. Now, all the projects at Shopify can leverage that integration to generate insights when the pipelines are run.</p>
<h2 id="recommendations">Recommendations</h2>
<h3 id="battery-build-trust-with-the-users-of-your-tools">🔋 Build trust with the users of your tools</h3>
<p>If you want the developers to use your tools, you need to build some trust. Here are some ideas worth practicing:</p>
<ul>
<li>Be supportive, especially in the early stages of the adoptions of your tools. - Collect as much feedback as possible. - Be responsive when things are not working. - Be honest when setting expectations.</li>
</ul>
<p>One thing that you might struggle with at the beginning is the fact that only a few developers thank you when things are working, yet a lot approach you when they can’t do their work because of your buggy tool. What has worked for me is being empathetic by telling them how sorry I am about the tool not working as expected, and do my best to provide them with a solution as soon as possible. If the solution takes me some time, I think of a workaround that allows them to continue with their work.</p>
<h3 id="eyes-observe">👀 Observe</h3>
<p>Although ideas sometimes come from developers, you can also spot areas to improve and propose tools yourself. Developers are so focused on building product, that they barely step back to see how they can improve their workflows with tooling. You are in the position to do it so don’t miss the opportunity. You can see what developers complain about on Slack, tasks that take way too much time, or common patterns that could be abstracted.</p>
<p>When you come up with a tool for an idea, make a proposal, present it to your team, and prioritize it in your team’s backlog. You might feel tempted to jump right into coding, but don’t let the excitement shift your focus.</p>
<h3 id="chart-with-upwards-trend-incremental-interface">📈 Incremental interface</h3>
<p>As soon as the developers start using your tools, they’ll depend on their interfaces. Be mindful when you evolve the interface, embrace semantic versioning, and avoid introducing many breaking changes. Before introducing a breaking change, think if it’s possible to introduce a non-breaking change that helps developers transition towards the new interface. If you release a many breaking changes and force developers to change their code with every new version, you’ll frustrate and disappoint them, and that’s the last thing that we want.</p>
<p>If you are not sure about the interface that you designed, <strong>validate it first</strong>. You can find a project and work with the team behind it to validate your assumptions and introduce the necessary changes to make the interface convenient and flexible for other teams to start using it.</p>
<h3 id="white-check-mark-metrics">✅ Metrics</h3>
<p>Measure your tools. Understand how developers are using them and how efficient they are. Measure whether they behave as expected, or they have some bugs that need to be tackled. Get metrics that are handy for developers to improve their workflows. For example, if your tool helps to compile a project, measure how often the project gets compiled, the average compilation time, how many times it fails, which tests are the ones that fail the most.</p>
<p>Measurement not only helps you improve your tools but the teams to improve their workflows. It’s an everyone wins effort.</p>
<h3 id="rocket-sell-the-tool">🚀 Sell the tool</h3>
<p>You don’t want to implement a tool that no one wants to use, do you? Once the tool is built, market it internally and do some work on getting the teams to use it. Don’t publish it on a GitHub repository and expect the users to grow as if by magic. You can talk to entrepreneurs about this, and I’m sure they’ll give you many tips of things that they do to get more users into their products.</p>
<p>As a good product, make sure it’s documented, has a rememberable name, and provides easy instructions to get onboard. Don’t be a developer and think the only important thing in the tool is the code. If it doesn’t appeal to them from the outside, they won’t use it.</p>
<p><a rel="external" href="https://fastlane.tools">Fastlane</a> is an excellent example of a well-marketed tool. You can use it as a reference to market yours.</p>
<h3 id="integration-tests">❇️ Integration tests</h3>
<p>Tools often have a contract with other tools and services. For example, when you wrap the compilation process of an iOS app, the tool needs to meet the contract with <code>xcodebuild</code>. The most reliable way to know if the contract is properly met is by running a test that tests the integration. Same goes when your tool interacts with HTTP APIs. Although you can use the documentation to implement the request generation and the response parsing, you’d better test it with real data coming from the API. As opposed to apps, where the contract with internal backend APIs is more predictable, and changes are communicated beforehand, the environment and the services the tools depend on are not that predictable.</p>
<p>As an example, at Shopify, we run our actions which wrap <code>xcodebuild</code> and <code>gradle</code> with real builds of fixture projects. If they interact with any REST API, we record real responses using <a rel="external" href="https://github.com/vcr/vcr">VCR</a> and use those responses for the tests.</p>
<h2 id="1-bad-practices">👎 Bad practices</h2>
<h3 id="broken-heart-carelessness">💔 Carelessness</h3>
<p>For some reason we, developers, don’t treat tooling with the same level of care as we do with the main code of the project. I thought it was because usually the tools are written in a language other than the project’s but a colleague of mine proved me wrong. In my experience in different projects, the tools are usually not that well structured, don’t include tests, and the code is a bit unmanageable. If you need an example, you can think about <code>Fastfiles</code> or the bash scripts someone added to the project a while ago. That code that has grown and been tweaked several times until it became the fragile piece of code that your team depends on.</p>
<p>I think tools should be treated with the same care as the project’s code. It should be structured and tested regardless of the language it’s written in. <strong>If you don’t put love on that code, no one in your team does</strong>, and all of you end up depending on a piece of code that can break at any time. <em>Do you need an example? Have you ever experienced painful releases because the script that is responsible for pushing the app to the store broke without no one in the team noticing it?</em></p>
<h3 id="beetle-deficient-error-handling">🐞 Deficient error handling</h3>
<p>How often have you seen a tool blowing up an error which outputs the whole stacktrace. <em>Is it valuable for the developer using the tool?</em> No, that’s handy for the developer that writes the tool. The users of the tools need to know what happened, and why they couldn’t achieve what they were trying to achieve. <strong>What caused the problem is an implementation detail that shouldn’t be exposed to the user.</strong> If you are writing the tool, it takes more work to handle all possible scenarios, but by doing that you’ll offer the users a better experience, and they’ll be thankful for that. What's more, if you output a stack trace, they’ll think the source of the problem is in the tool itself.</p>
<h3 id="boom-noisy-output">💥 Noisy output</h3>
<p>In comparison to non-CLI software, like web or mobile apps, the interaction with the tools happens through the standard input and the standard output, what they type and what they see in the terminal. <strong>There’s only one channel to communicate things to the user, so we have to use it well.</strong> We might feel tempted to dump anything, but that results in a bad experience because we may present information that is irrelevant to the user. Not showing enough information is as bad as showing too much. If we show nothing, the developer might think that the process got stuck and that they should interrupt it. Too much information might make the developer feel overwhelmed. Whenever you plan to add an output, answer this question: <em>“Is this useful for the user?”</em>. If it’s not, don’t output it. See the terminal as a constrained canvas where strokes are expensive.</p>
<h2 id="palms-up-together-open-source-and-third-party-tools">🤲 Open source and third-party tools</h2>
<p>Also, last but not least, I’d like to touch the usage of open source and third-party tools briefly.. When you build tools, you don’t need to build everything yourself. <em>Does your tool need to have error reporting?</em> You’d better consider third-party error tracking services that offer SDK in multiple programming languages. <em>Do you need to process some snapshot tests images?</em> You can find a lot of libraries out there that help you with the image processing.</p>
<p>Don’t spend your time building something that someone has already built. If it’s reliable and helps you solve your particular problem, it’s worth a try. It might happen that the dependency doesn’t fit your needs exactly as you planned. In that case, you can either make a contribution upstream to the project or fork it out and modify according to your needs.</p>
<p>For instance, at Shopify, most of the automation was done with Fastlane. It saved us much time and allowed teams to build their tools easily by combining the lanes that Fastlane provides. However, we’ve reached a point where we need more standardization and reliability which is unfeasible to achieve with Fastlane. We are replacing some of its features with a solution more tailored to our needs. Some of the tools that we build use Fastlane internally, but <strong>it’s on us how the framework is used, not on the users of our tools.</strong></p>
<p>—</p>
<p>As you have seen, working on tooling is <strong>exciting and challenging</strong>. The process of bringing tools into developers’ workflows goes from the conception of the idea, until the marketing step, including the design, proposal, and development of the tools. Not only you grow as a developer but <strong>learn how to collaborate with other teams in your company, how to listen to them, and how to leverage your experience</strong> to provide the best solution for their problems and needs.</p>
<p>If you found it exciting and you’d like to speak further, don’t hesitate to leave a comment or write me an email. We, mobile toolers <em>(if that’s an accepted word)</em>, go through similar struggles so the more we share, the more we can learn from each other.</p>
<p>Have a nice week!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>What a psychologist helped me realize</title>
      <link>https://pepicrft.me/blog/what-psychologist-helped-me-realize/</link>
      <guid>https://pepicrft.me/blog/what-psychologist-helped-me-realize/</guid>
      <pubDate>Sat, 06 Oct 2018 12:00:00 +0000</pubDate>
      <description>It&#x27;s been a few months going through a therapy that has helped me understand how my brain works and where the stress that I used to experience came from.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>A while ago I wrote a <a href="https://pepicrft.me/blog/what-psychologist-helped-me-realize/__GHOST_URL__/2018/05/25/stress">blog post</a> about the stress that I was suffering in my life. Back then, I decided to get some professional help, which turned out to be a great decision. Not only she helped me manage the stress, but I understood better how our brain works. I'm so glad that I made that decision, and I encourage anyone suffering stress or emotional issues to get help as well.</p>
<p>I learned about balancing things in life, emotional intelligence, social conducts, communication... Many things that I assumed were right in my life, were not well taken care of. I've been so focused on work for the last 4 years that I neglected other important aspects that contribute towards one's happiness and a sense of purpose and fulfillment.</p>
<p>I still remember when I had my first session with the psychologist. She asked me <strong>how much time I work daily.</strong> I told her that 8 hours, but that I also spend time doing open source. I cheated myself by putting open source outside the work bucket, and then she asked me: <em>What is open source? Isn't that work?</em> Interesting... I hadn't looked at it as work, but in the end, it is work. Then we talked about the things that I did before or after work, for instance, reading or listening to music or podcasts. She asked me which kind of reading and podcasts. When I answered that question, I realized that <strong>most of the reading and podcasts had a connection with work</strong> because all of them were technical.</p>
<p>I was investing so much time in work that other areas of my life were ignored. I was not working on my social life, taking care of my relationship and the family, exploring or just dedicating time to myself. <em>How did I end up like this?</em> I think it was the wrong idea of having to renovate myself as the industry evolves. Maybe seeing everyone around me creating, renovating themselves, trying the latest framework and programming language, made me think that I had to do the same to be accepted by the industry, find opportunities, and take part in the new and fresh things that everyone is talking about. <strong>That idea is wrong.</strong> I don't need to renovate myself, listen to podcasts, check Twitter, or attend conferences. The only thing that I need is to find something that motivates me, learn about it, whether that is a programming language, a framework, or a hobby, and don't feel I need to play with the thing everyone around me is playing with. In that regards, I admire people in our industry like <a rel="external" href="https://twitter.com/mojombo">Tom Preston</a> and <a rel="external" href="https://twitter.com/dhh">DHH</a>, who found their passion in Ruby and Rails, became good at them, and focused on creating things with value for the society.</p>
<p>I learned that <strong>I can't and don't have to know everything</strong>. When I accepted that, I stopped listening to podcasts, attending conferences, or reading blog posts very often. Ignoring those things decreased my anxiety, and worry for missing out. I had more focus and more time that I could invest in something else. The psychologist showed me an analogy between those areas and a table with 4 legs. The only way a table can stay steady is if the 4 legs are strong. If one of the legs is weak or has flaws, the table will fall down. Our life has 4 legs as well: <em>ourselves, family, friends, and work</em>. If we don't balance them, one of them is stronger than the others, and the table will drop: <em>meaningless relationships, arguments with our partner, ill health</em>. <strong>The strongest leg in my table was work</strong>. When I dedicated time to the other legs, I did it in the context of work: <em>I attended tech meetups to meet new people, hung out with people I had met in conferences or at work and ended up talking about work.</em></p>
<p>I started working on the other three legs by dissociating them from the work's leg. It was an uncomfortable feeling first, but a pleasing one once I controlled it. I <a href="https://pepicrft.me/blog/what-psychologist-helped-me-realize/__GHOST_URL__/2018/09/10/oberbaum-bridge">started painting</a>, which is something that I used to do when I was young. I realized that the exercise of painting has the power of disconnecting my mind. I do it old style, with ors, brushes, and paper. I can do it with an iPad, but I would be connected to work and technology in some way <em>(push notifications, email, Twitter)</em>, and the experience wouldn't be the same. I encourage anyone to find an analog activity and practice it, but without tracking or writing about it on Twitter or Facebook. <strong>I think feeling disconnection and boredom is something we should find time for in our busy world and industry.</strong></p>
<p><strong>When was the last time you felt boredom?</strong> I was presented with that question and didn't have an answer for it. It's been such a long time without feeling bored that I don't remember how that feels. Boredom became so uncomfortable that I appealed to my phone to not handle it. I didn't realize that experiencing boredom is an important thing to do. Many people call it meditation nowadays, but I think the industry has misled that term and made us believe that playing a 5 minutes audio on an app is meditation That's just pausing the chaos, and noise around us for 5 minutes, which will slap our face afterward. We are offered with tons of options to celebrate our achievement by sharing the disconnection with the world on social networks. That's not meditation, that's a product. I tried to find more of those moments. I'm glad that we moved into a new apartment with a balcony. I got one of those beach chairs, and I can lay on it looking at the sky, and the planes landing in Berlin. No phone, computer, talk, or thoughts whatsoever. I do the same thing when I'm on the public transport or riding my bike. I let my thoughts wander, I look at the things around me, the people, the buildings, nature, everything.</p>
<p>Another domain of psychology that we put the focus on is on <strong>assertiveness</strong>. Assertiveness is the ability to manifest your rights and respecting others' rights. I realized that I'm a person that respects everyone's rights, but when it comes to manifesting my own, I often don't do it <em>(I'm a passive assertive)</em>. For example, if I'm with friends, and I have a different opinion that I'd like to share, I'd be assertive by sharing my thoughts <em>(the right to be heard and taken into account)</em>. Being a passive person when it comes to assertiveness leads to things like interpersonal conflicts, depression, anger, or having a poor image of ourselves. After recognizing that, I worked a lot to be more assertive. Whenever I feel I have the right to something, I just manifest it. It was hard at the beginning, but once I experienced the benefits of being an assertive person, it got more natural.</p>
<p>Last but not least, I was introduced to the notion of <strong>emotional intelligence</strong>, something I hadn't heard about before. I used to think that one becomes successful in life by working on its intellect. That's not necessarily true, because there's another intelligence, the emotional, that we are not told about and thus barely work on. It's been proven that having good emotional intelligence is crucial to being emotionally stable and making great decisions in life. When I reflected on the intelligence I had worked on the last few years I realized that it was mainly the intellectual one. As a consequence, when I was presented with hard and deep emotions, I felt overwhelmed, responded fast and often without reasoning.</p>
<p><strong>Reasoning about my thinking, emotions, and time management</strong> has significantly improved my life. Work is no longer my main focus, and I don't let it invade other areas of my life. I learned how to make better decisions and deal with emotions that used to affect me. All of that thanks to the professional help of a psychologist that understands how we, humans, think and behave. Our brain 🧠 is a muscle which we need to take care of. <strong>Take care of it ❤️, take care of yourself.</strong></p>
<p>If you are experiencing similar things in your life and would like to chat about it, don't hesitate to let me know. I'll be glad to share with you the ideas that worked for me.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>GitHub workspaces using email</title>
      <link>https://pepicrft.me/blog/github-workspaces-using-email/</link>
      <guid>https://pepicrft.me/blog/github-workspaces-using-email/</guid>
      <pubDate>Thu, 06 Sep 2018 12:00:00 +0000</pubDate>
      <description>With this simple tweak I managed to have a notifications-free GitHub dashboard with workspaces right on my email.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>In my effort of moving away form Gmail, I took the opportunity to set up my new email account in such a way that I could better organize my work on GitHub.</p>
<p>There's a feature that GitHub has never had and that I'd find very useful, workspaces. I used to look at the notifications to know the things I should focus on. If you are part of multiple organizations, all those notifications show up in the same place. As a result, when I open the notifications page to plan the open source work, I end up looking at work stuff and the other way around.</p>
<p><strong>Luckily, most email providers offer defining rules for emails.</strong> With rules, you can match certain emails that you receive, and define an action for them, for example archiving or deleting.</p>
<p>Thanks to rules I was able to have workspaces for GitHub right on my inbox. This is what I did:</p>
<ol>
<li>Add an email address per workspace to your GitHub account. 2. Configure the notifications per organization and forward them to the right email account. 3. Create a folder per workspace. In my case it was "shopify", "work", and "tuist". 4. Define a rule where you match the recepient with the emails above and send the email to the right folder.</li>
</ol>
<p>Simple, isn't it? With this little tweak I can access a notifications-free GitHub, focus on my work, and check the notifications on my email when I need to plan the work.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Open source mindfulness</title>
      <link>https://pepicrft.me/blog/open-source-mindfulneess/</link>
      <guid>https://pepicrft.me/blog/open-source-mindfulneess/</guid>
      <pubDate>Sun, 19 Aug 2018 12:00:00 +0000</pubDate>
      <description>Not being mindful when contributing and maintaining open source projects might lead to burnout or low self-steem. In this blog post I talk about some principles that I applied to have a healthier relationship with the open source.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As a developer who likes and believes in the benefits of making our software open, I devoted a vast amount of time building open source libraries and tools in the open. It helps me learn and grow as a software engineer and experiment with things I can't experiment with at work. In most cases, those contributions happen before/after work, when you need to care about other important things in life like family, friends, and health. Yes, those things are more important than work or open source, regardless of how much you like it.</p>
<p>One of the things that I find the most difficult of working on open source is doing it with mindfulness. I tend to get trapped by the joy and spend too much time thinking and working on it. As a result, I reach burnout points when I start wondering why I'm working on the project, what's the value of it, what if I spend my time on something else, what if no one uses it. I even lose the motivation for it.</p>
<p>Getting burnout of doing open source work is not something new. If you do a bit of research you can find a lot written about the topic:</p>
<ul>
<li><a rel="external" href="https://thenewstack.io/darker-side-open-source/">How to Avoid Burnout Managing an Open Source Project</a> - <a rel="external" href="https://staltz.com/open-source-without-maintainers.html">Open source without maintainers</a> - <a rel="external" href="https://medium.com/@oleg008/fighting-burnout-with-open-source-ba87559ad844">Fighting burnout with Open Source</a> - <a rel="external" href="https://www.techrepublic.com/article/why-open-source-developers-are-burning-out-no-respect/">Why open source developers are burning out: No respect</a> - <a rel="external" href="https://nolanlawson.com/2017/03/05/what-it-feels-like-to-be-an-open-source-maintainer/">https://nolanlawson.com/2017/03/05/what-it-feels-like-to-be-an-open-source-maintainer/</a></li>
</ul>
<p>In this blog post I'll walk you through some of the principles I'm sticking to to have healthier open source contributions:</p>
<h3 id="responsibilities">Responsibilities</h3>
<p>Open source is something that I do in my free time, something I'm not getting paid for, and which I do for fun. I dedicate the amount of time I consider healthy and balanced with other responsibilities. If I assume too many responsibilities and devote too much time to it, I stop having fun and start worrying too much about the project.</p>
<h3 id="vision">Vision</h3>
<p>When I start an open source project, I write down what I'm aiming for with it. Which problem I'm trying to solve, the project, is it a short or long-term project? By doing so, I avoid wrong expectations, and I can use it to steer the project. For example, if it's an experimental project that I don't plan to maintain, I reflect it somewhere on the README.</p>
<p>Having a vision in the project is useful in discussions, where you need to justify why you are making individual decisions.</p>
<h3 id="no">No</h3>
<p>This is something I struggle a lot with because overall, I don't know how to say no. Luckily, I'm getting better at this with some work. Some examples of when I have to say know are:</p>
<ul>
<li>When a feature request is outside the scope of the project. - When the code quality doesn't follow the project standards. - When tests are missing. Not being assertive in an open source project might lead to some frustration and lousy self-esteem.</li>
</ul>
<h3 id="goal">Goal</h3>
<p>A project without a goal is hard to steer. When I work on a new project, and I tell people about it, I hear lots of different opinions along the way. People that like the project, and start supporting, people that don't believe in the idea and think it's not worth spending time on something like that. If I dreamed with the project and envisioned it, I appreciate the feedback a lot, but I'd like to prove to myself whether it was a wrong decision or something that brings value to developers.</p>
<p>I've sometimes been concerned about what other developers thought about the project and ended up losing motivation for the project.</p>
<h3 id="priorities">Priorities</h3>
<p>When I work on a new task, I prioritize either the ones that add the most value to the project, or which help achieve the next milestone to the project. Along the way, ideas and external contributions come out. I add them to a processing backlog and decide which level of attention they need. Concentration is gold nowadays, so even if I feel tempted to shift my focus to them, I try not to.</p>
<hr />
<p>Those are some principles that I recently applied to have a healthy relationship with the open source project. It's hard, especially when it's something that I enjoy doing, but something that I have to do if I don't want to burn myself out.</p>
<p>Are you an open source contributor/maintainer? I'd love to know how your relationship with open source looks.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Open Source</title>
      <link>https://pepicrft.me/blog/open-source/</link>
      <guid>https://pepicrft.me/blog/open-source/</guid>
      <pubDate>Sun, 29 Apr 2018 12:00:00 +0000</pubDate>
      <description>In this blog post I talk about why I work on open source projects and what are the most important elements for me when starting an open source community.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've been wondering how many things that I do, I do them because everyone does them. With everyone sharing how they do things, and pitching us their library, their work-style, or even their tools I think software engineers are strongly biased by external opinions, including me. Are you using VIPER because it's a good fit for your project's needs or because you saw a few companies using it? Are you using that library because it's saving you time, or because you saw an example of how to use it and you thought you could go with replicating the example?</p>
<p>Answering those questions has been eye-opening, and made me realize that some of my opinions and decisions were not made by myself If you have never done this exercise I encourage you to include an extra question when you have to make decisions:</p>
<blockquote>
<p>Am I doing this because everyone's doing it?</p>
</blockquote>
<p>I don't like doing something when I don't feel passionate about it. It's easy to follow a trend and end up doing what everyone else is doing, but I prefer not to. Following trends and already formed opinions do not help with building yours; you repeat what others are saying. Sometimes it might happen that the conclusion that you have, is the same as others', and that's fine, but I think there's a considerable value in spending some time to form it.</p>
<p><strong>I asked myself the same question for open source</strong>. I realized that I prefer doing open source software over private's. Open source has become an important thing in the software industry, and companies that traditionally didn't do any open source started doing it. <strong>Am I doing this because of the trend?</strong> <strong>Why am I doing it in the first place?</strong>.</p>
<p>This question led me to an answer which I think describes well what open source means to me and why I devote part of my time to it, <strong>interaction with people</strong>. I like working with people more than computers. Unfortunately, that's something you don't have a lot if you work in tech, where your best friend is your computer. That changes if you do open source because all of a sudden you are connected with people from all over the world working together towards the same goals.</p>
<p>For me, the beauty of open source is <strong>creating community</strong>. When I envision a new open source project, I like spending some time thinking about how I'd love the community to be. One of the first things that I do is <strong>creating an organization</strong> which they can feel part of. I could create the repositories on my GitHub profile, but it wouldn't be fair, in a sense that, they'd be contributing to a repository that belongs to me. I want them to feel they are contributing to something that also belongs to them. I use the <a rel="external" href="https://github.com/moya/aeryn">Aeryn</a> tool from the Moya community to invite contributors after they merge their first PR. That makes them feel part of the family and encourages them to continue contributing to the project.</p>
<p>Interacting with people is harder than doing it with computers and software. Different profiles of developers will land on your project:</p>
<ul>
<li>A developer who interested in contributing altruisticly because they like the idea behind it. - A developer who contributes towards their interests. - A developer who extensively uses it and reports a lot of bugs and great ideas. - A developer who will make you feel like you are serving them and you should do whatever the asked you to do.</li>
</ul>
<p>Working in open source has helped me improve my communication and interaction skills. Dealing with all different profiles and choosing the right language for every interaction is not easy. It's a challenge, but one of those challenges I enjoy going through. I still have a lot to learn, but I'm enjoying the process.</p>
<p>As an example, I recently started working on a new open source project, <a rel="external" href="https://github.com/xcbuddy">xcbuddy</a>. It's been a few years working as iOS Engineer and suffered the pain of using Xcode at scale. Instead of keeping complaining I just decided to build a tool that helps teams overcome the most common challenges when scaling their projects. The first version of the tool is not ready yet <em>(and there will be a more extense blog post talking about it)</em> , but I already established the foundation of the community around it. This is what I did:</p>
<ul>
<li><strong>Tweeter 🐦:</strong> I built a simple service that publishes tweets with the most recent updates of the project. What's more important, it publishes when <strong>there's a new contributor</strong> that has joined the organization. It makes the community more inclusive, making them feel part of the community. I think inclusion is not only about having a markdown in the repository that says that your project/organization is inclusive. It's all about little actions, like this one, that makes everyone feel welcome and part of the project. - <strong>Slack-free 🔇:</strong> Slack is great for real-time communications but in my opinion, not a good fit for open source projects where communications happen mostly asynchronously. Moreover, it's easy to lose track of discussions when there's a lot going on. - <strong>Spectrum 👥:</strong> <a rel="external" href="https://spectrum.chat">Spectrum</a> is a tool for communities which I recently came across. I'm still evaluating whether it's worth using it or we should keep things simple and use GitHub for everything. I decided to create a community in Spectrum because there are things like introductions, ideas, or off-topic threads that are not suitable for GitHub issues. - <strong>Website 🌎:</strong> I'm designing and developing a website, not only to explain to developers what the tool is about, but to praise, and thanks to contributors for the work they are doing. I think everyone deserves recognition for its work because, without them, most of the open source projects that we use nowadays wouldn't exist.</li>
</ul>
<p>When it comes to building open source projects, the essential element for me is the <strong>people that will make it possible</strong>. Although I might be the primary driver when the project takes the first steps, most of the projects keep moving thanks to the energy and the passion which external contributors bring. Sometimes you feel down, or a bit burnout after a lot of work on the project and it's energizing to see that the project grows thanks to the work of people that you welcomed to the project back in time. I still have a lot to learn, and things to improve, like how to <strong>be more transparent</strong>, or <strong>manage my time better</strong>, but this ride is fascinating and I'll continue doing more work in the open.</p>
<p>I'd like to thank people like <a rel="external" href="https://twitter.com/orta">@orta</a> because they are an excellent source of inspiration for me when it comes to creating communities and doing open source by default.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>On having focus</title>
      <link>https://pepicrft.me/blog/on-having-focus/</link>
      <guid>https://pepicrft.me/blog/on-having-focus/</guid>
      <pubDate>Wed, 11 Apr 2018 12:00:00 +0000</pubDate>
      <description>I&#x27;m struggling to have focus nowadays. In this post I describe why it&#x27;s so hard for me to focus, and the things that I&#x27;m doing to overcome the problem.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>There's something that has been happening to me lately, and that I'm struggling with: <strong>having focus</strong>. While this wasn't a problem a few years ago, and I was able to sit down and work on one thing at a time without distractions, I can't do that anymore. It might be that I'm getting older, or that I ambitiously pushed myself beyond my limits. The fact is that this started affecting me, losing motivation for things, and feeling exhausted with technology overall.</p>
<p>I found myself involved in multiple projects at the same time. I'm terrible at saying no, especially if it's an exciting project where I can contribute. I'm also bad at processing ideas. Every time I have an idea, I overexcite instead of sleeping over it, and adding it to a backlog in case it's something feasible with high potential to be worked on in the future. Imagine that happening every day and your list of active projects growing endlessly. You open your laptop in the morning, try to plan your day, and you don't know in which project you should focus on. Should I work on this because today I feel that I'd love to do this one? Or should I work on this other one that has a couple of issues opened waiting for feedback from me?</p>
<p>Moreover, and like most developers, we are forced to work on the <strong>ongoing project of renovating ourselves</strong>. You can't just learn a language X and expect that knowledge to be enough for your whole career. Language X evolves, and with it, some other technologies or languages that emerge. There are trends that you need to follow, even if don't want to because that's the only way you'll have decent work opportunities in the future. For example, if you were Objective-C developer until Swift came out, and you didn't invest time in learning Swift, you would very likely be missing a lot of opportunities nowadays. That applies to any language and technology: the Javascript developer that hasn't learned declarative UIs using components, or the Android developer that is still using Java.</p>
<p>With so many projects to dedicate time to and a lot of distractions, having a lack of focus is a natural consequence. These are the things that I'm currently doing to bring that focus back and feel less overwhelmed:</p>
<ul>
<li><strong>Slow down:</strong> This might seem obvious but my personality leads me to the opposite. I'm a person who reacts quickly without thinking thoroughly. Changing this is tough because there is an inner Pedro whose excitement would lead him to answer without thinking twice. - <strong>Notifications-free phone setup:</strong> I decided to leave my iPhone at home and go with an old Nokia that only allows me to make and receive calls and SMS. That's all I need. Notifications are rarely important, and that consumes a lot of energy and focus from me. All work-related emails or Slack messages will be accessible only from my computer and the same with the social networks that I barely use. - <strong>A side project at a time:</strong> Instead of kicking off and dragging multiple projects at the same time I'd devote my time to one project instead. I became less active in open source projects than I used to be, and I'm focusing on my first software product project that I'll share with you soon. - <strong>It's ok not to stay up to date with technologies:</strong> There are new technologies, blog posts, and projects coming out every day so I changed my mindset from having to be aware of all of them, to filtering those who really matter to me. As an example, I don't follow the evolution of Swift actively but only skim through the release notes when there's a new version. - <strong>Spend less time with technology:</strong> I love technology, but like any other thing, too much of it creates an addiction, and that's not good. Instead, I'm devoting more time to myself and to the people around me. Spending more time with people helps you make your software more human-driven.</li>
</ul>
<p>I think it's important to have these retrospectives with ourselves where we can see how technology is impacting us and how healthy our relationship is. We spend an insane amount of time with it, and this time is increasing every day. We shouldn't allow technology take control over our focus, whether that is being happy, or be an astronaut.</p>
<p>If you are a developer, who has experienced something similar I'm curious to know how you overcame it and how you make to stay focus in this world where it's easy to get distracted.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Hallo Ruby, wie geht&#x27;s?</title>
      <link>https://pepicrft.me/blog/hallo-ruby/</link>
      <guid>https://pepicrft.me/blog/hallo-ruby/</guid>
      <pubDate>Fri, 23 Feb 2018 12:00:00 +0000</pubDate>
      <description>It&#x27;s been a long time since the last time I coded something on Ruby. In this blog post I talk about why I started using it again, and how it feels after spending a few years working with a compiled language like Swift.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It's been a long time since the last time I built something in Ruby. Most of the work that I've done with the language while I was iOS developer were changes on either the CocoaPods <code>Podfile</code>, or the <code>Fastfile</code>. I became super optimistic when Swift came out, and even built some command line tools and libraries contributing to the community. However, as I wrote in one of my posts, I decided to devote most of my time on interpreted and community-driven languages like Ruby or Javascript. Two things motivated me to make this decision:</p>
<ul>
<li>Ruby is the primary programming language at <a rel="external" href="https://shopify.com">Shopify</a>, my current company. That was a decision made a while ago, and all the internal tools and libraries are built in Ruby. It didn't make any sense to push for another language that couldn't fully leverage the existing stuff or be integrated easily. - I've been doing Swift since it was released. Most of my open source projects are written in Swift, and I like the language. It's beautiful and well designed. Things are moving fast, and the community is very involed the development and the decisions that are being made. However, I did a retrospective on what doing Swift means to me as a developer, and I realized that I was limiting the scope of the software that I build, contributing towards an ecosystem that is controlled by a company with a lot of power, Apple. Doing Ruby and Javascript, programming languages mainly driven my communities, I'd make my software accessible from any platform, or ecosystem. Anyone can access a website, but not everyone can have access to an iPhone or a macOS device.</li>
</ul>
<p>Since I joined Shopify, I've been doing mostly Ruby. There are great engineers with a lot of experience here, and it's a fantastic opportunity for me to learn. It felt bizarre the first time that I tried to write some Ruby after some time off. I'd like to outline some of these strange feelings:</p>
<ul>
<li><strong>Types:</strong> This was probably the most awful thing for me. I wasn't aware of how much I was used to types. I just used them, and I safely wrote my apps or Swift scripts. There are no types in Ruby. You call a method that takes a few arguments with some names, but you don't know which types the method implementation is expecting. Should this argument that I'm passing be a string? Should it be an array of String? With Swift you can write the code with a lot of confidence, but with Ruby most of the times, you have to dig into implementations to know what types the method expects. I've seen some Ruby projects, and they seem to leverage documentation to offer types information. - <strong>Where should I validate my data:</strong> Our software gets input and returns output. If we take a mobile app, for instance, inputs are user interactions, and the output is the views presented on the screen. When an input is received, the action is propagated through our software, to produce the output. In every step of the propagation, we have the types system and the compiler to make sure that all the pieces in our software match. It won't let us go to production or the store if there's a mismatch. With Ruby, the validation happens as the action propagates through the system. If the system hasn't been designed properly, it'll result in a runtime error, and the system will need to recover from it. That scares me, and to be honest, I don't know what's the best approach to minimize this yet. It doesn't make sense to validate all the inputs in our methods because it's slow and we shouldn't assert for something that we've wrongly implemented. But if we only validate the input, can expect some runtime errors to blow up unless we thoroughly test all kind of integrations in our software.</li>
<li><strong>Code organization:</strong> In Ruby, there's this notion of modules. Modules are used among others, to create namespaces. That's an idea that didn't take me much to swallow cause there's something similar in Swift, but how to split modules and classes in different <code>.rb</code> files is another story. I've checked multiple open source projects, and each of them does it differently. I've seen some using <code>require_relative</code>, others using an umbrella entry point Ruby file that defines the project hierarchy autoloading all the components. I've stuck to the latter, and it's working well for me. <code>autoload</code> is not thread-safe, and that it'll be deprecated, but since I don't have any thread-safety requirements in the tools that I write, it's safe to use it. This is an example of what an umbrella Ruby file looks like:</li>
</ul>
<pre><code>module Catalisis
 module Builder
 autoload :Project, &#39;catalisis/builder/project&#39;
 end
end
</code></pre>
<p>I'm getting used to the things that I mentioned above. When you spend some years with a language, you tend to replicate the patterns and styles into the new language. For example, instead of using the naming convention that is commonly used in Ruby projects I literally brought the one that Swift recommends, where if something can be encoded, it should be called <code>Encodable</code>.</p>
<p>There are things from writing software in Ruby that I'm enjoying a lot:</p>
<ul>
<li><strong>Minitest/guard:</strong> You can see how mature the language and the community are when you start using the tools. One that surprised me a lot if miniguard. When you write tests, it detects the files that you changed and runs the tests of those files, imediately. You can focus on writing your code/tests, and there'll be a parallel process running and telling you whether everything passes or there's an issue. You can do proper TDD.</li>
<li><strong>Editor:</strong> The language is not tied to any editor/IDE so you can choose whatever works best for you. If you prefer something closer to the Xcode experience, you can try any IDE from the JetBrains suite. If you are a minimalist and just want a simple text editor with syntax highlighting and pluggable add-ons to customize your workflows and make you more productive you can use Sublime, Atom or VSCode. I personally use VSCode. It' simple, fast and extensible. It has just what I need to work on my projects.</li>
<li><strong>Libraries:</strong> Whatever you can imagine can very likely found as a Gem. The community has been building libraries for a long time. This saves you a considerable amount of time.</li>
<li><strong>Distribution:</strong> Your projects can be distributed as gems. You can install it on your system, and it'll install all the necessary components to get it working. This is not officially supported by Swift and its package manager, so you have to appeal to non-official tools. I wouldn't be surprised if Apple includes this as a feature in the Swift Package Manager, but even with that, pre-compiled binaries would break with new versions of Swift because it hasn't reached ABI stability yet.</li>
</ul>
<p>I hope you enjoyed this brief reflection. If you are more familiar with Kotlin or Javascript, you can replace Swift and Ruby by Kotlin and Javascript and the points mentioned above should apply as well. As I mentioned earlier, making the software that I write more accessible is for me one of the key motivators and having the opportunity to do it at Shopify is one of the best decisions I've recently made. You can expect more Ruby OSS coming from me from now on :).</p>
<p>If you have had a similar experience transitioning from a static to a dynamic language I'd like to hear your experience. Don't hesitate to leave a comment right below.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Thoughtful usage of technology</title>
      <link>https://pepicrft.me/blog/thoughtful-usage-of-technology/</link>
      <guid>https://pepicrft.me/blog/thoughtful-usage-of-technology/</guid>
      <pubDate>Wed, 14 Feb 2018 12:00:00 +0000</pubDate>
      <description>I gave up using Medium and here are the reasons that led me to make the decission.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<ul>
<li>I struggle to concentrate when I read. - I struggle to listen when someone is talking to me. - Doing something that doesn't involve technology is something that I don't feel like doing. - Receiving notifications and updating everyone about what I'm doing has become part of me. - The streams of information are flooding my attention, and it tires me daily.</li>
</ul>
<p>Like many other things in life, doing too much of something is not healthy. A cup of coffee a day is not bad, drinking five can be very dangerous for your health. Playing video games once a week is not bad, but doing it as a daily routine can have a very negative impact on you. Although technology is useful, and it's enabling many things that were impossible a few years ago, I think the fact that I'm fully immersed in it every day is having a not so good impact on me. This is something that I realized, but I've never taken any action. I feel that technology is like candies, you consume it, you enjoy the moment, your brain does it, and you don't realize how bad a lot of it can be until you see the long-term impact it's having. Candies make you fatter, and it doesn't happen overnight. You enjoy every single candy that you put in your mouth. They come with beautiful colors because that tricks your brain; they are sweet, and your mouth likes that pleasure. Do that every day, and sooner or later your body will manifest. Our brain is the result of millions of years of evolution. Technology has rapidly evolved in less than 50 years. Do you think our brains have been able to keep up with that fast-speed evolution that surrounds us? I don't think so.</p>
<p>I work in technology. I'm a software engineer, so working with technology is part of my job. I spend my days using apps, exploring the internet, reading news, checking my email, downloading the last updates, buying the latest technology. It feels so exhausting when I write it down... On one side I like it because technology helps to solve real-world problems <em>(not only the ones that people working and living in the Bay Area have)</em>, but on the other side, I think there's beauty on living a technology-free life and doing things without technology.</p>
<p>When I look at all the innovation that is coming, the new technologies companies are investing money in it scares me. It scares me the fact that technology is evolving with a lot of side effects on humans along the way. We are becoming addicted to it; we don't know how to live without it. We've come to think that all around us is about technology. Technology is always there to surprise us, to gives a new thing, new feelings that we haven't experienced before, new gadgets to try out, problems that didn't exist before. We've unconsciously become non-conformist people. We are always expecting technology to feed our need of having more, of experiencing more, of being more connected. Technology has learned how to prove us that we need it, and that scares me even more. In the recent weeks, I've been detoxing from it, and I realized how much stuff that I thought I needed is useless. Call me a hipster or retro person, but I'm trying to live like I used to live before technology invaded us. I don't feel excited when Amazon says they plan to remove the cashiers from the supermarket because the future is that technology should control everything. I like going to the supermarket and talking to the cashier about the news, or even some gossips. I love smiling at each other and keeping that smile for the rest of the day. I don't feel thrilled either when Elon Musk says that he's planning trips to Mars and sending cars to space. We have a beautiful planet, with a lot of problems with it, and that we are destroying slowly. Why don't we invest money in using technology to solve real world's problems?</p>
<p>When we are told that VR is the future and that social networks make people more connected I always wonder how likely these statements can turn to be true. How can you dare to say that you are making people more connected if you are introducing something that has never been tried before and that radically changes the way people interact? VR will be the future in a couple of years and then what? Will there be any other thing that will be new future? What if we freeze the time for a while and reflect on where technology drove us to; what we learned, what we failed at doing, the direction technology should take. The world is moving to fast to stop it, the machine is running, and it's impossible to stop it. Would you imagine Facebook ending everything that they are doing to reflect the impact Facebook is having on people's lives?</p>
<p>I'm optimistic. I also look a technology from another angle. I see projects coming up shining human values, so there's some hope. I'm using technology, but not in the same way I used it before. Our relationship is simpler, I use technology only when I think it offers me any value, and don't feel addicted to it.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>I gave up using Medium</title>
      <link>https://pepicrft.me/blog/gave-up-medium/</link>
      <guid>https://pepicrft.me/blog/gave-up-medium/</guid>
      <pubDate>Wed, 31 Jan 2018 12:00:00 +0000</pubDate>
      <description>I gave up using Medium and here are the reasons that led me to make the decission.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>A week ago I decided to remove all my publications from <a rel="external" href="https://mediu.com">Medium</a>. I've been using Medium together with my blog to publish articles, and also to find content from other publishers. I like how clean the design of the platform is, and how easy it is to discover new content based on other publications that you liked. However, several reasons made me decide to stop using it, remove my posts and focus on my personal blog instead. These are the reasons:</p>
<ul>
<li><strong>Pull vs push:</strong> I became anti-push products or technologies. For me, push products are those who push content to you, instead of expecting you to appeal to the product whenever you want. In other words, opening a website to read something because you want to read at this particular moment, instead of getting notifications every time there's something new that <em>"you might like"</em>. I hate that products try to guess what and when I might need something. I hate that from Facebook, I hate that from marketing emails, I hate that from Amazon. Medium does it as well, and I don't like it. We have a saying in Spanish that says: <em>"don't want for others, what you don't want for you"</em>. Since I don't like being pushed with new content, I don't want others to feel the same when I publish an article. We are overwhelmed with a lot of streams of information every day, and I don't want to add up to that stream. I don't want to be feeding machine learning engines, and recommendation algorithms to spread my blog post around the world. I don't care if I don't reach that many people, or if my blog posts are not read by as many people as they used to be. I'm caring more about people's time, and since I can't change the way most of the products work, I'll stop being part of them. The people that like reading what I write can always use a convenient web feed format called <a rel="external" href="https://en.wikipedia.org/wiki/RSS">RSS</a>. I'm using it a lot these days, and have it setup on my desktop and mobile phone to read <strong>whenever I feel I'd like to read something</strong>.</li>
<li><strong>Content:</strong> Ultimately, I don't find any good blog post on Medium. The homepage is full of sensationalist and superficial blog posts that have no value at all. <em>"7 tips to have a successful life"</em>, <em>"Why you should start your own company"</em>, <em>"How meditation changed my life"</em>, <em>"8 reasons why you should invest on Bitcoins"</em>, <em>"Why you should use Kotlin"</em>. Not sure if it's their recommendation algorithm that doesn't work well with my profile, but I don't like most of the posts that I find there. As I said, I set up my RSS client again, and I subscribed to the blogs whose content I like because they are well written, with strong arguments, and with a lot of value.</li>
<li><strong>Claps:</strong> Most of the things on the Internet are built around the need humans have of being recognized, including Medium. It's all about the impact: the likes that you got on your publication, the people that watched your Instagram stories, the retweets on your last tweet or the stars on your GitHub repository. On Medium the impact is measured by claps, and in some way is a mechanism to hook publishers into the platform and get them to write more. Have you ever thought about the profound effect this subtle thing has in your mind? You end up publishing more because you want to get more claps the next time. That doesn't go with me, and even though I've suffered it in the past, I don't want to publish anymore driven by the recognition on a platform.</li>
<li><strong>Jekyll:</strong> I like the flexibility Jekyll offers me. I can write my blog posts using Markdown, easily add code examples, add Ruby code to automate the project generation or use Javascript to add components to the website. As a developer, having such flexibility is something that I like a lot. Moreover, using only Jekyll, I don't have to maintain the blog posts in two places. I didn't have anything automated, so when I wrote a blog post, I copied and pasted it into Medium. When there was a typo, I had to fix it in on both sides. I don't have to do that anymore. There's a single source of truth, and I have full control over it. It's an open source git repository on GitHub. I can deploy the site to any hosting service. The content that I write is not used to run businesses with it. It's a content that I write because I like sharing all the work that I do and the things that I learn. It's not a business, it's knowledge that should be shared on the open Internet.</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>The hermeticism and rigidity of Xcode and its projects</title>
      <link>https://pepicrft.me/blog/xcode-rigidity-hermeticism/</link>
      <guid>https://pepicrft.me/blog/xcode-rigidity-hermeticism/</guid>
      <pubDate>Sun, 28 Jan 2018 12:00:00 +0000</pubDate>
      <description>Xcode and its projects are not as flexible as they could be, which makes it hard for companies to optimize their workflows and processes. In this post I&#x27;ll analyze some of the things that I would improve from its build system and projects.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If you work with Xcode you are most likely familiar with its hermeticism. Compared to other programming languages, like Kotlin, where the build system is independent of the IDE <em>(Gradle)</em>, in Xcode everything is together and not well documented. Xcode projects have build settings and build phases that are the input to the build system that Xcode uses. Have you ever searched for what each of the build settings means? You'll most likely end up on StackOverflow or some random website where someone tried to figure out what these settings are for. Documentation is terrible, and developers have to do some reverse engineering to understand what they are for. When I see other build systems like Gradle, where you have total flexibility during the build process, and everything is documented I feel jealous. I wish Apple had something like that with Xcode. I'm optimistic, and I believe it's going to happen sooner or later, but I think we are far from having it.</p>
<p>Besides the hermeticism of the build system, another thing that annoys me is its rigidness. Build settings and build phases is the only input, and they are very static, you can't do much with them. For example, if you want to link a library/framework when some conditions are met you cannot. You need to write your scripts that can be hooked from Xcode build phases but they cannot participate in the build of the source code. Only build settings, and sources buidl phases can determine what and how needs to be built. If you add a custom build phase that links a library conditionally, then it breaks the scheme <em>"Find implicit dependencies"</em> because Xcode is not aware of your custom linking. Bad, isn't it?</p>
<p>Although this works for most of the projects, as soon as you need to optimize things in the way your project is built, then you are fucked. Companies like Pinterest, Uber, or Facebook has moved to other build systems like Bazel and Buck. Besides the powerful features that they get from them, they are very flexible, especially Bazel, so you can customize any step of your project build. One important difference between Buck and Bazel for instance is that Bazel allows you to define custom phases using a programming language similar to Python. For companies like Shopify, where there a lot of engineers building the app every day, where our CI infrastructure is compiling every commit that is sent to the git repository, it's essential that we have a fair amount of flexibility. We'll work soon on having incremental builds on CI. The idea is to dynamically share build artifacts across the pipeline builds, copying only the artifacts that are necessary for Xcode not to compile the frameworks/libraries that don't need to be compiled. To do that, you need to know how Xcode manages the derived data directory, how the build system turns the input <em>(build settings, build phases, source files, and resources)</em> into intermediate and final artifacts. Does Xcode use the file update date to determine what needs to be built? Is it necessary to copy the intermediate files if there are some final ones? Well, we don't know. With Bazel and Buck, not only they know about what output is generated from some given input, but also you know.</p>
<p>Another rigid component of Xcode is its projects. When a company has a few Xcode projects to maintain, it's important to be consistent and share as much as possible across all the projects. It makes maintenance easier. Someone might argue that sharing is possible using .xcconfig files, and it's true, but partially. .xcconfig files allow you to reuse build settings, but if you want to reuse build phases, targets or schemes structure, then you cannot. We have a few modules at Shopify that are shared across all the company iOS applications. They have similar build settings, same targets and schemes structure, but they are not sharing anything. If we want to update the deployment target or add a new target in each of them, we have to go one by one updating it manually. While this is something we can do when there are 4/5 modules, it becomes a pain in the ass when there are 10 or 20. It's easy to forget something, and suddenly the project doesn't compile. <a rel="external" href="https://github.com/yonaskolb/XcodeGen">XcodeGen</a> is an open source tool that helps you overcome this issue. Projects are defined in yaml, so you can use all reusing options that the yaml format offers. It also provides a more flexible way to define and share your build settings. I've used it to describe a <a rel="external" href="https://github.com/pepicrft/xcode-modular-apps-workshop">modular app</a> that I'll build in the workshop that I'm giving at <a rel="external" href="http://romobos.com/">Mobos</a>, and I was able to have a repository with no Xcode project in it, and sharing configuration across all modules that are part of the project. Wouldn't it be great if Apple followed a similar approach and provided something similar? Imagine something like the SPM <code>Package.swift</code> but for apps projects, <code>Project.swift</code>.</p>
<p>As I said, I'm optimistic. Apple open sourced Swift, and is open sourcing components of the Xcode and its build system. Not sure if having it open source will make it more flexible, but at least there will be an open space where we'll be able to participate in discussions about the future of the build system. Software engineers will be able to bring ideas to the Xcode build system, and other build systems will be able to take some from Apple's one.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>This app could not be installed at this time</title>
      <link>https://pepicrft.me/blog/watchapp-and-xcode-nightmare/</link>
      <guid>https://pepicrft.me/blog/watchapp-and-xcode-nightmare/</guid>
      <pubDate>Sat, 20 Jan 2018 12:00:00 +0000</pubDate>
      <description>Because sometimes Xcode cannot install your apps, and you have to figure out why.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've spent a whole Sunday trying to get an Xcode project running. The project contains an iOS and watchOS app sharing code using frameworks. Moreover, I've automated the generation of the Xcode projects using <a rel="external" href="https://github.com/yonaskolb/xcodegen">XcodeGen</a>. Everything seemed to be fine; I was able to generate the projects, compile the modules individually, run their tests, but at some point, I got stuck at something that after a few hours, can't understand. Whenever I tried to run the iOS app or the watchOS application I got the error that you can see in the screenshot below:</p>
<p><img src="https://pepicrft.me/blog/watchapp-and-xcode-nightmare/__GHOST_URL__/images/posts/app-could-not-be-installed.png" alt="Xcode error saying that the app could not be installed this time" /></p>
<p><strong>This app could not be installed at this time.</strong> At first I thought my compiler became time sensitive, but after a while, nothing changed. Xcode kept complaining about the same thing. The second thing that I tried was creating the project manually. I dragged and drop a bunch of stuff, update the project build settings, and to my surprise, the same thing happened 🙄. I've never had a good experience working on watchOS applications using Xcode. I haven't done it for a while but it seems that there hasn't been much improvement. I think this is so far the second most frustrating issues that I've got so far from Xcode. The first one is of course, <strong>Segmentation Fault</strong>. I love that one, especially when you have to debug it, and you end up reverting all the code that you recently added.</p>
<p>I try to be optimistic but lately, working using Apple's tools have been very frustrating. I feel they are investing a lot of effort in pushing Swift but that they are forgetting about some elemental things like the editor that most of the people use to develop in Swift.</p>
<p>Anyways! I was building an app that I plan to build in a workshop that I'm giving at <a rel="external" href="http://romobos.com/">Romobos</a>. The preparation of the workshop was going very smoothly until I came across this nice Xcode gift. I haven't been able to understand the issue so far, and I think I'll end up building a today extension, rather than a watchOS application. If you are interested in the project and would like to try it by yourself you can check out this git repository <code>https://github.com/pepicrft/xcode-modular-apps-workshop</code> and go to the tag <code>0.6.0</code>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Random thoughts a Friday night in Ottawa</title>
      <link>https://pepicrft.me/blog/random-reflection/</link>
      <guid>https://pepicrft.me/blog/random-reflection/</guid>
      <pubDate>Fri, 19 Jan 2018 12:00:00 +0000</pubDate>
      <description>I sat down after work and thought about some things that have been in my mind for some time. I wrote them in this blog post that if I have to summarize it, it talks about minimalism, open source, egno, and career paths.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It's January 19th, and I'm right now in Canada. It's been a fascinating beginning of the year, starting with my onboarding at Shopify. I had forgotten how it feels to start a new job, with a lot of tools and processes to learn, and a lot of people to meet. It requires a lot of energy, and I tend to overwhelm, but I'm trying to take it easy this time, step by step. What excites me the most about joining this new company is that I'll be able to dive deeper into how to make developers productive working on mobile codebases. I've been learning a lot about it in the last couple of years, and I love building tools to make developers' life easier. Shopify has a team for that I'm glad to be part of it. I'm excited about all the stuff that I'll have the opportunity to learn here.</p>
<p>This post is somehow unique. I couldn't come up with a name that summarizes what I'm going to write about <em>(because I don't know)</em>, but I just wanted to write down some thoughts which have been in my head for quite some time. Do you know these moments in life when you ask yourself so many questions, and they don't allow you to see any light at all? That's sort of how I'm feeling. Professionally speaking, I've had a very intense career since I became a developer. I taught myself most of the stuff that I know nowadays. That requires being very active, reading a lot of books and tutorials, using the social networks very actively, especially Twitter where you can get the most recent tech news, getting involved in open source projects and working on your own. Sometimes I was like a horse, I was moving fast, but I didn't have time to enjoy the journey genuinely. That moment when you can sit back, relax, and celebrate your achievements. My achievements quickly faded away because I was already thinking about the next step in the journey. I think this goes pretty much with my personality, and the people that know me well will most likely agree on that. I'm working a lot to slow down my life, but I'm finding it very hard. A side of me says that I should stop it because otherwise, I'll run into troubles soon, the other side tells me that I should continue because that's the only way to be successful in life. It's like having a devil and an angel on your shoulders pushing you to opposite directions. That's my daily dilemma.</p>
<p>I'd love to slow down, and have more focus in my life. Moving fast with no focus brings me stress and anxiety. It makes me feel bad about myself and with the people around me. I don't want that. I want to feel good and enjoy my work and the people around me. It's hard, isn't it? I don't know if you have ever been in that situation, but I struggle to make another version of me. As a consequence, things that I used to like, I don't enjoy them anymore. I used to run a lot, but a lot. It was my mindfulness moment of the day. When I ran, I didn't think about anything; I focused on my breathing, my steps, the things around me. Nowadays, when I go out for running, I keep thinking about my everyday struggles. They are with me all the day long. It's so exhausting that I don't like running anymore. It's not running; it's me. I go to the cinema, I spend some time with the family, and the horse Pedro continues looking straight and moving. I don't know another way to describe it better, but I think the horse metaphor is very representative.</p>
<p>There are a lot of great resources out there with people talking about similar struggles. We live in a very competitive environment, with the insane amount of information being thrown at us every day. We sometimes push us so hard, because we think that the only thing we need in our life is success. We want to have the best job, a high recognition, and be the expert on some given areas. We are surrounded with such positiveness, that we demand us more than what we should. And to me, it's not surprising that such thing happens. You , and you find tons of articles titled like "X ways to be successful in Y". You open Instagram or Twitter, and everyone is so happy and has a great life that they become a source of inspiration for you. You lose personality; you want to meditate because person X said that meditation is what makes him/her a happy person, you want the new thing Y because you saw on Instagram a lot of people are enjoying that thing. I've been there, I'm still there, and sometimes I have zero time to listen myself, to hear my feelings, to reflect on my thoughts, to understand what motivates me or what doesn't. I just let myself be influenced by the competitive and overwhelming environment. <strong>Isn't it sad?</strong> I lost some personality.</p>
<p>One thing that I'm currently doing to help me get some focus is decluttering my life. I'm getting rid of all the things that I don't need, and which don't add anything other than noise. There's a buzzword for that, <a rel="external" href="https://www.theminimalists.com/minimalism/">Minimalism</a>, but it's not something that has been recently invented. People were minimalists in the past. They had all they needed to have a happy and quiet life. Before the capitalism and the Internet revolution people cared more about each other and themselves <em>(something that we are losing more and more nowadays)</em>. Anyways, that's another interesting discussion topic. Simplifying one's life is not only about materialistic elements but also non-materialistic ones. I'm getting rid of the gadgets that I don't need in my life, replacing the expensive ones with a cheaper version <em>(I'm replacing my iPhone with a cheap Xiaomi more than enough for my needs)</em>. Closing the accounts that I don't use, leaving Slack organizations in which I don't participate, reducing the tools that I use, leaving only the ones that are indispensable. I shut down my Instagram account and cleaned up my Facebook's one. I'd love to close it as well, but I find the events section very useful, especially when you live abroad. I have a list of all clothes that I'm going to give away and stuff that I'm going to sell in secondhand Facebook groups.</p>
<p>Getting rid of the stuff that I don't need is making me feel more relaxed. I don't have to think about these things anymore; I can open the laptop and have just a few apps that I need, and not a bunch of apps with badges trying to catch my attention. I have more time to read, to learn languages, to learn new technologies, without any distraction at all. It feels great, and overall, I have time to think about myself. Maybe that's what made me sit down and start writing this post today. Ideally, I'd like my life to be a continuous technology detox, where I can control when it's time to think about technology. I want to read more, and I don't mean tweets or Medium articles, I mean proper books. Wake up, and with a relaxed mind, start reading and don't feel that the time is passing. Read pages without thinking about any notification coming in, or meetings in the calendar waiting for your attention. I think the last time I had that feeling was in high school, where there was no phone, nor distractions to think about. Don't you miss them as well?</p>
<p>Minimalism is giving me time and space to think selfishly about me, about this horse that has been moving fast for some months/years. There's something that is coming up every time that I stop to reflect on myself, and it's the impact the work I'm doing has. Open sourcing used to be my mean to help people giving them some piece of software that they could use to build software with good intentions. It felt good helping other developers, talking to them and iterating the projects, but at some point, I came across the reality. It's a competitive industry, where not many people want to share efforts towards making useful open source tools, but instead, individually work on their own. I found out that communities in open source are rarely communities, they are just a bunch of people working with the same programming language, reading the same articles, and watching the same videos, but with different interests in the end. It was for me hard to understand why there was such a polemic in the <a rel="external" href="https://cocoapods.org">CocoaPods</a> team when there was another dependency management tool coming out, <a rel="external" href="https://github.com/carthage">Carthage</a>. I understand their position much better now. That's what I meant with communities formed by individuals with different interests, rather than shared interests. That disappointed me a lot. For me, one of the charming things about open source software is sharing efforts with other people and working together towards the same goals. In the competitive society where we live nowadays, it's becoming impossible, and I can't believe I'd say this but, I'm not as motivated as I was before working on open source projects.</p>
<p>I've also been there myself. I've mistakenly built projects thinking own my interests. Core Data wrappers, Xcode project parsers. I've contributed towards making everyone more confused and adding some fragmentation. I feel terrible about it. Interests in open source communities result in fragmentation, and we see it everywhere: <a rel="external" href="https://buckbuild.com/">Buck</a> &amp; <a rel="external" href="https://bazel.build/">Bazel</a>, <a rel="external" href="https://yarnpkg.com/en/">Yarn</a> &amp; <a rel="external" href="https://www.npmjs.com/">npm</a>. It's been a tremendous recent lesson for me.</p>
<p>Another thing that I had some time to think about is the <strong>ego</strong>. I started writing about it on this blog, but I stopped it. I instead reflected on it. As I mentioned, I was very active working on open source projects, writing articles, sharing stuff on Twitter. People used my projects, replied to my posts, asked me questions, and I felt that I was important. That wasn't me, that was the ego speaking in my name. When my ego felt important, it wanted to feel more important, do more, and publish more, and be more active. That's a shit-ton of energy for the sake of being recognized. Has it ever happened to you? Open source can be a good candy for your ego, because you expose your project and the person who worked on it, publicly to be used and liked. I knew the ego was speaking in my name because something that didn't use to be vital for me, like the stars on GitHub, or projects using it, started to be more important. When I decided to work on a new open source project, I started working on the facade, rather than the core. I managed to control it, and I'm working hard to change my mindset. Rather than publishing things, just with the mere intention of being used, or liked, because that increases my dopamine levels, I'd do it anonymously and participate less in social discussions.</p>
<p>We were told during the Shopify onboarding that sometimes we have to <strong>unlearn things to learn new things</strong>. That resonated with me and I felt that I have to unlearn a few things to progress in my career <em>(or at least in the way that I want to)</em>:</p>
<ul>
<li>I want to unlearn my individual perception of open source projects and work towards having a collective one. - I want to unlearn all the stuff fed my ego, and learn how to work towards having great impact anonymously. - I want to unlearn the importance of being liked and learn the significance of the work that I do.</li>
</ul>
<p>And last but not least, there's another thought that has been on my mind for quite a long time. I've been doing Swift/Objective-C for a few years, and even though Swift is open source, I'm not as motivated as I used to be with it. I feel like its scope is limited to an operating system and that it's constrained to Apple interests. When I look at other languages such as Kotlin, Ruby, Go, or Javascript I feel that they are more community driven and that there are fewer interests behind them. People experiment with them and try to push them to their limits, like Javascript on mobile apps with React Native, or on Desktop with Electron. Kotlin being transpiled to Javascript, or compiled to run on iOS devices. I see a lot of criticism on the iOS/macOS ecosystem when intruder languages are making their way into such a closed ecosystem that Apple provides. To be honest, that makes me feel sad. Rather than opening the ecosystem, and allowing languages such os Kotlin, or Javascript, or opening APIs so that other companies can provide their IDE they prefer to keep things private.</p>
<p>I'm considering a significant turn in my career, and I'll most likely focus on <strong>Javascript/Ruby</strong>. Ruby because it's a very mature language, with a mature ecosystem and community, and it's the primary programming language at Shopify. It's an excellent opportunity for me to learn from the people that I work with, and work on projects that are not tied to the Apple ecosystem but can be used in many other operating systems. Javascript because of similar reasons, and because I'd love to do some web with frameworks such as <a rel="external" href="https://reactjs.org/">React</a>, and it can even be used to build mobile apps. In the end, we are all software engineers and focusing on such closed environment narrows our points of view on the problems around us. I'd like to break that barrier and look at those issues with a broader and more open angle.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Wrapping up 2017</title>
      <link>https://pepicrft.me/blog/wrapping-up-2017/</link>
      <guid>https://pepicrft.me/blog/wrapping-up-2017/</guid>
      <pubDate>Mon, 25 Dec 2017 12:00:00 +0000</pubDate>
      <description>A retrospective on what 2017 has been</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>2017 is almost over. What a year! Like I did last year I'd like to reflect on what 2017 has been for me and wrote down the highlights in this post. I don't have any structure for it other than just a list of things that come up to my mind while I'm writing it:</p>
<ul>
<li><strong>Budapest 🏰</strong> - I lived in this city from January to July. María José, my girlfriend, was living and working there and I asked the company for working remotely. They allowed me to do so and I moved there. Budapest is a lovely city with a wonderful tech ecosystem growing up. I got to make some friends in the city and even organized a Meetup for runners. I liked from Hungary that people preserve values that have been lost in other countries like appreciation and gratitude. Eventually, Maria José found a job in Berlin, and we decided to move to Berlin. I had fallen in love with Berlin, and I missed it so much that I found it hard to get used to Budapest.</li>
<li><strong>ADDC 🎤</strong> - It was the first time in my life that I organized a conference. ADDC took place in Barcelona, and we brought app designers and developers from all over the world to learn and connect. I learned that organizing a conference is not as easy as it might seem and it requires a lot of energy, coordination, and a good team. The first edition of ADDC was very successful and we are very excited to work on the second edition of the conference that will take place in July. We got a lot of feedback that we'll use to make ADDC better. You can check out the conference <a rel="external" href="https://addconf.com">website</a>.</li>
<li><strong>German 🇩🇪</strong> - My German got terribly stuck. Since I moved to Budapest, I didn't put much effort on it. When we moved back, I realized that I should continue learning it and invest more energy. Maria José joined in November a company, <a rel="external" href="https://chatterbug.com">Chatterbug</a> which offers an effective method to learn languages <em>(she is working on the Spanish curriculum)</em>. I signed up , and I have gained some discipline taking lessons almost every day. I hope I have good news about it in next year's wrapping up post.</li>
<li><strong>Social Networks 👨‍👨‍👦‍👦</strong> - I learned how to use social networks more thoughtfully. I was somehow addicted to them and most of my time was spent scrolling through their infinite timelines or stories list. I don't like the social interactions that happen on social networks and decided to invest that time in something more valuable to me, like reading or meeting people outside the Internet. It was tough to do it because sometimes I felt I wanted to check my social profiles but by disabling push notifications, uninstalling the apps, and using extensions on Google Chrome, like <a rel="external" href="https://chrome.google.com/webstore/detail/news-feed-eradicator-for/fjcldmjmjhkklehbacihaiopjklihlgg?hl=en">News Feed Eradicator</a> I got a lot of discipline. Although I spend some time on them nowadays, it's nothing compared to the time I spent one year ago.</li>
<li><strong>Twitter 🐦</strong> - I changed the way I use Twitter. Rather than keeping it open to see what's going on at any time and participate in any active discussions, I only check the timeline at the end of the day. When I find something interesting to read, I use Instapaper to read it later. I tweet much less and try to clean up my tweets from time to time. When there's any hot topic, everyone is talking about I try not open Twitter. I'm not used to processing so much condensed information. Trying to keep up with everything makes me feel anxious.</li>
<li><strong>From the music 🎵 to the e-commerce 🛒</strong> - As I announced a few days ago, I moved on from SoundCloud, and I will be joining Shopify in January. I grew a lot as an engineer during my time at SoundCloud. It's an fantastic company with a great culture and a lot of talent to learn from. I became very interested in scalability and contributed with modularizing the codebase to make developers more productive working on new features. I wrote some guidelines on <a rel="external" href="https://github.com/microfeatures/guidelines">this repository</a> and gave a talk at <a rel="external" href="https://www.2017.mobiconf.org/">Mobiconf</a> about how we built features at SoundCloud. This passion for scalability led me to Shopify and its Developer Acceleration team, where I'll be working on tools and processes to scale the company's mobile apps. Can't wait for it!</li>
<li><strong>Open source ✏️</strong> - I've been a big fan of the open source philosophy since I started my career. I like sharing what I learn with others and work with other developers to build tools that can be leveraged to create apps. One of the open source projects I'm most proud of is <a rel="external" href="https://github.com/xcodeswift/xcproj">xcproj</a>, a Swift library to read and update Xcode projects. xcproj became part of an open source organization, <a rel="external" href="https://github.com/xcodeswift/xcproj">xcode.swift</a> which I'm part of and where I got to know amazing people with whom I share my daily struggles working with Xcode. We all help each other and build open source tools in Swift. In 2018 I'll continue contributing to xcode.swift, helping developers that want to use or participate in any of the open source tools that we are building.</li>
<li><strong>Homo Deus 🐒</strong> - It's my favorite book of 2017. If you haven't read it yet, I'd recommend it to you. Before reading Homo Deus I read another book by the same author, Sapiens. It was fascinating to know how our history influenced how humans are nowadays. Homo Deus is the continuation of that book and talks about how humans are using technology towards becoming superhumans.</li>
<li><strong>React ⭐️</strong> - I'm not married to any technology or programming language so when there's something that I find interesting to learn I just read about it. By understanding other platforms, technologies or languages, you gain different points of view when you need to solve problems. Moreover, you know the good and bad things of each of them and have enough grounds to participate in discussions. React was one of these technologies that I wanted to learn, and I ended up learning the basics. Together with React I also learned a bit about Typescript <em>(I missed not having types)</em>.</li>
<li><strong>Running 🏃</strong> - I used to run more a few years, ago and this year I miserably failed at trying to get in shape again. I didn't run as much as I wanted and I got some extra kilos as a result. I participated in Berlin's marathon, but it was the hardest one for me since I hadn't trained enough.</li>
<li><strong>WWDC and my first time in the US 🇺🇸</strong> - In June I visited USA for the first time. I attended Apple Developers event, WWDC in San José. I took the opportunity to visit the so famous San Francisco, took a photo with the bridge in the background, visited Facebook's office and saw UFO-alike Apple's campus. What's more, we drove to Las Vegas and visited the Grand Canyon on a helicopter. The Grand Canyon's views from the helicopter were stunning!</li>
<li><strong>Coffee ☕️</strong> - I reduced the amount of coffee intake that I used to drink. It was tough because I went from drinking around 5 cups every day to not drink any. The first two days I had extreme headaches, but after it, I had much better and deeper sleep.</li>
<li><strong>Other 😜</strong> - I learned how to think slower and be less hot-headed. - I learned how to give a fuck about what people say about me. - I lost the fear to share my opinion even if it goes against others'.</li>
</ul>
<h2 id="goals-for-2018">Goals for 2018</h2>
<ul>
<li>Learn German and try to get to a B1 level. - Lose the extra kilos that I gained and commit to a running routine. - Read a bit more than what I did this year <em>(preferably non-techie books)</em>. - Learn Kotlin and how it can be used to build iOS apps. - Organize the second edition of ADDC. - Visit a new country <em>(Iceland and Japan are on my mind)</em>. - Write an open book.</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Linting your Xcode projects with xclint</title>
      <link>https://pepicrft.me/blog/xclint/</link>
      <guid>https://pepicrft.me/blog/xclint/</guid>
      <pubDate>Thu, 02 Nov 2017 12:00:00 +0000</pubDate>
      <description>In this post I talk about a tool I&#x27;ve been working on that allows you to check the state of your Xcode projects, finding missing references and duplicated files.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>In this post I'll talk about a tool that I have recently released <a rel="external" href="https://github.com/xcodeswift/xclint">xclint</a>, which validates the structure of your Xcode projects, offering insightful warnings about things that might be wrong in the project structure.</p>
<p>Xcode projects are hard to work with, especially when there is a team behind using git. It's straightforward to mess things up and end up with a project, which Xcode might be able to read and compile, but that internally is not in a good state:</p>
<ul>
<li>There are entries that are duplicated <em>(a common issue when solving git conflicts in the project file)</em>. - There are elements that refer to others that don't exist anymore. - There are attributes that are missing. - Some file references point to files that don't exist anymore.</li>
</ul>
<p>Keeping Xcode projects in a healthy state is very important and unfortunately, there was no tool that helped you validate that. <a rel="external" href="https://cocoapods.org">CocoaPods</a> for instance throws a warning when you do <code>pod install</code>, if there are multiple elements with the same identifier.</p>
<p>Since <a rel="external" href="https://github.com/xcodeswift/xcproj">xcproj</a>, opened an API to read any Xcode project, I decided to leverage it to build a command line tool, <a rel="external" href="https://github.com/xcodeswift/xclint">xclint</a> that we could use to validate the state of our Xcode projects.</p>
<h3 id="install-usage">Install &amp; Usage</h3>
<p>You can install the tool using Homebrew:</p>
<pre><code>brew tap xcodeswift/xclint git@github.com:xcodeswift/xclint.git
brew install xclint
</code></pre>
<p>Or run it using <a rel="external" href="https://github.com/yonaskolb/mint">Mint 🌱</a>:</p>
<pre><code>mint install xcodeswift/xclint
</code></pre>
<p>Its usage is very simple, you just need to pass one parameter, which is the Xcode project that you want to validate:</p>
<pre><code>xclint MyProject.xcodeproj
</code></pre>
<p>The screenshot below shows an example of the tool output when there are validation errors:</p>
<p><img src="https://pepicrft.me/blog/xclint/__GHOST_URL__/images/posts/xclint.png" alt="xclint output when there are warnings" /></p>
<h3 id="what-s-next">What's next</h3>
<p>The tool currently supports validation of missing references, and attributes that there are things that we'd like to support in future editions:</p>
<ul>
<li>Detect multiple elements with the same reference. - Spot files that are referred from the project that are missing.</li>
</ul>
<p>Moreover, we plan to support CocoaPods, so that you could install the tool using CocoaPods and use the binary from a project build phase.</p>
<h3 id="feedback">Feedback</h3>
<p>It's the first version of the tool, <code>0.1.0</code> so it's very likely that you encounter some errors. If so, don't hesitate to open issues on GitHub with all sort of issues that you found using the tool. Moreover, if you have any idea of things that we could validate or features that we could add to the tool, feel free to open issues or pull requests with your proposals. You're very welcome!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Consistent vs convenient</title>
      <link>https://pepicrft.me/blog/consistent-vs-convenient/</link>
      <guid>https://pepicrft.me/blog/consistent-vs-convenient/</guid>
      <pubDate>Mon, 30 Oct 2017 12:00:00 +0000</pubDate>
      <description>I analyze in this post why some decisions that we make in our projects might turn into bad viruses that spread all over the code base.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Have you ever used programming paradigms like <a rel="external" href="https://en.wikipedia.org/wiki/Functional_programming">functional</a> or <a rel="external" href="https://en.wikipedia.org/wiki/Functional_reactive_programming">reactive programming</a>? Have you tried the revolutionary approach to model how the state is contained and flows in your app, <a rel="external" href="http://redux.js.org/">Redux</a>? I find it great that companies and open source organizations try to solve issues that we developers, have to face on a daily basis by introducing new concepts in the industry. We'll see more of those coming, and what it's cool nowadays won't be in a matter of months/years. Do you think reactive programming is the coolest thing ever? Let's see in a few years if it was the coolest thing ever, or there was still space for even cooler alternatives.</p>
<p>If there's something I've learned in my short career as a software engineer is that there's no perfect paradigm, pattern, or architecture and that it all depends on our problems or particular needs. Something that is convenient for other projects and teams might not be convenient for us. <em>Have you worked on a code base where someone introduced a new concept/library, like a Reactive programming library, and you ended up very concerned when that thing spread all over the codebase?</em> There are libraries that we introduce and that are isolated, we can easily abstract them with an interface, but there are others that as soon as we use them, they spread very quickly across the codebase. They are like viruses, and as soon as you open them the door, they have everything they need to spread around.</p>
<blockquote>
<p>I have nothing against the paradigms mentioned above. I think each paradigm that changes the way we code should be used consciously, and we should regularly evaluate if the choice we made works out for us and that is not becoming a burden that we need to carry on.</p>
</blockquote>
<p>I wondered why those elements end up behaving like viruses. There must be something, in the team or the project, that helps them spread that fast. I think the reason why that happens is that it brings up a dilemma to developers when they need to work with code that already includes the virus. <strong>They need to decide between choosing the consistent solution, or the convenient one</strong>, and most of the times we lean towards the consistent solution. You'll understand this better with a couple of examples.</p>
<hr />
<h5 id="example-1-reactive-programming">Example 1 - Reactive programming</h5>
<p>Let's say there's a component A, whose interface is mostly implemented with reactive observables <em>(even if methods are just simple getters that return values synchronously)</em>. You need to extend that interface to just return a property whose value you need from outside. <em>Will you expose an observable, or just a getter?</em> For your particular use-case it may make more sense going with just a simple getter since you don't need any reactive magic like scheduling in threads or doing a binding. But you'll most likely be influenced by the existing API and do it with observables, since you want to be consistent with the code that is already there. Little by little, what was an isolated interface, is powerful enough to force the usage of observables far beyond the closest element.</p>
<h5 id="example-2-redux-store">Example 2 - Redux store</h5>
<p>Redux was introduced in the codebase, and we already moved a lot of states to the store. The session of the user, the state of the navigation, the settings, the search results that will be presented in the search view. We need to work on a new view whose simple state we need to persist in memory. Again, it might be more convenient to do it in a view model next to the view, but since we already have some views that do it in Redux, we do the same, and we add some complexity to the store state.</p>
<hr />
<p>These are two examples to illustrate what I'm talking about, but you can think of any other element that you can introduce in a codebase: <em>VIPER, declarative programming, MVVM, Realm</em>. When we developers, have to choose between consistency and convenience we usually lean toward consistency. By doing that we push new element beyond its scope and we turn it into a burden that the team has to carry on. Usually, when we realize that the burden is a heavy burden, it's too late to give steps back.</p>
<p>I'm a bit skeptical when it comes to introducing such elements in codebases where more people are working on. This involves being able to control the hype those new technologies, libraries, paradigms come with. In my experience, the closest you are to the language and the system frameworks, the more familiar your team is with the codebase. They feel more confident when they need to make changes when they need to propose improvements, and they don't have to go through any cumbersome dilemma that the codebase exposes them to. If you are not sure whether a new thing could potentially be a <em>"virus"</em> I recommend you to talk to other teams that have experience using it. Talk to as many teams as possible before making the decision because, because you won't find such information in documentation websites, READMEs, or even tech-talks.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Modular Xcode projects</title>
      <link>https://pepicrft.me/blog/modular-xcode-projects/</link>
      <guid>https://pepicrft.me/blog/modular-xcode-projects/</guid>
      <pubDate>Fri, 29 Sep 2017 12:00:00 +0000</pubDate>
      <description>This post presents some elementary concepts of how Xcode projects are structured, and introduces an structural approach to build modular Xcode apps.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Building modular projects with Xcode requires a good understanding of the project structure and its foundational concepts. The project structure is something that we don't usually care much about unless we start growing the project by adding more dependencies. Even in that case, most of the projects use <a rel="external" href="https://cocoapods.org">CocoaPods</a> that does the setup for us, or <a rel="external" href="https://github.com/carthage">Carthage</a> that doesn't do the setup, but makes it as easy as just adding a couple of changes in your project build phases. When the configuration becomes more complicated, it's very likely that we get confused because we didn't fully grasp all the elements that are involved in Xcode projects. I usually get asked questions like:</p>
<ul>
<li>Can I have Carthage, Cocoapods and my dependencies? - I added my dependency but when the simulator opens the app crashes. - Why do I have to embed the frameworks in some targets only? - Should my framework be static, or dynamic?</li>
</ul>
<p>In this blog post, I'd like to guide you through the Xcode projects elements, and the principles to modularize your setup by leveraging them. I hope that the next time you face any of those issues, you don't need to spend a lot of time on Stack Overflow trying to find a non-random response.</p>
<h1 id="elements-hammer-pick">Elements ⚒</h1>
<h2 id="target">Target</h2>
<p>Projects are made of smaller units called targets. Targets include the necessary configuration to build platform products such as frameworks, libraries, apps, testing bundles, extensions. You can see all the available types of target <a rel="external" href="https://github.com/xcodeswift/xcproj/blob/master/Sources/xcproj/PBXProductType.swift">here</a>. Targets can depend on each other. When a target depends on another, that target is built first to use its product from the dependent target. The target configuration is defined in the following places:</p>
<ul>
<li><strong>Info.plist file:</strong> This file contains product specific settings like the version, the name of the app or the type of app. You can read more about this file <a rel="external" href="https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Introduction/Introduction.html">here</a> - <strong>Entitlements:</strong> It specifies the application capabilities. If the capabilities in the entitlement file mismatch the ones in the developer portal, the signing process fails. - <strong>Build settings:</strong> As its name says, those are settings necessary to build the target. Build settings can be defined in the target itself, or in a <code>xcconfig</code> file. The configuration of a target is inherited being the first parent the config file <em>(if any)</em>, then the target configuration, and in the last place the project configuration. - <strong>Build phases:</strong> The build pipeline is defined using build phases. When a target gets created, it contains the default build phases <em>(building source code, copying resources)</em> but you can add as much as you want. As an example, there’s a shell script phase that allows you to do some scripting as part of the build process. Those scripts have access to the build variables that are exposed from Xcode.</li>
</ul>
<p>Due to the composability and reusability of <code>.xcconfig</code> files, it's very recommended that you define the build settings in those files. Changes in the target configuration such as changes in the build settings, or build phases are reflected in the <code>.pbxproj</code> file, a custom-plist representation of your project that is a common source of conflicts when we work with Git in our projects. The easiest way to update the configuration in the <code>pbxproj</code> file is using Xcode, which knows how to read and write changes to those files. If for any reason, you were interested in updating those files without using Xcode, you could use tools like Xcodeproj for <a rel="external" href="https://github.com/cocoapods/xcodeproj">Ruby</a> or <a rel="external" href="https://github.com/swift-xcode/xcodeproj">Swift</a></p>
<blockquote>
<p>I hope that Apple makes the definition of the projects more accessible by either using a different definition syntax or opening APIs. This lack of accessibility led me to write a tool like <a rel="external" href="https://github.com/swift-xcode/xcodeproj">xcodeproj</a> to read and update your Xcode projects in Swift.</p>
</blockquote>
<p>The output of building the targets are either <strong>bundles</strong> such as apps, extensions, or tests that are loaded on the platform they were built for, or <strong>intermediate products</strong> such as libraries or frameworks that encapsulate code and resources to be used for other targets. The products that are generated as a result of building a target can be seen in the group <code>Products</code> of your target. A red color in these files references indicates that there's no product, most likely because you haven't built the target before.</p>
<h2 id="scheme">Scheme</h2>
<p>Another element of Xcode projects is schemes. A project can have multiple of them, and they can be shared and included as part of the project to be used by the people working on the project. Schemes specify the configuration for each of the available actions in Xcode: <strong>run, test, profile, analyze and archive</strong>. We can specify which targets are built, in which order, and for which actions. We can also define the tests that will be run when we test that scheme and the configuration that is used for each of the actions.</p>
<p>It's worth mentioning a few things about the build config of the scheme. When we specify which targets are built for which action, we don't need to include the dependencies of our target in the following two cases:</p>
<ul>
<li>If the dependency is part of the same project and is already defined in the <code>Target dependencies</code> build phases. - <code>Find implicit dependencies</code> is enabled.</li>
</ul>
<p>By enabling the second flag, the build process should identify the dependencies of the targets that you are building and build them first. Moreover, if you enable <code>Parallelize build</code>, you'll save some time since targets that don't depend on each other will be built in parallel.</p>
<p>A bad build config might eventually lead to errors building your targets such as <code>Framework XXX not found</code>. If you ever encounter one of those, check if all the dependencies of your target are getting built when you build the scheme.</p>
<p>The scheme definition is stored in a xml file under <code>Project.xcodeproj/xcshareddata/xcodeproj.xcscheme</code>. In this case the format is plain xml and can be easily modified with any xml editor.</p>
<h2 id="workspace">Workspace</h2>
<p>Multiple projects can be grouped in a workspace. When projects are added to a workspace:</p>
<ul>
<li>Their schemes are listed in the workspace list of schemes. - Projects can depend on each other as we'll see later.</li>
</ul>
<p>As with schemes, workspaces are plain xml files that can be easily modified.</p>
<p><img src="https://pepicrft.me/blog/modular-xcode-projects/__GHOST_URL__/images/posts/modular-workspace.png" alt="" /></p>
<h1 id="dependencies-seedling">Dependencies 🌱</h1>
<p>Targets can have dependencies. Dependencies are frameworks or libraries that our targets link against, and that include source code and resources to be shared with our target. Those dependencies can be linked static or dynamically:</p>
<ul>
<li><strong>Static linking:</strong> - The linking happens when the app gets compiled. - The object file code from the library gets included into the application binary <em>(larger application binary size)</em>. - Libraries use the file extension ".a", which comes from the (ar)chive file type. - If the same library gets linked more than once, the compiler fails because of duplicated symbols. - <strong>Dynamic linking:</strong> - Modules are loaded at launch or runtime of an application. - Application and extension targets can share the same dynamic library <em>(only copied once)</em>.</li>
</ul>
<p>The difference between a framework and a library <em>(linked static or dynamically)</em> is that frameworks can contain multiple versions in the same bundle, and also additional assets that can be used by the code.</p>
<blockquote>
<p>A library is a <em>.a</em> file which comes from the (ar)chive file type. A single archive file can only support a single architecture. If more than one architecture needs to be packaged, they can be bundled in a <strong>fat Mach-O binary</strong>, a simple container format that can house multiple files of different architectures. If we would like to generate a fat Mach-O binary, modify an existing one, or extract a library based on a specific architecture, we can use a command line tool called <code>lipo</code>.</p>
</blockquote>
<p>You can read more about frameworks/libraries and static/dynamic on the <a rel="external" href="https://pewpewthespells.com/blog/static_and_dynamic_libraries.html">following link</a>.</p>
<p><img src="https://pepicrft.me/blog/modular-xcode-projects/__GHOST_URL__/images/posts/modular-linking.png" alt="" /></p>
<p>Applications can depend on <strong>precompiled</strong> and <strong>not-compiled</strong> dependencies.</p>
<h3 id="precompiled-dependencies">Precompiled dependencies</h3>
<p><a rel="external" href="https://github.com/carthage">Carthage</a> is a good example of this kind of dependencies. Some SDKs are also distributed as compiled dependencies, like <a rel="external" href="https://github.com/CocoaPods/Specs/blob/master/Specs/0/3/5/Firebase/4.2.0/Firebase.podspec.json#L23">Firebase</a>. When precompiled dependencies are libraries, they include the <code>.a</code> library and the public headers that represent the public interface of the library. When they are frameworks, they are distributed as a <code>.framework</code> that contains the library and resources.</p>
<p>When our app depends on precompiled dependencies it's important that the dependency is built for the architecture we are building our app for. If any of the architectures is missing, we'll get compilation errors trying to compile our apps. As we'll see later, Carthage uses lipo to generate frameworks that contain the necessary architectures for the simulator and the device, stripping the ones that are not necessary based on the build configuration.</p>
<h3 id="non-compiled-dependencies">Non-compiled dependencies</h3>
<p><a rel="external" href="https://cocoapods.org">CocoaPods</a> is a good example here. Dependencies are defined in targets that compile the frameworks/libraries that we link against. There are multiple ways to specify in Xcode that our target depends on other target's products:</p>
<ul>
<li><strong>If the targets are in the same project:</strong> You can define the dependency in the build phase <em>Target dependencies</em>. Xcode will automatically build that dependency first to use its products for the target that we are building. - <strong>If the targets are in different projects:</strong> We can define the dependencies between the targets using <em>Schemes</em>. In the scheme Build section, we can define the targets that are built and in which order <em>(based on the dependencies between them)</em>. Xcode is able to guess the dependencies if you enable the flag <em>Find implicit dependencies</em>. It's able to make a guess, by understanding what the target that you are building depends on, and who builds that product. If there is anything missconfiguration in the scheme, you might get an error like <code>xxxx.framework not found</code>. You might also get that error if you have circular dependencies between the frameworks that cannot be resolved.</li>
</ul>
<blockquote>
<p><strong>A note on dependencies and configurations:</strong> The configurations of all the dependencies should match. If you are building your app with the Alpha configuration and any of the dependencies doesn't have that configuration, the compilation will fail with a framework not found error. When that happens, Xcode doesn't compile the framework but doesn't throw any error.</p>
</blockquote>
<p><img src="https://pepicrft.me/blog/modular-xcode-projects/__GHOST_URL__/images/posts/modular-dependencies.png" alt="" /></p>
<h2 id="linking-with-xcode">Linking with Xcode</h2>
<p>Targets can link against other targets outputs, and we can define the dependencies using Xcode tools like schemes, or target dependencies, but... how can we glue the dependencies defining the links between them?</p>
<h3 id="1-linking-static-or-dynamic-libraries-and-frameworks">1. Linking (static or dynamic) libraries and frameworks</h3>
<p>We can define the linking via:</p>
<ul>
<li><strong>A build phase:</strong> Among all the available build phases, there's one for defining the linking, <em>Link Binary With Libraries</em>. You can add there the dependencies of your target, that can be part of the same project, or from another project in the same workspace. This build phase is used by Xcode to figure out the dependencies of your target when the target is getting built. - <strong>Compiler build setting:</strong> A build phase turns the list into compiler flags underneath. That's something we can also do by defining some build settings: - <code>FRAMEWORK_SEARCH_PATHS</code>: We define in this setting the paths where the compiler can find the frameworks that we are linking against. - <code>LIBRARY_SEARCH_PATHS</code>: Similarly, we specify in this setting the paths where the compiler can find the libraries that we are linking against. - <code>OTHER_LDFLAGS</code> <em>(Other Linker Flags)</em>: We can specify the libraries we are linking against by using the <code>-l</code> argument: <code>-l"1PasswordExtension" -l"Adjust"</code>. If we are linking against a framework, we use the <code>-framework</code> argument instead: <code>-framework "GoogleSignIn" -framework "HockeySDK"</code>. If we try to link against a framework/library that cannot be found in the defined paths, the compilation will fail.</li>
</ul>
<h3 id="2-exposing-library-headers">2. Exposing library headers</h3>
<p>Libraries headers need to be exposed to the target that depends on the library. To do that, there's a build setting, <code>HEADER_SEARCH_PATHS</code> where we can define the paths where the headers of the dependencies can be found. If we link a library but forget about exposing their headers, the compilation will fail because it won't be able to find its headers.</p>
<h3 id="3-embedding-frameworks-into-the-products">3. Embedding frameworks into the products</h3>
<p>App targets that link against dynamic framework need to copy those dependencies into the application bundle. This process is known as framework embedding. To do that we can use a Xcode <strong>Copy Files Phase</strong>, copying the frameworks to the <code>Frameworks</code> directory. Not only direct dependencies should be embedded, but also dependencies of our direct dependencies. If we miss any framework, the simulator will throw an error when we try to open the app.</p>
<hr />
<h1 id="cases-of-study-man-computer">Cases of study 👨‍💻</h1>
<p>In this section, we'll analyze how tools like CocoaPods and Carthage leverage the concepts introduced above to manage your project dependencies.</p>
<h2 id="cocoapods">CocoaPods</h2>
<p><img src="https://cocoapods.org/favicons/apple-touch-icon-144x144.png" alt="" /></p>
<p>CocoaPods resolves your project dependencies and integrates them into your project. It's been very criticised for modifying your project settings, but they improved a lot since the early versions, and they do it in such a way that it doesn't require many changes in your project. What does it do under the hood?</p>
<ul>
<li>It creates a project <em>(<code>Pods.xcodeproj</code>)</em> that contains all the dependencies as targets. Each of those targets compiles the dependency that needs to be linked from the app. - It adds an extra target that depends on the other targets. It's an umbrella target that is used to trigger the compilation of the other targets. It does it to minimize the changes that are required in your project. By linking your app against that target, Xcode will compile all its dependencies first, and then your app. - It creates a workspace with your project and the Pods project. - Frameworks/libraries are linked using <code>.xcconfig</code> files that are added to your project group and set as configurations of your project targets. - Embedding is done using a build phase script. Similarly, they copy all the frameworks resources using a build phase.</li>
</ul>
<p>The image below illustrates how the setup looks like:</p>
<p><img src="https://pepicrft.me/blog/modular-xcode-projects/__GHOST_URL__/images/posts/modular-cocoapods.png" alt="" /></p>
<h2 id="carthage">Carthage</h2>
<p><img src="https://avatars2.githubusercontent.com/u/9146792?v=4&amp;s=280" alt="" /></p>
<p>Carthage approach is pretty different. Besides the resolution of dependencies, that in this case it's decentralized, the tool generates pre-compiled frameworks that the developer needs to link and embed from its app:</p>
<ul>
<li>Carthage resolves the dependencies and compiles them to generate dynamic frameworks that you can link from the app and their symbols for debugging purposes. These frameworks are fat frameworks, supporting both the simulator and device architectures. - The frameworks are manually linked by the user using the <em>Link Binary With Libraries</em> build phase. - The embedding is done using a script that Carthage provides. The script strips those architectures that are not necessary for the destination that we are building for. - The same script copies the symbols to the proper folder to make them debuggable.</li>
</ul>
<p><img src="https://pepicrft.me/blog/modular-xcode-projects/__GHOST_URL__/images/posts/modular-carthage.png" alt="" /></p>
<hr />
<p>I hope you found this post very insightful and that you could find answers to any doubt that you might have had. I'm not an expert on Xcode so you should expect some mistakes in the post. If you find any, please, don't hesitate to report it to me. Xcode has good and bad things, like any other IDE, but having a better understanding of its elements will help you get the best out of it. Don't be afraid of changing the setup and playing with schemes, targets, configurations. If you find yourself lost, I left a bunch of references in the section below. I recommend you to also use CocoaPods and Carthage as a reference and learn from them because they already spent a lot of time getting to know Xcode better to provide you with excellent tools for your projects.</p>
<p>Please, drop me a line <a href="mailto://pedropb@hey.com">pedropb@hey.com</a> with any question, concern or doubt you have.</p>
<h1 id="references">References</h1>
<ul>
<li><a rel="external" href="http://www.knowstack.com/framework-vs-library-cocoa-ios/">Framework vs Library</a> - <a rel="external" href="https://pewpewthespells.com/blog/static_and_dynamic_libraries.html">Static and dynamic libraries</a> - <a rel="external" href="https://pewpewthespells.com/blog/buildsettings.html">Xcode Build Settings Reference</a> - <a rel="external" href="https://developer.apple.com/library/content/technotes/tn2435/_index.html">Embedding Frameworks in an App</a> - <a rel="external" href="https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPFrameworks/Frameworks.html">Introduction to Framework Programming Guide</a> - <a rel="external" href="https://www.cocoanetics.com/2015/04/skipping-copy-phase-strip/">Skippy Copy Phase Strip</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Providing mocks and testing data from your frameworks.</title>
      <link>https://pepicrft.me/blog/frameworks-testing/</link>
      <guid>https://pepicrft.me/blog/frameworks-testing/</guid>
      <pubDate>Wed, 13 Sep 2017 12:00:00 +0000</pubDate>
      <description>This post introduces an approach to share testing data and mocks from your frameworks to other frameworks that might need them for testing purposes.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>If you build your apps in a modular manner using Swift, you have probably been in the situation where a <code>ModuleX</code> defines some mocks or testing data for its tests in its tests target, but they cannot be shared to be used from other tests targets, playgrounds, example apps... <em>(essentially because they cannot import a tests target)</em> With Objective-C it wasn't an issue at all because we could mock the interface of our dependencies at runtime with just one line of code. In Swift, the definition of mocks or data for testing requires some manual work <em>(unless you have some code generation in place)</em> that we don't want to have to do it more than once. Listed below you can see some scenarios where you face this issue:</p>
<ul>
<li>Playground of <code>ModuleX</code> wants to access a <code>Track.testData()</code> defined in <code>ModuleXTests</code>. - Example app of <code>ModuleX</code> wants to access a <code>Track.testData()</code> defined in <code>ModuleXTests</code>. - Some tests from <code>ModuleY</code>, that depends on <code>ModuleX</code>, wants to access <code>MockClient</code> defined in <code>FrameworkXTests</code>.</li>
</ul>
<blockquote>
<p><code>Module</code> stands for <code>Library</code> or <code>Framework</code>, depending on your project setup.</p>
</blockquote>
<p>We can overcome this issue by adding another module, that depends on <code>ModuleX</code> and exposes your module testing elements, <code>ModuleXTesting</code>. Since we would like to use the components in there from <code>Playgrounds</code> and example apps it's important that <code>ModuleXTesting</code> doesn't depend on the framework <code>XCTest</code>. In the snippet below you can see two examples, one of them shows how we use <code>ModuleXTesting</code> to define a mock for a protocol, and the other one how we extend an entity to provide testing data.</p>
<pre><code>// ModuleX - MyProtocol.swift
public protocol MyProtocol {
 func sync() throws
}
// ModuleX - Entity.swift
public struct Entity {
 public let name: String
 public init(name: String) {
 self.name = name
 }
}

// ModuleXTesting - MockMyProtocol.swift
import ModuleX

class MockMyProtocol: MyProtocol {
 var syncCount: UInt = 0
 var syncStub: Error?
 func sync() {
 syncCount += 1
 if let syncStub = syncStub { throw syncStub }
 }
}
// ModuleXTesting - Entity+TestData.swift
import ModuleX

extension Entity {
 static func testData() -&gt; Entity {
 return Entity(name: String.random)
 }
}
</code></pre>
<p><strong>Applying this little tip to your projects setup, you'll have more reusable testing components and you will save a lot of time when you need to write tests for your projects. The only thing you need to do, is defining your testing elements in a new module that playgrounds, example apps, and other modules have access to.</strong></p>
<blockquote>
<p>Note: Defining testing data or mocks in a new module applies only to the elements with <strong>public</strong> access. Those are the ones that are accessed from outside the framework tha contains them.</p>
</blockquote>
<p>I hope you find the tip useful. If you have gone through this challenge before, I'd love to know how you overcame the issue in your projects.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Conditionally embed your dynamic frameworks</title>
      <link>https://pepicrft.me/blog/xcodembed/</link>
      <guid>https://pepicrft.me/blog/xcodembed/</guid>
      <pubDate>Wed, 13 Sep 2017 12:00:00 +0000</pubDate>
      <description>A command line tool written in Swift for copying the frameworks from your project to the output frameworks directory.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As part of dynamic linking frameworks in your Xcode apps frameworks need to be copied into your app <code>Frameworks</code> folder. There are multiples ways to do so:</p>
<ol>
<li>Add a new <strong>Copy Files Build Phase</strong>, selecting <code>Frameworks</code> as the directory where you want the frameworks to be copied. 2. Running a script that automates the copy step for you.</li>
</ol>
<p>The most popular dependency management tools in the community use the second one. <a rel="external" href="https://cocoapods.org">CocoaPods</a> for example creates a new build phase called <code>[CP] Embed Pods Frameworks</code> containing all the frameworks that need to be copied. If you dive into the script you'll see that CocoaPods doesn't use those inputs and outputs <em>(although they Xcode exposes them as environment variables)</em>. Having your frameworks as input and outputs allows Xcode determine if the copy script has to be executed based on the changes in these files. Similarly, Carthage asks you to add an extra build phase that executes their script for copying the frameworks that they build under <code>Carthage/Build</code>.</p>
<p><strong>What if you want to embed a framework only when a given condition is satisfied?</strong> For example when you compile the project for "Debug". You might want to link your app against a framework that is only used for debugging purposes. CocoaPods handles this but if you are not using CocoaPods, it's not possible without a bit of scripting.</p>
<p>I found myself in that situation and I was between modifying in the CocoaPods bash script, or coming up with something in Swift that other developers could easily install and use in their projects. I decided opted for the latter, and I added a new command to <a rel="external" href="https://github.com/swift-xcode/xcode"><strong>xcode</strong></a>.</p>
<p>You can easily install the tool using <a rel="external" href="https://brew.sh/">Homebrew</a> with the following command:</p>
<pre><code>brew tap swift-xcode/xcodembed git@github.com:swift-xcode/xcode.git
brew install xcode
</code></pre>
<h2 id="a-side-note-on-xcode">A side note on xcode</h2>
<p><code>xcode</code> is a command line tool built in Swift that offers tasks that facilitate working with your Xcode projects. The first task supported by the tool is embedding frameworks, but there are more that are about to come, like cleaning build settings or linting your Xcode projects.</p>
<h2 id="embedding-your-frameworks">Embedding your frameworks</h2>
<p>If you have used Carthage before in your projects you might already be familiar with the process. You'll need an Xcode build phase in your project that runs the command passing the frameworks that will be copied. The example below shows your build phase should look like:</p>
<p><img src="https://pepicrft.me/blog/xcodembed/__GHOST_URL__/images/posts/Frameworks-Embed.png" alt="An example of the Xcode build phase that uses the command to embed the frameworks" /></p>
<ol>
<li>We run the command <code>xcode frameworks embed</code> using bash. 2. We specified as input files all the frameworks that will be copied. The path can be absolute or relative to the project directory. Remember that you can use any of the available Xcode build variables, like <code>$(SRCROOT)</code>. 3. Similarly we specify where those files will be copied. The path should be <code>$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/MyFramework.framework</code> where <code>MyFramework.framework</code> is the name of the framework.</li>
</ol>
<blockquote>
<p>Note: Input and output files must be paired. In other words, the output file x path is used to determined where the input file x will be copied.</p>
</blockquote>
<p><strong>Besides copying the frameworks, the tool also copies the symbols and the <code>bcsymbolmap</code> files of your framework, stripping the architectures that are not necessary</strong>. By default, the command embeds the frameworks for all the configurations. If you would like to do it only for some configurations, you can do it by just passing a parameter to the command above:</p>
<pre><code>xcode frameworks embed -config Debug,Release
xcode frameworks embed --config Debug
</code></pre>
<blockquote>
<p>Out of curiosity, Xcode uses the input and output files to determine if the script needs to be executed. For example, if an output file is missing, or any of the input files changed, Xcode will run the script the next time your build your project.</p>
</blockquote>
<h2 id="big-thanks">Big thanks</h2>
<p>To <a rel="external" href="https://cocoapods.org">CocoaPods</a> &amp; <a rel="external" href="https://github.com/carthage">Carthage</a> for diving into this issue in the past and coming up with their own solution to this problem. Both of them were a good reference for me to build up this command for <code>xcode</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a rel="external" href="https://github.com/Carthage/Carthage/blob/master/Source/carthage/CopyFrameworks.swift">Carthage copy frameworks</a> - <a rel="external" href="https://github.com/CocoaPods/CocoaPods/blob/master/lib/cocoapods/generator/embed_frameworks_script.rb">CocoaPods embed frameworks</a> - <a rel="external" href="https://github.com/kylef/Commander">Commander</a></li>
</ul>
<p>I hope you find the tool useful. Don't hesitate to open any issue or PR with fixes, ideas, comments!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Little tweak to be more productive writing XCTest tests</title>
      <link>https://pepicrft.me/blog/tweak-xctest/</link>
      <guid>https://pepicrft.me/blog/tweak-xctest/</guid>
      <pubDate>Mon, 21 Aug 2017 12:00:00 +0000</pubDate>
      <description>Because readability might compromise productivity.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><strong>Are you using <a rel="external" href="https://github.com/quick/quick">Quick</a> or <a rel="external" href="https://github.com/specta/specta">Specta</a> for your XCTest unit tests?</strong> They provide you with a nice DSL to define your tests in a more descriptive way using the keywords: <em>“describe”, “context”, “it”</em>. Although it makes your tests more readable, it breaks the integration of XCTest with Xcode. The example below shows a test written with Specta:</p>
<p><img src="https://pepicrft.me/blog/tweak-xctest/__GHOST_URL__/images/posts/xctest-specta.png" alt="An example of a test using Specta" /></p>
<p>At <a rel="external" href="https://soundcloud.com">SoundCloud</a>, we found the process of executing a single unit test with Xcode a bit cumbersome when using one of those DSLs, especially if your tests target contains a lot of tests. By using plain XCTest, Xcode automatically shows you a play button next to your tests that you can click if you want to execute that particular test. With a DSL there’s no play button next to your tests. The only way to manually execute one is either using the exclusive keywords from the DSL or executing the tests once to see all the available tests in the “Tests Navigator”.</p>
<p>The example below shows a plain XCTest and the button to run that individual test:</p>
<p><img src="https://pepicrft.me/blog/tweak-xctest/__GHOST_URL__/images/posts/xctest-plain.png" alt="An example of a test using plain XCTest" /></p>
<p>Putting on a balance readability and productivity we decided to go for productivity, coming up with some guidelines to make plain XCTest tests very readable, and leveraging the IDE to be more productive writing and executing unit tests.</p>
<p>Since then running and debugging our tests is much quicker and pleasant. And you? Do you use any DSL for your tests?</p>
<p><strong>Happy testing!</strong> :tada:</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Introducing xcodeproj</title>
      <link>https://pepicrft.me/blog/introducing-xcodeproj/</link>
      <guid>https://pepicrft.me/blog/introducing-xcodeproj/</guid>
      <pubDate>Mon, 31 Jul 2017 12:00:00 +0000</pubDate>
      <description>Read, update and write your Xcode projects from Swift</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Today I’m pleased to announce a new open source project I’ve been working on for the last few months, <a rel="external" href="https://github.com/carambalabs/xcodeproj">xcodeproj</a>. Xcodeproj is a library written in Swift that allows you interact with your Xcode projects from Swift. It provides a foundational API to build up your scripts and tools on top of it. It’s entirely written in Swift, documented and ready to be used. In this post, I’ll explain the motivation behind working on xcodeproj, show you the “get started” steps to start using the library, and give you some hints about ideas that I have to leverage this tool.</p>
<h2 id="motivation">Motivation</h2>
<p>This year, I’ve been very passionate about leveraging modularization to overcome scalability issues in mobile projects/teams. For every new module that I created I had to always go through the same manual steps: create the project, set the config, link dependencies, update the schemes… It was a very repetitive process, and it was easy to forget any of the steps, having some inconsistencies in the setup. I tried automating it by coming up with a script that clones a template Xcode project, and modifies some values in it. Although it solves the problem, it does it partially. It’s not flexible at all since it was hard to extend the template <em>(you had to update the original one, or create copies of it according to your requirements)</em>.</p>
<p>At some point I thought, what if there was a way to specify the project that you want, and there was a tool that would generate it for you? Something like: <em>“I want a project, with an iOS app, an iMessage extension, and a framework to share some code between them”</em>.</p>
<p>The closest tool that I found was <a rel="external" href="https://github.com/jcamp">xcake</a>. It does exactly what I was thinking of. It’s written in Ruby and it uses a gem from the CocoaPods team, <a rel="external" href="https://github.com/CocoaPods/Xcodeproj">xcodeproj</a> that allows you modifying your Xcode projects and workspaces. Although I’ve done some Ruby before, and I know the APIs a little bit, I’m not very familiar with them and I wanted to experiment with Swift. I thought it would be a good idea to come up with something written in Swift, that other Swift developers could use to build their own tools on top of a foundational API. I started writing the swift version of <a rel="external" href="https://github.com/xcodeproj">xcodeproj</a>.</p>
<p>Xcodeproj is a swift library that provides components for reading, modifying and writing Xcode projects and workspaces. In other words, it opens a new API for interacting with your Xcode projects. If you wonder what you can use xcodeproj for here are some ideas:</p>
<ul>
<li>Finding duplicate files. - Checking if the groups hierarchy matches the system one. - Detecting which targets have to be run/tested as a result of some files being modified. - Generating projects from a specification file.</li>
</ul>
<p>There are bunch of opportunities and I’m eager to see what developers can build using this new API.</p>
<h2 id="how-to-use-it">How to use it</h2>
<p>If you are very excited and can’t wait to try it out, these are the steps that you can follow to start using xcodeproj within your projects.</p>
<p>First of all you have to add the dependency. You can do it by specifying the dependency in your Package.swift</p>
<p><code>gist:pepibumur/b0d53f59b471047abb7a4275008964d6</code></p>
<p>If you are using <a rel="external" href="https://github.com/JohnSundell/Marathon">Marathon</a>, you can update your <code>Marathonfile</code> to specify the dependency</p>
<p><code>gist:pepibumur/f069ea32f1685fa85680608670d9ed14</code></p>
<p>Once done, you can use it by just importing xcodeproj. Here you have some examples of things that you can do with xcodeproj:</p>
<p><code>gist:pepibumur/649fa8fe22f27d176ddf78c5e524e536</code></p>
<h2 id="what-s-next">What’s next</h2>
<p>While I was working on xcodeproj I got a few ideas about how to use xcodeproj. Here are some of them.</p>
<ul>
<li><strong>Generation of Xcode projects</strong>. That was my original motivation but <a rel="external" href="https://twitter.com/yonaskolb">@yonaskolb</a> was faster than me and started building <a rel="external" href="https://github.com/yonaskolb/XcodeGen">XcodeGen</a>. Instead of starting another project I think it makes more sense to support the project contribute with it. - <strong>Project linting:</strong> Have you been in that situation when the compiler tells you about duplicated files, or when a file is missing but it’s still your project group (because those things happen when you screw it up solving your project conflicts). I’d like to provide linting for projects that identify those problems in your projects, alert you about them and offer the option to fix them automatically. - <strong>TDD:</strong> I was fascinated when I saw <a rel="external" href="http://www.scala-sbt.org/">scala-sbt</a>, the build tool for Scala. When you use it in your projects it has a mode that detects changes in files and runs only the tests of the files that have been impacted by those changes. I’d like to port that idea to the Xcode build system and being able to do something similar. That would allow developers iterate faster with confidence.</li>
</ul>
<h2 id="thanks">Thanks</h2>
<p>This project wouldn’t have been possible without all the resources and open source projects that I’ve listed in the sections below. Also, I’d like to thank <a rel="external" href="https://twitter.com/yonaskolb">@yonaskolb</a>, first official user of xcodeproj that is leveraging it to build <a rel="external" href="https://github.com/yonaskolb/XcodeGen">XcodeGen</a>, a tool for generating Xcode projects from a specification file. He’s contributed a lot to the library. Also thanks to @saky and @sergigram reviewing the post.</p>
<p>Also thanks to <a rel="external" href="https://twitter.com/saky">@saky</a> and <a rel="external" href="https://twitter.com/sergigram">@sergigram</a> reviewing the post.</p>
<h2 id="references">References</h2>
<ul>
<li><a rel="external" href="https://github.com/apple/swift-package-manager/tree/master/Sources/Xcodeproj">Swift Package Manager — Xcodeproj</a> - <a rel="external" href="https://buckbuild.com/javadoc/com/facebook/buck/apple/xcode/xcodeproj/package-summary.html">Facebook Buck</a> - <a rel="external" href="https://pewpewthespells.com/blog/pbxproj_identifiers.html">Pbxproj identifiers</a> - <a rel="external" href="http://danwright.info/blog/2010/10/xcode-pbxproject-files/">A brief look at the Xcode project format</a> - <a rel="external" href="http://www.monobjc.net/xcode-project-file-format.html">Xcode Project File Format</a> - XcodeGen</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Moving back to Berlin</title>
      <link>https://pepicrft.me/blog/moving-back-to-berlin/</link>
      <guid>https://pepicrft.me/blog/moving-back-to-berlin/</guid>
      <pubDate>Tue, 18 Jul 2017 12:00:00 +0000</pubDate>
      <description>A brief retrospective on what my life has been in the last few months and my thougts on my move to Berlin.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>On January 2017 I moved to Budapest. My girlfriend was living there, and the distance was very hard. I had been in Berlin for approximately two years, and although I loved the city, I thought that moving to Budapest was the right call to make. I liked, and like my company, SoundCloud, so I wanted to continue working for it. I appreciate a lot the opportunity that I was given by them, working remotely supporting the team and the project from there. I was very excited; new working setup, new city and life style.</p>
<blockquote>
<p>Working remotely is great if you are a remote person. I'm not.</p>
</blockquote>
<p>The first thing that I noticed during that period is that I'm not a remote person <em>(thanks Maria for helping me to notice it)</em>. I had read a lot about remote working and how cool it is, and I started the remote setup full of appealing expectations. Unfortunately, none of them were as expected, and I went through a very tough period. I missed hanging out with my colleagues, grabbing a coffee or a beer after work, brainstorming using the whiteboards at the office. I felt that I lost what I liked the most of working from an office, the people. I tried to prove myself that what wasn't working wasn't me, but the setup. That working from a coworking space would help with my bad feelings, but it turned out that it didn't. At the same time, I was hiding all those feelings because I didn't want Maria to see that moving to Budapest was affecting me so badly workwise. But she is smart, and she noticed it from the first day. I still remember her describing me as a <em>"non-remote person"</em>. She knows me very well!</p>
<p>Budapest is a charming city, full of stunning views to enjoy, and thermal baths to relax after a very intense day. However, I found very difficult to have friends in the city. Compared to Berlin, where you find a lot of people relocating to the city and having the need to meet new people, Budapest was very hard in that sense. It makes total sense. The majority of the population is local and they have their friends circles. The same thing would happen if you moved to Spain, people would have their friends and use Spanish all the time. This difficulty making friends, together with the work situation, wasn't a good experience for me. My team at SoundCloud and Maria were very supportive all the time. They both were aware of my feelings and tried to help me as much as they could.</p>
<p>Maria, who had been searching for a job to move on from Budapest, got a job offer in Berlin to start in August. I couldn't believe it! Both of us were very excited. I would come back to the office, and she'd start working in the area she had studied for, translation and interpretation.</p>
<p>Sometimes in your life, there are calls that you have to make, and put your emotions in front. I don't regret having moved there, even though the decision came with some uncertainty. Eventually, those decisions pay off, and your life finds its way to its fullness. I learned not to keep those things with myself, as I did with Maria, because the people around you, who know about your feelings, are the people that might do their best to help you.</p>
<p>On Sunday we are flying to Berlin! New adventures and experiences are about to come, and I can't wait for them. Ping me if you are around, or you plan to visit the city, I'd love to meet up.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Composable UIs</title>
      <link>https://pepicrft.me/blog/composable-uis/</link>
      <guid>https://pepicrft.me/blog/composable-uis/</guid>
      <pubDate>Thu, 02 Mar 2017 12:00:00 +0000</pubDate>
      <description>Build UIs based on reusable components that you can compose in more complex hierarchies.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One important aspect that as developers, we should keep in mind, is trying to reuse the code that we write whenever it's possible. The main reason behind that is saving time. For example, if you write a cell for your app, <code>TrackCell</code> and you need the same <em>(or similar)</em> cell in a different collection view, you should try to reuse the one that you already have. However, sometimes the specifications of that cell change a little bit, and we end up with a bunch of properties that are being passed and a lot of if-elses in code updating the layout accordingly. Another approach would be using inheritance, but we'd easily get into a mess, breaking the SOLID principles and spreading the cell logic between the parent and the children. <em>Have you ever find yourself in that situation?</em></p>
<p>Making the matter worse, even if the UI is reusable, the data that feeds the UI comes from a data source that most likely is far from the component. On iOS collection views you'll have a schema similar to the one shown below where a model from the store, is mapped into a plain entity, provided by a data source, that is hooked with the collection view, and passed to the cell by using the collection view presenter.</p>
<p><img src="https://pepicrft.me/blog/composable-uis/__GHOST_URL__/images/posts/components-without.png" alt="An example of a typical collection view presenting data in cells" /></p>
<p>If you wanted to reuse any component from that cell you'd be <em>forced</em> to update all components in that hierarchy, <strong>all</strong>. And if you have unit tests for these components, you'd need to update them as well. It doesn't scale well, does it?</p>
<p>Another common issue besides the reusability is the fact that whenever the data changes, we either reload whole collection view, or only the cells that changed. In both cases, we need to do it at the collection view. If your app is very heavy in background operations that might eventually lead to crashes if you don't manage the concurrency properly or performance degradation.</p>
<p><a rel="external" href="https://facebook.github.io/react/">React</a> and React Native have solved this problem nicely. UIs are defined in components, these self-contained components have a lifecycle, and know how to update its state. Moreover, these components can easily be composed in higher hierarchies. The benefit of that components-based approach is that you can easily drag-and-drop these components around. For example, if you come up with a <code>LikeButton</code> that you use in a <code>TrackCell</code>, you can use the same <code>LikeButton</code> in another cell by just inserting it and defining how it should be positioned. Another awesome benefit of using <em>React</em> is that it knows what needs to reload and it only reloads that element in the dom. That's very powerful if you combine it with <a rel="external" href="https://facebook.github.io/relay/">Relay</a> and <a rel="external" href="http://graphql.org/learn/">GraphQL</a>.</p>
<blockquote>
<p>An advantage of using components is that it's easier to <strong>ensure consistency</strong>. The same component is used from different places, and when a change needs to be done, you do it in one place and you get the change in all the places where the component is being used.</p>
</blockquote>
<p>Despite you can use <em>React</em> natively with <em>React Native</em>, you don't need a framework for that, but just change your mindset when defining app ui-data hierarchies. Companies like <a rel="external" href="https://spotify.com">Spotify</a> have come up with a similar approach, the <a rel="external" href="https://github.com/spotify/HubFramework">Hub Framework</a>, that abstracts you from composition, action handling, and lifecycle management. I like how flexible the framework it but I'm not a big fan of very opinionated frameworks, and Hub Framework is. As soon as you start using it, it influences the architecture of your apps heavily. I recommend you to watch this talk from <a rel="external" href="https://twitter.com/johnsundell">John Sundell</a>, <a rel="external" href="https://www.youtube.com/watch?v=ypk-72mhYBk">Backend-driven UIs</a>. It looks magic!</p>
<p>As I pointed out, with a mindset change, you can also have your own component-driven UI, with reusable and composable components:</p>
<p><img src="https://pepicrft.me/blog/composable-uis/__GHOST_URL__/images/posts/components-with.png" alt="An example of UI built with the component-based style" /></p>
<p>A component is a <strong>class</strong> that gives you the view and an interface to set up the view. Whoever uses these components shouldn't know anything other than what it needs. Internally the view can use programming patterns like MVP, MVC, MVVM... But these patterns are <em>invisible</em> from the outside.</p>
<pre><code>class LikeComponent {
 typealias TrackId = String
 var view: UIView
 func setup(for: TrackId)
}
</code></pre>
<p>Components can also respond to <strong>actions</strong>. For example, if you are trying to like a track, that turns into a few background operations to persist the new state into the API and the local store. In case the action response is more complicated and involves some UI, you can delegate de action to the app by using a delegate pattern. As an example, some actions might require a confirmation from the user. That confirmation can be handled from the outside.</p>
<p>Since with this approach, each component brings its state from the data source, so it's important that the access to the data is <strong>fast</strong>. Otherwise, the UI will flicker, and that's terrible for the user experience. One idea to prevent that is having an in-memory data source where the states are indexed, for example using a <code>Dictionary</code>. This data source can be filled lazily, fetching the data the first time the data is needed, and ensuring the data keeps synchronized with the store underneath <em>(Core Data, Realm, serialization into disk..)</em></p>
<p><strong>Compose all the things!</strong></p>
<hr />
<p>Do you follow a similar approach in your projects? Are you considering moving towards that approach? I'd like to hear about your experience and the problems you found along the way. Reach out to <a href="mailto://pedropb@hey.com">pedropb@hey.com</a> or leave a comment below.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Divide and conquer</title>
      <link>https://pepicrft.me/blog/divide-and-conquer/</link>
      <guid>https://pepicrft.me/blog/divide-and-conquer/</guid>
      <pubDate>Thu, 16 Feb 2017 12:00:00 +0000</pubDate>
      <description>How modularizing your apps is helping us to scale our Xcode app.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<blockquote>
<p><strong>Divide and rule</strong> <em>(or divide and conquer, from Latin dīvide et īmpera)</em> in politics and <a rel="external" href="https://en.wikipedia.org/wiki/Sociology">sociology</a> is gaining and maintaining <a rel="external" href="https://en.wikipedia.org/wiki/Power_(social_and_political)">power</a> by breaking up larger concentrations of power into pieces that individually have less power than the one implementing the strategy. The concept refers to a strategy that breaks up existing power structures, and especially prevents smaller power groups from linking up, causing rivalries and fomenting discord among the people.</p>
</blockquote>
<p>More and more we see companies that run away from Xcode to try the dynamism of languages like Javascript on their mobiles apps. Just mentioning some examples:</p>
<ul>
<li><a rel="external" href="http://artsy.github.io/blog/2017/02/05/Retrospective-Swift-at-Artsy/">Retrospective: Swift at Arsty</a> written by <a rel="external" href="https://twitter.com/orta">Orta</a> - <a rel="external" href="https://ashfurrow.com/blog/swift-vs-react-native-feels/">Swift vs. React Native Feels</a> by <a rel="external" href="https://ashfurrow.com/">Ash Furrow</a>. - <a rel="external" href="https://engineering.instagram.com/react-native-at-instagram-dd828a9a90c7#.vph72j14f">React Native at Instagram</a> - <a rel="external" href="https://developers.soundcloud.com/blog/react-native-at-soundcloud">React Native at SoundCloud</a></li>
</ul>
<p>Amongst other reasons, teams decide to give an opportunity to React Native because they want their teams to <strong>ship features faster</strong>, eliminate the compile-install cycles or overcome scalability issues that they are facing because of the team and project's growth. It's a reality that the tools and the patterns that Apple gives us don't scale. While everything works when the app and the team are small, it quickly becomes a nightmare.</p>
<ul>
<li>Slow compilation times. - Slow testing cycles, it makes TDD impossible.</li>
</ul>
<p>If we counted the time we spend on these slow cycles, we'd notice the amount of time that developers spend unnecessarily. Moreove, motivation in the team goes down. It takes a lot of time for them to build something, and the product managers are putting pressure on them to deliver features fast. The company thinks that it's a matter of people in the team, and they hire more, but the productivity stays the same.</p>
<p>Other companies, like Spotify, have preferred to moved that dynamism to the server <em>(with their <a rel="external" href="https://github.com/spotify/HubFramework">Hub Framework</a>)</em> and have developers focused on building components that they decide how to render with some backend logic. <strong>Companies are desperately looking for dynamism in their projects that is not given by Apple and their tools.</strong></p>
<p>I'm not against React Native, I like it, and the direction all these projects are taking makes total sense. But this whole movement that is becoming a standard makes me feel sort of sad. It's becoming standard to open Medium and read an article about a new company trying React Native. Developers and companies need to find their workaround to a problem that I'd expect Apple to fix it. It seems to me that they didn't stop to think about how their tools allow projects to scale. How could Facebook build their apps using Xcode or the command line tools? How can developers do TDD in large projects avoiding these slow build/run cycles?</p>
<p>At <a rel="external" href="https://soundcloud.com">SoundCloud</a> we were suffering similar pains, build and testing times were a nightmare, our Core Data model didn't scale anymore, and the engineers in the team were looking forward to starting doing pure Swift in the apps. Although React Native has always been around, we've been figuring out with the help of everyone in the team and other companies, how to tackle these issues with the tools our developers are familiar with, Swift, Objective-C and Xcode. It's been very challenging, and thanks to this awesome team's effort we're seeing some light and changes start having a huge impact on the app and teams' performance.</p>
<blockquote>
<p>We're making our Xcode project <strong>great again</strong>.</p>
</blockquote>
<p>To add up to the lack of dynamism, our extensive use of Core Data didn't scale either. We shared a data model across the whole app. We were suffering performance issues, and our architecture was much Core Data dependent.</p>
<p>Surprisingly the solution started with something very simple:</p>
<p><strong>Dividing and conquer</strong></p>
<p>Our app was a monolith. One target with the source code, another one for the specs, and the rests from CocoaPods for the external dependencies. The bigger these targets are, the more they take to compile. Although Xcode doesn't recompile the targets that didn't change, sometimes it has to, for example:</p>
<ul>
<li>When it's a clean build. - When Xcode messes it up <em>(something it's very likely to happen)</em>. - After doing <code>pod install</code>.</li>
</ul>
<p>Inspired by other companies, and our <a rel="external" href="https://developers.soundcloud.com/blog/microservices-and-the-monolith">micro services architecture</a>, we built a similar approach. The fact that we splitted the monolith into smaller pieces made workflows faster; developers could modify a class, or a test, and build/run the tests in a matter of seconds. We started modularizing our iOS application.</p>
<p><img src="https://pepicrft.me/blog/divide-and-conquer/__GHOST_URL__/images/posts/monolith_to_frameworks.png" alt="From monolith to frameworks" /></p>
<p>It was just the first step toward that project environment we were aiming for. Soon we noticed the fact that frameworks didn't have to talk to the existing Objective-C code base allowed teams to do pure Swift <em>(at least in private)</em>. They didn't have to deal with the bridging all the time as it was happening in the primary application target. The motivation went up; Swift was becoming real!</p>
<p>It was also a good opportunity to review <strong>how</strong> we were building the iOS app, the code architecture. <a rel="external" href="https://twitter.com/garriguv">@garriguv</a> iterated with the team over what would be the Swift architecture for the project. Defining things such as:</p>
<ul>
<li>How and where we would fetch the data from. - How the architecture elements would fit in all the frameworks. - How teams could be components that could be reused by other teams. - How the interfaces should look like to ensure a compatibility with the existing code base.</li>
</ul>
<p>Everything was moving at a good pace. We decided not to rely on external dependencies and build everything by ourselves because it'd be easier to maintain. We focused on building just the things that we needed, keeping them simple and open to extension. Although we initially brought Quick and Nimble as dependencies, we soon figured out that they were breaking the good integration that Xcode has with plain XCTestCases <em>(allowing you to run the tests directly from the IDE editor)</em>. We stepped back and reverted the few unit tests that we wrote to be plain XCTest.</p>
<p>We also came up with testing guidelines. We didn't have the Objective-C runtime, and libraries like <code>OCMock</code> or <code>OCMockito</code> on Swift and people followed different approaches for mocking and generating data. The fact that we're a very proactive team led Graeme, one of my colleagues, to come up with testing guidelines that the team could stick to. Furthermore, we added a <code>Testing</code> framework, where all our custom expectations and testing helpers would be. Whenever a developer came up with a testing component that could be shared with the rest, he/she could add the component to that framework.</p>
<p>As I mentioned earlier, Core Data was extensively used. We were hitting some performance issues and most of our features were very coupled to Core Data. Data that didn't need persistence ended up persisted, data that was very critical, got removed because migration issues in other models, our model concurrency was limited to prevent threading issues. We learned from companies like Facebook, Linkedin that moved away from shared models and embraced distributed stores with immutable models. If you haven't watched these talks, I recommend them to you:</p>
<ul>
<li><a rel="external" href="https://www.youtube.com/watch?v=-G8nZpif1rA">Inside the Big Blue App</a> - <a rel="external" href="https://www.youtube.com/watch?v=XhXC4SKOGfQ">Facebook's iOS Infrastructure</a> - <a rel="external" href="https://engineering.linkedin.com/blog/2016/07/rocket-data--faster-model-management-for-ios">Rocket Data: Faster Model Management for iOS</a> - <a rel="external" href="https://eng.uber.com/new-rider-app/">Engineering the architecture behind Uber's rider app</a></li>
</ul>
<p>Features data will be persisted <em>(if needed)</em> in different stores, deciding about the invalidation policy, if migration is supported, and providing APIs in case other parts of the app need to access the data that they are storing. Developers don't have to worry anymore about Core Data, and the big shared model that we're currently maintaining. The immutable nature of the models will prevent a lot of threading issues.</p>
<p>We were inspired by the components driven movement. By building your UI in components you make these components more reusable. You can drag &amp; drop them in different parts of your apps without caring much about what's inside the component.</p>
<blockquote>
<p>Let's say you work on all the engagement features, for example, likes. Instead of exposing the access to the data, you could expose a like button <em>(that can be customized)</em>. The like button responds to actions <em>(triggering data operations)</em> and updates its state accordingly <em>(observing data changes)</em></p>
</blockquote>
<p>In our previous setup, adding a like in a cell, involved changes in the cell, the presenter, the data source. The only change that is needed with the components-based approach is the UI layer. That's it!</p>
<p><img src="https://pepicrft.me/blog/divide-and-conquer/__GHOST_URL__/images/posts/divide-components.png" alt="Divide and conquer" /></p>
<hr />
<p>I'm very excited about the direction of the project and all the challenges to come. Although we are not that close to the dynamic experience Javascript and React Native provides, we're getting better compare to the experience we have with the monolith approach. There are things that we'd like to try, like <a rel="external" href="https://buckbuild.com/">Buck from Facebook</a>. The build tool that speeds up builds with a powerful distributed cache <em>(the support with Swift and dynamic frameworks is not that good yet)</em>.</p>
<p>Although it seems a very straightforward journey, it isn't. Migration can be a nightmare because all the dependencies that your components might have. <em>Where should I start from?</em> <em>What if I build this abstraction layer here that gives me some flexibility?</em> Delegation to the app will be your best friend during the migration.</p>
<p>And closing with one good tip: <strong>control the excitement</strong>. An empty framework is a white canvas for developers; they can start adding code without many constraints. The guidelines that you have for the app doesn't work anymore for the new architecture, and it's crucial that you come up with some. Otherwise, you'll easily find yourself with inconsistencies on APIs and patterns.</p>
<p><strong>Don't forget to document the architecture in your frameworks</strong></p>
<hr />
<h2 id="if-you-want-to-join-us-in-this-exciting-journey-and-help-connecting-people-through-music-soundcloud-is-looking-for-ios-engineers">If you want to join us in this exciting journey and help connecting people through music, SoundCloud is looking for <a rel="external" href="https://soundcloud.com/jobs/2017-01-23-ios-engineer-berlin">iOS engineers</a>.</h2>
]]></content:encoded>
    </item>
    
    <item>
      <title>Wrapping up 2016</title>
      <link>https://pepicrft.me/blog/wrapping-up-2016/</link>
      <guid>https://pepicrft.me/blog/wrapping-up-2016/</guid>
      <pubDate>Sun, 18 Dec 2016 12:00:00 +0000</pubDate>
      <description>The year is almost over. In this post I summarize everything that happened this year and my new year resolutions.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>The year is almost over. A friend of mine, <a rel="external" href="https://twitter.com/esttorhe">Esteban</a>, published a <a rel="external" href="https://estebantorr.es/blog/2016/12/16/Wrapping-up-2017/">blog post</a>, wrapping up his year and it inspired me to do the same.</p>
<p>Starting from my personal life, I unexpectedly met Maria José, my girlfriend. We were friends in the high school, and we hadn't talked or a long time. Nevertheless, the world is sometimes not that big, and you don't know when and where you can meet a person again. The fate brought us together; we met in Budapest and magic came out. After some flights between Berlin and Budapest I decided to move to Budapest, so I'll start living there from January. I'll be working for SoundCloud, the company I joined in October 2015. So far, it's been the company I've been working the longest time with. It has a very inspiring culture, and it's a good place to grow as an engineer because of its values, people and product. In 2016 I moved to a new team, Core Clients, working this time on tools for other developers.</p>
<p>In 2016 I've also attended many conferences, speaking about a project that we're currently developing at SoundCloud, <em>"Framework Oriented Programming"</em> or <em>"Apps Modularization"</em>. All the slides are published on my <a rel="external" href="http://speakerdeck.com/pepibumur">SpeakerDeck</a> account. I spoke at the following conferences:</p>
<ul>
<li><a rel="external" href="http://amsterdam2016.codemotionworld.com/">CodeMotion Amsterdam</a> - <a rel="external" href="https://skillsmatter.com/conferences/7598-ioscon-2016-the-conference-for-ios-and-swift-developers">iOSCon</a> - <a rel="external" href="http://www.cmduconf.com/">CMD+U</a> - <a rel="external" href="http://2016.nsspain.com/">NSSpain</a> - <a rel="external" href="http://www.2016.mobiconf.org/">Mobiconf</a> - <a rel="external" href="http://2016.mobilization.pl/">Mobilization</a></li>
</ul>
<p>I had the opportunity to meet <strong>world-class engineers and people</strong>, like <a rel="external" href="https://twitter.com/esttorhe">Esteban Torres</a>, who I have the pleasure to work with. <a rel="external" href="https://twitter.com/benjaminencz">Benjamin</a> who I met at iOSCon, I still remember the very inspiring talk that we had in our way to the airport. <a rel="external" href="https://twitter.com/marmelroy">Roy</a>, whose open source contributions were part of most of my projects. <a rel="external" href="https://twitter.com/NeoNacho">Boris</a> and his <em>#yatusabes</em>🍷 and <a rel="external" href="https://twitter.com/mrackwitz">Marius</a>.</p>
<p>I <strong>travelled</strong> around Europe more than what I used to. Living in Berlin makes it easier since you can be in another country in just a few hours. I took the flights on Friday evening, and I flew back on Monday morning. I went straight from the airport to the office. Budapest, Granada, Malaga, Sevilla, Amsterdam, Copenhagen, Scotland, London, Stockholm, San Sebastian, Logroño, Viena, Praga, Greece, Slovakia, Krakow, Switzerland, Verona and Morroco. <a rel="external" href="https://pbs.twimg.com/profile_images/2218121082/mochilo.jpg">This</a> is how my mother sees me after 2017 full of trips.</p>
<p>I started a <strong>newsletter</strong> and quit it after almost ten issues. Thanks to it, I had interesting discussions with <a rel="external" href="https://twitter.com/wolffan">Raimon</a> since we had similar concerns about the topics I talked about. I kept writing articles. One of them, <a href="https://pepicrft.me/blog/wrapping-up-2016/__GHOST_URL__/2016/11/16/in-a-world.html">In a world...</a> became very controversial in the iOS and Android communities and had a lot of retweets and comments on the social networks. Another one, <a rel="external" href="https://blog.caramba.io/micro-features-architecture-for-ios-f81ca18f03ac">Micro Features Architecture for iOS</a> turned out to be attractive to the community and got almost 100 likes on Medium.</p>
<p>I published on a new <strong>spare-time</strong> project with <a rel="external" href="https://twitter.com/saky">Isaac</a>, GitDo, and stop its development to focus on a new project with Sergi and Ana, <a rel="external" href="http://caramba.io">Caramba</a>. We'd develop and design our apps as we did when we started as developers. So far we've developed multiple apps, Open Source projects, and written numerous articles that we've shared on <a rel="external" href="https://github.com/carambalabs">GitHub</a> and <a rel="external" href="https://medium.com/@caramba">Medium</a> respectively.</p>
<p>I've tried to read more this year. Among other <strong>books</strong>, I've read: <em>Peopleware</em>, <em>Tribe</em>, <em>Who moved my cheese?</em>, <em>Drive - The surprising truth about what motivates us</em>. I started using <a rel="external" href="https://goodreads.com">GoodReads</a> to track them and get recommendations based on my reads and my friends' lectures. You can find me as @pepibumur on the platform.</p>
<h2 id="2017-what-s-coming">2017 - What's coming?</h2>
<p>Languages have been a challenge for me. I want to keep improving my English this year, and try with a new language, which will most likely be <strong>German</strong> <em>(yes... now that I moved to Budapest)</em>. I also want to learn a new programming skill. My focus, since I became a developer, has been iOS. I learnt Objective-C, and later Swift. However, when it's about the web I know just a little. While I know how to develop and app from scratch and ship it to production, I don't know how to do the equivalent with a website. I'd like to be able to code a frontend <em>(HTML and CSS)</em> and include some client <em>Javascript</em> logic. Moreover, Swift can be used in server environments and macOS applications. I'd like to explore Swift on the server side, implementing a backend on Swift, and learn about <em>AppKit</em> and learn apps development for macOS.</p>
<p>I'll keep writing and sharing my learnings in the open. I'll be in Budapest most of 2017, but I might consider moving somewhere else... <strong>Looking forward to starting 2017.</strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Extensions, dependency injection and frameworks</title>
      <link>https://pepicrft.me/blog/extensions-frameworks/</link>
      <guid>https://pepicrft.me/blog/extensions-frameworks/</guid>
      <pubDate>Wed, 16 Nov 2016 12:00:00 +0000</pubDate>
      <description>Learn how handy protocol extensions can be, when used in a frameworks architecture.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I'd barely used extensions in my Swift code. When we started using Swift at SoundCloud I noticed a common parttern that most of people follow. They created extensions to organize the interface methods in different <em>"namespaces"</em>. As shown in the example below:</p>
<pre><code>struct MyStruct {
 let name: String
}

extension MyStruct {
 func run() {
 print(&quot;\(name) runs&quot;)
 }
}
</code></pre>
<p>Extensions were used for pure style reasons, keeping the interface well organized. The interface could even be separated in different files follogin the <code>Objective-C</code> name style, <code>MyStruct+Runner.swift</code>.</p>
<p>With the transition into frameworks we found out a couple of use cases for extensions that might help you if you plan to transition your monolithic app into frameworks. I'll go through them and show you some exaples:</p>
<h3 id="implicit-dependency-injection">Implicit dependency injection</h3>
<p>When a framework provides a feature, it takes all the dependencies <em>(aka Services)</em> from the app. Typically a constructor of a feature that is defined in a framework looks like this:</p>
<pre><code>// Feature.framework
public class MyFeature {
 private let client: Client
 public init(client: Client) {
 self.client = client
 }
 public var service: Service { return MyFeatureService(client: self.client) }
}
</code></pre>
<p>Every time we instantiate the feature from the app, we'll end up writing the same initialization, passing the dependencies managed by the app:</p>
<pre><code>// App
class Services {
 static var client: Client!
}

let feature = Feature(client: Services.client)
let anotherInstance = Feature(client: Services.client)
</code></pre>
<p>The more dependencies our feature has, the more code we'll duplicate, since by default, all the instances will take the same dependencies <em>(in rare cases we'll inject a different dependency into a feature)</em>. <strong>Here is where extensions came very handy</strong>. Since we want to prevent our developers from write the same initialization logic all the time, we can extend the class from the app, adding up a convenience initializer:</p>
<pre><code>// App
extension Feature {
 convenience init() {
 self.init(client: Services.client)
 }
}
let feature = Feature()
let anotherInstance = Feature()
</code></pre>
<h3 id="behaviour-conformance">Behaviour conformance</h3>
<p>Another very useful use case for extensions in a frameworks setup is the conformance of application protocols from a framework model. In our transition into frameworks, we wanted to be able to reuse components from the app until we had time to migrate them into their own framework. To reuse these components <em>(e.g. a TableViewCell presenter)</em>, the component <em>(in the app)</em> and the model <em>(in the framework)</em> had to speak the same language, in other words, they had to know about a shared interface. Since these interfaces are something application specific, that the framework shouldn't be aware of, it didn't make sense to pull them out to the framework. It'll be clearer with an example:</p>
<ol>
<li>The model <code>SearchEntity</code> is extracted into its own <code>Search.framework</code>. 2. From the app, the user can select a search result and open the player. The player requires the entity to conform a <code>PlayQueueEntity</code> protocol that is defined in the app. 3. Since the <code>Search.framework</code> could be used in a different app/target where the results are not opened in a player, conforming the <code>PlayQueueEntity</code> protocol from the <code>Search.framework</code> wouldn't make sense. Otherwise, the framework would know <strong>where</strong> it's going to be used.</li>
</ol>
<p>Thanks to extensions we can solve this issue. By just conforming a protocol from the app, we provide our framework models with a behaviour that they didn't have originally:</p>
<pre><code>// Search.framework
struct SearchEntity {
 let title: String
 let identifier: Sring
}

// App
extension SearchEntity: PlayQueueEntity {
 let artworkUrl: URL {
 return &quot;xxxx/\(self.identifier)&quot;
 }
}
</code></pre>
<p>By doing that the <code>Search.framework</code> can be very generic, and depending on where they are used, we extend the interfaces of its models.</p>
<hr />
<h4 id="these-are-two-examples-where-extensions-in-swift-saved-us-a-lof-of-time-duplicated-and-coupled-coded-if-you-are-using-also-entensions-in-your-projects-and-you-d-like-to-share-your-use-cases-do-not-hesitate-to-leave-a-comment-below-i-m-looking-forward-to-hear-how-you-use-them">These are two examples where extensions in Swift saved us a lof of time, duplicated and coupled coded. If you are using also entensions in your projects and you'd like to share your use cases do not hesitate to leave a comment below. I'm looking forward to hear how you use them.</h4>
]]></content:encoded>
    </item>
    
    <item>
      <title>Developing tools for developers</title>
      <link>https://pepicrft.me/blog/developing-tools-for-developers/</link>
      <guid>https://pepicrft.me/blog/developing-tools-for-developers/</guid>
      <pubDate>Sat, 12 Nov 2016 12:00:00 +0000</pubDate>
      <description>Learnings from being a core developer and providing other teams with the tools that they need for their daily work.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It’s been a few months since I moved to the iOS Core team at SoundCloud. The team is responsible for providing other developers with the tools that they need to develop features for users. We could say that our users are the developers. We are responsible for designing, implementing and maintaining the tools that allow them to interact with core services like the storage and the API. Although what we do at the end is writing code, there are a lot of things that change in comparison with coding features for users. It took me time to adopt the new mindset, and I keep learning new things as I work with my colleagues iterating over the processes and the solutions that we’re designing. In this short journey, I’ve discovered a lot of things, working with other teams, and with people inside the team. In this post, I’ll share some of these learnings.</p>
<p><strong>Developers love to have fun.</strong> If you don't provide your team with a challenging environment, they might lose all the motivation that they had for the project and start working on side projects. One of the reasons why people start working on side projects is because their full-time job doesn’t allow them to experiment and try out new things. Make sure you as a team, or your company work on providing the team with that space. Give them the <em>playground</em> that they're asking for and make them feel like children inside the project.</p>
<blockquote>
<p>One of the projects that we’re currently working on at SoundCloud is the <em>“app modularization”</em>. Developers can enjoy writing pure Swift without dealing with Objective-C interoperability. Moreover, since these modules are reusable, they can try out the interfaces from Playgrounds, or experiment with other targets and platforms.</p>
</blockquote>
<p><strong>Don’t force teams to do the things in a particular manner</strong>. For example, if you expose a reactive interface from the tools you limit them to follow the same paradigm. <em>What if the developer is not familiar with it?</em> <em>What if that paradigm is not the appropriate one for the developer use case?</em>. Offer them foundational interfaces and let them decide about the patterns that make them most productive.</p>
<blockquote>
<p>With the app modularization, we’re revisiting the interfaces of our networking and storage layers. The old ones exposed reactive observables. Reactive programming ended up everywhere. It also slowed down the onboarding since we had to onboard people in a new paradigm they weren’t familiar with.</p>
</blockquote>
<p>But if developers have freedom, <em>does that mean that they could end up misusing the tools?</em> It could happen, but thankfully you can prevent it by designing <strong>restrictive interfaces</strong>. You have the modifier <code>final</code> for classes and methods, and the <em>access levels</em> to decide whether something should be exposed or shouldn’t. If a developer needs something that a tool doesn’t provide it’ll open a discussion, feature-request like, where developers will discuss how the new feature fits into the tool. GitHub issues are very handy for that, in the same way, users request/propose features using social networks, developers can request/propose features/enhancements using the issues of the repository where the tools are. It’s very important that your team encourages <strong>communication</strong>. We are developers, and to achieve X we know we can take many paths to get it done, no matter if any of them implies workarounding any of the existing tools <em>(for example, by doing some reverse engineering)</em>. If all developers start doing it, we’ll end up with solutions that are supposed to solve problems that are only solving by being workarounded. In that regards, it’s very important that you <strong>actively review PRs</strong> and how they use core solutions.</p>
<p>Work following the <strong>lean principle</strong> as a startup would do with its product:</p>
<ul>
<li><strong>Identify the problem</strong>, collect as much info as possible, see if other teams are also affected and define your success criteria. - Come up with a <strong>first iteration of the solution</strong>, merge it to master and pair on the new solution with the teams. - <strong>Evaluate the success criteria</strong>. If it’s not satisfied, work on a new iteration of the solution until you get something that solves that works for all the interested teams.</li>
</ul>
<p>A solution that works today might not work in a few months. In this, so dynamic ecosystem, many things can happen. In that regards, it’s crucial to define your team <em>KPIs</em> for your work. You could revisit these <em>KPIs</em> from time to time to make sure you are aligned with them. One important <em>KPI</em> could be the teams’ performance: <em>How much time do they spend implementing a new request for the API?</em> <em>How many classes do they need for that?</em> <em>Do they spend a lot of time testing?</em> Don’t expect these KPIs to be easy to quantify. If you work on a feature for a user, you can report events to analytics providers and see the impact that your new feature has on the users. However, If you work on a core solution that is supposed to improve the team performance how do you measure that? One thing that helps a lot is offering <strong>feedback channels</strong>. It can be a pair-programming session, a meeting, or a backlog of issues in a repository. Via these feedback channels, you know if your solution achieves what it’s supposed to achieve. You should be very open to feedback. Most of the times you’ll have to encourage being transparent. When there’s a developer’s effort in the component, people stay away from giving feedback. Why so? Because they think that by giving you feedback might imply that you have to keep working on the solution. And that’s totally fine; that’s part of the iteration process of coming up with the solution. <strong>Listen actively</strong>; it’ll help you to identify when something is not working. Developers will thank you when you help them make their daily work easier.</p>
<p>Working as a core engineer and being able to take decisions about the project architecture allows you to influence other areas of the team. An area that we’ve also been able to influence is the on-boarding of newcomers. When a project gets bigger, the learning curve that they have to go through before they get into speed gets higher. That’s a bit frustrating for them. They have to learn about a lot of components, paradigms, tools, and it can take weeks or months. What if they were able to <strong>influence the code base since the first day</strong>?. Thanks to our modularization project we’ve been able to split the cake into small manageable pieces that include their on-boarding <em>(for example using Playgrounds in Xcode or an example app)</em>. Developers can get on-boarded in any particular area, and when they became interested in other, they can just go through the on-boarding of that area to get familiar with it.</p>
<p><strong>Do you work on tools for other teams and would like to share them here? I’d like to hear about them. Do not hesitate to share them using the comments below or reach out to me via Twitter, <a rel="external" href="https://twitter.com/pepicrft">@pepibumur</a>, or email, <a href="mailto://pedropb@hey.com">pedropb@hey.com</a></strong></p>
<blockquote>
<p>Would you like to work with the SoundCloud iOS in a very challenging and exciting environment? SoundCloud is currently looking for iOS Engineers, check out the <a rel="external" href="https://soundcloud.com/jobs/2016-08-05-ios-engineer-berlin">positions page</a> for engineering to know about the open positions.</p>
</blockquote>
]]></content:encoded>
    </item>
    
    <item>
      <title>Stepping off the social world</title>
      <link>https://pepicrft.me/blog/off-the-social/</link>
      <guid>https://pepicrft.me/blog/off-the-social/</guid>
      <pubDate>Wed, 09 Nov 2016 12:00:00 +0000</pubDate>
      <description>I became addicted to social networks. What&#x27;s addicted for me? Opening apps like Facebook , Twitter and Instagram from time to time and scrolling on their home page up and down for minutes. I was at that point when unconsciously ended up ope…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I became addicted to social networks. <strong>What's addicted for me?</strong> Opening apps like <a rel="external" href="https://facebook.com">Facebook</a>, <a rel="external" href="https://twitter.com">Twitter</a> and <a rel="external" href="https://instagram.com">Instagram</a> from time to time and scrolling on their home page up and down for minutes. I was at that point when unconsciously ended up opening the apps. <em>Do I have free time?</em> Then let's open Facebook. <em>Is the project taking a lot of time to compile?</em> Let's check what's going on on Instagram. A lot of context switching during the day...</p>
<p>Adding up, I became crazy using <a rel="external" href="https://snapchat.com">Snapchat</a> and <a rel="external" href="https://instagram.com">Instagram Stories</a>, posting videos talking about my life, I've done this, and I'll do that, and this weekend I'll be in this other place. Was I trying to feel socially active? Was I trying to be an influencer? I didn't track it but I could say I spent at least 1 hour every day in social networks. Besides the context switching, staying in the loop boosted my ego and made me feel bad sometimes. I travel somewhere, and I have the need for sharing your trip, because why not, everyone is doing it. I had a bad day, and you scroll your Facebook timeline all the way down, and everyone seems happy, why should I feel so bad? These places are not spaces where you usually talk about bad things; these are things that we usually keep for ourselves.I cared more about my social Pedro than the one in the earth.</p>
<p>Moreover, it brought me some anxiety, in particular with Twitter. Many things are going on there, that I felt bad if I wasn't in the loop, and I didn't open Twitter for days. I felt that I'd missed a lot and then spent half an hour reading what I've missed. I also became addicted to reading short pieces of text, status on Facebook, Tweets... When I tried to relax and enjoy reading larger pieces of text, I struggled to keep concentration and get the ideas out of the chapters. Most of the times I couldn't concentrate on the content, and my brain kept thinking about what was going on the Internet.</p>
<p>I then jumped back in time and think about me a few years ago, when I rarely used Twitter, when I didn't open Instagram in weeks, and I didn't care about the updates on Facebook. I had no distraction; I enjoyed more every single thing that I did. I could do some jogging, read a book, or enjoy a dinner with some friends, having my mind present, and in only one context. Because I didn't give a shit about my social presence. It happens to me nowadays, that I try to keep a conversation with someone and it is like trying to talk to a wall, just throwing words out of your mouth that go nowhere. It also happened to me trying to follow someone's speech and not being able to stay concentrated. I felt terrible. I think about all the tools, which are coming out to make people more connected, but they are getting the opposite. I used to think that I was more connected by posting more on Facebook, or by Tweeting about the ultimate tools that I was using as a developer when I wasn't.</p>
<p><strong>Why was I doing it?</strong> From the developer side I was unconsciously trying to find some recognition in the community <em>(Person X has done app Y)</em>. That opens up more opportunities but also some pressure. People set expectations, and you set yourself under pressure to satisfy these expectations. I tried to stop using Twitter, but after a few days, I thought... but all developers are using it, in a few years I'll be unknown if I don't use Twitter, where all the things are taking place. <em>Is there something bad about it?</em> Not really, I enjoyed building apps and tools being unknown. I enjoyed more doing stuff as an unknown developer than as known one. Now I care more about sharing than about doing. I felt that I became a <em>sayer</em> instead of a <em>doer</em>. Communities and companies are misusing the terms <em>good developer</em> and <em>known developer</em> nowadays. I'd like to be more <em>unknown</em>, use Twitter less, and if in a few years someone recognizes me, that he/she does it because of the work that I've done as a developer, not as a Twitter rockstar. Hopefully, newspapers, books and technical blogs will stay with us for a long time.</p>
<p>I wondered the same question for Facebook and Instagram. I mostly use them for my personal stuff. I share the achievements, trips, and the cool things that I do. I use it mostly when I'm travelling. I share the things that I do abroad, waiting for these likes, <em>(or loves)</em> on Facebook. I like when I see people liking the photo and commenting on it. But these things end up leading to ego: <em>"Don't forget to share the cool thing that you're doing right now, either your awesome trip or the food at the fancy restaurant"</em>. When I did show off my ego using these tools I ended up regretting. <em>What if I do focus on the moment itself and forget about sharing it?</em> Yeah, no one will know about your life unless you live in the same city where they live, but trust me, catching up while you grab a beer with your friends is worth it.</p>
<p><strong>I uninstalled these three apps. I don't have that easy way to use them from the phone. Since I did, I've spent more time reading and focusing in things other than the social activity. I also sleep better at night since checking social networks is not the last thing that I do before going to sleep. I'm not saying with that that you should do the same. The problems that I mentioned come from the way I use these tools and not from the tools themselves.</strong></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Be Reactive my friend</title>
      <link>https://pepicrft.me/blog/be-reactive-my-friend/</link>
      <guid>https://pepicrft.me/blog/be-reactive-my-friend/</guid>
      <pubDate>Tue, 12 Jul 2016 12:00:00 +0000</pubDate>
      <description>Article that explains the benefits of reactive programming in the iOS world.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>In a world where data comes from everywhere being reactive when coding your apps could make a huge difference in the user experience. Even though Reactive is becoming more popular across the community the benefits are not clear enough. Entities can trigger events from many places around the app. It can be either from an user action, an application lifecycle or a push notification. These triggers turn into some state changes that our app has to reflect somehow. Some examples could be:</p>
<ul>
<li>Opening a detail view when a push notification is received. - <strong>Push Notification into Navigation State Change</strong> - View reload due to a sync of data in background. - <strong>Data Refresh into a Collection View Reload</strong> - Events from a player, for example new track. - <strong>User action into a Player Controls Update</strong></li>
</ul>
<p>When our code is imperative, we notify the interested entities manually. How many of you have written pieces of code like these in your apps:</p>
<pre><code>// Synchronizing data
apiClient.synchronizeTracks { [weak self] tracks in
 self?.tracks = tracks
 self?.tableView.reloadData()
}

// Player
func loadTrack(track: Track) {
 self.player.instance.loadTrack(track)
 self.playerControls.updateWithTrack(track)
}
</code></pre>
<p>Entities change the state in our <strong>sources of truth</strong> from many points <em>(e.g. tracks in a <code>database</code> or current track in the <code>player</code>)</em>. Think about a player that is playing tracks in background. The player controls are floating in the UI and the user opens a track from a new view controller. <em>What if the developer forgets about updating the controls?</em> Or think about a predictive data sync. For example, we sync the notifications when a push notification is received. How would you update the collection view if you don't know about the notifications view controller from the AppDelegate? (and no... appealing to singletons or inspection is not a good solution).</p>
<p>There’s a clear need to be reactive, react to the things that are happening in your app, no matter who’s triggering them and from where. Being reactive doesn’t mean add one of these reactive libraries in your project as a pod and use it. But design your application to be Reactive. These libraries will help you making things easier and nicer.</p>
<blockquote>
<p>Being <strong>reactive</strong> is about designing your app to react to changes. It requires some effort to set your mindset away from the imperative world.</p>
</blockquote>
<p>I’ll guide you in this post through some common scenarios and explain how to separate the action <em>triggering</em> from the <em>reaction</em>.</p>
<h2 id="databases-and-data-synchronization">Databases and data synchronization</h2>
<p><img src="https://pepicrft.me/blog/be-reactive-my-friend/__GHOST_URL__/images/posts/reactive-database.png" alt="Reactive database" /></p>
<h4 id="scenario">Scenario</h4>
<p>Databases are sources of truth in our apps. They save the data, in most of cases coming from an external <em>API</em>. Since apps want to offer the best user experience, they get sync with the API as the user navigates through the app. <code>viewDidLoad()</code> is the common place where most of developers trigger the data sync. However, there are more places where the data can be sync. Those apps that sync the data predictively do it from places such as background operations or push notifications.</p>
<p>In these cases it’s important that any entity in the app <strong>interested</strong> in that data, gets notified when these syncs take place.</p>
<h4 id="example">Example</h4>
<p>When the <code>StreamViewController</code> is loaded we ask for data synchronization. This event doesn't report anything but it could return an error if we're interested in presenting an alert in that case. When the data is updated in the database we'll be observing it and updating the collection view presenting that new data that has been inserted.</p>
<pre><code>class StreamViewController: UIViewController {
 func viewDidLoad() {
 super.viewDidLoad()
 self.synchronizeStream()
 self.observeStreamTracks()
 }

 func synchronizeStream() {
 // Synchronization logic
 }

 func observeStreamTracks() {
 //TODO
 }
}
</code></pre>
<h4 id="implementation">Implementation</h4>
<ul>
<li>If you're using <code>Realm</code>/<code>CoreData</code> you can use <a rel="external" href="https://github.com/pepicrft/sugarrecord">SugarRecord</a> that provides a <code>StorageObservable</code> object. - There's a Realm reactive extension for RxSwift, <a rel="external" href="https://github.com/RxSwiftCommunity/RxRealm">RxRealm</a> that supports notifications.</li>
</ul>
<h2 id="keychain-and-user-login-logout">Keychain and user login/logout</h2>
<p><img src="https://pepicrft.me/blog/be-reactive-my-friend/__GHOST_URL__/images/posts/reactive-keychain.png" alt="Reactive keychain" /></p>
<h4 id="scenario-1">Scenario</h4>
<p>If we support authentication in our apps we might be saving user's credentials in Keychain. Login is done from the login view and the logout most likely from an account/settings view. When login/logout take place in the app there are some entities that might be interested about session changes in the Keychain, for example, your app navigation and your http client:</p>
<ul>
<li>When the user signs in, you might want to reset the application <code>rootViewController</code> and create the new views hierarchy for authenticated users. The same with the signout. - If you have a http client that holds the user session state you might need resetting the token from that client instance, otherwise you'll be sending requests with the wrong authentication state.</li>
</ul>
<h4 id="example-1">Example</h4>
<p>We subscribe in the <code>AppDelegate</code> to session changes. Since we're only interested in the transition between states, we use the operator <code>distinctUntilChanged</code>. When there's a new <code>.Next(Session?)</code> event sent we update the root view controller according to that.</p>
<pre><code>class AppDelegate {

 func observeUserSession() {
 let sessionObserver = SessionObserver(name: &quot;my-service&quot;)
 sessionObserver
 .map { $0 != nil }
 .distinctUntilChanged()
 .subscribeNext { [weak self] authenticated in
 if authenticated {
 self?.showLogin()
 } else {
 self?.showApp()
 }
 }
 }
}
</code></pre>
<h4 id="implementation-1">Implementation</h4>
<p>Keychain is not KVO compliant so we cannot subscribe to changes at a given keypath. <em>How can we observe it then?</em> You have to proxy the access to the Keychain registering observers there. Whenever the Keychain is accessed through this proxy all the observers are notified if they are concerned about the updated keychain element. It's very important that the access to the keychain is always done via that proxy class, otherwise your observers wouldn't get notifications when the state changes in the Keychain.</p>
<p>The interface would look like this one:</p>
<pre><code>class KeychainRepository {
 static let instance: KeychainRepository = KeychainRepository()
 func save(session session: Session, name: String)
 func clear(name name: String)
 func fetch(name name: String) -&gt; Session?
 func observe(name name: String) -&gt; Observable
}
</code></pre>
<h2 id="userdefaults-and-local-states">UserDefaults and local states</h2>
<h4 id="scenario-2">Scenario</h4>
<p>There's some data that is not persisted in databases for example the user profile or local configuration that is not sync in the API and that is cleaned up once the user removes the app.</p>
<h4 id="example-2">Example</h4>
<pre><code>func viewDidLoad() {
 super.viewDidLoad()
 self.userObserver = UserObserver()
 self.userObserver.rx().subscribeNext { [weak self] user in
 self.avatarImageView.setImage(url: user.avatarUrl)
 }
}
</code></pre>
<h4 id="implementation-2">Implementation</h4>
<p>If we support authentication in our apps we might be saving user’s credentials in Keychain. User signs in from the login view and the logout most likely from an account/settings view. When login/logout take place in the app there are some entities that might be interested about session changes in the Keychain. For example, your app navigation and your http client:</p>
<pre><code>protocol Repository {
 typealias T
 func save(entity entity: T, name: String)
 func clear(name name: String)
 func fetch(name name: String) -&gt; T?
 func observe(name name: String) -&gt; Observable
}
</code></pre>
<blockquote>
<p>I did an implementation that is available on this <a rel="external" href="https://gist.github.com/pepicrft/ba7a1b459634ebf29de0772272b8460b">gist</a>. It defines an <code>UserDefaultsObservable</code> that allows you to subscribe to. To keep the subscription alive you must keep a reference to the observable.</p>
</blockquote>
<h1 id="conclusion">Conclusion</h1>
<p>Our apps are full of these scenarios where triggers and observations are completely separated. In that sense reacting to these triggers would prevent us from imperatively looking for the entities that might be interested in these events. We also decouple synchronization from fetching so if we wanted to replace any of those elements, you could easily do it without affecting the other. Moreover, don't think that being reactive is about using reactive concepts and libraries out of there. You can be reactive as well by subscribing to the <code>NSNotificationCenter</code> or using a <code>NSFetchedResultsController</code>. Libraries such as <code>RxSwift</code> and <code>ReactiveCocoa</code> provide a typed, more stream based solution, with some operators that allows you combining these events before they reach the subscribers.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Micro Features Architecture for iOS</title>
      <link>https://pepicrft.me/blog/microfeatures/</link>
      <guid>https://pepicrft.me/blog/microfeatures/</guid>
      <pubDate>Sun, 10 Jul 2016 12:00:00 +0000</pubDate>
      <description>Organize your app in small features that you </description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>When teams grow, maintaining large codebases can be a big pain in the ass. You end up having a lot of conflicts because when a feature is built up, it relies on horizontal layers and across teams that are shared with other features. One example for an horizontal layer could be the database.</p>
<blockquote>
<p>Have you ever seen yourself in a situation where one of your colleagues modified that layer and bugs came out from other features?</p>
</blockquote>
<p>Companies such as <a rel="external" href="https://www.facebook.com">Facebook</a>, <a rel="external" href="https://uber.com">Uber</a> or <a rel="external" href="https://www.spotify.com">Spotify</a> have their projects organised in small projects that are linked together, maintained by different teams that are responsible of their development, versioning, documentation, testing… Unless the architecture of your project is as atomic as your teams, you’ll end up with more conflicts that you had initially since these teams will end up depending on other teams progress. As there isn’t a lot of information about how these companies are managing it I started thinking about it, and what these atomic features would look like answering questions such as <em>how would the navigation to these features be?, who’d inject the dependencies between features?, would it be possible to share wrappers across these features?…</em></p>
<p>The problem is sort of similar to what happened in backend services. Code bases written with frameworks such as <a rel="external" href="http://rubyonrails.org/">Ruby and Rails</a>, or <a rel="external" href="https://www.djangoproject.com/">Django</a> didn’t scale as teams became bigger. They wound up moving into something you might have probably heard about, <em>”Microservices”</em> <em>(Martin Fowler writes about it <a rel="external" href="http://martinfowler.com/articles/microservices.html"><strong>here</strong></a>)</em>. In that architecture, backend infrastructures are organised in multiple microservices responsible of different areas, for example, one microservice just for the payments, another one for users, one for the search feature… They discover each other and interact between them, <em>for example, if the payments microservice needs to fetch something about the user whose information is provided by another microservice, it will use that microservice instead to fetch that information</em>. These backend microservices are completely atomic, they can use any programming language, internal architecture, dependencies… The only requirement for these atomic microservices is that they provide an accessible interface that other services can consume through network.</p>
<p>Since they tackled the same problems in backend services I started thinking about how the same ideas would apply to an environment other than servers, iOS.</p>
<blockquote>
<p>Would it be possible to build atomic features that could be hooked up within the app?</p>
</blockquote>
<p>It is a big challenge, but what if we could? Features as packages, that implement their own views, models, programming language, business logic... They’d offer a <em>linkable</em> interface and the app responsibility would be just hooking all of them and injecting the dependencies as needed.</p>
<p>On this post, I'll go through some basic definitions and ideas that I came up with about this architectural challenge, establishing analogies with microservices for server environments.</p>
<h1 id="framework">Framework</h1>
<p><img src="https://pepicrft.me/blog/microfeatures/__GHOST_URL__/images/posts/microfeatures-framework.png" alt="framework" /></p>
<p>Features should be atomic, thus, contained in themselves. They should have clearly defined responsibilities and boundaries. In microservices we have instances running on servers, either Ruby on Rails projects, Scala… where the boundaries are defined by the network layer. But what about mobile? <strong>frameworks</strong>. Frameworks are a way to encapsulate your source code, deciding which elements should be accessible, and in essence, defining the interface of your feature in code.</p>
<p>Frameworks should <strong>speak</strong> the same public language. As we can code on <em>Swift/Objective-C/Objective-C++/React Native</em> for iOS we have to ensure that no matter which language they use internally, there’s a contract for the public language. Otherwise the connection between them would be impossible.</p>
<p>It doesn’t necessarily mean every feature has to be one framework. In most of cases it’ll be but it can also be more than one. For example, a <em>Player</em> feature, could be 2 frameworks, a <em>PlayerCore</em> with everything that has to be with the interaction with <a rel="external" href="https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVPlayer_Class/index.html"><code>AVPlayer</code></a> and a <code>PlayerUI</code> offers the <em>View/ViewController</em> that uses the <em>PlayerCore</em> underneath.</p>
<p>If you want to know more about frameworks, I’ve written about them before, but there are also good articles out there where they explain what a framework is in essence, what’s the difference between framework and a Library, and the difference between Static and Dynamic ones. Here you have a list of good references to check out:</p>
<ul>
<li><a rel="external" href="https://pewpewthespells.com/blog/static_and_dynamic_libraries.html">Static and Dynamic libraries</a> - <a rel="external" href="https://www.raywenderlich.com/65964/create-a-framework-for-ios">How to create a framework for iOS</a> - <a rel="external" href="https://hacking-ios.cocoagarage.com/working-with-a-static-library-framework-vs-embedded-framework-9ca7cd77b4f9#.pm3yebkk7">Working with a Static Library/framework vs Embedded framework</a></li>
</ul>
<h3 id="data-source-framework">Data Source framework</h3>
<p>As I pointed out, frameworks should be atomic. However some will access resources that are shared with other frameworks. Just to mention some, the disk space through <a rel="external" href="https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/index.html"><code>NSFileManager</code></a> or the user preferences via <a rel="external" href="https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/"><code>NSUserDefaults</code></a>… We should try the access to be also atomic. <em>How?</em>, organise the resource atomically, providing subspaces in those resources that you access from all your feature frameworks. As an example we could have different databases in different folders inside a <code>Databases</code> root folder:</p>
<pre><code>Databases/
 Player/
 Database.sqlite
 Stream/
 Database.sqlite
</code></pre>
<p>Since frameworks shouldn’t know about where others are saving their data, you might have conflicts accessing/writing that shared resource. You could end up with a non consistent resource structure where each feature has taken its own <em>”portion”</em> of the pizza and used it. <strong>How can we prevent it? Providing access frameworks for these resources</strong></p>
<p>Providing wrappers for accessing these resources, you ensure the consistency when organising the shared resources. A <em>CoreDataframework</em> for example, could guarantee that the structure is the one shown above. Or a <em>Keychainframework</em> that guarantees a proper access to the Keychain from multiple frameworks.</p>
<blockquote>
<p>These wrappers should never be tied to use cases. If we think about CoreData, they shouldn’t provide a data model. This one should be defined and provided externally from the framework using the wrapper.</p>
</blockquote>
<p>Some examples of these frameworks could be:</p>
<ul>
<li>CoreData framework - Network framework - Keychain framework - FileManager framework</li>
</ul>
<p>These frameworks are also useful to avoid the boilerplate setup code that some persistence solutions require, for example CoreData.</p>
<p><img src="https://pepicrft.me/blog/microfeatures/__GHOST_URL__/images/posts/microfeatures-shared.png" alt="Shared microfeatures" /></p>
<h3 id="backend-framework">Backend framework</h3>
<p>A <strong>backend</strong> framework is a framework that doesn't provide an UI interface. In most of cases they'll fetch data from somewhere, apply some business logic and return data back to be consumed. In some other cases they might be input only frameworks, for example, we could have a framework that is responsible for downloading images and persisting them in the disk. The API of that framework would look like this:</p>
<pre><code>// Image Caching framework
class ImageCaching {
 func isCached(url: String) -&gt; Bool
 func fetchCaching(url: String) throws -&gt; UIImage?
}
</code></pre>
<h3 id="ui-framework">UI framework</h3>
<p>A <strong>UI</strong> framework represents a component that your application can navigate to. It could internally include backend components, or have them as a separate framework that would be the backend of your feature. Think about any of your apps, and think about the features users can see. If I take as a example for example SoundCloud, these features would most likely be:</p>
<ul>
<li>Search - Stream - Player - UserProfile - Settings</li>
</ul>
<p>The example below shows two different setups. The one on the left includes everything in the same framework whereas the one on the right separates the UI layer from the backend one:</p>
<p><img src="https://pepicrft.me/blog/microfeatures/__GHOST_URL__/images/posts/microfeatures-ui.png" alt="UI microfeatures" /></p>
<p>UI frameworks must be <em>navigatable</em> <em>(i.e. the application should be able to navigate to them)</em>. We can achieve that by just exposing the <code>ViewController</code> but there's a more interesting approach that doesn't expose any <code>UIKit</code> component but coordinators. Before diving into the idea I'd like to share with you this talk from NSSpain about <a rel="external" href="https://vimeo.com/144116310">Presenting Coordinators</a> that introduces the coordinators idea and inspired me to use them for this architecture.</p>
<p>The idea of coordinator is extracting the navigation from <code>ViewController</code>s and move it to entities called <code>Coordinators</code>. Coordinators are responsible of instantiate your <code>ViewController</code>s and setup everything necesary to navigate to the <code>ViewController</code>. Coordinators build up a tree that you can navigate through, and the only thing they need to navigate is a navigation context, for example a <code>ViewController</code>. They could also set up some information, for example a track identifier. The example below shows how these components would work in practice.</p>
<pre><code>// Player.swift
class Player {
 let storage: Storage
}

// Player+API
extension Player {
 func createQueue(tracks: [PlayerTrack]) -&gt; String
}

// Player+Coordinators.swift
extension Player {
 func coordinator(fromViewController viewController: UIViewController, queueId: String) -&gt; Coordinator
}
</code></pre>
<p>Then let's say we launch the player from the search results <em>(Search framework)</em>:</p>
<pre><code>// Search.swift
class Search {
 let player: Player
 let storage: Storage

 init(player: Player) {
 self.player = player
 self.storage = Storage(model: &quot;Player&quot;)
 self.storage.setup()
 }
}

// SearchResultsCoordinator
class SearchResultsCoordinator {
 weak var search: Search?
 weak var viewController: UIViewController?

 func userDidSelectSearchTrack(track: Track) {
 guard let search = self.search, viewController = self.viewController else { return }
 let player = search.player
 let queueId = self.createQueueFromSearchTrack(track)
 let coordinator = player.coordinator(fromViewController: viewController, queueId: queueId)
 }
}
</code></pre>
<h3 id="schema">Schema</h3>
<p>This is an example of what the architecture would look like in an application such as <a rel="external" href="https://soundcloud.com">SoundCloud</a>. I haven't drawn the dependencies between them but the frameworks that we'd have in each of these layers. The frameworks will vary depending on your application features but you'll probably need an <code>API</code> framework or a <code>Session</code> framework that is responsible to provide the user session to those frameworks that need it, for example <code>API</code>:</p>
<p><img src="https://pepicrft.me/blog/microfeatures/__GHOST_URL__/images/posts/microfeatures-schema.png" alt="Microfeatures schema" /></p>
<h1 id="dependencies">Dependencies</h1>
<p>Some of the modules that are defined require some setup and an instance to be created. Since the might be expensive we cannot be creating module instances from the other modules, but pass the instance instead <em>(we inject the module dependency)</em>. It's exactly the same concept that we use for code but in this case in a higher level and with modules.</p>
<blockquote>
<p>Remember something very important. Your modules should be stateless. Only if needed, instantiate your modules with a setup configuration. And that's all. They should be like a REST APIs, they don't hold any state but send you a representational state of the data that comes from a data source.</p>
</blockquote>
<p>Modules must be designed to be <em>injectable</em>. <strong>What does it mean?</strong> We have to define a module class that is the entry point of our module. We should then think our module API as a class that we instantiate.</p>
<pre><code>// Offline.swift
class Offline {

 // MARK: - Internal

 internal var storage: Storage


 // MARK: - Init

 public init() {
 self.storage = Storage(modeL: &quot;Offline&quot;)
 self.storage.setup()
 }
}
</code></pre>
<p>Since we have extensions we're not forced to implement the entire API in the same Swift file. We could separate it in multiple files and have everything better organized:</p>
<pre><code>// Offline+API.swift
public extension Offline {
 func isTrackOffline(track: Track) -&gt; Bool
 func downloadTrackIfNeeded(track: Track, completion: (error: NSError?) -&gt; Void)
}
</code></pre>
<h1 id="coupling">Coupling</h1>
<p>Compared to microservices where the communication is performed via network in this case modules know about each other and communicate directly calling the methods from their public APIs. As mentioned earlier it requires some dependencies to be injected that leads to a coupling between these modules. Depending on how we handle that coupling, replacing the framework in the future might be a truly pain in the ass. <strong>How can we prevent it?</strong></p>
<ul>
<li>If framework <em>A</em> depends on framework <em>B</em> that exposes an API, <em>B_API</em>. <em>A</em> could define an access protocol for any <em>B</em> framework and could extend <em>B_API</em> to conform that API <em>(using protocol extensions)</em>. Since <em>A</em> then depends on the protocol, if the framework is replaced in the future, the new framework API should be extended as we did with <em>B</em> conforming that protocol. - We could use the <a rel="external" href="https://en.wikipedia.org/wiki/Decorator_pattern"><em>decorator pattern</em></a> and decorate the <em>B</em> instance in new instance that exposes another interface. That new instance interface is define and known by <em>A</em> and it'd behave as a <em>proxy</em>.</li>
</ul>
<p>In either cases we might also avoid the coupling with modelss since other frameworks might expose their own models. As we might not be interested in all the exposed properties we can define a simplified version of the models that we'd use from the framework that is depending on another. These models can expose a constructor that takes the model coming from the other framework.</p>
<h1 id="versions-and-dependency-graph">Versions and dependency graph</h1>
<p>The more frameworks you have the more complex the graph becomes. In that regards, keeping a good versioning system is very important, for example <a rel="external" href="http://semver.org/">semantic versioning</a>. If you are not familiar enough with Semantic Versioning, this is what it states:</p>
<ul>
<li><strong>MAJOR</strong> version when you make incompatible API changes, - <strong>MINOR</strong> version when you add functionality in a backwards-compatible manner, and - <strong>PATCH</strong> version when you make backwards-compatible bug fixes. Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.</li>
</ul>
<p>Used properly, we notify the modules that rely on our module when we might break the communication with our public API due to important changes.</p>
<p>Since multiple frameworks might depend on another one it's very important, when we bump the major version, for all to be aligned with that version bump. Maybe bump a dependency version number, benefit from the new improvements, but also get a broken module because of the change. Big companies have specialized teams for this, they are responsible of ensuring a good connection between all the frameworks within the app and that all the teams are aware about the state of their dependencies.</p>
<h1 id="summing-up">Summing up</h1>
<p>Monolithic projects don't scale when used in big or feature teams. The sooner you tackle these conflicts the more straightforward the transition into modules will be.</p>
<p>This is one approach with some ideas, an example of how to do it but this is not the only ones. Think about your app and think about the components that your app has. You could slice it in very small modules or just give your first steps with a few modules. There are great tools out there that help in this regards. Thanks to <a rel="external" href="https://cocoapods.org">CocoaPods</a> you can define your modules as pods and integrate them using CocoaPods. Or you can just define your projects in the same Xcode workspace and connect the dependencies manually.</p>
<p>As side advantages of this movement as well as having teams and features atomic, your teams could define their own style guidelines, the private language they use, <em>Swift, C++, Objective-C++, React Native,...</em> As long as they offer a generic interface that everyone can access to, it works. If your company can afford it, a good team organization could include a team that ensures consistency in the contracts between these public interfaces and connection between them.</p>
<p>Are you a big company and you are already doing or trying to move into modules? I'd love to hear about you. At SoundCloud we've already started this transition. And amongst all the benefits, we want to be able to have modularized teams, be able to include features writen in languages such as React Native, and experiment with build tools such as <a rel="external" href="https://buckbuild.com/">Buck</a> from <a rel="external" href="https://facebook.com">Facebook</a></p>
<h1 id="thanks-reviewers">Thanks reviewers</h1>
<p>I'd like to thanks people below that helped me reviewing the article:</p>
<ul>
<li><a rel="external" href="https://github.com/frowing">Fran Sevillano</a> - <a rel="external" href="https://github.com/gabornagyfarkas">Gábor Nagy Farkas</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Network Testing - Say hello to Szimpla</title>
      <link>https://pepicrft.me/blog/testing-networking/</link>
      <guid>https://pepicrft.me/blog/testing-networking/</guid>
      <pubDate>Wed, 22 Jun 2016 12:00:00 +0000</pubDate>
      <description>Introduction post for the last library that I&#x27;ve been working on, Szimpla.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><strong>Where does Szimpla come from?</strong> For those who are curious about the naming, I got the name from a famous <a rel="external" href="http://welovebudapest.com/clubs.and.nightlife.1/budapest.s.most.famous.ruin.pub.szimpla.kert">Ruinpub in Budapest</a> I liked the name the first time I heard about it and I decided to use the name for this testing library <em>(later on I discovered that there’s also a <a rel="external" href="http://www.szimpla.de/">Szimpla in Berlin</a>)</em>. Translated from the Hungarian it means <em>“Single”</em> which doesn’t match with what the library is actually doing…😖</p>
<p><strong>What’s Szimpla?</strong> It’s a Swift framework that helps developers testing Networking on their applications.</p>
<p><strong>But.. what’s the purpose?</strong> Although we might provide unit and acceptance tests with our apps, for example, how request factories build the requests <em>(unit tests)</em>, how the application can navigate from one view to the other <em>(acceptance tests)</em>, there’s some stuff that is hard to test with the existing testing approaches &amp; frameworks. That explains why companies like Facebook came up with a <a rel="external" href="https://github.com/facebook/ios-snapshot-test-case"><em>library</em></a> for testing layouts using snapshots, and developers keep building tools, ensuring we don’t leave any area without testing. Szimpla does something similar to what the Facebook library does but instead of snapshotting views, it records requests. <em>The library allows you record all the requests that have been sent during some code execution or while navigating through the app and use the recorded data as expectations for future executions.</em></p>
<p><strong>Where is it useful for?</strong> It’s useful for all the networking stuff whose result has no direct result over the UI, for example Analytics. <em>How many times have you forgotten sending an event, or you just sent it with the wrong parameters and them the analytics team at your company complained about events not being sent or sent with the wrong information?</em> Probably a few times before… One of the reason why these things happen is because we cannot test it with Acceptance Tests since it’s a “backend” functionality and because these network calls are triggered probably from user actions, views life cycles and it’s something we don’t usually test with unit tests. <em>There’s a clear need there, isn’t there?</em></p>
<blockquote>
<p>Inspired by a similar library that we use at SoundCloud for acceptance tests implemented in Frank I came up with a solution more flexible that can be used directly XCTest. Check it out at <a rel="external" href="https://github.com/pepicrft/szimpla">https://github.com/pepicrft/szimpla</a></p>
</blockquote>
<hr />
<h2 id="installing-szimpla">Installing Szimpla</h2>
<p>Thanks CocoaPods! It’s super easy if you’re using CocoaPods with your project. Just add the line for the <a rel="external" href="https://github.com/pepicrft/szimpla">Szimpla</a> dependency:</p>
<p><code>gist:pepibumur/056f9d27d90096f7084fa7f24bdbd3fc</code></p>
<h2 id="defining-the-snapshots-directory">Defining the Snapshots Directory</h2>
<p>Part of the setups including specifying in which directory the requests snapshots should be saved. It’s done via an Environment Variable that has to be defined in the application scheme as shown in the screenshot below:</p>
<blockquote>
<p>If for any reason you forget this step, the test will assert trying to initialize Szimpla.</p>
</blockquote>
<h2 id="using-it-with-acceptance-tests">Using it with Acceptance Tests</h2>
<p>The first time you define the test you should run it recording the requests and saving them locally. Execute your test with record. Once it gets recorded. You can update the recorded requests according to your needs <em>(you can even use regular expression)</em>. Then update the record method to use the validate one. Future tests executions will use the recorded data to match the requests.</p>
<p><code>gist:pepibumur/7bfe2c9bc71298cb2bb02989111b6afd</code></p>
<h2 id="using-it-with-unit-tests-nimble-expectation">Using it with Unit Tests (Nimble Expectation)</h2>
<p><a rel="external" href="https://github.com/pepicrft/szimpla">Szimpla</a> also provides expectations for Nimble. You can apply the same logic to your pieces of code and check if after a given closure is executed, a set of requests have been sent:</p>
<p><code>gist:pepibumur/09cb0838aef77fdd3726fa98271f7b16</code></p>
<hr />
<h2 id="next-steps">Next steps</h2>
<p>I have some ideas in mind to keep improving the library and adding more features. Once developers and companies start using it I guess more will come up. Just mentioning a few of them:</p>
<ul>
<li><strong>Allow custom validators:</strong> The users could provide the own validators. So they could define how to match the recorded requests with the saved requests.</li>
<li><strong>More filters:</strong> The library only provides one filter based on the base URL. New filters would allow the user to filter the requests depending on parameters, headers, …</li>
</ul>
<h4 id="feedback-is-welcome-i-m-looking-forward-to-hearing-from-you-and-improve-the-library-with-your-help-drop-me-a-line-to-pedropb-hey-com-if-you-re-considering-using-it-and-you-have-some-concerns-or-ideas">Feedback is welcome, I’m looking forward to hearing from you and improve the library with your help. Drop me a line to <a href="mailto://pedropb@hey.com">pedropb@hey.com</a> if you’re considering using it and you have some concerns or ideas.</h4>
]]></content:encoded>
    </item>
    
    <item>
      <title>A journey into Frameworks - Le Testing Framework</title>
      <link>https://pepicrft.me/blog/a-journey-into-frameworks/</link>
      <guid>https://pepicrft.me/blog/a-journey-into-frameworks/</guid>
      <pubDate>Tue, 21 Jun 2016 12:00:00 +0000</pubDate>
      <description>One of posts that tells about the migration from a monolithic architecture based in single target to have multiple reusable Frameworks.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’ve been lately focused on architecting the apps in multiple frameworks that are platform independent. I’ve also given [some talks] about it and applied these principles to a personal project, [GitDo]. However, who could benefit most from that architecture that would be SoundCloud. I proposed it internally and started taking the first steps on one direction. Being a so consolidated project used by many users around the world makes things more complicated compared to GitDo, but… let’s accept the challenge, shouldn’t we?</p>
<p>The application was organised in one single application target whose external dependencies were brought with CocoaPods as static libraries. We hadn’t moved yet into Swift so we kept the libraries as static so that we didn’t affect the application launch time. Once we had an idea of how the frameworks stack would look like we designed how the iterations would be. We’d create these frameworks progressively, starting for those at the bottom (foundation frameworks) and going up in the stack. The two big frameworks in the bottom would be <strong>Core</strong> and <strong>Testing</strong>. <strong>Core</strong> would be the framework that includes the Foundation components such as <em>ReactiveCocoa</em>, <em>CocoaLumberjack</em>, <em>Crashlytics</em>, … These are frameworks that are needed from all the layers since we log from all of them, or report errors whenever any is thrown. The brother of this one would be <strong>Testing</strong>. In the same manner, this one would include foundation testing components such as testing libraries like <em>Specta</em>, <em>Expecta</em>, or mocking ones, <em>OCMock</em>, <em>OCMockito</em>. This one would also include any helper class that we created to automate testing tasks that we repeated over an over.</p>
<p>Between these two <strong>Testing</strong> was the first one. I had to redo the setup of this one multiple times until I found the setup that match our needs. We want the Frameworks not to affect the launch time <em>(since a lot of them does)</em>, avoid conflicts when changing between branches and commits, and have a very robust setup that didn’t break with language or IDE updates. These are the setup configurations that we tried and why we decided to move away from them:</p>
<ul>
<li><strong>External dependencies manually fetched into the project and separated in Frameworks</strong>: We fetched the external dependencies manually, put them into its own folder, and created a framework per dependency <em>(plus the Testing one)</em>. We ended up with around 8 Frameworks just only for testing. That setup wouldn’t affect the user launch time since only the Testing targets would be linked against them, but that setup for other Frameworks would make the launch time slower. Moreover the manual fetching caused one of the developers, to be the contributor in the project of these external dependencies code <em>(which is not true)</em>. - <strong>External dependencies manually fetched into the project and one Framework</strong>: Dependencies would still be fetched manually but instead of adding them in separated Frameworks that Testing would link against to, all of them were part of the same Testing framework. We did setup the Testing framework to work with all these dependencies in the same place and it worked pretty well. However, we still fetched the source code of these external dependencies manually. These dependencies would be part of our source code, and we didn’t want that. - <strong>External dependencies with git submodules and one Framework</strong>: This setup is similar to the previous one but instead of adding the external dependencies as part of the project we just fetched them with git submodules.</li>
</ul>
<blockquote>
<p>For those who might wonder we not CocoaPods for all the setup there’s a couple of reason. The first reason is that we’re not going to be versioning for the first iterations of this setup. That makes hard to work with that setup in teams since CocoaPods would be caching versions of the frameworks and wouldn’t take the changes. The second reason is that if we use the <code>use_frameworks</code> flag, it converts all the dependencies into Framework. That would turn into more than 20 Frameworks for the project <em>(And [according to Apple] it shouldn’t be more than 6 Framework if you don’t want to get your app startup time affected)</em></p>
</blockquote>
<h2 id="steps">Steps</h2>
<p>It’s not that hard as it seems, but we are so used to let CocoaPods that we forget about the <em>”what’s behind</em>.</p>
<ol>
<li>Create a Framework. In our case we called it <strong>Testing</strong>. 2. Setup the project to use a [multi-platform configuration file] for that Framework. You should be able to compile the Framework for more than one platform. 3. Fetch the external dependencies that you need using Git submodules. Each dependency should be in a different directory. Add the source code of these dependencies as source files of your Framework. 4. Check the <code>.podspec</code> of these dependencies. Some might need some especial flags or be linked agains a system Framework. In that case, make sure you link your Framework agains these frameworks and add these flags. 5. You might need some macros or custom setup if these external dependencies code is not valid for all the platforms. In that case, fork the dependency and modify these things that prevent you from compiling the Framework for other platforms.</li>
</ol>
<blockquote>
<p>Note: You might find some external dependencies as already compiled Frameworks <em>(e.g. Crashlytics)</em>. In that case, add the Framework as part of the project and link your Framework against these Frameworks. They’ll probably offer a binary per platform. In order to keep your Framework multi-platform you should play with the <em>Frameworks Search Path</em>. You should point that attribute to a different folder depending on the platform:</p>
</blockquote>
<p><code>gist:pepibumur/79ce98a26949e20d526acb201359433b</code></p>
<h2 id="next-steps">Next steps</h2>
<p>Once the <strong>Testing</strong> framework is defined these testing dependencies can be removed from the <code>Podfile</code> and use the Framework instead. It can be easily linking from the application target <em>Build phases</em>. You’ll probably have to refactor some imports because they were importing the external dependencies directly. It becomes simpler thanks to the Framework.</p>
<pre><code>@import Testing;
</code></pre>
<p>The next one in the list: <strong>Core</strong></p>
<h3 id="enjoy-frameworks">Enjoy frameworks!</h3>
]]></content:encoded>
    </item>
    
    <item>
      <title>Being disconnected in a connected world</title>
      <link>https://pepicrft.me/blog/being-disconnected-in-a-connected-world/</link>
      <guid>https://pepicrft.me/blog/being-disconnected-in-a-connected-world/</guid>
      <pubDate>Mon, 20 Jun 2016 12:00:00 +0000</pubDate>
      <description>In a world where social networks are moving relationships to the Internet people is becoming more disconnected.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>We live in a connected world. We all are connected with our mobile phones, computers, social accounts. We spend our time tweeting, posting the photos of our last trip on Facebook, or recording Snapchats to let everyone know what we are doing right now. I watched this TED talk, <a rel="external" href="https://www.ted.com/talks/sherry_turkle_alone_together?language=en"><strong>Connected but alone?</strong></a> while I was having a coffee and it made me think about the way people interact nowadays. How this has changed compared to a few years ago and what does it mean for us, and for the future generations.</p>
<hr />
<h2 id="social-networks">Social Networks</h2>
<p>We don’t know how to live without social networks. It’s a reality. The young generations started this movement and later on, parents, and also grandparents joined it. When we first tried the social revolution it was odd. <em>Why should we be sharing what we are doing every time something happens?</em> No one used it as first, but the more people started using it the more addictive it became. People became interested in it, they could know about other peoples lives and also show off theirs. We got to that point where we needed to share every single thing that happened to us to truly believe it was happening. Your last party, the trip with your friends, your first summer swim, your birthday gifts, … It was <em>(and it is)</em> the perfect place to show off yourself. It <strong>became a race that fed ego and envy</strong> and I’m sure most of you have already felt it <em>(I’m also part of it)</em>. Social networks also became the perfect procrastination place. They are the perfect showcase for people full of ego, for people that feel alone in the real world but full of friends in the social space and for gossip people that love knowing about others people life. Interactions turn into asynchronous.</p>
<p>Moreover, everybody seems <strong>happy on the internet</strong>. We share happiness and turn loneliness and bad things into positiveness. <em>Because people out there cannot see us sad, right?</em> That makes social networks a fake environment. When you get surrounded by such positiveness any negative feeling in your life makes you feel bad. <em>How is it possible that I feel such in a bad mood when everyone around me seems to be so happy?</em> In that regards, I try to stay away from social networks as much as possible. It’s hard since social networks is the only way to reach most of your friends nowadays, and you want be in touch with your friends and family that are remote. It’s very important to use social networks consciously, but I’m the first one being unconscious when it’s about using them. I spend time scrolling down to see what’s new around me, to see who posted what, or who had a trip recently.</p>
<blockquote>
<p>We stopped interacting face to face, your eyes in front of other person’s eyes. Instead, we spend time thinking about how to formulate our thoughts, how to make the other person think about us what we’re not actually feeling.</p>
</blockquote>
<hr />
<h2 id="messaging">Messaging</h2>
<p>Social networks were only the first step. Messaging apps quickly joined to this party. Whatsapp, Facebook Messenger, Hangouts, Snapchat. Each of them trying to offer more than their competitor, videos that can only be seen once, stickers, customised photos,… Social networks like Facebook noticed this was going to be the next big revolution in communications and they acquired Whatsapp paying $22 Billion. People started moving their conversations to these platforms, where you can think about what you are going to reply, where you can use emojis to express yourself and hide yourself behind a screen. People feel more secure when they use these apps because they are not looking at the other person eyes. You can be sharing something which is not what you’re feeling. Only when you talk to that person face by face, can notice these feelings. And that’s what makes communication so special. We’re getting so used to messaging apps that when we have to speak in front of another person we don’t know how to express ourselves.</p>
<blockquote>
<p>It has happened to me trying to express myself in front of another person or a group of people and not being able to say anything. Struggling to convert my ideas into words, to listen to the other person and keep up with the conversation. I had to made some effort to learn back what I forgot.</p>
</blockquote>
<p>It’s hard for me to see how new generations are more and more into mobile phones and social apps. Seeing group of young people hanging out and looking at their mobile phones instead of talking to each other laughing and having fun. It’s also hard to see how my family is too addicted to it. Talking to them means talking about what’s going on on the social world, who married whom, who posted what,… People are forgetting what listening it, what paying attention to a person who is talking is, because when you’re speaking, the other person is thinking about when he/she will get a new Whatsapp or when he/she’ll get a new like on his/her uploaded photo. <strong>Can we be connected in this social revolution?</strong></p>
<ul>
<li>Don’t use your mobile phone when you’re with your friends. Enjoy the beer! And make sure, you all have fun. - If you’re dating a girl/guy, remember, mobile at home! - If your children spend a lot of time with the mobile phones then spend some time teaching them how fulfilling real relationships are. - If you feel like you are scrolling too much on Facebook, think about your finger getting damaged and another cool things that you could be doing instead. - If other person’s life is more interesting than yours then move the focus back to yours because your life is passing.</li>
</ul>
<p>Have social networks affected you or any person around you negatively? Feel free to write a comment commenting how you addressed the problem. It’s up to us to stop this.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Boy Scouts rule with Danger</title>
      <link>https://pepicrft.me/blog/danger-and-boyscout-rule/</link>
      <guid>https://pepicrft.me/blog/danger-and-boyscout-rule/</guid>
      <pubDate>Mon, 23 May 2016 12:00:00 +0000</pubDate>
      <description>Post where I explain how Danger helped us at SoundCloud to apply the programming Boy Scouts rule to our workflow</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><img src="https://pepicrft.me/blog/danger-and-boyscout-rule/__GHOST_URL__/images/posts/boyscouts.jpg" alt="Boy Scouts" /></p>
<p>Some months ago I did introduce <a rel="external" href="https://github.com/danger/danger">Danger</a> in the SoundCloud project. When I first read about it was in Artsy Engineering Blog where Orta explained how they used at Artsy. For those who don't know what Danger is, it's a Ruby tool designed to be run on CI and allows you to execute some checks on your PRs and report the results back to the PR adding a comment. It's like a linting step but that have access to the PR information and send the report back to the PR.</p>
<p>When we started using it, there was no support for plugins <em>(now it has)</em> and we came up with a solution for creating our reusable checks as explained on this post. With the time we've been adding new checks to Danger and so far we have around 12 Danger checks that run every time someone commits something to GitHub. What initially turned out to be a tool for ensuring good code quality and prevent some mistakes to be merged into master has turned into a tool that enforces the famous <a rel="external" href="http://programmer.97things.oreilly.com/wiki/index.php/The_Boy_Scout_Rule"><strong>Boy Scouts Rule for programmers</strong></a>.</p>
<p>If you don't know what the Boy Scouts Rule is about I'll copy &amp; paste it here:</p>
<blockquote>
<p>The Boy Scouts have a rule: "Always leave the campground cleaner than you found it." If you find a mess on the ground, you clean it up regardless of who might have made the mess. You intentionally improve the environment for the next group of campers. Actually the original form of that rule, written by Robert Stephenson Smyth Baden-Powell, the father of scouting, was "Try and leave this world a little better than you found it." &gt; What if we followed a similar rule in our code: "Always check a module in cleaner than when you checked it out." No matter who the original author was, what if we always made some effort, no matter how small, to improve the module. What would be the result? &gt; I think if we all followed that simple rule, we'd see the end of the relentless deterioration of our software systems. Instead, our systems would gradually get better and better as they evolved. We'd also see teams caring for the system as a whole, rather than just individuals caring for their own small little part. &gt; I don't think this rule is too much to ask. You don't have to make every module perfect before you check it in. You simply have to make it a little bit better than when you checked it out. Of course, this means that any code you add to a module must be clean. It also means that you clean up at least one other thing before you check the module back in. You might simply improve the name of one variable, or split one long function into two smaller functions. You might break a circular dependency, or add an interface to decouple policy from detail. &gt; Frankly, this just sounds like common decency to me — like washing your hands after you use the restroom, or putting your trash in the bin instead of dropping it on the floor. Indeed the act of leaving a mess in the code should be as socially unacceptable as littering. It should be something that just isn't done. &gt; But it's more than that. Caring for our own code is one thing. Caring for the team's code is quite another. Teams help each other, and clean up after each other. They follow the Boy Scout rule because it's good for everyone, not just good for themselves. &gt; by Uncle Bob.</p>
</blockquote>
<p>That summarizes with this statement <code>Always leave the campground cleaner than you found it</code>. The problem is that if you don't commit none of the developers in the team would apply it unless there was something that would force them to do it. There is where Danger played an important role for us.</p>
<h3 id="danger-enforcing-boy-scouts-rule">Danger enforcing <em>Boy Scouts rule</em></h3>
<p>Danger provides you with the list of files that have been modified in the PR. We started running the checks against these files and reporting warnings in the project. Some of these checks that we run against new PRs are:</p>
<ul>
<li>Check that there are no <code>TODO</code> comments. - Check if there are header comments. - Check if there are implemented tests. - Check if there are Nullability macros.</li>
</ul>
<p>All these tests are run against <strong>modified files</strong>, and as a result, it warns you to improve these files <em>(even if you are not the original author)</em>. For example:</p>
<ol>
<li>I modify a class method because I have to pass an extra parameter. 2. The file doesn't include Nullability Objective-C macros, <code>NS_ASSUME_NONNULL_BEGIN</code> <em>(worse compatibility with Swift)</em>. 3. I create a PR and Danger will warn me about that modified file not including the macros. 4. I'll take advantage of my changes to add the macros to that file. 5. Voila :tada:, thanks to Danger I improved the project a little bit.</li>
</ol>
<p>Since we started using it at SoundCloud the project has been improving progressively and we're enforcing new good practices every day with new rules. Whenever we feel something can be <em>"Danger Checkable"</em> we implement the check and add it to the list of existing check.</p>
<blockquote>
<p>How do you ensure good practices in your projects?</p>
</blockquote>
]]></content:encoded>
    </item>
    
    <item>
      <title>Automating iOS review tasks with Danger</title>
      <link>https://pepicrft.me/blog/automating-review-tasks/</link>
      <guid>https://pepicrft.me/blog/automating-review-tasks/</guid>
      <pubDate>Wed, 23 Mar 2016 12:00:00 +0000</pubDate>
      <description>Post that explains how to automate review tasks with the help of the tool Danger</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>This week I've been working automating some review tasks at SoundCloud with a tool called <a rel="external" href="https://github.com/danger/danger">Danger</a> from <a rel="external" href="https://github.com/orta/">@orta</a> and <a rel="external" href="https://github.com/KrauseFx">@krausefx</a>. We had some linting tasks in CI that analyzed the code and stopped the whole build process notifying the affected developers about something not matching the project specs. Developers had to go into Jenkins (in our case), check out the build log, fix what was failing, commit and push the changes restarting the pipeline execution. <strong>What if we could report all that handy information and check results directly to GitHub?</strong> That's exactly what Danger tool does. I first heard about it reading this very interesting article from Orta title <a rel="external" href="http://artsy.github.io/blog/2016/03/02/Lazily-Automation/">"Being a Better Programmer When You're Actually Lazy"</a>. Just summarizing what Danger does:</p>
<ol>
<li>You include an extra step in your CI build process that executes danger <code>bundle exec danger</code> 2. Danger reads a file <code>Dangerfile</code> that contains the checks <em>(ruby code)</em>. 3. It exposes a set of useful environment variables like the PR title, the files that changed,... It also exposes methods to report the result of these checks <code>warn()</code>, <code>fail()</code>, <code>message()</code>. 4. Once <code>Danger</code> completes it sends a comment to the opened PR with the results <em>(as you can see in the screenshot below taken from the article mentioned)</em>.</li>
</ol>
<blockquote>
<p>The tool uses the user you specify through a DANGER_GITHUB_API_TOKEN environment variable</p>
</blockquote>
<p><img src="https://artsy.github.io/images/2016-03-02-Lazily-Automation/danger.png" alt="Danger" /></p>
<h3 id="creating-dangers-in-multiple-ruby-files">Creating "dangers" in multiple ruby files</h3>
<p>When I tried the tool I felt that adding all the Ruby logic in a single <code>Dangerfile</code> was going to turn the file into a big mess. <em>What about having a <code>danger</code> folder with all the tasks?</em> Then we could require these tasks from <code>Dangerfile</code> and execute them one after another.</p>
<blockquote>
<p>The steps below show how I ended up doing it. It doesn't mean it's then only way. There're probably some other alternatives. This is the one I tried and that worked with our project structure, keeping all the danger checks in their own folder.</p>
</blockquote>
<ul>
<li>First create a folder <code>danger</code> where all the tasks/checks will be. - Each of these checks represents a ruby file. Its structure would be like this one:</li>
</ul>
<pre><code>require &#39;danger&#39;

module Danger
 module Checks

 # This Danger step checks if the number of line is over a maximum value.
 # In that case it warns the developer
 class PRSize &lt; Base

 def initialize(dangerfile, max_lines)
 @max_lines = max_lines
 @dangerfile = dangerfile
 end

 def execute
 @dangerfile.warn(&quot;This PR is over #{@max_lines} lines of code. Make it smaller or create multiple PRs.&quot;) if @dangerfile.lines_of_code &gt; @max_lines
 end

 end

 end
end
</code></pre>
<p>Where every check inherits from <code>Danger::Checks::Base</code>. That base class defines a base constructor with taking a <code>Danger::Dangerfile</code> instance that contains all the environment variables exposed from Danger, variables like the number of lines of your PR, the new files added,...:</p>
<pre><code>require &#39;danger&#39;

module Danger
 module Checks
 class Base

 attr_accessor :dangerfile

 def initialize(dangerfile)
 @dangerfile = dangerfile
 end

 def execute
 raise &quot;-execute method must be overriden&quot;
 end

 end

 end
end
</code></pre>
<blockquote>
<p>If you want to use <code>warn</code>, <code>message</code>, <code>fail</code> methods and environment variables you can access them from the @dangerfile attribute.</p>
</blockquote>
<p>Then the structure of your <code>Dangerfile</code> would look like this one:</p>
<pre><code>Dir[&quot;./danger/*.rb&quot;].each {|file| require file }

## Constants
MAX_PR_LINES = 500
PINGEABLE_RESOURCES = [
 { regex: /SoundCloud\/Classes\/Player/, username: &quot;pepibumur&quot;, name: &quot;Player&quot;}
]
# Checks
Danger::Checks::PRSize.new(self, MAX_PR_LINES).execute()
Danger::Checks::IncludeSpecs.new(self).execute()
Danger::Checks::Todo.new(self).execute()
Danger::Checks::Ping.new(self, PINGEABLE_RESOURCES).execute()
</code></pre>
<p>These are just some examples of <em>checks</em> that we're using but the options are infinite:</p>
<ul>
<li><strong>PRSize</strong>: Checks if the number of lines in the PR is over a given value. - <strong>IncludeSpecs</strong>: Checks if any new <code>.m</code> file includes unit tests. - <strong>Todo</strong>: Checks if the developer forgot any <code>// TODO</code> somewhere in the code. - <strong>Ping</strong>: Analyzes modified files and notifies developers that might be directly concerned about these changes because they, for example, own the feature whose file has been modified.</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>There're manual processes that are unavoidable, even though, tools like Fastlane &amp; Danger are helping to automate the majority of them. When we're so focused on our projects we don't worry that much about the time we spend in repetitive tasks <em>(since we only think about developin)</em>. The time that we can spend on these tasks can be huge and it's worth to spend some time setting up either <em>Danger</em>, <em>Fastlane</em> and try to automate as many processes as you can.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Marcheta en la vida</title>
      <link>https://pepicrft.me/blog/marcheta-en-la-vida/</link>
      <guid>https://pepicrft.me/blog/marcheta-en-la-vida/</guid>
      <pubDate>Sun, 28 Feb 2016 12:00:00 +0000</pubDate>
      <description>Mi experiencia de haber salido a vivir fuera de España y las lecciones aprendidas</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Volando de vuelta a Berlin, ha sido un fin de semana reconfortante con familia y amigos, de esos que te sirven para cargar las basterías. Llevaba tiempo queriendo escribir sobre la experiencia que ha supuesto salir del país, y lo que ha sido para mí el casi un año que llevo viviendo en Berlín. Era difícil elegir el título para esta entrada, en la que a priori no se ni lo que voy a acabar contando, pero finalmente me vino <em>marcheta</em> a la mente. Aquellos que me conocen, conocen muy bien lo que marcheta significa para mi. Desafortunadamente no se encuentra en el diccionario y lo más parecido es <strong>marchar</strong> <em>(ni qué decir de explicar fuera de España lo que es marcheta)</em>. Marchar significa seguir hacia adelante, puedes marchar en una carrera, y también puedes hacerlo en la vida. También puedes hacerlo de casa, o marchar de fiesta. De marcha, marcheta, y de marchares este último año, un año de marchetas.</p>
<p>Hace casi un año salí a vivir fuera del España, mi vida cambió de un día para otro y decidí que la mejor decisión en aquel momento era <strong>marchar</strong> a otro país. La empresa con la que estaba trabajando por aquel entonces estaba trasladando sus oficinas a Berlín, la novia había decidio poner punto y final a la relación, <strong>¿por qué no?</strong> pensé. Nunca he tenido miedo a las aventuras, vulgarmente me gusta decir que <em>"me ponen palote"</em>, tanto aventuras como retos, y este cambio para mí fue una auténtica aventura.</p>
<p>Cuando alguien me pregunta qué tal vivir en Berlín, o qué tal vivir fuera de casa, no puedo evitar recomendarle a esa persona que si tiene la oportunidad, que no dude en hacerlo. Es apasionante, pero también difícil, echas de menos muchas cosas, pero se compensa con las otras muchas que aprendes: otras culturas, formas de pensar, idiomas, visión del mundo y de la vida. ¡Sal de España! Ahora casi un año después echo la vista atrás, pienso en todo lo aprendido, y todas las aventuras que me gustaría vivir o países a los cuales viajar.</p>
<blockquote>
<p>"Esta es tu vida y se acaba a cada minuto.". El club de la lucha</p>
</blockquote>
<p>La vida es corta, cada oportunidad no aprovechada, es una oportunidad que puede no volver a aparecer. Aprendí a no cuestionarme más de dos veces si hacer o no las cosas, tan pronto como mi cuerpo me pide <em>"marcheta"</em>, yo le doy marcha. Nos acostumbramos a vivir rodeados de inseguridad, también lo hacemos a nuestra zona de comfort, y tenemos miedo de salir de ella. ¿Por qué aprender un idioma si con el que utilizo a diario me es suficiente? ¿Por qué aprender a dibujar si soy técnico? Qué miedo, y ¿viajas a esos sitios sólo? ¿Y sí te pasa algo?.</p>
<p>Son las preguntas que escucho constantemente cuando vuelvo a España, las mismas que yo mismo me hacía hace unos años. Cuando tenía ganas de hacer algo, antes, tenía que responder unas cuantas preguntas, y después buscar aprobación de familia y amigos. Ahora todo es distinto, si tengo ganas de cumplir un sueño, alineo mi vida para conseguirlo, incluso si no tengo tal aprobación. Esta parte es dura especialmente para los padres, que te ven como un loco. A unos padres, no les hace especialmente ilusión ver a un hijo marchar a otro país, ni a unos amigos, perder a uno de la pandilla por largas temporadas, sin emargo es lo que te hace feliz, es tu combustible, <em>¿por qué no hacerlo?</em>.</p>
<h4 id="la-vida-y-sus-caminos">La vida y sus caminos</h4>
<p>Tuve la oportunidad de conocer a un grande del deporte, que admiro un montón, Valenti San Juan. Su vida dio un giro rádical, mucho mayor si cabe que el mio, y encontró en el deporte el motor de su vida. En uno de sus documentales donde cuenta la hazaña de una carrera ciclista en Cuba mostró una cita que me hizo pensar bastante. La cita es de <em>Henry Charles Burowski</em> y enuncia lo siguiente:</p>
<blockquote>
<p>Si vas a intentarlo, ve hasta el final, de lo contrario, no empieces siquiera. Tal vez suponga perder novias, esposas, familia, trabajo, y quizá, la cabeza. Tal vez suponga no comer durante tres o cuatro días. Tal vez suponga helarte en el banco de un parquet. Tal vez suponga la cárcel. Tal vez suponga la humillación. Tal vez suponga desdén, aislamiento... el aislamiento es el premio. Todo lo demás es para poner a prueba tu resistencia, tus auténticas ganas de hacerlo. Y lo harás, a pesar del rechazo y de las ínfimas probabilidades. Y si será mejor que cualqueir cosa que pudieras imaginar. Si vas a intentarlo, ve hasta el final. No existe sensación igual. Estarás sólo, con los dioses, y las noches arderán en llamas. Lllevarán las riendas de la vida hasta la risa perfecta. Es por lo único que vale la pena luchar".</p>
</blockquote>
<p>Me encanta pensar en la vida y las aventuras como caminos, cómo retos que permiten ponerte a prueba y te ayudan a ser mejor persona y a encontrar tus límites. <em>"Commit to your dreams"</em>, o para mis padres, ser un cabezón, este no para hasta que lo consiga. He sufrido inseguridad anteriormente, he buscado validación para cumplir mis sueños, he esperado que muchos factores se alinien para ir a por el sueño, y he dejado cosas por el camido por esa inseguridad. <em>¡Mal!</em> Recórrelo cuando veas la entrada, ve hasta la salida, y sé valiente, comprometido, y deja que tu motivación te lleve.</p>
<p><strong>Aprende a recorrer los caminos sólo</strong>, podrás encontrar compañeros durante la aventura, otros incluso estarán ahí animándote, pero al final eres tú y tus metas. Compáralo con la vida, al final no deja de ser otro gran camino, de unos cuantos años, pero un camino. Gente te motivará en la vida, especialmente la familia, tus amigos estarán ahí para decirte que loco estás, y tu si cabe, te pones más palote de pensarlo. Amigos se quedan por el camino, es normal, otros no están ahí cuando los necesitas, pero aprendes a hacerlo sólo, y no cesas el paso. Es muy difícil aprender a caminar sólo en tus aventuras, pero recuerda, son tus aventuras. Las personas que te quieran, y que quieran lo mejor para tí estarán ahí para darte la energía que necesites. ¡No olvides agradecerlo!:</p>
<ul>
<li>No esperes que alguien te diga de salir a correr para empezar a hacer deporte. Ponte las zapatillas y sal a la calle. - Te gusta relacionarte con más gente y tus amigos no están muy predispuestos, busca actividades y eventos, ve allí y conoce a gente. - ¿Quieres visitar un país y ninguno de tus amigos tiene ganas? Ve a Skyscanner, busca un buen precio, y píllate el billete. No te arrepentirás</li>
</ul>
<h4 id="idioma">Idioma</h4>
<p>Este año viviendo en Berlín ha sido un año de retos en este camino llamado vida. Llegas a otro país, muy ilusionado e inconscientemente acostrumbrado a tu país. Acostumbrado a un idioma, y también a una cultura, al principio sorprende, luego te acabas adaptando, incluso contrastando. ¿Qué nivel de Inglés tienes? B2, respondía yo en España, porque así lo decía un papelito, de un examen llamado First. Supuestamente estás apto para mantener una conversación con cualquier nativo de manera fluida, fluída en España quería decir. Cuando llegué Alemania me sentía un completo incompetente, pues cuando intentaba usar el Inglés para expresar mis sentimientos, mis ideas, o dar mi opinión sentía que no sabía utilizar el idioma. Las primeras veces es duro, eres incapaz de articular dos frases seguidas, y sufres, mucho. Vas aprendiendo a usar verdaderamente el idioma, y a organizar mejor tus ideas para expresarlas con mayor claridad, pensando en el idioma que estás utilizando. Finalmente, ¿por qué no?, intentarlo con otro idioma <em>(para mi todavía un reto pendiente, el Alemán me espera)</em>.</p>
<blockquote>
<p>El idioma es una herramienta muy potente, y en general la comunicación. Cuando no dominas el idioma, te sientes muy indefenso, especialmente en las situaciones en las que tienes que acabar usando gestos para comunicarte.</p>
</blockquote>
<h4 id="comida">Comida</h4>
<p>Aprendes a valorar el cocido de tu abuela, o las paellas del fin de semana. Echas la vista atrás y te recuerdas renegando a tu madre cuando aparecía con un plato de cocido en la mesa. ¡Ya no lo harás más! El Jamón serrano pasa a ser delicatessen, la espetec, sólo en los supermecados más internacionales, y pescado fresco, pasa a no serlo tanto. ¿Tapas? No las conocen, ¿cerveza?, la mejor. Así que si vives cerca de casa y tienes la oportunidad de seguir probando esos platos, saborea cada cucharada como si fuera la última.</p>
<h4 id="amigos">Amigos</h4>
<p>Los encuentros con tus amigos pasarán a ser encontronazos. Cuando vives en la misma ciudad, y los ves todos los días, tus relaciones acaban siendo monótonas. Sin embargo cuando pasas mucho tiempo fuera y vuelves para fechas señaladas, aprendes lo que son auténticas fiestas. Cada vez que vuelvo a España, aunque sea por pocos días, vuelvo cansado, cansado de no haber dormido lo suficiente, pero contento de haber pasado muy buenas noches con tus amigos. O como me gusta llamarlas, noches de "marcheta".</p>
<h4 id="relaciones">Relaciones</h4>
<p>Conoces otra cultura, y te das cuenta de como nos ven a los Españoles <em>(y en parte lo entiendes)</em>. El calor, la alegría, y forma abierta de ser de los Españoles es muy particular. Pasas de eso a una forma de ser más fría, racional y formal. No es nada malo, de hecho enriqueces carácter con ello. También conoces a personas muy interesantes, como bien decía, en el camino personas entran y salen, personas que conoces por trabajo, por la calle, o en situaciones que no esperarías. Personas con las que compartes experiencias, y de las que acabas aprendiendo, así como enseñando. Aprendes a ser más humilde, y tus fallos como persona se hacen más visibles, ¡no somos perfectos!, y siempre estamos a tiempo de mejorar. Te vuelves incluso a encontrar con personas en otras partes del mundo, y compruebas que sí, efectivamente <em>el mundo es un pañuelo</em>, por eso la importancia de cuidar tus relaciones, nunca sabes cómo, ni de qué forma, esa persona aparecerá en el futuro en tu vida.</p>
<h4 id="los-verdaderos-problemas">Los verdaderos problemas</h4>
<p>Viajando, tuve la opurtunidad de coincidir con una compañera de instituto que hacía muchísimos años que no veía. Hablando e la experiencia de vivir fuera, y de todo lo que habíamos aprendido durante esos años, me sorprendío ver la cantidad de elementos en común. En concreto este:</p>
<blockquote>
<p>Es que cuando vuelvo a mi casa y escucho los problemas de mis amigas, me río.</p>
</blockquote>
<p>Porque no somos conscientes de las preocupaciones tan <em>tontas</em> que tenemos cuando estamos cerca de casa hasta que realmente estamos fuera. Es entonces cuando los problemas aparecen, y nos sentimos totalmente indefensos, sin nuestro idioma, sin nuestra familia, solo tú y el problema. Dejas de tener preocupaciones tontas cuando tu chico no te ha escrito desde hace 3 horas, o porque no sabes que ponerte esa noche.</p>
<h2 id="llena-tu-vida-de-experiencias">Llena tu vida de experiencias</h2>
<p>Y para mi sin duda, uno de mis mayores lecciones ha sido aprender la importancia de llenar tu vida de experiencias. He ido deshaciéndome de todos y cada uno de los elementos materiales a los cuales me sentía atado, y he evitado atarme a nuevos:</p>
<ul>
<li><strong>¿Comprarme un coche?</strong> No por ahora, si puedo evitarlo con transporte público y o bicicleta, paso de seguros, revisiones, averías, ... - <strong>¿Casa?</strong> Nada, hipotecas para los bancos. Que no me espere el sueño de las familias Españolas de casarse cuanto antes, comprar una casa tan pronto como se tenga trabajo, porque claro, hay que dejarle algo a los hijos en el futuro, ¿no? - <strong>¿Tres armarios de ropa?</strong> Claro para tener miles de conjuntos posibles. Me deshice de ropa que no necesitaba donándola, y ahora soy feliz con menos de un armario de ropa. Puedo viajar empaquetando lo que necesito en una mochila.</li>
</ul>
<p>¿Dónde invierto parte de mis ingresos? En esas experiencias. Entre las muchas experiencias que puedas tener en la vida, hay una en concreto, que me ha llenado como ninguna otra, <strong>viajar</strong>. <em>Hong Kong, Bali, Pekín, Camboya, Thailandia, Budapest, ...</em> Por mucho que pasen los años nunca podré olvidar cada uno de los momentos vividos en esos viajes. Desearía tener mucho más tiempo libre para poder viajar, pero como no es posible aprovecho fines de semana para salir a cualquier país de Europa y visitar otras ciudades. Mochila a la espalda y con mucha ilusón.</p>
<p>Ahora cada vez que tengo que gastar dinero en algo, me detengo a pensar cual es mi relación con ese algo. Si se trata de algo material, pienso si realmente lo necesito y si puedo prescindir de ese capricho. Si puedo, lo evito, es dinero tirado a la basura. Unos meses después ese algo se deteriorará y abrá pasado a la nada. Y si se trata de gastar dinero para vivir una experiencia nueva y disfrutar del momento, adelante:</p>
<ul>
<li>Un viaje - Unas cervezas con unos amigos. - Visita a alguien que llevas tiempo sin visitar. - Viaje de vuelta a casa a casa. - Inscripción a una maratón. - Unas cenas con una persona querida.</li>
</ul>
<blockquote>
<p>"Lo que hacemos en esta vida, tiene su eco en la eternidad". Gladiator</p>
</blockquote>
<p>La vida continúa, no se donde estaré de aqui a dentro de un año, en qué estaré trabajando, ni siquiera cuales van a ser futuras metas. Sin embargo, tengo una cosa muy clara, estaré disfrutando como un niño donde quiera que esté. Como bien decía <em>"Gladiator"</em>, lo que hacemos en esta vida, tiene su eco en la eternidad, disfrútala, gózala, y ponte bien palote con cada cosa que hagas en ella. No dejes que tus sueños se trunquen por estar atado a algo o a alguien. Vida hay sólo una:</p>
<ul>
<li>¿Te gustó una chica? Díselo. - ¿Y si tengo vergüenza? Te la tragas. - ¿Te apetece viajar? Viaja. - ¿Quieres vivir en otro país? ¿Qué te lo impide? - ¿No te gusta tu trabajo? Busca otro. - ¿Echas de menos a una persona? Reencuéentrate con ella. - ¿Tienes un sueño? Ve a por el. - ¿Y si tienes varios? No dejes que cesen. - ¿No te apoyan? No lo necesitas. - ¿Te dan una patada en el culo? Coje impulso y ponte un casco. - ¿Y si crees que no puedes? Creeme, puedes. - ¿Opinan de tí? ¡Mejor! - ¿No lo hacen? Haz que lo hagan. - Y sobre todo, se feliz y disfruta de lo que te rodea.</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Xcode scripts to rule them all</title>
      <link>https://pepicrft.me/blog/xcode-scripts-that-rule-them-all/</link>
      <guid>https://pepicrft.me/blog/xcode-scripts-that-rule-them-all/</guid>
      <pubDate>Sun, 07 Feb 2016 12:00:00 +0000</pubDate>
      <description>Set of normalized scripts very useful for Xcode projects. Individual contributors will be familiar with them after they clone the project.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><img src="https://pepicrft.me/blog/xcode-scripts-that-rule-them-all/__GHOST_URL__/images/posts/scripts-rule-them-all.png" alt="Scripts" /></p>
<p>I have been recently working on <a rel="external" href="https://github.com/pepicrft/sugarrecord">SugarRecord 2.0</a> and one of the things I tried to do for that version was making it easier for contributors to clone the project and start contributing with it. I realized a few months ago that <a rel="external" href="https://github.com/carthage/carthage">Carthage</a> and <a rel="external" href="https://github.com/reactivecocoa/reactive">ReactiveCocoa</a> had a folder called <code>script</code> with a set of normalized scripts. I cloned these projects, executed the script <code>bootstrap</code> there and I had the project ready to contribute with. Wow! that's awesome.</p>
<p>The idea was great, I copied these scripts cloning them from <a rel="external" href="https://github.com/jspahrsummers/objc-build-scripts">this repository</a> from <a rel="external" href="https://twitter.com/jspahrsummers">@jspahrsummers</a>. He got implemented a set of very reusable scripts for any Xcode project. I've been using them since then. <strong>Why?</strong>:</p>
<ul>
<li>Developers don't need installing dependencies like Fastlane, Bundle Gems, ... Scripts are implemented using bash. - Setup task turns into just one line of code in your console. - You can build all your project shared schemes and use that build script for CI.</li>
</ul>
<p>If you're working on Xcode projects, no matter if they're a company project, an open source library, whatever.. Add them in your project and leave a comment in the <code>README.md</code> explaining how to use them <em>(very straightforward)</em>.</p>
<h3 id="where-does-the-idea-of-normalized-scripts-come-from">Where does the idea of normalized scripts come from?</h3>
<p>This idea comes originally from <a rel="external" href="https://github.com">Github</a>. It was a few weeks ago when googling, I found this <a rel="external" href="http://githubengineering.com/scripts-to-rule-them-all/">blog post</a> from the GitHub engineering team. They realized that thereis a set of repetitive tasks on any project that could be normalized in scripts. The decided to stanrdize these scripts and call it <em>Scripts to Rule Them All</em>. <strong>What a brilliant idea</strong>.</p>
<p>Thanks <em>GitHub</em> for the idea and <em>@jspahrsummers</em> for creating the equivalent version for Xcode projects.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>States - The source of truth</title>
      <link>https://pepicrft.me/blog/states-the-source-of-truth/</link>
      <guid>https://pepicrft.me/blog/states-the-source-of-truth/</guid>
      <pubDate>Thu, 14 Jan 2016 12:00:00 +0000</pubDate>
      <description>Overview of states in iOS apps, how we tipically handle them, current challenges with states and how to overcome them</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I have been these days thinking about how we do manage states in our iOS apps. States are a source of information but also the source of bugs, why? Because we spread states across multiple components, duplicate them, and we forget about considering derived states. Our app shows off unexpected behaviors, and we struggle to find the reason. The user credentials are persisted in the <em>Keychain</em>, so we know whether the user is logged in or not, but our <em>ApiClient</em> also contains that information. Which one should I trust? Are you sure both are synchronizing when any of them changes? I’m sure you miss some. States are a common source of bugs in our apps. There are no silver bullets to solve this problem but multiple approaches out there, programming paradigms, patterns and tricks that can help you with the state simplification.</p>
<h2 id="singletons">Singletons</h2>
<h3 id="an-attempt-to-centralize-state">An attempt to centralize state</h3>
<p>Have you ever wondered why we use singletons for some components in our apps? There are performance reasons, it also provides an instance that can be accessed from any point of your app, and in regard states, it has a reference to a state. The famous <em>ApiClient.sharedIntance()</em> that has information about the access token is a great example. Singletons are great to keep states, as we can access them from anywhere. Nonetheless, we tend to modify its state imperatively without considering that all the consumers of the singleton instance might get into an inconsistent state since they are not subscribed to state changes of the singleton instance.</p>
<blockquote>
<p>Since we don’t subscribe to singleton state changes, we might reach inconsistent states in entities that depend on the singleton state.</p>
</blockquote>
<p><img src="https://pepicrft.me/blog/states-the-source-of-truth/__GHOST_URL__/images/posts/states_1.png" alt="States" /></p>
<h2 id="flux">Flux</h2>
<h3 id="centralized-state-with-propagation">Centralized state with propagation</h3>
<p>If you haven’t seen it yet, I recommend you to watch this two talks:</p>
<ul>
<li>Unidirectional Data Flow in Swift: An Alternative to Massive View Controllers: <a rel="external" href="https://realm.io/news/benji-encz-unidirectional-data-flow-swift/">Link</a> - Flux — Application Architecture for Building User Interfaces: <a rel="external" href="https://facebook.github.io/flux/">Link</a></li>
</ul>
<p>I heard about Flux a few days ago when I watch the talk Realm published on their website. Flux is an architecture originally proposed by Facebook that aims unidirectional data flows in apps to build user interfaces. What’s the core idea of Flux?</p>
<p><img src="https://pepicrft.me/blog/states-the-source-of-truth/__GHOST_URL__/images/posts/states_2.png" alt="States" /></p>
<ul>
<li><strong>States are persisted in stores.</strong> You can have multiple stores in your app depending on how many states you want to have. For example, you can have a state that reflects the app navigation state, or another state that reflects the user session in your app. States would be persisted in two respective stores, <code>NavigationStore</code>, and <code>UserSessionStore</code>. - <strong>Actions fire state changes:</strong> Actions are the source of state changes as side effects. Actions can be view lifecycle events, user actions, … Whenever something can change the store state, that’s an action. They don’t contain information about how the state will change. - <strong>State changes are driven by reducers:</strong> Whenever an action is received, it’s passed to all the reducers registered in the store. A reducer is responsible to given the current status and the action that took place, decide the new state of the store. A store can have multiple reducers. - <strong>States changes are forwarded to subscribers:</strong> When the state of the store changes, it’s notified to multiple subscribers that might be interested in these changes.</li>
</ul>
<p>There are some frameworks that implement the core concepts of Flux for Swift, the most popular one is <a rel="external" href="https://github.com/ReduxKit/ReduxKit">ReduxKit</a> that also offers reactive wrappers.</p>
<p><img src="https://pepicrft.me/blog/states-the-source-of-truth/__GHOST_URL__/images/posts/states_3.png" alt="States" /></p>
<h2 id="reactive-programming">Reactive Programming</h2>
<h3 id="aiming-unidirectional-data-flow">Aiming unidirectional data flow</h3>
<p>In this playground with states moving around, paradigms like Reactive Programming contribute creating harmony. The core idea of Reactive Programming is that information flows through streams from data sources. Streams events can be combined, and manipulated but side effects can never be introduced in the equation. How does it relate to states propagation? Sources of truth, where states are located are the source of these streams. Every time the state changes, the source sends the change through the stream. Interested entities can subscribe to these streams, deciding what to do when the state changes.</p>
<h3 id="how-do-we-move-from-the-imperative-world-to-a-reactive-one">How do we move from the imperative world to a reactive one?</h3>
<p>Some frameworks provide components that are based on notifications when state changes take place:</p>
<ul>
<li><strong><code>CoreData</code>:</strong> <em>NSFetchedResultsController</em> notifies when there are changes in the database. We react to these changes, updating our collection, and inserting, updating, deleting items from a collection/table view. - <strong><code>NSUserDefaults</code>:</strong> We can use <em>NSNotifications</em> to detect when something has changed in user default and then propagate the changes back to the subscribers. - <strong><code>Realm</code>:</strong> It also provides very generic notifications which might not be enough for your use cases <em>(they are working on improving them)</em>. Hopefully, there are libraries like <a rel="external" href="https://github.com/redbooth/RealmResultsController">RealmResultsController</a> that implements the idea of <em>NSFetchedResultsController</em> for Realm.</li>
</ul>
<p>These components could be easily wrapped into <em>Observables</em>, or <em>Signals/SignalProducers</em> if you want to work with Reactive concepts. Once wrapped, you can map, filter, combine, observe on a given <em>scheduler</em>, … The magic of Reactive.</p>
<blockquote>
<p>Reactive is not a requirement for unidirectional data flow design but makes it easier</p>
</blockquote>
<h2 id="data-source-and-states">Data source and states</h2>
<h3 id="performance-implications">Performance implications</h3>
<p>There are some scenarios where it’s impossible to have a single source of truth because of performance reasons. Accessing data sources like databases or <em>APIs</em> is expensive in term of resources consumption. We cannot execute a request to an <em>API</em> for every row in a <em>TableView</em>, or a execute a query against a database every time we render a cell. Those are typical examples where we are forced to duplicate our source of truth and have a cached version that can be quickly accessed <em>(typically in memory)</em>.</p>
<p>Whenever you think about cache the source of truth ask yourself the following question:</p>
<blockquote>
<p>Is it expensive in terms of performance?</p>
</blockquote>
<p>Is it expensive accessing <code>NSUserDefaults</code>? And <code>Keychain</code>? If it isn’t why do we create cached copies and add complexity making sure states are synchronized? Can’t the <em>ApiClient</em> have an accessor to <code>Keychain</code> instead of the copied token that is restored when the app is opened?</p>
<h3 id="examples-of-cached-states">Examples of cached states</h3>
<p>We are forced to cache states in our apps to offer a good experience to our users. Two common scenarios where we cache states are when we’re persisting data from an API in our database since we want the state to be quickly accessed and when we cache a database query results in memory to be presented in a collection view.</p>
<p><strong>Local database caching an API state</strong></p>
<p>The reason for persisting the API state in our local database or storage is to make navigation in the app faster. If we download the user repositories on GitHub and persist them in our database, when the user goes into the repositories view we don’t have to show a hilarious spinner while we are downloading the data. The schema of states would be the following one:</p>
<p><img src="https://pepicrft.me/blog/states-the-source-of-truth/__GHOST_URL__/images/posts/states_4.png" alt="States" /></p>
<p>Deciding when the state is synchronized is crucial for a good user experience. Synchronizing it too often can be bad in terms of performance but synchronizing it not enough times can lead to a bad experience. Once you decide which states are going to be persisted from the API and you have a schema of your app structure, design when the states will be synchronized.</p>
<blockquote>
<p>Designing the data model is as important as deciding when the data model is synchronized with the source of truth which is in the API. Be predictive and make sure the states reflect the real value when the user access them.</p>
</blockquote>
<p><strong>Memory collection caching a local database collection</strong></p>
<p>As I mentioned earlier, due to performance reasons, when the data from a database is accessed we create a cached version in memory that we access to. It means we add a new state to the game, having then the API state, the database state, and our copy in memory of the database state. <em>Three states that has to be synchronized!</em> The schema looks like this one:</p>
<p><img src="https://pepicrft.me/blog/states-the-source-of-truth/__GHOST_URL__/images/posts/states_5.png" alt="States" /></p>
<p>The complexity increases since we need to synchronize two states, the API with the database, and the database with the memory. Plus, the view has to react to the memory copy changes. Since the state is automatically propagated from the presentation layer we have to subscribe to these states and update the view accordingly and trigger the synchronization action.</p>
<h2 id="recommendations">Recommendations</h2>
<p>We cannot avoid states in our apps, but simplify and avoid derived states. There isn’t a perfect solution, synchronization is complex. You cannot ensure that states are perfectly synchronized since synchronization between local and remote states involves network requests <em>(and they can fail)</em>, but at least, follow safe principles that will get us close to the ideal synchronization state. These are some principles that I personally try to follow in my apps:</p>
<ul>
<li><strong>Design where the sources of truth will be:</strong> Where your session will be persisted, where the collections of data will be. And whenever it’s possible, avoid duplicating states. Don’t copy the <code>Keychain</code> user session to an instance in memory, or the user profile persisted in <code>NSUserDefaults</code> to a copy in memory. If there are no performance implications, don’t copy the data. - <strong>Designing when the states are synchronizing is as important as designing the states:</strong> You can have a good states design but they are not properly synchronized. Consequently, the user experience of your app is bad. States synchronization is usually driven by your Application lifecycle and navigation. <em>Be predictive!</em> - <strong>Design unidirectional flows for states propagation:</strong> Don’t move states in multiple directions. Derived states should be generated automatically when the source states change. - <strong>State generation independent from state subscription:</strong> Keep the schema of Flux in mind. With actions states change but nothing else. Any side action is the result of a subscription to these states.</li>
</ul>
<h4 id="i-hope-you-liked-the-article-the-best-solution-for-your-app-depends-on-your-app-itself-its-data-model-its-persistence-solution-find-what-s-the-architecture-that-best-adapt-to-your-problem-and-try-to-keep-the-principles-mentioned-above-in-mind-and-simplify-states">I hope you liked the article, the best solution for your app depends on your app itself, its data model, its persistence solution, … Find what’s the architecture that best adapt to your problem and try to keep the principles mentioned above in mind and simplify states!</h4>
]]></content:encoded>
    </item>
    
    <item>
      <title>Install the last Carthage version on CI services (Travis, Circle, ...)</title>
      <link>https://pepicrft.me/blog/install-last-carthage-ci/</link>
      <guid>https://pepicrft.me/blog/install-last-carthage-ci/</guid>
      <pubDate>Tue, 29 Dec 2015 12:00:00 +0000</pubDate>
      <description>Very simple script to keep your Carthage version updated without depending on Brew.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've lately been working with multiple libraries and integrating them with CI, in particular Travis-CI because these libraries are Open Source. These libraries have dependencies that are resolved and built using <a rel="external" href="https://github.com/carthage">Carthage</a> which is distributed through Github Releases and <a rel="external" href="http://brew.sh">Brew</a>. However, the version in brew does not always match the last version available on Github Releases and your CI providers don't offer the last version either. <strong>What can you do then?</strong>. Get the last version from Github and install it with a very simple script, <em>how?</em>:</p>
<p><code>gist:pepibumur/3e088a936b9b03359af1</code></p>
<p>Use that bash script passing as argument the version of Carthage that you want to install. It'll download the last <code>.pkg</code> available and install it. For example, if we wanted to use it in our <code>.travis.yml</code> script:</p>
<pre><code>language: objective-c
notifications:
 email: false
xcode_project: SugarRecord.xcodeproj
osx_image: xcode7.2
before_install:
 - bash update_carthage.sh 0.11
</code></pre>
<p>Short but useful! Enjoy coding</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Rewriting SugarRecord, 2.0</title>
      <link>https://pepicrft.me/blog/rewriting-sugar-record/</link>
      <guid>https://pepicrft.me/blog/rewriting-sugar-record/</guid>
      <pubDate>Mon, 21 Dec 2015 12:00:00 +0000</pubDate>
      <description>I explain in this post how was the process of rewriting SugarRecord, a CoreData&#x2F;Realm wrapper for Swift.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><a rel="external" href="https://github.com/swiftreactive/sugarrecord">SugarRecord</a> is one of the libraries I'm most proud of. It has currently 1.155 favs and 98 forks on Github and a couple of issues opened. I wrote this library when the first version of Swift was released since I wanted to learn the language and I thought that writing a library could be a great idea for learning.</p>
<h3 id="sugarrecord-1-x-suffering-swift-evolution">SugarRecord 1.x, suffering Swift evolution</h3>
<p>Swift changed very fast with every new version, moreover we didn't have <a rel="external" href="https://cocoapods.org">CocoaPods</a> support yet so all the integration steps were manual. Realm was still giving its first steps and my knowledge about CoreData was quite limited. I had used <a rel="external" href="https://github.com/magicalpanda/MagicalRecord">MagicalRecord</a> and I used it as inspiration to implement the Swift equivalent. The structure was quite similar but taking advantage of Swift features like generics. One of the most difficult things by that time was designing an abstraction layer that could wrap both, <a rel="external" href="https://realm.io">Realm</a> and CoreData simultaneously. The interface of Realm was much more fresh than CoreData and I was trying a to achieve a similar approach with SugarRecord.</p>
<blockquote>
<p>The power of CoreData and Realm but with a nice to use interface.</p>
</blockquote>
<p>I released the first version of SugarRecord and kept updating and adding new features according to developers requests. However, a few months later I had to left the project because I didn't have enough time to invest, I spent most of my time with my full-time job and I was simultaneously working on another project in my free time. I tweeted if someone could be interested in continuing with the project and make it a great reference in the Swift community. With some help a few versions were launched after I abandoned the project but there was a lack of motivation in the team that handed-over the project and it remained outdated for some months. Developers started forking, solving the bugs on their own repositories, and some amount of issues opened in the repository increased.</p>
<h3 id="swift-2-0-time-to-update">Swift 2.0, time to update</h3>
<p>I still had the SugarRecord account active and I saw how people were tweeting about SugarRecord and reporting issues on Github. Swift 2.0 was launched by that time and people were asking for support for that new version. SugarRecord was completely broken in that version and people needed a new version of SugarRecord for their Swift 2.0 projects.</p>
<p><em>"I born that project and helped it growing, couldn't leave it abandoned"</em> I thought, and then took the decision to start working in SugarRecord 2.0. Here's the tweet I published notifying the developers that the next version was in the oven:</p>
<blockquote>
<p>We've started working on SugarRecord 2.0 with Swift 2.0 compatibility and an improved API, stay tuned{" "} <a rel="external" href="https://twitter.com/hashtag/swift2?src=hash">#swift2</a></p>
<p>— Sugar Record (@sugar_record) <a rel="external" href="https://twitter.com/sugar_record/status/635682614012194816">agosto 24, 2015</a></p>
</blockquote>
<p>I decided not to continue with the same codebase which was strongly inspired in MagicalRecord but starting from the scratch. Take all the good practices, new Swift 2.0 features, and problems that developers reported with the previous version and try to do something better, more robust, safe and actively supported. I started working on it. It was a few months of development since I didn't have much time, but I was able to finish it and publish the first version of SugarRecord 2.0 whose features are listed below:</p>
<h3 id="features">Features</h3>
<ul>
<li><strong>Carthage &amp; CocoaPods</strong>: With the first version I had to explain developers how to install it manually. All of them were used to use CocoaPods and it was kind of difficult to do it manually <em>(although it wasn't at all)</em>. When CocoaPods finally launched its version with support for Dynamic Frameworks <em>(yes, it's popular <code>use_frameworks!</code>)</em> I couldn't update because Realm wasn't giving support yet, so had to keep the manual process at least for Realm. With this version 2.0 I could finally give support to CocoaPods, adding the external dependencies like <a rel="external" href="https://github.com/realm/realm-cocoa">Realm</a>, <a rel="external" href="https://github.com/reactivecocoa/reactivecocoa">ReactiveCocoa</a> and <a rel="external" href="https://github.com/reactivex/rxswift">RxSwift</a> as pod dependencies of the library. I also added support to the recently popular dependency manager <a rel="external" href="https://github.com/carthage/carthage">Carthage</a>. Now it's up to you to choose the solution that fits into your project, SugarRecord supports it.</li>
<li><strong>Realm inspired</strong>: These months I've been using Realm more and more and I wanted to inspire the SugarRecord interface in Realm. I built a fluent interface for building fetch requests and also operations methods that you can use to perform saving/updating/deleting tasks. Mapping that API with Realm was relatively easy but it was a bit complicated in case of CoreData. I could manage to solve it creating the concept of <code>Context</code> and <code>Storage</code> that behaves as a proxy class for accessing the database.</li>
<li><strong>Reactive interface</strong>: I've also been playing recently with Reactive Programming and I thought it would be a great idea to expose SugarRecord methods as <code>Observable</code> entities. Then if you're app is based on Reactive, you can have the same paradigm in your data layer, fetch requests and operations turn into <code>Observable</code> entities that are executed once you subscribe to them. I also added <strong>fetch in background</strong> with a fetch method that takes a map function, fetches your entities using a request in background, and return the <em>thread-safe</em> entities to be used from the thread you need <em>(e.g. Main thread for presenting in UI)</em>.</li>
<li><strong>Storage protocol</strong>: Although SugarRecord offers two predefined storages, <code>CoreDataDefaultStorage</code> and <code>RealmDefaultStorage</code> you can add your own. The only requirement is that they conform the protocol <code>Storage</code>. Although the default storage will be enough for the 90% of the cases, you might need something extra that the default storage doesn't provide. You can extend it and add a non-existing functionality. If you come up with a new storage, propose a PR so that we can include it as a <code>Storage</code> of the library.</li>
<li><strong>Fully Tested</strong>: I wanted the library to be robust and the best way to ensure that is through unit tests. I ensured that every of the methods provided behaves as expected and that the designed storages don't throw unexpected errors that might cause instability in developers apps. Thanks to <a rel="external" href="https://github.com/quick/quick">Quick</a> and <a rel="external" href="https://github.com/quick/nimble">Nimble</a> for its great Swift testing and mocking frameworks.</li>
</ul>
<h3 id="things-learned-with-sugarrecord">Things learned with SugarRecord</h3>
<ul>
<li><strong>Developers want an example project:</strong> Event if you fill the README with a lot of examples they want to see a project working where you show all the things they can do with your library. - <strong>Developers don't read</strong>: Use <em>cursive</em>, <strong>bold</strong> or quotes. They won't read, they want to install it using <code>CocoaPods</code> and start using it. You'll find developers that even don't know anything about CoreData and think that the magic of your library is the only thing they have to learn. - <strong>Developers prefer requesting instead of proposing</strong>: It's hard to find developers that want to contribute with your library, if they find a bug they will report it, if they need a feature, they'll ask you for it. They want to be <em>consumers</em> of your <em>product</em>.</li>
</ul>
<blockquote>
<p>With SugarRecord it's the first time I see someone creating an issue that starts with <strong>I need an example project......</strong>. It made me feel like a servant.</p>
</blockquote>
<ul>
<li><strong>Building a team around an Open Source project is not easy</strong>: It's hard to find developers that want to actively contribute with the project, and if you find them it's difficult to keep them as motivated as you are. I couldn't find people that actively continued the first version of 1.0 and I still haven't found the team for the version 2.0. - <strong>Developers will ask you for a lot of features, but you decide</strong>: They want to do everything with your library, but you, designer of code, are the responsible to decide if that requested feature is in the scope of your library. <em>You don't always have to say YES if it doesn't make sense for your library</em>. - <strong>Make it easy:</strong> Try to make everything easy, from the <em>setup</em> to the <em>use</em> of your library. If a developer finds your library and thinks it is too complex for him, he/she won't use it.</li>
<li>Integrate it with the most popular dependency managers. - Design a friendly API. Avoid complexity. - If they ask you doubts about how to use your library, your design can be improved.</li>
</ul>
<blockquote>
<p>SugarRecord is listed in the RxSwiftCommunity webpage after our last update. <a rel="external" href="https://t.co/YCNoeQkdb8">https://t.co/YCNoeQkdb8</a></p>
<p>— Sugar Record (@sugar_record) <a rel="external" href="https://twitter.com/sugar_record/status/678665283813441536">diciembre 20, 2015</a></p>
</blockquote>
<p>SugarRecord is <a rel="external" href="https://cocoapods.org/?q=sugarrecord">available</a> for your Swift projects. If you don't want to save time setting up your CoreData/Realm stack, you can use it. I'm also looking for contributors that want to contribute with the project, help fixing bugs, adding new features, and definitively making SugarRecord better every day. If you're interested, drop me a line <a href="mailto://pedropb@hey.com">pedropb@hey.com</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Functional is about functions (Swift)</title>
      <link>https://pepicrft.me/blog/functional-is-about-functions/</link>
      <guid>https://pepicrft.me/blog/functional-is-about-functions/</guid>
      <pubDate>Tue, 27 Oct 2015 12:00:00 +0000</pubDate>
      <description>Quick introduction to what Functional Programming in Swift is from the simple perspective of functions</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Since Swift 2.0 was launched this term has become very popular. You attend conferences and this is usually the topic most of the people talk about. You see people even struggling for its use in their apps, really overwhelming for it. Why? It’s <strong>something that can be easily done with Swift but it’s not something new</strong> <em>(a lot of languages where already offering fully functional paradigms before)</em></p>
<blockquote>
<p>Ey Pedro! Do you use functional in your apps? I wanna start using it, I’m watching a lot of talks and reading a couple of books. What do you think about? Should I use it?</p>
</blockquote>
<h2 id="maths">Maths</h2>
<p>Functions is not anything new, back in the school we were told that a function is something that has some input arguments or variables and after some operations they return a value. From the Engineer perspective I was told that these was systems or black boxes that depend on an input stream of data and the output only depends on the input in each instance (no feedback cycle systems)</p>
<blockquote>
<p>f(x, y) = x + y</p>
</blockquote>
<p>Notice that when we create a function we’re actually a scope of operations that doesn’t take data out of there, consequently the logic subset is constrained. Thinking about it the concept isn’t complex at all, but… we were given more flexibility when we were told that we could save states under something called classes, voila! OOP</p>
<p><img src="https://pepicrft.me/blog/functional-is-about-functions/__GHOST_URL__/images/posts/black-box.png" alt="Black box" /></p>
<h2 id="object-oriented-programming">Object oriented programming</h2>
<p>We started grouping these functions into something called classes and assigning it a state which is created when and instance of this class is created. We still have functions but they seem to belong now to something and in languages like Objective-C <em>we cannot extract them from its scope (ask a Javascript developer about functions and contexts and you’ll get surprise about what they’re able to do)</em>. We sticked to Object Oriented principles and we set ourselves far from the basic function concept we saw above. Object Oriented programming introduces a grade of flexibility and mutability working with objects and its functions. I’m sure most of you have coded something like this:</p>
<pre><code>class ApiClient {

 // MARK: - Attributes

 var token: String?

 // MARK: - Init

 init(token: String) {
 self.token = token
 }

 // MARK: - Public

 func reset() {
 token = nil
 cancelRequests()
 }

 func execute(request: Request, completion: (Result) -&gt; Void) {
 let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
 dispatch_async(dispatch_get_global_queue(priority, 0)) {
 	let authRequest: Request = self.authenticatedRequest(request)
 	// Execute the request and get the response: let result
 	dispatch_async(dispatch_get_main_queue()) {
 	 completion(result)
 	}
 }
 }

 // MARK: - Private

 func authenticatedRequest(request: Request) -&gt; Request {
 // Authenticating
 }
}
</code></pre>
<p>Let’s analyse the problems the implementation above presents. It’s a typical pattern on mobile apps and I’ve seen lots of workarounds facing different unexpected states that weren’t taken into account when it was implemented <em>(Note: This implementation can be more secure with Swift immutability concepts but I just copied how it would be using the same Objective-C format)</em></p>
<ul>
<li><strong>State mutability:</strong> We have a function that depends on an input value, Request <em>(great!)</em> and also depend on two other variables, the token status and the time <em>(yes, we added asynchronous inside)</em>. We have three time states <em>(before asynchronous, in asynchronous block, and in main thread block)</em> and two variable states <em>(valid / invalid)</em>. Grouping them we have two states for every time instance. Do we usually cover all of them when we implement a function like that? Probably <strong>not</strong>. If our execution reaches any of the states our app won’t know what to do or with treat it as an other existing contemplated case.</li>
</ul>
<p><em>Note: Adding threading logic inside functions adds an extra complexity because by the time these closures are executed the state might have changed.</em></p>
<ul>
<li><strong>External control:</strong> In relation with the previous, this mutability is mostly controlled externally, we end up using a <a rel="external" href="https://en.wikipedia.org/wiki/Singleton_pattern">Singleton</a> pattern used all around the app. When we login we set the token, when we logout, we clean the token. This adds some uncertainty to our internal implementation. What happens if I try to execute the request and someone removed the token, for example resetting the client?</li>
<li><strong>Retain cycles:</strong> I talked about classes as scopes for functions that have a state. When we define functions that use the object state we’re indirectly retaining that scope which means, if that function is in memory, the object that contains the function will be as well. In the example above the GCD asynchronous closure is retaining self to generate authenticated request. Until this closure gets executed ApiEntity is going to be retained by two entities. If for any reason the closure was retained in memory, you’ll be retaining side objects.</li>
</ul>
<blockquote>
<p>This is a common mistake for Objective-C, and most of them even don’t know what’s going on when they’re using reference objects inside blocks. Fortunately Swift solved it pretty well with types and retain level specification when closures are defined.</p>
</blockquote>
<p>I’ve seem the problems above manifesting when the user logouts and you want to reset the state of your static/singleton API client. Things start to behave quite randomly.</p>
<h2 id="functional">Functional</h2>
<p>Let’s bring our function concept and make it simpler. Remember:</p>
<pre><code>func execute(request: Request, session: Session, completion: (Result) -&gt; Void) {
 let authenticatedRequest: (Request, Session) -&gt; (Request) = { request in
 // Authenticates the request
 }
 let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
 dispatch_async(dispatch_get_global_queue(priority, 0)) {
 let authRequest: Request = authenticatedRequest(request, session)
 // Execute the request and get the response: let result
 dispatch_async(dispatch_get_main_queue()) {
 	 completion(result)
 }
 }
}
</code></pre>
<p>The example above have in essence two functions:</p>
<blockquote>
<p>g(request, session) = auth_request</p>
</blockquote>
<blockquote>
<p>f(request, session, completion) = execute(g(request, session), completion)</p>
</blockquote>
<p>We’re not accessing any external scope that retains the state, we’re instead passing all the data needed for this operation as input parameters and even using internal helper functions that in the same way take input parameters and returns data.</p>
<p>As you see functional is not something magic, it’s something that has been always with us, but that being Objective-C developers we forgot and now we have the opportunity to use it again with a better and readable syntax.</p>
<h2 id="namespaces">Namespaces</h2>
<h3 id="where-should-i-place-my-functions">Where should I place my functions?</h3>
<p>With OOP it’s seems easier to organise our code logic, we have models, controllers, presenters, factories, … Each of these entities as its own file and we group them by type or by feature inside the app. But what about organising functions? Where should I have them? You can do it everything as top level entities but you’ll end up messing up the top-level namespace with tons of functions.</p>
<p><strong>Building namespaces with Structs</strong> My suggestion about this is use structs to create namespaces in Swift grouping the functions that are related to the same business logic. For example if you have a set of functions related to network. Group them under Network as shown below:</p>
<pre><code>struct Network {
 static func execute(request: Request, completion: (Result) -&gt; Void)
 static func authenticate(username: String, password: String, completion Result -&gt; Void)
}
</code></pre>
<h2 id="recommendations">Recommendations</h2>
<p>If you’re thinking about using functional approaches in your Swift code but you don’t know how, or what to do don’t worry, it’s not something you have to necessarily do to get your app working, but it’s something definitively will help your code to be more reusable, robust, and stable. From my experience try to keep the following points in mind:</p>
<ul>
<li><strong>Think on problems as functions.</strong> If problems are too big, think about them as small problems combined. - <strong>Swift offers immutability concepts:</strong> Use let variables and avoid unpredictable states. Force yourself to check the state of the variables or copy the values instead of modifying existing values. - <strong>Prefer value to reference types:</strong> When you’ve to model an entity, try to do it first using an struct. Use let attributes in that struct and in case you want a new struct with an attribute changed, create a new struct changing that attribute. Structs offer mutability but again, force yourself to don’t mutate states. - <strong>Be hybrid:</strong> There’s no need to do it everything functional. When you have a bit of experience you’ll understand what your code asks you for.</li>
</ul>
<p>And overall, don’t overwhelm with this concepts. You can also use Object Oriented Programming with Functional safety thanks to Swift immutability concept concepts.</p>
<h2 id="references">References</h2>
<ul>
<li><a rel="external" href="https://www.youtube.com/watch?v=oFlJMkOJz70">Functions, a love story</a> by Josh Abernathy - <a rel="external" href="https://realm.io/news/nacho-soto-functional-reactive-programming/">Functional Reactive Programming in an Imperative World</a> by Nacho Soto - <a rel="external" href="https://www.youtube.com/watch?v=7AqXBuJOJkY">Enemy of state</a> by Justin Spahr-Summers</li>
</ul>
<p>If you are interested also in the Reactive paradigm you can subscribe here <a rel="external" href="https://leanpub.com/functionalreactiveprogrammingswift">https://leanpub.com/functionalreactiveprogrammingswift</a> to a book I’m writing about Functional Reactive Programming with Swift.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Implementing a Mutable Collection Property for ReactiveCocoa</title>
      <link>https://pepicrft.me/blog/implementing-a-reactive-collection-property/</link>
      <guid>https://pepicrft.me/blog/implementing-a-reactive-collection-property/</guid>
      <pubDate>Wed, 14 Oct 2015 12:00:00 +0000</pubDate>
      <description>These are the steps I followed to create a Mutable Collection Property for ReactiveCocoa. Very useful if you want to get events about changes produced in a collection</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I've been recently playing a lot with Reactive, especially ReactiveCocoa. Since they launched the version for Swift I can say I'm like a baby using it in my project. There's something in particular which I use a lot in a MVVM pattern which are properties.</p>
<h3 id="what-s-a-property">What's a property?</h3>
<p>For those who don't know what a Property is in ReactiveCocoa 3/4 it's a custom generic type that encapsulates a variable internally. Why? Because this new variable exposes a <code>SignalProducer</code> that reports changes on this variable as events. That way you can know when the variable value changes and subscribe to these changes using ReactiveCocoa concepts.</p>
<p>Here's an example of a property:</p>
<pre><code>import ReactiveCocoa

let myProperty: MutableProperty = MutableProperty(&quot;&quot;)
myProperty.producer.startWithNext {(newValue) in print(&quot;This is my new value \(newValue)&quot;)}
myProperty.value = &quot;yai!&quot;
</code></pre>
<p>As you can see we in the example above the property has a producer that we can subscribe to, and it sends new values of that property when the value changes. In that case we're updating the value to <code>yai!</code> and then the subscriber is printing that value.</p>
<h3 id="types-of-properties">Types of properties</h3>
<p>ReactiveCocoa offers currently three types of Properties that cover most of the cases where we'll need to this pattern and all of them conform the same protocol:</p>
<pre><code>public protocol PropertyType {
	typealias Value
	var value: Value { get }
	var producer: SignalProducer { get }
}
</code></pre>
<ul>
<li><strong>ConstantProperty</strong>: Kind of property that doesn't mutate its value once it's initialized. The main advantage <em>(in my opinion)</em> on using this kind of property is the fact that you can connect it with other ReactiveCocoa components.</li>
<li><strong>PropertyOf</strong>: It's a kind of property that once created doesn't allow the modification of it's value externaly. You can only subscribe to the changes of this property that are sent from another Signal/SignalProducer or even another property. Consequently this kind of property can be initialized using these three components:</li>
</ul>
<pre><code>public init(_ property: P)
public init(initialValue: T, producer: SignalProducer)
public init(initialValue: T, signal: Signal)
</code></pre>
<ul>
<li><strong>MutableProperty</strong>: Compared with the previous property in this case you can update the property value after being initialized and in the same way all these changes will be propagated to the producer subscribers.</li>
</ul>
<h3 id="properties-in-mvvm-pattern">Properties in MVVM pattern</h3>
<p>Properties are very useful in the MVVM pattern because it allows us to detect changes int hese properties values and then update the view according to these changes. For example, imagine the following situation:</p>
<pre><code>class ProfileView: UIView {
	// MARK: - Attributes
	let avatarView: UIImageView = UIImageView()
	let viewModel: ProfileViewModel

	// MARK: - Constructors
	init(viewModel: ProfileViewModel) {
		self.viewModel = viewModel
		setupObservers()
	}

	// MARK: - Setup
	private func setupObservers() {
		self.viewModel.avatarImage.startWithNext { [weak self] (avatarImage) in
			self?.avatarView.image = avatarImage
		}
	}
}

class ProfileViewModel {
	// MARK: - Attributes
	let avatarImage: MutableProperty = MutableProperty(UIImage())
}
</code></pre>
<p>We want to update the avatar image in the ProfileView when we get the image from somewhere, no matter the source. Then we would define our Profile view ViewModel that includes that <code>MutableProperty</code> of type <code>UIImage</code>. From the view we subscribe to that property and when there's a new image we just set it to the <code>UIImageView</code>. Data source and its use in the layout is fully decouple. The view doesn't know where the data comes from, the image might come from a local cache, from a web request, from the camera... It just has to know how to set that image in the view. Great right? You can extend that to more views around the app and for more types of properties and then you can have your views <em>"synchronizes"</em> with the data source.</p>
<blockquote>
<p>There's also a great avantage when working with ReactiveCocoa properties and is the fact tat you can use Reactive concepts like for example applying functional operators and combine multiple properties in a single one.</p>
</blockquote>
<p>In the example above, we could for example define a map function with the following format:</p>
<pre><code>func addBadge(badgeConfig: BadgeConfig)(image: UIImage) -&gt; UIImage {
	// Add badge logic
}
</code></pre>
<p>Then have a new property in the view model</p>
<pre><code>lazy var avatarImageWithBadge: MutableProperty = {
	PropertyOf(avatarImage.value, producer: avatarImage.producer |&gt; map(addBadge(myBadgeConfig)))
}()
</code></pre>
<h3 id="collection-property">Collection property</h3>
<p>When you work with collections in your view it's very complicated to have granularity with these properties deteting what really changed in the collection. I noticed I ended up calling <code>reloadData()</code> method in the table/collection view and forcing a relayout of all the elements in the view. Not good performance right? Components like the NSFetchedResultsController were designed to avoid this things but in this case the component is extremly coupled to CoreData, if you want to use it for example with your custom collections you have to look for a custom implementation <em>(I don't have any in mind right now)</em> that proxies collections operations and notifies different observers about these operations like insertion, deletion, update, passing the index back where these operations where executed.</p>
<blockquote>
<p>What if we had this approach based on ReactiveCocoa, using Properties? Let's try to develop a MutableCollectionProperty</p>
</blockquote>
<p><em>Note: I've created a repository where this new component has been implemented, <a rel="external" href="https://github.com/gitdoapp/RAC-MutableCollectionProperty">https://github.com/gitdoapp/RAC-MutableCollectionProperty</a>. You can clone the repository and try it on your environment</em></p>
<h3 id="rac-mutablecollectionproperty">RAC-MutableCollectionProperty</h3>
<p><code>MutableCollectionProperty</code> is a ReactiveCocoa property that notifies about the changes that are produced in an internal collection. It exposes Swift array methods to modify collections in order to redirect these changes to the attached subscribers as shown in the example below:</p>
<pre><code>let property: MutableCollectionProperty = MutableCollectionProperty([&quot;test1&quot;, &quot;test2&quot;])
property.changesProducer.startWithNext { [weak self] next in
 case .StartChange:
 self?.tableView.beginUpdates()
 case .Insertion(let index, let element):
 self?.tableView.insertRowsAtIndexPaths([NSIndexPath(row: index, section: 0)], withRowAnimation: .Automatic)
 case .EndChange:
 self?.tableView.beginUpdates()
 default: break
}
property.append(&quot;test3&quot;)
property.append(&quot;test4&quot;s)
</code></pre>
<p>Every sequence of changes is preceded by an event <code>StartChange</code> and ends with a <code>EndChange</code>. It allows multiple changes together and set the view which is going to reflect these changes in an "update" state. The methods exposed by the property are:</p>
<pre><code>public func removeFirst()
public func removeLast()
public func removeAll()
public func removeAtIndex(index: Int)
public func append(element: T)
public func appendContentsOf(elements: [T])
public func insert(newElement: T, atIndex index: Int)
public func replace(subRange: Range, with elements: [T])
</code></pre>
<p>You can get this component from <a rel="external" href="https://github.com/gitdoapp/RAC-MutableCollectionProperty">here</a> and use it with ReactiveCocoa on your projects. I've already proposed the feature to the ReactiveCocoa team on this <a rel="external" href="https://github.com/ReactiveCocoa/ReactiveCocoa/pull/2485">PR</a> still waiting for response :).</p>
<p>If you're interested on Reactive paradigms and you want to keep learning, I'm currently writing about about the use of Reactive in Swift apps using ReactiveCocoa. You follow the status <a rel="external" href="https://leanpub.com/functionalreactiveprogrammingswift">here</a></p>
<blockquote>
<p>If you found any bug or you would like to comment something about Reactive or this port in particular, feel free to drop me a line, <a href="mailto:pedropb@hey.com">pedropb@hey.com</a>. We're using this an another Reactive concepts on <a href="https://pepicrft.me/blog/implementing-a-reactive-collection-property/www.gitdo.io">GitDo</a></p>
</blockquote>
]]></content:encoded>
    </item>
    
    <item>
      <title>Programación Reactiva en Swift: Parte 1, Introducción</title>
      <link>https://pepicrft.me/blog/programacion-reactiva-swift-parte-1/</link>
      <guid>https://pepicrft.me/blog/programacion-reactiva-swift-parte-1/</guid>
      <pubDate>Sun, 09 Aug 2015 12:00:00 +0000</pubDate>
      <description>Con la llegada de Swift y la introducción de interesantes operadores, conceptos funcionales, y la seguridad de tipos el paradigma de programación reactiva ha cobrado especial importancia en el desarrollo de apps. En comparación con la progr…</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Con la llegada de Swift y la introducción de interesantes operadores, conceptos funcionales, y la seguridad de tipos el paradigma de programación reactiva ha cobrado especial importancia en el desarrollo de apps. En comparación con la programación imperativa a la que la mayoría de desarrolladores estamos acostumbrados <em>(yo incluido)</em> programar de forma reactiva consiste en modelar los sucesos que tienen lugar en el sistema como un conjunto de <em>eventos</em> que son enviados a través de un “stream” de datos. El concepto es bastante sencillo, y aunque no todos los sucesos tienen carácter de <em>stream</em>, pueden acabar siendo modelados como tal. Desde acciones que realiza el usuario sobre la UI, hasta la información que proviene del framework de localización.</p>
<p>Todas las librerías que encontramos hoy en día si echamos un vistazo en Github tratan de modelar todos los conceptos reactivos a través de una serie componentes y operadores para manipular y procesar los eventos. La diferencia entre ellas es principalmente la sintaxis y el nombre que usan para los componentes. Algunas de ellas incluso añaden operaciones como por ejemplo de <em>retry</em>. Encontramos librerías como <a rel="external" href="https://github.com/ReactiveCocoa/ReactiveCocoa">ReactiveCocoa</a> que recientemente ha actualizado toda su API para adaptarse a las ventajas que Swift aporta como lenguaje, o <a rel="external" href="https://github.com/ReactiveX/RxSwift">RXSwift</a> cuya base es ReactiveX disponible para otros lenguajes como Java o Javascript.</p>
<blockquote>
<p>Si tienes curiosidad en el repositorio de <a rel="external" href="https://github.com/ReactiveX/RxSwift">RXSwift</a> encontrarás una tabla donde comparan RXSwift con el resto de alternativas para Swift.</p>
</blockquote>
<p><img src="https://pepicrft.me/blog/programacion-reactiva-swift-parte-1/__GHOST_URL__/images/posts/reactive_sream.png" alt="Reactive stream" /></p>
<h2 id="patrones-de-observacion">Patrones de observación</h2>
<p>Cuando empecé a introducir los conceptos reactivos una de mis primeras inquietudes fue entender qué patrones similares había estado usando hasta ahora, que problemas presentaban, y de qué forma la programación reactiva ayudaba o facilitaba estos patrones. La mayoría de ellos los usas a diario:</p>
<h3 id="kvo">KVO</h3>
<p>Extensivamente usado en Cocoa. Permite observar el estado de las properties de un objeto determinado y reaccionar antes sus cambios. El mayor problema de KVO es que no es fácil de usar, su API está demasiado recargada y todavía no dispone de una interfaz basada en bloques (o closures en Swift)</p>
<pre><code>objectToObserve.addObserver(self, forKeyPath: &quot;myDate&quot;, options: .New, context: &amp;myContext)
</code></pre>
<h3 id="delegados">Delegados</h3>
<p>Uno de los primeros patrones que aprendes cuando das tus primeros pasos en el desarrollo para iOS/OSX ya que la mayoría de componentes de los frameworks de Apple lo implementan. <em>UITableViewDelegate, UITableViewDataSource</em>, … son algunos ejemplos. El principal problema que presenta este patrón es que sólo puede haber un delegado registrado. Si estamos ante un escenario más complejo donde con una entidad suscrita no es suficiente el patrón requiere de algunas modificaciones para que pueda soportar múltiples delegados.</p>
<pre><code>func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -&gt; UITableViewCell {
 return UITableViewCell()
}
</code></pre>
<h3 id="notificaciones">Notificaciones</h3>
<p>Cuando es complejo aproximarnos al componente fuente del evento para <em>subscribirnos</em> se usa el patrón que consiste en el envío de notificaciones. ¿Conóces NSNotificationCenter? CoreData lo utiliza por ejemplo para notificar cuando un contexto va a ejecutar una operación de guardado. El problema que tiene este patrón es que toda la información enviada se retorna en un diccionario, <em>UserInfo</em>, y el observador tiene que conocer previamente la estructura de este diccionario para poder interpretarlo. No hay por lo tanto seguridad ni en la estructura ni en los tipos enviados.</p>
<pre><code>NSNotificationCenter.defaultCenter().addObserver(self, selector: &quot;contextWillSave:&quot;, name: NSManagedObjectContextWillSaveNotification, object: self)
</code></pre>
<blockquote>
<p>Las librerías reactivas disponibles actualmente ofrecen extensiones para pasar de esos patrones al formato reactivo. Desde generar señales para notificaciones enviadas al NSNotificationCenter, como para detectar los taps de un UIButton.</p>
</blockquote>
<h2 id="ventajas-de-programar-de-forma-reactiva">Ventajas de programar de forma Reactiva</h2>
<p>La programación reactiva tiene grandes ventajas usada en esos ámbitos donde es bastante directo aplicar el sentido de stream. Como bien comentaba al comienzo, todo puede ser modelado como un stream, y podrías de hecho tener un proyecto completamente reactivo pero bajo mi punto de vista, acabarías teniendo una compleja lógica de generación de streams que acabará dificultando la lectura del código.</p>
<blockquote>
<p>Con la programación Reactiva sucede algo similar a la programación Funcional. Se trata de un paradigma de programación que ha tenido un gran impulso en el desarrollo de iOS/OSX con la llegada de Swift pero no es necesario agobiarse y sentir una presión inmensa por migrar proyectos hacia esos paradigmas. Usa estos en tus proyectos a medida que te vayas sintiendo cómodo y notes que tu proyecto te los pide en determinadas partes. ¡Eras feliz sin ellos!, ahora puedes serlo incluso más, pero con tranquilidad…</p>
</blockquote>
<p>Después de unos meses usando <a rel="external" href="https://github.com/ReactiveCocoa/ReactiveCocoa">ReactiveCocoa</a> en mis proyectos, especialmente en la parte relativa a la fuente de datos (local &amp; remota) he percibido una serie de ventajas:</p>
<ul>
<li><strong>Seguridad de tipos</strong>: Gracias al uso de genéricos podemos tener validación de tipos a nivel de compilador y evitar tener que estar trabajando con tipos genéricos como <em>AnyObject</em> o <em>NSObjects</em>. - <strong>Facilita la manipulación de datos</strong>: Los eventos recibidos a través de los streams pueden ser mapeados, filtrados, reducidos. Gracias al uso de funciones definidas podemos aplicar infinidad de operaciones sobre los eventos. - <strong>Subscripción en threads</strong>: Independientemente de la gestión interna de threads que pueda llevar a cabo la ejecución de un stream <em>(por ejemplo, una petición web)</em>, podemos indicar en qué thread subscribirnos para escuchar las respuestas. La forma de indicar el thread de subscripción se traduce en una simple linea de código. - <strong>Fácil composición y reusabilidad:</strong> Los streams pueden ser combinados de infinitas formas (gracias a los operadores que los propios frameworks facilitan). Además podemos generar los nuestros propios de forma que podamos obtener streams de eventos a partir de una combinación de otros muchos. - <strong>Bindeado de datos:</strong> Podemos conectar todos los eventos que llegan a través de un stream por ejemplo con una colección de forma que nuevas colecciones que lleguen en formato de eventos actualizarán la colección <em>“bindeada”</em>. De la misma forma por podemos actualizar una property de un elemento de UI con eventos recibidos. - <strong>Gestión de errores:</strong> Por defecto los frameworks reactivos dan la opción de reintentar la operación fuente del stream en el caso de fallo. Por ejemplo, si un stream recibe la respuesta de una petición web y queremos que está se reintente en el caso de fallo podemos usar el operador y la petición se volverá a ejecutar:</li>
</ul>
<pre><code>NSURLSession.sharedSession().rac_dataWithRequest(URLRequest)
 |&gt; retry(2)
 |&gt; catch { error in
 println(&quot;Network error occurred: \(error)&quot;)
 return SignalProducer.empty
 }
</code></pre>
<ul>
<li><strong>Simplificación de estados:</strong> Debido al hecho de que la información se modela en un stream <em>unidireccional</em>. El número de estados que puedan introducirse se reduce simplificando la lógica de nuestro código.</li>
</ul>
<h2 id="reactive-cocoa-aunque-para-swift-podamos-encontrar-varios-frameworks-que-tratan-de-modelar-todo-el-paradigma-reactivo-a-traves-de-una-serie-de-componentes-y-operadores-los-siguientes-posts-estaran-basados-en-reactivecocoa-la-principal-diferencia-de-reactivecocoa-con-el-resto-es-que-este-no-se-trata-de-un-port-de-la-libreria-original-de-microsoft-rx-sino-que-implementa-su-propia-api-mas-sencilla-y-cercana-a-las-convenciones-cocoa">Reactive Cocoa Aunque para Swift podamos encontrar varios frameworks que tratan de modelar todo el paradigma reactivo a través de una serie de componentes y operadores, los siguientes posts estarán basados en <a rel="external" href="https://github.com/ReactiveCocoa/ReactiveCocoa">ReactiveCocoa</a>. La principal diferencia de ReactiveCocoa con el resto es que este no se trata de un port de la librería original de <a rel="external" href="https://msdn.microsoft.com/en-us/data/gg577609.aspx">Microsoft (Rx)</a> sino que implementa su propia API, más sencilla y cercana a las convenciones Cocoa.</h2>
<p>Este es el primero de una serie de posts de introducción a la Programación Reactiva donde además detallaremos el uso de la misma en el modelado de las fuentes de datos (API, y local). Todos serán recopilados en este libro <a rel="external" href="https://leanpub.com/programacionreactivaenswift">https://leanpub.com/programacionreactivaenswift</a> que actualmente estoy escribiendo y qué publicaré en unos meses.</p>
<p><strong>En el siguiente post realizaré una introducción a los componentes de Reactive Cocoa.</strong></p>
<h3 id="recomendacion">Recomendación</h3>
<p>En el siguiente <a rel="external" href="https://gist.github.com/staltz/868e7e9bc2a7b8c1f754">enlace</a> encontrarás una interesante explicación de la programación Reactiva con ejemplos en Javascript.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Paginated API requests using Functional Reactive in Swift</title>
      <link>https://pepicrft.me/blog/paginated-api-requests-using-functional-reactive-in-swift/</link>
      <guid>https://pepicrft.me/blog/paginated-api-requests-using-functional-reactive-in-swift/</guid>
      <pubDate>Thu, 18 Jun 2015 12:00:00 +0000</pubDate>
      <description>Reactive is magic, transform your API responses into streams of data and you&#x27;ll se how easy is to build for example paginated API requests</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I’ve been playing the days with Reactive Cocoa. I fell in love with that programming paradigm. I had heard about it before but hadn’t stopped to play a little bit with it. Although it might be scary at first, and most of the concepts are difficult to understand when you first take a look at them. The more you get familiarized with it the more you think in term of streams.</p>
<p>In order to practice a little bit with reactive programming I implemented an API client offering a public reactive interface. That client has methods that instead of using blocks to notify the completion of the API request, return a signal which is executed when someone subscribes to that signal. That API client pointed to an API that offered paginated responses, i.e. having execute different requests to get all the resources if the results number is higher than the page limit.</p>
<p>Taking advantange of the reactive approach of the client I implemented that paginated method and made it resusable for any client independent from the http framework you are using. Let's see how I did it:</p>
<pre><code>typealias PaginatedRequest = (page: Int, pageLimit: Int) -&gt; RACSignal

internal func rac_paginatedSignal(initialPage: Int, pageLimit: Int, requestSignal: PaginatedRequest) -&gt; RACSignal {
 var currentPage = initialPage
 let nextSignal = { () -&gt; RACSignal in
 let signal = requestSignal(page: currentPage, pageLimit: pageLimit)
 currentPage = currentPage + 1
 return signal
 }
 var subscribeNext: ((RACSubscriber!) -&gt; Void)?
 subscribeNext = { (s: RACSubscriber!) -&gt; Void in
 nextSignal().subscribeNext({ (response) -&gt; Void in
 if let items = response as? [AnyObject] {
 for item in items {
 s.sendNext(item)
 }
 if items.count == pageLimit {
 subscribeNext!(s)
 }
 }
 else {
 s.sendError(NSError(domain: &quot;invalid.response&quot;, code: -1, userInfo: nil))
 }
 }, error: { (error) -&gt; Void in
 s.sendError(error)
 }, completed: { () -&gt; Void in
 s.sendCompleted()
 })
 }
 return RACSignal.createSignal({ (subscriber) -&gt; RACDisposable! in
 subscribeNext!(subscriber)
 return nil
 })
}
</code></pre>
<h2 id="breaking-down">Breaking down</h2>
<ul>
<li><strong>PaginatedRequest</strong>: We define that typealias which represents a function that takes the page number and the page limit and returns the signal. If someone subscribes to that signal it'll execute the request and return the results or an error.</li>
</ul>
<pre><code>typealias PaginatedRequest = (page: Int, pageLimit: Int) -&gt; RACSignal
</code></pre>
<ul>
<li><strong>Paginated request signal generator</strong>: The paginated signal generator takes three parameters, the <strong>initialPage</strong>, the <strong>pageLimit</strong> and the <strong>PaginatedRequest</strong> and returns the signal. That signal encapsulates the iteration through all the pages and send the collection results as stream items.</li>
<li><strong>Next signal generator</strong>: That closure is the responsible to return the signal associated to the next page. The function context has a variable to keep a reference of the current page and every time this method is called, that counter is increased by 1. It uses the <em>PaginatedRequest</em> closure.</li>
</ul>
<pre><code>var currentPage = initialPage
let nextSignal = { () -&gt; RACSignal in
 let signal = requestSignal(page: currentPage, pageLimit: pageLimit)
 currentPage = currentPage + 1
 return signal
}
</code></pre>
<ul>
<li><strong>Subscribe next</strong>: The approach uses recursive subscribing to the next signal and passing the subscriber through. Subscribe next closure takes the source subscriber and depending on the next signal results it: - <em>Closes</em> the stream: Sending a completion or a failure message - <em>Sends</em> the results through the stream - Subscribes to the <em>next signal</em> when the results count is equal to the page limit</li>
</ul>
<pre><code>var subscribeNext: ((RACSubscriber!) -&gt; Void)?
subscribeNext = { (s: RACSubscriber!) -&gt; Void in
 nextSignal().subscribeNext({ (response) -&gt; Void in
 if let items = response as? [AnyObject] {
 for item in items {
 s.sendNext(item)
 }
 if items.count == pageLimit {
 subscribeNext!(s)
 }
 }
 else {
 s.sendError(NSError(domain: &quot;invalid.response&quot;, code: -1, userInfo: nil))
 }
 }, error: { (error) -&gt; Void in
 s.sendError(error)
 }, completed: { () -&gt; Void in
 s.sendCompleted()
 })
}
</code></pre>
<ul>
<li><strong>Entry signal</strong>: That's the source signal which fires the recursive subscribing. That just calls <em>subscribeNext</em> passing the subscriber.</li>
</ul>
<pre><code>RACSignal.createSignal({ (subscriber) -&gt; RACDisposable! in
 subscribeNext!(subscriber)
 return nil
})
</code></pre>
<h2 id="important-notes">Important notes</h2>
<ul>
<li>Collection results are <strong>sent one by one</strong> through the stream. Thanks to that you can update your collection as the items are being sent. In case you having all these results in an Array you can use the method <code>toArray()</code> of RACSignals. Be careful with that method because it blocks the thread execution until the stream is completed with either a completion or a failure message. - If <strong>any page fails</strong> the recursive algorighm stops and it sends an error message to the subscriber. The remaining pages won't be fetched</li>
</ul>
<blockquote>
<p>ReactiveCocoa is very useful when you're dealing with asynchronnous events because you can manipulate and combine them easily as you're receiving them. In that case we have different streams that we combine in a single stream we're we're receiving the collection items.</p>
</blockquote>
<p>If you want to use Reactive programming in your projects and don't know how, or you wanna talk about anything related with that, drop me a line, <a href="mailto://pedropb@hey.com">pedropb@hey.com</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Why Open Source helps you to become a better developer</title>
      <link>https://pepicrft.me/blog/you-should-try-open-sourcing/</link>
      <guid>https://pepicrft.me/blog/you-should-try-open-sourcing/</guid>
      <pubDate>Thu, 11 Jun 2015 12:00:00 +0000</pubDate>
      <description>Most of developers haven&#x27;t tried creating an Open Source component before. Since I apply it to every of my projects I feel the results and development process has improved a lot. In this article I will describe why it&#x27;s so important</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>For those who are not conscious about that, Open Source is the reason of the existence of many development communities. Would you imagine nowadays the iOS/OSX development without CocoaPods? And what about Ruby without its Gems? A lot of developers around the world put their efforts to simplify your daily stuff publishing their work in an Open Source way through these dependency managers (for them because otherwise it would be impossible to resolve many dependencies conflicts of our projects). Open Source a project doesn't mean just <code>git push origin</code> of your projects and making them public. It has some extra implications that will help you as a developer and with your future projects. Have you ever done it before? Would you like to know how it helped to me? Let's see.</p>
<h3 id="why-i-started-open-sourcing-some-libraries">Why I started Open Sourcing some libraries?</h3>
<p>When I started developing app some years ago I didn't know about what the term Open Source meant. I started with iOS, by that time there wasn't a dependency manager like CocoaPods and I integrated the libraries manually. There was though, reference websites like <a rel="external" href="https://www.cocoacontrols.com/">Cocoa Controls</a> where I could check the last libraries that other developers had published and were offering to the community.</p>
<p>I've always been a curious person and I wonder every day how the things work. I like to say that I can't be happy without knowing what there's inside the magic boxes around us. I wanted to know how these libraries worked, and why developers were spending their time developing libraries instead of working on their projects.</p>
<p>I found the answer, and liked the philosophy behind that. What makes a language very important is not only how good it is and what it offers that others don’t but the community that there’s supporting the language with new tools/libraries/tutorials, …. And Objective-C was building a great community thanks to the mobile apps development and tools like CocoaPods, or libraries like AFNetworking that you sure know about. <strong>People, packaging, code logic, to simplify others stuff and support the community with great tools</strong>. I liked it! I wanted to support the community as well and started giving my first steps sharing some code.</p>
<p>I remember having some friends who started developing apps for iOS as well and that saw (and still see) dependency managers as “tools for those developers that don’t know how to integrate libraries manually” or that think that “those who use libraries are not good developers, they have to use code from others”. <strong>Sorry, but I totally disagree with that</strong>. The point is that you have bundled something you have to code and that would make you save a lot of time. <em>Why not using it and extending in case you need extra features not supported?</em>. Those developers tend to see their code as Gollum saw the ring:</p>
<ul>
<li>This code is mine and only mine. - Sharing means, others get advantage of the time I spent coding. - But yes… I take code from others. And take part passively in the community. Resources rain over me.</li>
</ul>
<blockquote>
<p>It’s something really worth to try if you’re a Developer and you haven’t done it before.</p>
</blockquote>
<h3 id="why-contributing-with-open-source-projects-helps-you-as-a-developer">Why contributing with Open Source projects helps you as a developer?</h3>
<p>I said that it helps to developers but some of you might be thinking why?. These are some points I figured out after creating some Open Source libraries:</p>
<ul>
<li><strong>Think about code structure</strong>: Most of the times we’re constrained by defined patterns that come from the project itself, or maybe the language. <strong>We code for a product</strong> and forget about the code structure. The important fact there is coding a feature, or add a fix there that helps to solve this other bug. If you work in a team this might be a little bit different but if you work as a Freelance it’s something common. When you work on a library others developer are going to use it. The interface has to be clear, the code has to be well structured, otherwise they won’t be able to use “your product”. Before starting coding you’ll analyze your library requirements, how you would use that library if you were a developer and then design the core structure. I feel tempted to not follow these steps when I work for a project which is not a library. <strong>In my last project I’ve bundled the core business logic in modules, for example for 8fit, I called it EFKit, or EFWatchKit for the Apple Watch code</strong> It helps me to think on these code as a module that my main project depends on. - <strong>Tests are important</strong>: When you have an open source library published on Git developers will start contributing with it. They might not know about all the library and they want to just add an extra functionality. Do you know how easy it’s to introduce a regression there? Having everything tested ensures that nothing is broken and the project keeps stable. - <strong>Versioning is also very important</strong>: When you’ve other developers depending on your library you have to reflect the library changes through the versioning. I <strong>recommend you to follow the <a rel="external" href="http://semver.org/">Semantic versioning 2.0</a></strong>. That way you can reflect big important changes in the library interface through major updates and use minor updates with small fixes.</li>
</ul>
<blockquote>
<p><strong>Open Source opens your mind, and contributes to design cleaner and better code</strong></p>
</blockquote>
<h3 id="things-you-have-to-keep-in-mind">Things you have to keep in mind</h3>
<p>When you work an Open Source project that you are going to open to more people there’re some points that you don’t usually take care of but that you should if that project’s going to be opened to more people. These points help to get closer to the project and understand how it works. <strong>You know how it works, or it components</strong> because you have worked on that, but, what about the rest? Developers are your users and if you forget about these points, developers might end up not using your library. What are these points?:</p>
<ul>
<li><strong>Documentation</strong>: Code documentation is very important to understand the behaviour of classes/methods or other library components without digging into its implementation. Think about a method with multiple parameters, and a language not too stricter with types. How does the user know about the parameters you can pass to that method? If you’re using an strongly typed language, great! but otherwise not documented code might lead to big headaches working with the library. - <strong>Tests</strong>: Do you love testing? You’ll end up doing. Testing is very important on Open Source projects because the more developers you have developing for the library the easier it’s to introduce a regression and that nobody detects it. It’s very important to have your project integrated with any <strong>continuous integration</strong> solution <em>(Travis, Jenkins, …)</em> Most of them are free for Open Source projects. - <strong>Wiki page</strong>: I hadn’t used Wiki pages until I created my first project on Github. There were a lot of things I had to explain and the README file was getting larger and larger. My recommendation is that if your project size is small enough just to explain it in one page of README, do it there. If the README becomes larger, move it to the Wiki, organize the Wiki in different pages and add a home reference page that links to them. - <strong>Issues</strong>: Enable your repo issues. Some developers disable them because they don’t want to hear developers complaining about things working or because they don’t know how to use the library. After some libraries you’ll figure out that <strong>issues is the communication channel between developers and you</strong>. And something also important to keep in mind… Not all issues are valuable, don’t stress yourself trying to give a valid answer to all of them. You might find people asking for features that are impossible to support for the library that you designed. Think if it makes sense to add that feature, if it fits into the core code. After that design the feature and implement it. Always <strong>reference the issues</strong> in your Pull Requests because it’s a good way to let the user know that you’re working on that. - <strong>Contribution guidelines</strong>: Luckily your library will become popular and more developers will contribute with the project. In that case having contribution guidelines will be helpful to avoid messy code in the future. Explain there the code style you’re using, how the project is structured and how you can contribute with that structure, what new proposals must include, for example, new PR must include <em>documented code</em>, <em>tests for that new feature</em>, <em>wiki page update</em>, …. It’ll save you time explaining developers the things they must fix in every PR. - <strong>Code structure</strong>: Design first and then code. Think about how you would use that library, the public API you’ll like to find in that library, and then start designing the core components behind that API. Your code must be scalable and reusable, think where the project might have new features in the future, and design it to support them. When we develop for a product we tend to not thing about code reusability and scalability (and we shouldn’t). If we don’t think that way the library will be usable now but it probably won’t after some months <em>(and you won’t be willing to keep supporting it, you’ll be conscious about not having done the things properly before)</em></li>
</ul>
<p>Lastly and not less important, every Open Source project requires one thing, <strong>compromise</strong>. You’re building a product, you’re building a piece of code other projects depend on. I don’t know about any project that is self maintained. The project will have dependencies with system frameworks, or even with other libraries. Having dependencies mean that if these change the project will need some changes as well. If there’s no compromise with the project it’ll be unusable some months later <em>(unless you have a community that maintains it)</em>. An Open Source project <strong>requires invested time</strong>. The most common Open Source reference projects were built with a big community behind them. They started with a person having an idea, that was later supported by more and more developers that spent time to make it better and bigger.</p>
<blockquote>
<p>If you’re thinking about building something Open Source, let me give a recommendation. Try to build something that <strong>your project depends on</strong>. It’s a good way to committed to the library.</p>
</blockquote>
<h4 id="recent-open-source-project">Recent Open Source project</h4>
<ul>
<li><strong>GDAnalytics</strong>: I started that library for a side project I'm working on <a rel="external" href="http://gitdo.io">Gitdo</a>. The purpose of that library is centralize analytics <em>(Flurry, Google Analytics, Fabric,..)</em> in a single API. It's highly inspired by <a rel="external" href="https://segment.com/"><strong>SegmentIO</strong></a> and <a rel="external" href="https://github.com/orta/ARAnalytics"><strong>ARAnalytics</strong></a></li>
</ul>
<p>Hope you have enjoyed the article. If you’re another Open Source geek and you would like to comment any other point you consider is important also when working for these projects, feel free to add a comment or contact me, [pedropb@hey.com][2].</p>
<p>[1]: <a rel="external" href="http://semver.org/">http://semver.org/</a> 'Semanting Versioning' [2]: mailto://pedropb@hey.com</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>My first Apple Watch impressions</title>
      <link>https://pepicrft.me/blog/my-first-apple-watch-impressions/</link>
      <guid>https://pepicrft.me/blog/my-first-apple-watch-impressions/</guid>
      <pubDate>Sun, 07 Jun 2015 12:00:00 +0000</pubDate>
      <description>After a day using Apple Watch I would like to share my impressions with the new Apple toy and why I wouldn’t buy the first version</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>We’ve finally received the 8fit Apple Watch. We worked on 8fit on an Apple Watch App one month ago and since then we hadn’t had access to a real device. Only a few users had shown us our app working there but that’s all. The first thing did today after the unboxing was installing 8fit. I was a bit worried because since we released the first app version we haven’t released any new update. Was it working? Had it something broken? Could I send messages to the coach?</p>
<p>After installing it and testing I was able to complete a workout, send some messages to the coach and see the next meal, amazing! I don’t know when we’ll work in future improvements but at least I can say we did a great job with our current version and that the next step will probably be workouts <strong>independent from the mobile app</strong>. But let’s see in the future.</p>
<p>As a <strong>gadgets geek</strong> I have been playing all day with the toy. I wanted to check out how user interactions were. Opening notifications, dismissing them, receiving messages from messaging apps, checking productivity apps like calendars, slack, … Although the impression was good there were things I didn’t like at all. Those are my impressions:</p>
<h3 id="things-i-liked">Things I liked</h3>
<ul>
<li><strong>Activity alerts:</strong> Apple Watch comes with a default Activity app that helps you to keep active. It sends you an alert when you haven’t moved enough or when you need to walk a little bit because you have been a lot of time sat. It’s specially useful if you spend all day in front of a computer and forget about disconnecting periodically. I’m not a sedentary person and I achieve the activity goals easily but for sedentary people it can be a handy tool to become healthier. - <strong>Notifications</strong>: If I had to count the times I pick up my phone every day to see notifications that I end up dismissing I would get frightened. You can reply quicker with the watch and get your phone only if you received an important alert. Be careful! because it can also be annoying if you hate receiving notifications constantly, the watch shakes every time you receive a new one. - <strong>Glances</strong> At least for me, it’s the most handy feature of Apple Watch. You get the right refreshed information just when you need it. If it’s time to have lunch it lets you know your next meal, if you have 4 tasks to accomplish today it’ll give you a quick summary of your today’s productivity. I use <strong>Sunrise and Todoist</strong> to organize myself every day and I forget adding reminders to the tasks/events I created. Thanks to the watch I can periodically check the glance and see what tasks are missing or when I have the next event in the calendar.</li>
</ul>
<h3 id="things-i-didn-t-like">Things I didn’t like</h3>
<ul>
<li><strong>Loading…</strong>. When I tried to use some apps I got a bit frustrated because it took more than 5 seconds to load for some apps. Most of them don’t optimise their resources in the watch can’t process them as fast as the mobile device. When I take a look to the watch I basically want two things, <em>refreshed information</em> and <em>quick presentation</em>. I’m not going to be more than 5 seconds waiting for the app being loaded because I can pick up my phone, unlock it and open the app in 4 seconds. Wasn’t it expected to be a tool to avoid that? <strong>I think it’s something developers have to improve.. Optimize resources, specially images and refresh the information only if it has changed.</strong> - <strong>Running</strong>. <del>I’m a runner and yes, one of the firsts things I did was trying a running a running workout with the watch. I expected going running and that the information was presented as the main glance when you took a look to your wrist. Unfortunately it didn’t happen. After some minutes running I took a look to my watch and the first view was the default dashboard. I had two swipe to find the running glance. If you’re running or practise sport it doesn’t free you from not using your finger while running (sweaty).</del> <strong>EDITED: There's a settings option that allows you to specify that you want to see the last opened app when the Watch screen gets activated again</strong></li>
<li><strong>Open the iPhone app to use this Watch App:</strong> I’ve read this message in one of every three apps. We know that the Apple Watch SDK is quite limited and it forced some developers to rethink their apps for that platforms. There are some of them that didn’t do thought, and they tried to implement the same app core functionality on watch as well. I opened Shazam and the first message that I received was, please open your iPhone app to start detecting the song. Really? Do I really need a Watch App for that?. <strong>Hardware and SDK limitations are a good reason to rethink your app’s format for Apple Watch</strong> - <strong>Messy OS interactions:</strong> I haven’t get used to the Watch OS navigation yet. I still have some problems to show the notifications or open the glances list. I think the OS has to improve that part. Moreover when I turn my wrist, in order to activate the screen expecting any particular view, the watch resets the view hierarchy and then it shows you the dashboard again. Sometimes it freezes with a black screen blinking and thinking that you turned your wrist again.</li>
</ul>
<h3 id="useful-apps-for-watch">Useful apps for Watch</h3>
<ul>
<li><strong>Sunrise Calendar:</strong> It offers an app and a glance. They provide information about your next events in the calendar. I use the Glance a lot. I’m a very forgetful person and don’t check the calendar a quite often when I have it on my phone. - <strong>Todoist</strong>: It’s my best friend on the iPhone and OS X. I use it to organize my days and know at every moment what I have to do. Having it on the watch makes it even easier. Turn your wrist, swipe some glances and there you have your next task. Great format and well designed app. - <strong>Nike+</strong> Unfortunately it’s the best designed (in my opinion) running app for watch. I tried Runkeeper, the one I use all the times, but the design is not so good. As it has happened a lot of times before, new Apple’s products come with a smooth Nike integration (best friends forever). I still remember using the iPod Nano with the small transmitter you had to put into your shoes. The app shows the running information in a pretty clear way, and also offers you two more screens to see the map and control your music. <em>Apple watch also offers a Workouts app where you can start a running session and it provides more information like your BPM. The worst part is the fact that it reports your data to HealthKit (then you have data in two different services if you came from another running app)</em> - <strong>Passbook</strong> I remember staying at the train’s queue, with the bag, my luggage and a lot of things in my hands and having to pick up my phone, with some difficulties to show the Passbook QR with the ticket. It’s easier now. You open the Watch Passbook app, open your next ticket, and voila! The QR is there.</li>
</ul>
<h3 id="will-i-buy-a-watch">Will I buy a Watch?</h3>
<p>Sincerely <strong>I won’t</strong>. I wouldn’t use it as much as I expected. I have mostly used it to check notifications and I can do those actions using the iPhone instead of spending 400 Euros. Maybe if it allowed answering Telegram’s messages using your voice for example, i.e. a more opened SDK, so that the developers could offer richer apps, I would think about doing it. I’m not sure at all if the SDK is limited by hardware or by Apple. We know that here a product strategy comes up and they cannot offer <strong>everything</strong> at the beginning, even if they know it’s possible. They have to find a good reason to sell you the Apple Watch v2.0. I’m looking forward to seeing how the SDK improves with future versions and the things we’ll be able to do in a few months. I expected apps to rethink their formats for Apple Watch, so that they were independent from the phone but most of them didn’t. I don’t really want watch apps that tell me, <strong>open your iPhone app to keep using this one!</strong>. The SDK limitation shouldn’t lead us as developers to limitate the usability of our apps. And lastly, and as a runner, I expected a seamless experience with running apps and I didn’t. Only the Apple Workouts app has that integration (because Apple implemented it).</p>
<p>Have you tried an Apple watch and you would like to share your thoughts?</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Full control in your hybrid mobile apps with a local server, 8fit</title>
      <link>https://pepicrft.me/blog/full-control-in-your-hybrid-mobile-apps-with-a-local-server/</link>
      <guid>https://pepicrft.me/blog/full-control-in-your-hybrid-mobile-apps-with-a-local-server/</guid>
      <pubDate>Mon, 25 May 2015 12:00:00 +0000</pubDate>
      <description>Custom solution to have full control over your hybrid apps bundling the content locally and controlling updates</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Since 8fit was developed we’ve been using the webview application cache to send new updates to the users. It allowed us to update without releasing new apps (something slow if you think about the Apple review process). Although it’s something good, it has also some cons, it’s a bit difficult to setup everything properly, specially the server config to ensure the webview doesn’t cache the files that shouldn’t be cached. Moreover the control over the update process is very low and it increases the boot times because sometimes it has to get the resources remotely when it doesn’t actually need them.</p>
<p>Is there any other way to do it if my app is an hybrid app? Yes, there is. This solution is closer to the bundling format of native apps, where you package everything inside the app and that’s “server” to the Webview. Frameworks like Ionic does it, but if you bundle the web resource you have to follow the native release cycles and again, it’s slow in case of Apple (slow iteration speed).</p>
<p>We were thinking if there was a solution that took the advantages of having everything locally to serve it quickly and that had the flexibility to update remotely instead of having everything bundled with the app and started working on something we called internally “Frontend Manager’.</p>
<p>That approach gives us a lot flexibility, especially when working quickly on new features, designs and integrations. The web app still can decide when to download the frontend web app, when to inject it into the webview, and even force high-priority updates if needed.</p>
<h2 id="html5-application-cache">HTML5 Application Cache</h2>
<p>As I mentioned we’d been relying on Application Cache but the problems with app cache have been documented plenty of places (<a rel="external" href="http://alistapart.com/article/application-cache-is-a-douchebag">http://alistapart.com/article/application-cache-is-a-douchebag</a>). The main problem it has is that even after dealing with all the edge cases it’s possible to have users stuck on old versions, or experience very long “flaxes of blank white screen”. And it’s also impossible to force an update when necessary.</p>
<p>A lot of users have been reporting us white screens, frozen apps, and we could only tell them to clear the app data in order to clear the Application Cache and start the app with everything cleaned. It was really a frustrating user experience.</p>
<h2 id="native-frontend-manager">Native Frontend manager</h2>
<p>Why not having a kind of native controller controller that decided when and how inject the content into the app? That’s what we did and we’re very happy with it. It didn’t require a lot of changes in the frontend which is great because we didn’t have to couple our implementation to a particular problem. What did we need?</p>
<ul>
<li><strong>Manifest file:</strong> The controller had to know <em>what</em> files to download in order to have the whole frontend locally. We did it through a manifest file in the frontend which is generated when a new build is deployed. That file contains information about the commit, the deploy date and an array with all the files that are required for that frontend version and their routes. We’re thinking about having more control in the future here and use a custom endpoint that allows us to <strong>decide what version every user has</strong> to use but it’s still an idea and we want to firstly test this deeply, step by step.</li>
<li><strong>Native Frontend Manager:</strong> It’s the core native component and it’s responsible to synchronize the local with the remote folder. It downloads the manifest file and checks if it’s synchronized with the frontend specified there. It does it every time the app is opened and depending on the app status the update is forced or not. If the app is downloaded, the first time it’s opened there’s a <strong>loading screen</strong> that fires the frontend download. Once it’s downloaded it’s automatically loaded into the webview and the app is launched. If the frontend exists locally and consequently the app can be launched, it just downloads the last frontend version but doesn’t force the <strong>update because</strong> it would cause the white screen we wanted to avoid. <em>When is it loaded then?</em> The next time the app is opened it detects if there’s an <em>“enqueued”</em> frontend and it loads it before launching the app.</li>
<li><strong>Loading screen:</strong> As I mentioned the first time the app is launched there isn’t anything to load so we implemented a loading screen with a progress bar synchronized with the download process. In case of not having internet connection it’s notified to the user and we offer a contact button to report a but in the frontend manager attaching automatically an error log. The preload screen has design similar to the frontend one which makes the transition very smooth.</li>
</ul>
<blockquote>
<p>We’ve also another way to reload the frontend which is using a bridge call through Javascript but we only use it for testing and point the app to different environment instead of having to rebuild the app every time.</p>
</blockquote>
<ul>
<li><strong>Local server:</strong> The first iteration we did with this feature was thought to be loaded directly the frontend directly from the disk but we lose something that our frontend is dependent of, <strong>cookies</strong>. If you load the frontend from a local file forget about cookies, forget about persisting the user’s session using cookies, it would imply a lot of changes in the frontend just to adapt the frontend to solve a particular problem. What if we loaded 8fit in a desktop then? We did some changes and it worked but we didn’t really want that. Moreover before bringing this feature onboard we added <strong>WKWebKit</strong> to our app to be used only on iOS 8 devices, and luckily the load of files into the webview wasn’t a feature, we needed a different solution. We took a look and internet and we saw that we weren’t the only team looking for solutions for that, Phonegap was affected in the same way if they wanted to use WKWebKit for their <em>“automatically generated mobile projects”</em>. After thinking a bit about it and analyzing the existing frameworks and libraries available we took the decision to do it launching a local web server in the app which would be stopped if the app moved to the background. It might sound scary, but it isn’t. Some other apps do the same but you don’t actually know that they are doing, those apps that allow you to control your app remotely, or just share content to the television… After reviewing different libraries we integrated <strong>GCDWebServer</strong> which offered what we needed, serve static content in a local path and proxy API calls as our NGINX reverse proxy does <em>(the Android HTTP server that we ended up using was NanoHTTPD)</em>.</li>
</ul>
<p>The example below shows a config of the server to serve files and proxy some calls:</p>
<pre><code>- (void)setupServerHandlers:(NSString*)frontendPath
{
 [self addGETHandlerForBasePath:@&quot;/a/&quot;
 directoryPath:frontendPath
 indexFilename:@&quot;index.html&quot;
 cacheAge:3600
 allowRangeRequests:YES];
 [self addAPIHandlerForRequestMethod:@&quot;GET&quot;];
 [self addAPIHandlerForRequestMethod:@&quot;POST&quot;];
 [self addAPIHandlerForRequestMethod:@&quot;PUT&quot;];
 [self addAPIHandlerForRequestMethod:@&quot;PATCH&quot;];
 [self addAPIHandlerForRequestMethod:@&quot;DELETE&quot;];
}

#pragma mark - Custom Setters

- (void)addAPIHandlerForRequestMethod:(NSString *)requestMethod
{
 typeof (self) __weak welf = self;
 [self addHandlerForMethod:requestMethod
 pathRegex:API_PATH_REGEX
 requestClass:[GCDWebServerDataRequest class]
 asyncProcessBlock:^(GCDWebServerRequest *request, GCDWebServerCompletionBlock completionBlock) {
 // Proxying the source request
 NSString *urlString = [welf.remoteRootUrl stringByAppendingPathComponent:request.path];
 NSMutableURLRequest *proxyRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
 [proxyRequest setHTTPMethod:requestMethod];
 proxyRequest.allHTTPHeaderFields = request.headers;
 if ([request isKindOfClass:[GCDWebServerDataRequest class]]) {
 proxyRequest.HTTPBody = [(GCDWebServerDataRequest*)request data];
 }
 NSURLSessionDataTask *dataTask = [welf.manager dataTaskWithRequest:proxyRequest completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
 if (error) {
 completionBlock([GCDWebServerResponse responseWithStatusCode:[(NSHTTPURLResponse*)response statusCode]]);
 }
 else {
 NSString *contentType = [(NSHTTPURLResponse*)response allHeaderFields][@&quot;Content-Type&quot;];
 completionBlock([GCDWebServerDataResponse responseWithData:responseObject contentType:contentType]);
 }
 }];
 [dataTask resume];
 }];
}
</code></pre>
<p>As you can see in case of being an static file we can directly specify the local path where the files has to be read (we have to ensure the folders tree is the right one) and in case of the API we proxy the requests that match a regular expression and manage them using a web client, that in that case is AFNetworking. And <strong>the magic works!</strong></p>
<h2 id="hotfixes-pushing-updates">Hotfixes &amp; pushing updates</h2>
<p>Finally and taking advantage of the <strong>silent push notifications</strong> we have on iOS that are a kind of <em>“content notifications”</em> and the full control we have in case of Android we thought, why not connecting it with our frontend manager in order to sync the frontend under certain conditions? Yei! We did it. When the app receives the push notification it starts the synchronization and loads the frontend only if the app was in background. That way we don’t reload the app is the user is doing a workout. Thinking about the options that we have now with that feature…:</p>
<ul>
<li>We can force an update that fixes an important bug introduced in a previous version. - Also force a version that includes assets related to a campaign that we have to launch. - We can force an update to a particular user which might have problems with the app.</li>
</ul>
<h2 id="some-gotchas">Some gotchas</h2>
<ul>
<li>Implementing the Android version took us a lot of time. We had to implement the API proxy on our own. We had to do some research about proxying HTTP calls and do a lot of testing to ensure the API communication didn’t get broken.</li>
</ul>
<h2 id="next-steps">Next steps</h2>
<p>Frontend manager was our next big feature that we’ve been waiting for months. Now we want to test it deeply, include it in our release QA cycles and cover all possible edge cases because it’s a very critical feature. Frontend Manager has supposed a breath to keep thinking in the product and building more fluid experiences. We’ll start migrating features to native, the company is getting bigger and we’re having more resources to think about a future 8fit 100% written on Java, Objective-C, Swift.</p>
<h2 id="resources">Resources</h2>
<ul>
<li><strong>GCDWebServer:</strong> <a rel="external" href="https://github.com/swisspol/GCDWebServer">https://github.com/swisspol/GCDWebServer</a> - <strong>NanoHTTPD:</strong> <a rel="external" href="https://github.com/NanoHttpd/nanohttpd">https://github.com/NanoHttpd/nanohttpd</a></li>
</ul>
<p><strong>Note:</strong> If you also are working on an hybrid app and you're looking for a similar approach you can reach me at <a href="mailto:pepi@8fit.com">pepi@8fit.com</a>. I'll pleased to help you.</p>
<p>Thanks <a rel="external" href="https://twitter.com/p3drosola">Pedro Sola</a> for the article review and its help during the feature development</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Modularize your mobile projects</title>
      <link>https://pepicrft.me/blog/modularize-your-mobile-apps/</link>
      <guid>https://pepicrft.me/blog/modularize-your-mobile-apps/</guid>
      <pubDate>Wed, 28 Jan 2015 12:00:00 +0000</pubDate>
      <description>Learn how to split your app components in different bundles instead of dealing with an unique bundle that packages the whole app</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>When we start building mobile apps we tend to do everything on the same bundle. If you are an iOS developer that means only one target, with one scheme with the build config and that project has some dependencies that might be attached as frameworks, static libraries, or using a dependency manager like CocoaPods. If you are familiar with Android you probably use a module with some dependencies managed by Gradle.</p>
<p>If you think a bit about that solution it's mixing in the same bundle stuff which is strictly related to the device and the presentation layer, the application core logic, and the interaction with the system/external frameworks. <strong>What happens if Apple/Google change any of the existing frameworks?</strong> You'll have to analyze your app find all the framework dependencies and replace them and what about using your application core logic in a different device with a different interface? You'll probably end up adding a bunch of if/else statements in your code. <em>You know that's not a clean way to do the things...</em></p>
<p>Both <strong>iOS and Android development tools</strong> offer great tools to deal with that. However we only use them to link our big app bundle with other dependencies <em>(aka libraries)</em>. But.. what if we structure our app in small components which instead of packaging the whole app logic they have a components with the same responsibility grouped. We could easily interchange them easily without having to refactor all the app.</p>
<blockquote>
<p>If you are thinking in how to apply those terms to existing architectures like might be MVC, MVP, or VIPER an app structured in bundles separates those architecture components in different modules.</p>
</blockquote>
<h3 id="advantages-of-working-with-bundles">Advantages of working with bundles</h3>
<ul>
<li><strong>Have your team working in small projects:</strong> How many times have you had to deal with Git conflicts because two of you have been working on the same file? This way you can have some developers working on the interface, specially those who are expert building layouts, animations, and interactions with users. Have another group of developers developing the interaction with the data and translating user interactions to events applying some business logic. And finally those data expert dealing with API requests and database persistence. You can split data in two bundles LocalData and RemoteData as well. - <strong>Single Responsibility Principle and decoupled components:</strong> If you develop everything in a single bundle you tend to forget that principle and implement strongly coupled component. Working with bundles <em>helps</em> to implement decoupled components which don't know who's going to use them. - <strong>Easy to test and fast test executions:</strong> Every time you want to execute a suite of tests you have to build <strong>the entire project</strong> just for testing some pieces of your app. If you split your project in <em>"small projects"</em> you'll be able to test them individually and mock the dependencies. - <strong>Easy to recover from regressions thanks to splitted versioning</strong>: Argh! Juan introduced a regression on the version 2.0.2 of the Data project. Let's keep using the last version until the Data team solves it. It's much better, isn't it? That will help you to avoid some headaches.</li>
</ul>
<p>The image below shows the difference between working with only a big app bundle and splitting it in small bundles.</p>
<p><img src="https://pepicrft.me/blog/modularize-your-mobile-apps/__GHOST_URL__/images/posts/xcode_big_project.png" alt="Large project" /></p>
<h3 id="components">Components</h3>
<p>Thinking about the components of our apps most of them can be grouped in the following sacks:</p>
<ul>
<li><strong>App</strong>: App groups everything related to the view. It's related to the device and it's the bundle which is going to be compiled. <em>For example we might have an App for iPad and another one for iPhone which will result in two builds one for Android and another one for iPhone</em>. App shouldn't include any business logic. Just present the information it receives from a core component and notify those core components about events happening there, generally interactions with the user. Navigation logic must be included in this bundle. - Layouts - Views - Navigation - Animations - <strong>Core</strong>: Your application logic should be in this bundle. Core is like the link between the data source and the interface and includes the business and presentation logic. It must use the data bundle to bring data, apply the required logic and them return it to the view to be presented. - Presentation logic <em>(e.g. Presenters)</em> - Business logic <em>(e.g. Interactors)</em> - <strong>Data</strong>: Data will package your controllers that will interact with the system frameworks, like interaction with databases, interaction with APIs, interaction with sensors....</li>
<li>Database controller - API controllers - Device controllers</li>
</ul>
<p>You might wonder how to implement that on a real project, how to connect those dependencies and have everything working. Let's see how to do it on iOS and Android</p>
<h2 id="modules-on-ios">Modules on iOS</h2>
<p>Although you can create your own library projects with XCode and create the dependencies manually, we have a great tool you probably know, <a rel="external" href="http://cocoapods.org/">Cocoapods</a> you probably know about. We usually use it to connect our project with remote dependencies but it has the option to specify the dependency locally. Let's see how.</p>
<p>You have <strong>different approaches</strong> depending on your needs. The first one consists on managing those Core/Data bundles as libraries and then connecting your app bundle using the remote repositories. That's great if you have different teams working each one on a different "library" because they can keep their own versioning and build/deploy processes. If you have an small team and don't have enough resources to have separated build/deploy processes for each bundle you can have those bundles locally (using Gitmodule) but integrated with CocoaPods as well. That way you have flexibility to modify and report changes directly</p>
<ul>
<li><strong>Create three XCode projects</strong> in different folders, ExampleApp, ExampleCore, ExampleData. - ExampleApp doesn't need podspec file. <strong>ExampleCore and ExampleData need a podspec</strong> file with information about the bundle. The structure should be similar to the following:</li>
</ul>
<pre><code>Pod::Spec.new do |spec|
 spec.name = &#39;ExampleCore&#39;
 spec.version = &#39;0.0.1&#39;
 spec.homepage = &#39;https://github.com/Example/ExampleCore&#39;
 spec.authors = { &#39;pepi&#39; =&gt; &#39;pedropb@hey.com&#39; }
 spec.summary = &#39;Core logic of example&#39;
 spec.source = { :git =&gt; &#39;https://github.com/Example/ExampleCore.git&#39;, :tag =&gt; &#39;0.0.1&#39; }
 spec.source_files = &#39;./**/*.{h,m}&#39;
 spec.framework = &#39;&#39;
end
*Note: In case of ExampleData you might have dependencies with system frameworks or external libraries. You can specify them in the podspec as well*
</code></pre>
<ul>
<li>Upload those projects into their respective repositories <em>(e.g. github.com/Example/ExampleData, github.com/Example/ExampleCore, github.com/Example/ExampleApp)</em> - Once you have the bundles on a remote repository you can bring them to the ExampleApp <strong>bundle as submodules</strong> using</li>
</ul>
<pre><code>git submodule add https://github.com/Example/ExampleCore dependencies/core
git submodule add https://github.com/Example/ExampleCore dependencies/data
</code></pre>
<ul>
<li>In ExampleApp <strong>specify your CocoaPods dependencies locally</strong></li>
</ul>
<pre><code>source &#39;https://github.com/CocoaPods/Specs.git&#39;
inhibit_all_warnings!
pod &#39;ExampleData&#39;, :path =&gt; &#39;./dependencies/data&#39;
pod &#39;ExampleCore&#39;, :path =&gt; &#39;./dependencies/core&#39;
</code></pre>
<ul>
<li>Open your app project <strong>from the .xcworkspace</strong> file. You'll have your project linked to the ExampleData and ExampleCore bundles.</li>
</ul>
<h4 id="keep-in-mind">Keep in mind</h4>
<p>If you have never developed a library before there're some points you should keep in mind working with your bundles:</p>
<ul>
<li><strong>Expose only what is going to be used externally:</strong> The logic and communication with system frameworks are something private. Define a public communication layer and expose it making public headers which will be used by bundles that use that one as a dependency. <em>Read more about public headers with CocoaPods <a rel="external" href="http://guides.cocoapods.org/syntax/podspec.html#public_header_files">here</a></em></li>
<li><strong>Work on the bundle without thinking on who is going to use it</strong>: The idea behind that structure is also splitting responsibilities so for example the Data bundle shouldn't know anything about who is going to use it. Or the Core bundle about which view is going to use its data to present it. Working with bundles makes that easier but doesn't avoid the coupling <strong>if you still think on bundles as a single entity</strong>.</li>
<li><strong>Keep a versioning process for each bundle</strong>: Each version should be documented with the fixes and new features. If you have enough resources document it, that way your workmates who are working with it know how to communicate with it. You can use Github releases/milestones which are very useful for that purpose.</li>
</ul>
<blockquote>
<p>CocoaPods is just a simple way to manage dependencies which in my opinion makes it easier and cleaner. If you have enough experience working with libraries/frameworks and connecting dependencies into a single project feel free to do it that way, any dependency solution is possible.</p>
</blockquote>
<h2 id="modules-on-android">Modules on Android</h2>
<p>In case of Andorid we'll use Gradle to define our modules. Gradle allows you to specify in your app build file the dependencies the project has with other library-projects. We usually use that feature to link our project with 3rd party libraries but we can do it with other modules created by ourselves. Let's see how</p>
<ul>
<li>Let's create three a main Android app module and two Android Libraries. <em>For example, ExampleApp, ExampleCore, ExampleData</em></li>
</ul>
<p><img src="https://pepicrft.me/blog/modularize-your-mobile-apps/__GHOST_URL__/images/posts/posts/android-library.png" alt="Library" /> <img src="https://pepicrft.me/blog/modularize-your-mobile-apps/__GHOST_URL__/images/posts/posts/android-projects-list.png" alt="Projects list" /></p>
<ul>
<li>Inside <em>File &gt; Project Structure</em> define core and data modules <strong>as dependencies</strong> of the app module as shown below.</li>
</ul>
<p><img src="https://pepicrft.me/blog/modularize-your-mobile-apps/__GHOST_URL__/images/posts/android-dependencies.png" alt="Dependencies" /></p>
<ul>
<li>It will create automatically the dependencies in your app build.gradle file as shown below:</li>
</ul>
<pre><code>dependencies {
 compile fileTree(dir: &#39;libs&#39;, include: [&#39;*.jar&#39;])
 compile &#39;com.android.support:appcompat-v7:21.0.3&#39;
 compile project(&#39;:core&#39;)
 compile project(&#39;:data&#39;)
}
</code></pre>
<ul>
<li>I recommend you to have those library-modules in their own Git repository and manage them as Git submodules inside the app project. That way they can be maintained without any dependency with the app. You can read more about Git Submodules <a rel="external" href="http://git-scm.com/book/en/v2/Git-Tools-Submodules">here</a></li>
</ul>
<h4 id="keep-in-mind-1">Keep in mind</h4>
<p>Before working with Android modules in your projects there are some points I would like to highlight:</p>
<ul>
<li><strong>Data and Core modules don't have activities</strong>: Remember they don't have any relation with the presentation layer view layer so they shouldn't include any kind of Ativity/Fragment/Custom View.</li>
<li><strong>Manifest file of library projects will be empty</strong>: The Manifest file is the file in our app where we register activities, permissions, brodcast receivers, services, <strong>to be used by the app</strong>. Consequently the app's manifest will register those components which might be in library modules. <em>(e.g. Register in the app's manifest a BroadcastReceiver that handles push notifications. That receiver is defined in the core library module)</em></li>
<li><strong>Libraries DON'T have the main app as dependency:</strong> They must be agnostic to the app which is using them. You might find cases where you need notify something to the main app. In that case you can register broadcasts in your app which handles broadcasts coming from module libraries.</li>
</ul>
<h2 id="git-submodules-and-versions">Git Submodules and versions</h2>
<p>We've seen how to use modules in either iOS or Android and how to use Git Submodule to have a local git copy of those "library" modules but what if we want to have an specific branch of the core/data package? Submodules has support for it. If you edit your <strong>.gitmodules</strong> you'll have a structure similar to this one where you can specify the branch</p>
<pre><code>[submodule &quot;ExampleCore&quot;]
 path = core
 url = https://github.com/Example/ExampleApp.git
 branch = new-feature
</code></pre>
<blockquote>
<p>Git Submodules has no support to specify a tag instead of a branch. You can manually checkout to any tag in those submodule repositories.</p>
</blockquote>
<h2 id="documentation">Documentation</h2>
<ul>
<li>Git submodules - <a rel="external" href="http://git-scm.com/book/en/v2/Git-Tools-Submodules">Link</a> - XCode targets by Apple - <a rel="external" href="https://developer.apple.com/library/prerelease/ios/featuredarticles/XcodeConcepts/Concept-Targets.html">Link</a> - Targets for free/paid apps - <a rel="external" href="http://www.reigndesign.com/blog/building-flockwork-creating-targets-for-free-and-full-versions-in-a-single-xcode-project/">Link</a> - How to modularize your XCode apps - <a rel="external" href="http://blog.zoul.cz/post/10157814684/how-to-modularize-your-xcode-apps">Link</a> - CocoaPods - <a rel="external" href="http://cocoapods.org/">Link</a></li>
</ul>
<h2 id="thoughts">Thoughts</h2>
<p>Feel free to contact me on <a href="mailto:pedropb@hey.com">pedropb@hey.com</a>. I'll be please to comment that project organization with you</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Boosting your mobile app with Javascript and some mobile knowledge</title>
      <link>https://pepicrft.me/blog/boosting-your-mobile-app-with-javascript-and-some-mobile-knowledge/</link>
      <guid>https://pepicrft.me/blog/boosting-your-mobile-app-with-javascript-and-some-mobile-knowledge/</guid>
      <pubDate>Wed, 10 Dec 2014 12:00:00 +0000</pubDate>
      <description>Learn how useful might be giving some steps on mobile (Android&#x2F;iOS) launching mobile solutions with web knowledge and with the same mobile native experience as any other app</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>When the 8fit team started giving their first steps they decided that the product was going to be a web app with some kind of native integrations. It was something with a lot of sense if we think that the founders of the company feel very comfortable with the language and with web in general. Might we have a great mobile experience using web technologies?</p>
<p><strong>There's no web solution that equals the mobile native experience</strong>. That's the answer but the truth is that web is getting closer to native and it's possible (depending on your web stack) to export to native only those components that you need and have a communication interface between the web and the native world, implemented on your own, without Phonegap and some other frameworks that try to abstract the web developer from the mobile layer.</p>
<p>We didn't use any kind of <strong>bootstrap library, CSS package, or communication framework</strong> which allowed us to use only just what we needed. We tried to use as less Javascript frameworks as possible, because the web Javascript engine of the mobile devices is limited (comparing it with a desktop computer), and we don't want to load .css files that we don't actually need.</p>
<blockquote>
<p>Mobile web rendering engine is limited, get rid of fully featured web packages with tons of styles and Javascript helpers that you are not going to use at all. If you feel comfortable enough with the language like to not build a shitty and non-scalable stack do it. Otherwise appeal to any framework like Ionic Framework (based on AngularJS) which offers a mobile-like stack and components to work with.</p>
</blockquote>
<p>We only used Backbone, Underscore and JQuery for Javascript which simplified our project stack a lot and we avoid repetitive code (and we haven't found a bottleneck with that so far). No Ionic, Cordova, Phonegap or similar. How to have native components then? With the help of a mobile developer, in the 8fit case me. We built a communication layer between web and native. In the case of Android using a native WebView property that simplifies it a lot and in case of iOS using a <em>tricky</em> solution that we'll talk about.</p>
<h2 id="advantages">Advantages</h2>
<p>After being working with that solution for months we have figured out that it offers some advantages when you are working with an early product. Some of them are:</p>
<ul>
<li><strong>Automatic updated without having to pass through a release review</strong>: The resources are cached by the local Webview and every time we change the frontend version we don't have to generate a new build, update the assets, add a Changelog, wait until you get reviewed by Apple and then have another one prepared to send it again to the Apple Store. Forget about that, you can just use a <em>Gulp</em> task that randomizes your resources naming. That way the <strong>caching</strong> engine of the mobile browser detects that those files have changend and then it reloads them. <strong>Updates on the air!</strong></li>
<li><strong>One frontend version but customized for each system</strong>: The application logic is the same. What changes then between Android and iOS? Basically the navigation (Android users are adapted to some patterns that iOS users are not and viceversa) and the design. If you organize your frontend following the pattern MVC you can have the same model-controller for both iOS and Android and work change only the View (Layout) and Navigation. At the end if you work natively you talk with your Android/iOS friends and you figure out that they are implementing the same, following a similar structure, and in some cases even the same naming!</li>
<li><strong>Centralized point of bugs</strong>: That advantage is a consequence of the previous one. The more you move your application stuff to frontend the more your bugs will be centralized and easy to detect. In that case from Javascript. Does it mean that then there are no native bugs? No! there are and you have to keep having any reporting tool like Crashlytics, HockeyApp, ... but the number of those bugs will be much less than the number of bugs in frontend.</li>
</ul>
<h1 id="building-the-web-stack">Building the web stack</h1>
<p>The stack of web was based on a <strong>SPA, Single Page Application</strong>. For those who don't know about what a single page is it's basically a web which is only an HTML file that imports a bunch of Javascript which is the responsible of different tasks like routing, controlling views, binding data, .... Javascript becomes the main actor of the movie.</p>
<p>If you look for frameworks that help you to implement a SPA you'll find a lot of them, like BackboneJS, AngulrJS (by Google), or even some of them focused on mobile like it might be Ionic <em>(based on Angular)</em>. Those have different points in common and different concepts in other points. Choosing one solution on another depends on your familiarity with the concepts of the frameworks. If you looked for comparisons like I did a long time ago between the most popular ones (Angular and Backbone) you'll see that Angular offers you a more structured solution close to Ruby while Backbone might be more powerful if you talk to other developers (even if the architecture is not so structured). <strong>My recommendation</strong> <em>is that if you are starting with that kind of web applications, do it with Angular because Backbone requires having fought enough with Javascript before.</em></p>
<p>We use <strong>CoffeeScript</strong> instead of Javascript and <strong>Sass</strong> instead of CSS which is later converted using <strong>Gulp</strong> into the respective Javascript and CSS. Chose the tools that fits best with the way you work and your feeling with the language.</p>
<p>There's nothing special here but the fact that <strong>everything has to be responsive</strong> and you have to <strong>check the Javascript support</strong> of different devices because the web engine on mobile devices is more limited than on a Desktop. You can use here a website called <a rel="external" href="http://caniuse.com/">caniuse</a></p>
<p>Here's a summary of things we're using for the frontend:</p>
<ul>
<li>Backbone, Marionette, Underscore &amp; JQuery - Coffeescript - Sass - Jade for template - Gulp for build tasks - Capistrano for deploys</li>
</ul>
<p><em>Note: For those who might be interested in, we're using Rails for the backend</em></p>
<h1 id="mobile">Mobile</h1>
<p>We rejected any kind of <strong>mobile wrapper</strong> like Phonegap, Sencha or similars because we wanted custom communication plugins and we had a mobile developer to take care of that side. If you think about it, to have your web solution running on a mobile device (besides having done it responsive) you need a simple app project for Android and iOS <em>(which you can create from the IDE assistant)</em>, add a webview, and load the URL into it. Simple really?</p>
<p>That would be the simplest integration but we weren't a website, we were a platform which purpose was <strong>end up running on mobile devices taking advantage of mobile features</strong>. How many times do you complain when you have to introduce your credit card numbers for a payment? In app purchases is a great solution there for mobile, or why do you have to introduce your Facebook credentials for login if I have an app installed for that? Those are just some kind of integrations that we thought about and that we currently have.</p>
<blockquote>
<p>If you are planning to load a web into a mobile app the app behaves just as a simple window where you show the browser opening your website but if you want to take advantage of the real mobile advantages you need a kind of interaction between mobile-web</p>
</blockquote>
<p>That <strong>interaction</strong> is what we called <strong>native bridge</strong> and we built it from scratch. No framework, no abstraction, just analyzed the features we had on Android and iOS and then implemented it.</p>
<h2 id="native-bridge">Native bridge</h2>
<p>Bridging native and web depends on the platform where we're building the bridge because Apple and Google had different thoughts about giving support to web when they developed their mobile web engines.</p>
<h3 id="android">Android</h3>
<p>Fortunately Android did it best. The way you can bridge native with web is <strong>exposing a Java interface</strong> to Javascript. After exposing that interface the object is visible from Javascript and that object translates calls to its method into calls to the original Java interface. The communication would be something like this:</p>
<pre><code>// Communication Java -&gt; Javascript
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new JavascriptInteractor(), &quot;NativeBridge&quot;);
class JavascriptInteractor {
	@JavascriptInterface
	public void buyIAPProduct(String productId)
	{
		// MyPaymentsController.buy...
	}
}

// Communication Java -&gt; Javascript
public void loadJS(String js) {
 webView.loadUrl(&quot;javascript:&quot;+js);
}
</code></pre>
<p>Where we can see we're exposing a method called <code>buyIAPProduct</code> and executing something on Java. Notice that @JavascriptInterface is an annotation to let the compiler know that the method below should be exposed to Javascript, otherwise not.</p>
<p>The <strong>communication on the other direction</strong> is executed just <strong>evaluating javascript</strong> sentences directly loading URLs with the format <code>javascript: sentence</code>.</p>
<p>If we tried to close the payment flow, the exchange of calls would be something like:</p>
<pre><code>NativeBridge.buyIAPProduct(&#39;pro_subscription_1mo&#39;);
</code></pre>
<pre><code>webview.loadJS(&quot;Ef.vent.trigger(&#39;payment:completed&#39;, &quot;+payment.toString()+&quot;)&quot;)
</code></pre>
<h3 id="ios">iOS</h3>
<p>Apple did it difficult here. There's no native component to expose a kind of interface to Javascript as Android does. How can I do then? Well, if we take a look to the <em>UIWebViewDelegate</em> methods there's one called</p>
<pre><code>- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
 navigationType:(UIWebViewNavigationType)navigationType;
</code></pre>
<p>Which is a method to ask if the webview should or not load a given <code>NSURLRequest</code>. Although the purpose of this method is not to bridge Javascript with Mobile we took advantage of it for that. How? <strong>Building a custom URL Scheme</strong></p>
<p>Let's say that we built a custom <strong>communication API</strong> using the scheme <code>eightfit://</code> and that way any intercepted url with the scheme <code>eightfit://</code> would be passed to the <strong>NativeBridge</strong>. The previos <code>buyIAPProduct</code> would turn into <code>eightfit://buyiapproduct/product_id=pro_subscription</code>.</p>
<pre><code>- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
 navigationType:(UIWebViewNavigationType)navigationType
 {
 	// eightfit://buyiapproduct?product_id=pro_subscription_1mo
 	BOOL isNativeBridgeURL = [URLMatcher isForBridge:request.URL.absoluteURL];
 	if (isNativeBridgeURL){
 		[JLRoutes routeURL:request.URL.absoluteURL];
 		return NO;
 	}
 	return YES;
 }
</code></pre>
<p>The parsing of the URL can be made using <strong>regex</strong> but fortunately there were other developers thinking about it befure and we find libraries like <strong>JLRoutes</strong> which helps on that. What JLRoutes actually does is to build a local API passing the endpoints and actions for those endpoints:</p>
<pre><code>[JLRoutes addRoute:@&quot;/buyiapproduct/:product_id&quot; handler:^BOOL(NSDictionary *parameters) {

 NSString *productId = parameters[@&quot;product_id&quot;]; // defined in the route by specifying &quot;:product_id&quot;

 [PaymentsController buyProduct:product_id withCompletion:^void (NSError *error) {
 	// Notify JS about the result
 }];

 return YES; // return YES to say we have handled the route
}];
</code></pre>
<h3 id="some-points-about-the-bridge">Some points about the bridge</h3>
<p>As you might have noticed there are some interesting points to comment about the bridge. The first one is that the communication is a bidirectional communication. I ask for something you answer with another thing. There's no way (right now) to get the return parameter of the sentence evaluation and if there's a way it's only using the string type, <em>(what if I want to return a more complex object?)</em></p>
<p>Another interesting point is that there's no way to expose Javascript to Mobile (neither on iOS nor Android) Mobile doesn't know anything about Javascript and you as a mobile entity that has a Webview can only communicate with Javascript evaluating sentences on the browser or turn to tricky solutions.</p>
<p>Most of communication calls will be asynchronous so you need a kind of event handlers on Javascript (JQuery, Backbone, ... offer components for that) so what you actually do is call the bridge and then register a listener to listen when the mobile controller has finished what it had to do.</p>
<p>And finally as you might have noticed, there's no type validation. And that's something we can't avoid because the bridge inherits it from Javascript. Be careful here!</p>
<blockquote>
<p><strong>Exposing features:</strong> If you want to let your frontend know about the available mobile features, the device or the app version you can use the User-Agent and do something like: 8fit-iOS-8.1/iPhone-6/1.2.3 (iap, push, conn, res) . That way your frontend knows about what is available and what's not.</p>
</blockquote>
<h2 id="examples-of-controllers">Examples of controllers</h2>
<p>Since we starting building that bridge we've done more than 10 kind of native integrations. Some of them are <strong>payments (in app purchase), video/sound/audio player, push notifications, login with Facebook, resources downloader, social sharing...</strong></p>
<p>And some other interesting are coming. We're working on a frontend controller which is going to manage the frontend locally and inject it into the webview. We're finishing the integration with <strong>HealthKit and Google Fit</strong> and planning to do the workouts more interactive implementing them natively.</p>
<h2 id="pitfalls-and-recommendations">Pitfalls and recommendations</h2>
<p>Not everything can be magic, there are some <strong>pitfalls</strong> we found during the development of 8fit and that I would like to share with you too because you'll have to face with them sooner or later:</p>
<ol>
<li><strong>Native doesn't know about the Javascript</strong>: You can expose for example Java to Javascript (not possible with Objective-C). But there's no way to know what's happening on the Javascript context (variables, objects, ...). So the <strong>recomendation</strong> here is to documment the bridge in terms of (methods, objects, variables and types) and if it's possible to be mainteined by the same developer/s. We suffered a lot of headaches here. 2. <strong>Need a bit of mobile knowledge</strong> :iphone: : If you come from web you can learn it, the complexity will depend on the number of native integrations you have. If they are not too much give your first steps on mobile, otherwise <em>Phonegap</em> is not a bad solution but not too custom for us. 3. <strong>Experience close to mobile but not the same</strong>: We can start a big discussion here but my opinion about that is that there's no way (right now) to get the sdame experience than a native app using web technologies. Due (in part) to the companies behind the OS (Google &amp; Apple) which don't want to put their efforts on better web rendering engines. Fortunately, I've to say that the things and changes and we can see great news on iOS 8 and Lollipop :clap: 4. <strong>Test the mobile experience</strong>: This point is not taken a lot into account on a desktop solution but should be in case of mobile. Think about what should happens if your apps loses the connection, are the models properly persisted under wrong connection health, ... Check if the browser handles properly the cached resources. 5. <strong>Be careful with the cache:</strong> We had some troubles with the browser not reloading cached resources. To avoid that we started renaming the frontend resources on every build, that way the browser detected them as updated and forced the download of them. <em>Note: We're building here our current frontend controller which is going to be the repsonsible to download it and inject into the Webview! Yei!</em></li>
</ol>
<h2 id="conclusions">Conclusions</h2>
<p>After the previous (and big summary) of the technologies we're using at 8fit and different topics around it I would like to finish the post sharing some conclusions with you, the slides and the video of the talk given at <strong>@<a rel="external" href="https://twitter.com/geekshubs">Geekshubs</a></strong></p>
<ul>
<li><strong>Javascript is not a bad solution for the beginning</strong>. It allowed us to have a "ready-to-use" version of 8fit in less time that if we had decided that the development was on native iOS and Android. - <strong>It might be restrictive</strong> in the future in terms of interactivity, animations, ... If you start noticing that, you can remove those bottlenecks using a native solution for them. We're doing though with the interactive workouts. - <strong>Analyze your resources and your product</strong> If you have enough resources to have a mobile solution do it! But if now let's make web dancing on mobile <strong>we did it!</strong></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Swift and Objective-C playing together</title>
      <link>https://pepicrft.me/blog/swift-and-objc-playing-together/</link>
      <guid>https://pepicrft.me/blog/swift-and-objc-playing-together/</guid>
      <pubDate>Mon, 08 Dec 2014 12:00:00 +0000</pubDate>
      <description>Start using Swift in your Objective-C projects. Avoid some headaches with these useful tips and advices for the communication layer between your Objective-C code base and your future Swift implementations</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Since Swift was released, a lot of developers have been wondering about the Swift integration in their projects. If we take a look to the Apple documentation it seems that the integration is possible, the language was designed for having that kind of copmatibility instead. However the majority of them haven't taken the decission of start using it, sometimes for fear of breaking something on the current code base, or probably for not having enough time to learn it.</p>
<p>After the release I started working on <strong>SugarRecord</strong> an open source library that is a kind of wrapper to work with databases (CoreData and Realm). The reason basically was that I wanted to learn deeply the language and playing with Playgrounds and short examples wasn't going to help a lot. You end up forgetting those small examples, and not facing with the real problems you would face if you played with a big project/library.</p>
<p>The experience has been amazing because I've learnt <strong>how powerful Swift might be</strong> if we compare it with Objectve-C but a bit painful after having to deal with different updates on the language, some unstable versions of XCode (unstable already) and overall what things that language has in common with Objective-C and how we can have a communication layer between them.</p>
<p>It's possible to have Swift playing with Objective-C in the same project, however there are some points that it's important to keep in mind if you want to avoid a big headache. I would try to summarize most of them here with short examples that explain them.</p>
<h2 id="objective-c-projects">Objective-C projects</h2>
<p><img src="https://pepicrft.me/blog/swift-and-objc-playing-together/__GHOST_URL__/images/posts/swiftobjc-structure.png" alt="Structure" /></p>
<p>If we analyzed the structure of our Objective-C projects that would be something like what you can see in the figure above. We have some libraries integrated (or not) using an external dependency manager like CocoaPods into our Objective-C code base. Everything works great, we have both in the same language and the same language features are available in both sides. <strong>What happens when Swift appears in the scene?</strong> We have features that are available in a language (Swift) that aren't in the other and that introduces extra communication problems that we have to face. We'll see that we can use a kind of <strong>keywords</strong> or Swift types that are automatically translated into the equivalent ones in Objectve-C but that in some other cases we might end up using a wrapper component that allows us to stablish the communication with these Swift components.</p>
<h2 id="pure-swift">Pure Swift</h2>
<p>Firstly we have to be sure of which features are <em>"pure"</em> Swift features. What does pure suppose? Features that can only be used from Swift and Objective-C won't be able to work with them. Yes, those features make the language much better, and powerful and allows you to simplify much more your implementations but if what you actually want is to have something compatible with your Objective-C it's better to wait until you have more Swift than Objective-C to start enjoying them. Those features are:</p>
<ul>
<li>Generics - Tuples - Swift enums - Structures defined in Swift - Top-level functions defined in Swift - Global variables defined in Swift - Typealiases defined in Swift - Swift-style variadics - Nested types and curried functions</li>
</ul>
<p>If you don't know about any of those features I recommend you to take a look to the <a rel="external" href="https://www.google.es/search?q=swift+docs&amp;oq=swift+docs&amp;aqs=chrome..69i57j69i60l5.1273j0j4&amp;sourceid=chrome&amp;es_sm=91&amp;ie=UTF-8">docummentation</a> where you'll learn more about them.</p>
<p>Remember, <strong>Objective-C</strong> doesn't know about them and you <strong>must</strong> avoid them in the <em>public interface</em> of your Swift features/components. Otherwise you won't be able to use them from your Objective-C code</p>
<h2 id="bridging">Bridging</h2>
<p>The tool Apple released to bridge Swift and Objective-C was something called <strong>bridging-header</strong> (<em>what an original name</em>). We have <strong>two bridging directions:</strong> Swift into Objective-C and Objective-C into Swift and consequently two bridging mechanisms:</p>
<ul>
<li><strong>Project-Briding-Header.h</strong>: That file allows you to <em>make your target Objective-C files visible</em> to Swift, otherwise they won't and you won't be able to use them. That file is a simple <em>Objective-C header file</em> where you have a list of imports of other headers. <em>Note: If you wanna use Objective-C libraries that you have integrated through CocoaPods you have to import them in that header if you want to use them from Swift</em></li>
</ul>
<p><strong>Product-Bridging-Header.h</strong></p>
<pre><code>//
// Use this file to import your target&#39;s public headers that you would
// like to expose to Swift.
//

// I can import CocoaPods Libraries here!
#import 

// And my Objective-C classes
#import &quot;CocaColaAlgorithm.h&quot;
</code></pre>
<p><strong>Swift-Class.swift</strong></p>
<pre><code>// Use here your Objective-C exposed classes
let cola = CocaColaAlgorithm.prepareCola()
</code></pre>
<ul>
<li><strong>ProductName-Swift.h</strong>: That file is <em>automatically generated</em> by XCode. When you compile the project XCode generates a header file <em>"translating"</em> Swift code into Objective-C. That way you can use Swift classes and components from Objective-C. <strong>That have some restrictions that I'll tell you about because not everything will be available to use in Objective-C</strong></li>
</ul>
<p><strong>Swift.swift</strong></p>
<pre><code>class NSObjectSwiftClass: NSObject { }
</code></pre>
<p><strong>ProductName-Swift.h</strong></p>
<pre><code>SWIFT_CLASS(&quot;_TtC9SwiftObjc18NSObjectSwiftClass&quot;)
@interface NSObjectSwiftClass : NSObject
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end
</code></pre>
<p><img src="https://pepicrft.me/blog/swift-and-objc-playing-together/__GHOST_URL__/images/posts/swiftobjc-alert.png" alt="Alert" /></p>
<h2 id="what-s-really-exposed">What's really exposed?</h2>
<p>As I mentioned not all your Swift code is exposed. The point is that the compiler follows some rules to generate the header and not all of those rules are reflected on the Apple docummentation. You'll figure out some of them working on that type of integrations. Some others you'll learn them reading from other developers dealing with similar problems. Summarizing the most important ones, it will only be exposed:</p>
<ul>
<li>Classes, attributes and methods marked with the keyword <strong>@objc</strong> - Classes descendent of <strong>NSObject</strong> - <strong>Public</strong> elements - Private elements are exposed if marked with <strong>@IBAction, @IBOutlet, and @objc</strong> - <strong>Internal</strong> elements are exposed if the project has an Objective-C bridging header - <strong>Only</strong> Objective-C compatible features.</li>
</ul>
<h3 id="circular-dependencies">Circular dependencies</h3>
<p>When you import Objective-C generated classes into your Objective-C existing classes do it using a foward declaration @class. Otherwise you might have troubles with circular dependencies. Import only the header file in the body of your classes.</p>
<h3 id="product-package-naming">Product package naming</h3>
<p>XCode uses your product package name for the xxxxx-Swift.h file naming but replacing some non alpha-numeric characters by an underscore symbol. To avoid some problems rename your package name using an alpha-numeric name (that doesn't start by a number which is replaced too by underscore).</p>
<h1 id="what-can-i-do-once-defined-the-bridge">What can I do once defined the bridge?</h1>
<h2 id="subclassing">Subclassing</h2>
<p>You can subclass Objective-C classes in Swift, remember to use the <strong>override</strong> keyword wherever you are overriding a parent class implementation. <strong>Swift classes cannot be subclassed in Objective-C</strong> <em>(even if they are NSObject sublcass or labeled with the keyword @objc)</em></p>
<p><img src="https://pepicrft.me/blog/swift-and-objc-playing-together/__GHOST_URL__/images/posts/swiftobjc-subclass.png" alt="Subclass" /></p>
<pre><code>#if !defined(SWIFT_CLASS)
# if defined(__has_attribute) &amp;&amp; ...
# define SWIFT_CLASS(SWIFT_NAME)...
# else
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME...
# endif
#endif

SWIFT_CLASS(&quot;_TtC9SwiftObjc9ObjcClass&quot;)
@interface ObjcClass
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end
</code></pre>
<h2 id="anyobject">AnyObject</h2>
<p>AnyObject is the Swift equivalent of <strong>ids</strong>. However AnyObject in comparison with id is not a class type but a protocol. AnyObject <strong>is not known until runtime execution</strong>. It supposes that the compiler can pass if you call a method on the AnyObject object that it doesn't actually implement but if your program executes that line of code your app is going to crash. <strong>Be careful!</strong>:</p>
<pre><code>if let fifthCharacter = myObject.characterAtIndex?(5) {
 println(&quot;Found \(fifthCharacter) at index 5&quot;)
}
</code></pre>
<h2 id="nils">Nils</h2>
<p>As you probably know Swift introduced a new type of data, <strong>optionals</strong> those allow nil type and the real content of the type (in case of having) is wrapped inside that optional. Objective-C is more flexible in that aspect and allows you to call methods on those nil objects without causing exceptions or making your app crash. The way the <strong>compiler translates</strong> those variables or function return parameters that <strong>might be nil</strong> is using <strong>implicitly unwrapped optionals</strong> (var!). It implies that if you are planning to use one of those implicitly unwrapped optionals that the compiler generated from your Objective-C code do it carefully checking firstly if the value is nil. <strong>Otherwise, trying to access it being nil will cause a runtime error and your app will crash</strong></p>
<pre><code>- (NSDate *)dueDateForProject:(Project *)project;
</code></pre>
<pre><code>func dueDateForProject(project: Project!) -&gt; NSDate!
</code></pre>
<h2 id="extensions-and-categories">Extensions and categories</h2>
<p>Extensions are the equivalent of categories in Swift. The main difference is that we can use extensions in Swift to make classes conform protocols that they originally didn't. For example we can make our class <em>MyClass</em> conform the protocol <strong>StringLiteralCovertible</strong> and initialize it using an string:</p>
<pre><code>extension MyClass: StringLiteralConvertible
{
 typealias ExtendedGraphemeClusterLiteralType = StringLiteralType
 init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
 self.pattern = &quot;\(value)&quot;
 }

 init(extendedGraphemeClusterLiteral value: StringLiteralType) {
 self.pattern = value
 }

 init(stringLiteral value: StringLiteralType) {
 self.pattern = value
 }

}
</code></pre>
<p>I recommend you that interesting post of Matt <a rel="external" href="http://nshipster.com/swift-default-protocol-implementations/">http://nshipster.com/swift-default-protocol-implementations/</a> where he explains different uses of default system protocols to do something like what I have shown you above.</p>
<h2 id="closures-and-blocks">Closures and Blocks</h2>
<p>They are automatically converted too by the compiler. There's only a difference and it's that in Swift if you <strong>use an external variable in a closure</strong> it's automatically mutable (no copy of the bar). Do you remember when you had to do it in Objective-C using the keyword <code>__block</code> before the variable definition? No more required!</p>
<p><strong>Example in Objective-C</strong></p>
<pre><code>__block CustomObject *myObject = [CustomObject new];
void (^myBlock)() = ^void() {
 NSLog(@&quot;%@&quot;, myObject);
};
</code></pre>
<p><strong>Example in Swift</strong></p>
<pre><code>let customObject: MyObject = MyObject()
let myBlock: () -&gt; () = { in
 println(&quot;\(customObject)&quot;)
}
</code></pre>
<p>And yes! we have the <a href="https://pepicrft.me/blog/swift-and-objc-playing-together/www.fuckingblocksyntax.com">FuckingBlockSyntax.com</a> equivalent for Closures, <a href="https://pepicrft.me/blog/swift-and-objc-playing-together/www.fuckingclosuresyntax.com">FuckingClosureSyntax.com</a></p>
<h2 id="objc-keyword">@objc Keyword</h2>
<p>When you want to specify the compiler that any Swift class, property or method must be visible in Objective-C after your code has been compiled you have to use the keyword @objc. Take look to the example below where we say the <em>SwiftCat</em> is going to be visible in Objective-C with the name <em>ObjcCat</em></p>
<pre><code>@objc(ObjcCat)
class SwiftCat {
 @objc(initWithName:)
 init (name: String) { /*...*/ }
}
</code></pre>
<h2 id="protocols">Protocols</h2>
<p>In protocols there are such exceptions crossing the protocols usage between Objective-C and Swift. While Swift can adopt <strong>any</strong> Objective-C protocol, Objective-C <strong>can only adopt</strong> Swift protocols if they are of type NSObjectProtocol. Otherwise Swift won't be able to do it.</p>
<p>Moreover if you are using protocols in a <strong>Delegate</strong> pattern you have to declare your protocols as <strong>class</strong>. Why? Because not only classes in Swift can conform protocols but structs too. Strucs are passed by copy instead of by reference and we don't want have a copied object that conforms a protocol behaving as a delegate of something because it's not actually the real delegate object. When you set a protocol as <code>class</code>, <strong>only classes can conform that protocol</strong></p>
<pre><code>/** MyProtocol.swift */
@objc protocol MyProtocol: NSObjectProtocol {
 // Protocol stuff
}
</code></pre>
<h2 id="cocoa-data-types">Cocoa Data Types</h2>
<p>Most of the foundation data types can be used interchangeably with Swift types (<em>remember to import Foundation</em>). So for example you can initialize a NSSTring object in Swift using a Swift string:</p>
<pre><code>let myString: NSString = &quot;123&quot;
</code></pre>
<p><strong>Int, UInt, Float, Double and Bool</strong> have its equivalent in Objective-C that is <strong>NSNumber</strong></p>
<pre><code>let n = 42
let m: NSNumber = n
</code></pre>
<p>Regarding the collection types, we have equivalents too there. <strong>[AnyObject]</strong> Swift array is automatically converted into NSArray (if the elements are AnyObject compatible). <em>For example if we have an array of Int, [Int] it will be converted into an array of NSNumbers.</em></p>
<p>Any <strong>NSArray</strong> will be converted into a Swift [AnyObject] array. We can even downcast it into the real type:</p>
<pre><code>for myItem in foundationArray as [UIView] {
 // Do whatever you want
}
</code></pre>
<p>And something similar happens with <strong>NSDictionaries</strong>. They are converted into <strong>[NSObject: AnyObject]</strong> and we get <strong>NSDictionaries</strong> from <strong>[NSObject: AnyObject]</strong> if the keys and values are instances of a class or are bridgeable</p>
<h1 id="cocoapods">CocoaPods</h1>
<p><img src="https://nairteashop.org/wp-content/uploads/2013/11/CocoaPods.png" alt="CocoaPods" /></p>
<p>You might wonder if we can use CocoaPods with our projects where we've started using Swift. <strong>The answer is YES</strong>, you can so far, but only using <strong>Objective-C pods</strong>. You can add the headers into your project <em>Bridging-Header.h</em> file and then they will be visible in Swift.</p>
<p>The CocoaPods team are working on supporting Swift libraries too, <a rel="external" href="https://github.com/CocoaPods/CocoaPods/pull/2835">https://github.com/CocoaPods/CocoaPods/pull/2835</a> and they are pretty closed to have it. So you'll be able to have not only Objective-C but Swift libraries too.</p>
<h1 id="moving-to-swift-advices">Moving to Swift Advices</h1>
<p>Finally as a conclussion of this summary/helping post I would like to give you some advices for your Swift integrations. I figured out some of them when I had to deal with some problems and I would like you not to have to deal with the same problems.</p>
<ol>
<li><strong>Don't touch your Objective-C code base</strong>: If you have a clean, useful code base on Swift don't speedup. There's no limit date to have everything on Swift. It's just something that Apple expects to be a gradual process. Move your components to Swift <em>only if they require a refactor</em> or <em>they have been deprecated and a new one (in Swift) will replace them</em>.</li>
<li><strong>Most of libraries are in Objective-C</strong>: And that's something great because you can have both Objective-C and Swift communicating with them. Libraries like AFNetworking, MagicalRecord, ProgressHUD are still being actively developed in Objective-C but some others are appearing in Swift in order to replace them like Alamofire.</li>
<li><strong>Implement Swift in isolated features</strong>: Avoid crossed dependencies between Swift andn Objective-C and try to use pure Swift only internally on those components. Expose those things that you need from Objective-C using @objc compatible features.</li>
<li><strong>Swift libraries only when there's no option in Objective-C</strong>: If you have seen a library in Swift that you haven't seen any like that before in Objective-C then use it. It's probably that you have to implement any wrapper to use from Objective-C if that library uses pure Swift features. <em>AlamoFire for example uses top-level functions, structs, ... so yes we can have it in our project and use it from Swift but it's impoossible to do it from Objective-C</em></li>
<li><strong>Swift is a language STILL IN PROGRESS</strong>: Do not get frustrated if you have the <em>SourceKitService Crashed</em> famous crash every 10 minutes. The compiler and the language in general have a lot of things to improve. It seems more stable now that some months ago but not enough (in my opinion). Moreover they are still changing and improving it so it's probably that you compile your project tomorrow and then something there's an optional somewhere that it wasn't yesterday.</li>
</ol>
<h2 id="resources">Resources</h2>
<pre><code>//MARK: - You should read
let swiftTypes = &quot;https://github.com/jbrennan/swift-tips/blob/master/swift_tips.md&quot;
let realmAndObjc = &quot;http://realm.io/news/swift-objc-best-friends-forever&quot;
let swiftReady = &quot;http://www.toptal.com/swift/swift-is-it-ready-for-prime-time&quot;
let swiftImprovesObjc = &quot;http://spin.atomicobject.com/2014/06/13/swift-improves-objective-c/&quot;
</code></pre>
]]></content:encoded>
    </item>
    
    <item>
      <title>Codemotion experience</title>
      <link>https://pepicrft.me/blog/codemotion-experience/</link>
      <guid>https://pepicrft.me/blog/codemotion-experience/</guid>
      <pubDate>Sun, 23 Nov 2014 12:00:00 +0000</pubDate>
      <description>After two days of Codemotion I would like to share my experience in my first time in a developers event like that one</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It was the first time I attended a developers event of that magnitude and I did it as <em>a speaker</em>. It was a challenge for me because I had given the same talk in my previous job office but not in a national event like Codemotion is. More than 1500 developers sharing their knowledge, their skills, tools, ... and I was there to talk about the architecture VIPER we had been working with in Redbooth during the past months before leaving (I keep using it in my new job).</p>
<p>The <strong>organization</strong> of the event was perfect, time schedule, location of different talks regarding the talk expectancy, food, drinks, internet connection, ... There's something I think that could have been better but that is not related with the organization. It's the naming of the talks. I went to some talks after reading the titlte and the description and finally found a different talk that I didn't expect.</p>
<p>I've to say too that the <strong>level</strong> and the <strong>topic</strong> of talks there was amazing. Talks related with architecture, some others about testing, talks about tools, or workshops explaining you how to develop apps for Android wearable devices. I attended some iOS talks related with architectures where I was able to learn how other companies organize their code (especially those with a big projects that pay a lot of attention to their code base structure). I met <strong>people</strong> I only met from Twitter like @nsstudent or @alvaro_fr and talk a bit in person about our lifes and our current projects.</p>
<p>Regarding the talk I gave I have to say I <strong>wasn't as nervous as some other times before</strong>. I was really relaxed because I enjoyed talking about how to make your projects cleaner and better organized. <strong>However</strong> I did it a bit faster and I had some problems with the project resolution and contacts which didn't allow some attendants to read clearly the code examples on the slides. I was talking after the talk with some Tuenti engineers about different topics related with architecture and which one they are applying on their app. I'm glad to see that I was able to convince some developers <strong>about the importance of taking care of your code</strong> and not doing everything in a ViewController. Some of them contacted me later on Twitter and have started reading and analyzing the example project.</p>
<p>I have to say it was a tired experience because I didn't sleep so much, I had to take the train with my Android Redbooth friends but I <strong>learnt a lot</strong> and got a lot of ideas to apply in my daily work. There's no doubt that I'll try to be there the next year.</p>
<p>See you the next year!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>VIPER, Looking for the perfect architecture</title>
      <link>https://pepicrft.me/blog/viper-looking-for-the-perfect-architecture/</link>
      <guid>https://pepicrft.me/blog/viper-looking-for-the-perfect-architecture/</guid>
      <pubDate>Sun, 16 Nov 2014 12:00:00 +0000</pubDate>
      <description>Talk I gave in the Redbooth HQ office for NSBarcelona with the iOS team talking about the VIPER architecture</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>The past thursday I gave a talk at Redbooth Office with the iOS team about an architecture we had been working with during the past months. We didn't use any architecture until then and the code was too coupled and messy that it was hard to review, debug, detect bugs, ...</p>
<p>We read about VIPER the first time <a rel="external" href="http://www.objc.io/issue-13/viper.html">here</a> and we loved the idea of splitting reponsibilities in all those components. We took a look to the example project, analyzed it and finally we applied it to some of our ViewControllers. It was a heavy task because we had to refactor not only those components but those children too but at the end we liked the result, and what easy it was to review the code and understand the implementation.</p>
<p>Moreover I implemented a Ruby Gem to generate those templates automatically in Swift or Objective-C, I called it <a rel="external" href="https://github.com/pepicrft/viper-module-generator"><em>viper-module-generator</em></a> and you can easily install it with <code>sudo gem install vipergen</code>. We spent a lot of time implementing the same components too many times, the naming was similar, the connections between them too, so why not making this faster?</p>
<p>The talk was recorded and the slides are available in speakerdeck so I would like to share with you them. If you have any doubt about it or you would like to contribute in any way, we are pleased to hear you and talk to you.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Github as your project management tool</title>
      <link>https://pepicrft.me/blog/github-as-your-project-management-tool/</link>
      <guid>https://pepicrft.me/blog/github-as-your-project-management-tool/</guid>
      <pubDate>Tue, 04 Nov 2014 12:00:00 +0000</pubDate>
      <description>Github is a powerful Git platform commonly used between the developers community. It offers features like issues, labels, milestones, releases, that used properly might help you to manage not only your technical repos but different aspects around your project like design, ideas, ...</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Github is a well known Git solution between all developers around the world. It helps you to manage your Git repositories remotely and offers extra features to complement the Git core and make you more productive. These extra features are for example Issues, Pull Requests, Labels, Milestones, Releases... We know about about them becase we use Github daily but we're totally conscious of how productive we can be using these components properly.</p>
<h2 id="github-external-project-management-tool-synchronization">Github + External Project Management Tool = Synchronization</h2>
<p>I've been working during the past months in a project management tool as a developer. We used Github and tried to translate tasks from that platform to Github in order to work in them. Although we used milestones, and other internal methods to connect these developers items with the platform, all the management core was contained in that platform. This is something good but if you ensure that the synchronization between these two components is taken into account by all the team. Synchronization is something difficult to mantain, sometimes you feel a sync man! and you are focused on having a healthy communication between Github and your project management platform (PMP), but some others you feel so tired that you forget to report the status of your Github items to your PMP. When it happens the communication is broken and it implies extra work for your workmates like <em>where did you work on this?, why didn't you resolve the task?, why didn't you apply the proper label?</em> In these situations you feel like you are doing repeated stuff that you could do just once. Sometimes you make use of scrips that you develop on your own but if you can't spend a lot of time <strong>developing scripts</strong> for each communication flow.</p>
<h2 id="github-but-what-if-i-m-not-a-developer">Github, but what if I'm not a developer?</h2>
<p>Although it sounds strange Github is not only for developers. The entire Git concept can be applied to design, to the company related stuff, ... Once all the team members know about the flow it's pretty easy to stay connected an synchronized. Think about something like <a rel="external" href="http://whatismarkdown.com/"><strong>Markdown</strong></a>. Talking from the developer side we use a lot when we start a new repo and we have to fill the README.md file (<em>I remember the first time I knew about it when I created my first repo</em>). Markdown is becoming popular, it's used now in blogging platforms (<em>I'm in fact writting this article using markdown</em>). We could use Mardown in <strong>our website/landing page repository</strong> I've seen companies that took the decision to stick to Markdown instead of choosing over-loaded editors like the one Wordpress offers to you. If your project includes its own content <strong>your company content editors</strong> could write directly in Markdown and integrate that content into for example a Landing, a Web, or a Mobile application just commiting their changes. For <strong>designers</strong> it's something more complicated because they use mostly graphics instead of text but if you try to externalize all design related stuff <em>like css files, stylesheet file, snapshot testing,...</em> they can be more involved. This is something that everybody dreams with it, designers with the ability to go into your web project and tell you off about the styles your applied or a developer getting the styles and sizes directly from the designer's mockups. It depends a lot on the kind the product and on the level of integration of design and developers.</p>
<p><img src="https://www.wired.com/wp-content/uploads/blogs/opinion/wp-content/uploads/2013/03/socialite.jpg" alt="Socialite" /></p>
<h2 id="management-tips">Management tips</h2>
<h3 id="components">Components</h3>
<h4 id="issues">Issues</h4>
<p>When we think about an issue we tend to think about something negative (<em>as a developers we think about bugs</em>) but it doesn't has to why be something negative. Think that an issue should be something like a task, so it implies that you can use it as a for example <em>an idea you have had that would be cool to have it in the project</em> or <em>a new feature you have to implement in the current sprint</em>. Try to use a representative naming for your issues because the issues page is going to be your daily friend where you're going to constantly check your next stuff you have to work on. Take a look to the examples below</p>
<p><strong>Good naming</strong></p>
<ul>
<li>Steps counter feature - Crash caused by an empty response in the workout detail</li>
</ul>
<p><strong>Bad naming</strong></p>
<ul>
<li>steps - crash with response</li>
</ul>
<blockquote>
<p>Useful note: In most of cases we'll end up creating a PR to solve the issue purpose. Github thought about it and they made an easy way to close issues directly merging an opened PR. You have to add a comment into your PR explaining that you resolved, fixed or solved any opened issue (e.g solved #31)</p>
</blockquote>
<p><img src="https://pepicrft.me/blog/github-as-your-project-management-tool/__GHOST_URL__/images/posts/githubissues.png" alt="Github Issues Screenshot" /></p>
<h5 id="labels">Labels</h5>
<p>Labels is a way to clasify not only your issues but your pull requests too. Labels has a name and a color and Github allows you to filter your issues/PR using them as a filter element. Although Github offers you some labels by default I recommend you to analyze and adapt them to your needs and requirements. Labels for a landing page can't be the same for a backend project. I've been googling around to have some ideas about labels other companies use in their project and I liked the idea of the first answer in this question in stack exchange, <a rel="external" href="http://programmers.stackexchange.com/questions/129714/how-to-manage-github-issues-for-priority-etc">http://programmers.stackexchange.com/questions/129714/how-to-manage-github-issues-for-priority-etc</a>. Tags that guy uses are:</p>
<p><img src="https://pepicrft.me/blog/github-as-your-project-management-tool/__GHOST_URL__/images/posts/githublabels.png" alt="Github Labels Screenshot" /></p>
<h4 id="milestones">Milestones</h4>
<p>Issues we'll be the core of hour project management, they will be our tasks and it's important to keep them organized. We've seen that labels allows us to tag them in terms of status, priority, type,... We can easily have either an idea of the most priority issues to work on, or the recent bugs related with UI but it doesn't allow to <strong>group different issues because they have something in common</strong>. The grouping reason might not only be related with the versioning but might be related with a refactor too, or even with a redesign. Think about Milestones like a bag with a well defined <strong>purpose</strong> that you are going to cover ussing the issues you are going to put inside.</p>
<p><img src="https://pepicrft.me/blog/github-as-your-project-management-tool/__GHOST_URL__/images/posts/githubmilestones.png" alt="Github Labels Screenshot" /></p>
<p>The example above shows different milestones related with some versions of the library and one of them is focused in issues/PRs that are planned to be in the future versions. Notice that you have a bar that indicates the <strong>precentage of issues/PR finished</strong>. This way you have a global idea of the status of that milestone.</p>
<h4 id="assignees">Assignees</h4>
<p>Tasks (issues) in groups (milestones) labeled and executed, developed, reviewed by your team. Here's where the people come into play. Thanks to the <strong>assignee</strong> feature of Github you can assign a Github issue or a PR to someone. This person is responsible to move this item forward, work on it, ensure that the status of this item is updated (using comments, changing labels, mentioning work mates if something is blocking, ...). Moreover you can filter by your issues/PRs so it's easy for you to know what involes you. Imagine you turning on your computer every morning and wondering what you should work on. <strong>Easy, take a look to your issues on Github</strong></p>
<p><img src="https://pepicrft.me/blog/github-as-your-project-management-tool/__GHOST_URL__/images/posts/githubassignees.png" alt="Github Labels Screenshot" /></p>
<h3 id="flow">Flow</h3>
<p>Understood these components someone might wonder how they could be applied into a project sprint. We're still working on 8fit to have a fixed flow that matches our needs, after using different tools for project management and we ended up with Github and we've inspired our flow in others' flows with our little details:</p>
<ol>
<li><strong>Apply any methodology</strong>: We strongly recommend any Agile methodology like Scrum. We've been using them previously and we're very happy we are very productive with it. Teach your entire team that methodology and make sure everybody knows about it. Although everybody should be responsible of its closest sprint, when the project is that manager role should cover more than one sprint. This person is going to be responsble to move issues between these sprints depending on the project schedule, priorities, ... Your team should meet for example at the beginning of the week to organize the product and sprint backlong and then during the week everybody should work with the sprint backlog and report the daily scrum status through meetings or any real time communication tool (<em>e.g. Slack HQ</em>). _There are some tools that apply a layer over Github that add these extra management features. In our case we're using one called <a rel="external" href="http://www.zenhub.io">Zenhub</a>. You can install it as a Chrome extension and it's directly integrated with Github. Other solutions work as an external component*</li>
<li><strong>Keep tasks updated</strong>: It's a common error to not update your project issues since they are created. You know their statuses but what happens if your workmate wants to know about any task/issue and you haven't reported anything since you started working on it? Labels and assignees are not only used when the issue/PR is created, re-assign it if another person has to work on it, change the label if the priority has increased, connect it with other PRs that have something in common. It's very important to keep this engagement with the issues board.</li>
<li><strong>Group your issues (and make them small)</strong>: Think about a refactor, split it in small refactors, and group them into the same milestone refactor's bag. If you tried to locate that refactor in the future it would be easier to locate the milestone instead of the small issues. If the milestone is grouping a version, ensure that once the the milestone is closed you create a new release with the milestone version adding a changelog with the points that new version has covered and generate a tag to mark that status on the timeline.</li>
<li><strong>Review</strong>: Before closing any issue/PR and if you have workmates that can review your work, ask them to do it. Don't merge your changes until you have their confirmations. It's better having more than two eyes. We are not magicians and it's probable that we forget any edge case.</li>
</ol>
<p>Keep in mind the previous points and try to apply them in your projects, try to be constant with them, and try your team to be too. Improve your management tools and flow every day regarding your needs and boost your team productivity. <strong>You just only need Github!</strong></p>
<p><img src="https://pepicrft.me/blog/github-as-your-project-management-tool/__GHOST_URL__/images/posts/githubboard.png" alt="Zenhub board in Github" /></p>
<h2 id="recommended-articles">Recommended articles</h2>
<ul>
<li><a rel="external" href="http://whatismarkdown.com/"><strong>What is Markdown</strong>?</a> - <a rel="external" href="https://huboard.com/"><strong>Instant project management for your Github issues: HuBoard</strong></a> - <a rel="external" href="http://liftux.com/posts/using-github-issues-project-management/"><strong>Using Github for Project Management</strong></a> - <a rel="external" href="https://guides.github.com/features/issues/"><strong>Mastering issues. Github</strong></a> - <a rel="external" href="https://github.com/blog/831-issues-2-0-the-next-generation"><strong>Issues 2.0: The next generation</strong></a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Leaving Redbooth</title>
      <link>https://pepicrft.me/blog/leaving-redbooth/</link>
      <guid>https://pepicrft.me/blog/leaving-redbooth/</guid>
      <pubDate>Wed, 29 Oct 2014 12:00:00 +0000</pubDate>
      <description>I took de decision to leave Redbooth and join to a new adventure. I explain here the reasons, everything I learned from there and my expectations for 8fit</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>It's difficult for me to talk about this and it was a few days ago when I had to tell my workmates about my decission, leaving Redbooth. I started with that startup from Barcelona when I haven't finished my bachelor yet. They gave me the opportunity to work remotely and I did my best. I help firstly the iOS team when the company's name was aready Teambox. Then I learnt a <strong>bit of Android</strong> when thought that I was able to help them and I thought why not?</p>
<p>It was difficult for me at first because I was used to Objective-C patterns and tools like XCode, Cocoapods, ... Moreover the project was a bit messy but I did my best and then I improved the Java I had learnt at the University. I have to say that it was a great opportunity for me that I took advantage of. Since then I've done different mini projects/libraries in Android and I want to keep learning it (<em>although I keep my strong opinion about the tools Google's offering that are not as good as they shouln't if we compare them with XCode for example</em>)</p>
<p>I missed iOS, since I moved to Android the iOS team had implemented the iPad version, new components and some other interesting features. I wasn't any more than a Junior developer in Android and I told the company about joinning again iOS as soon as they had a senior Android to replace me. Months later I ended up moving to iOS again until now.</p>
<h2 id="things-i-learnt-from-redbooth">Things I learnt from Redbooth</h2>
<p>I've learnt a lot of since during these months in Redbooth that I will never forget and that have made me a better developer. Some of them has been:</p>
<ul>
<li><strong>Git</strong>: I remember the first meeting we had with the lead and the team to talk about us, about our experience and how Teambox iOS Universal was organized. I didn't know a lot about Git, if I had used it before it had been usint graphic tools and the first task that day was to learn Git. I use it almost everyday for all my projects and only form console. Once you get used to the Git commands I think that it's easier and you can get rid of these graphic tools. We used Github, and its different features like Issues, Milestones, Releases, ... <em>We even had a bot to let you know about cowboys in the project!</em></li>
<li><strong>Work in a team</strong>: I had never worked before in a team. Projects I had done before were of maximum two people (<em>Dropbox was our Git</em>) and Trello was our collaboration tool. When you join a team you learn how important is to be coordinated with the team, and with the company's track. When this feature has to be implemented, these bugs have to be fixed because QA team reported it, you should review that PR to see if everything is ok, ... Moreover you can talk with your workmates about implementations, architectures, code structure... I enjoyed using Redbooth as a collaboration tool and learnt how powerful it can be if you use it perfectly.</li>
<li><strong>Guidelines</strong>: This point is related with the previous one. When you work alone there are some points you don't pay attention to. Overall these related with the code style. In the same way you need a language to communicate with others and you have to use it properly when you work in a team you have a language that is the code language and some rules that tell you how to use the language. Without these rules everybody would do what he wanted. We used them for Objective-C style (<em>forked from New York Times</em>) and one part of the PR review was to review if the style points were respected.</li>
<li><strong>Architecture</strong>: When you work in a project that becomes bigger and where new features are coming every week you have to pay attention to your project architecture. In Redbooth we stopped to think about it some months ago when we read about VIPER and saw that we were not respecting SOLID and Clean Architecture principles. That made the code difficult to debug/test/read and understand. Our experience refactoring these components with VIPER has been very satisfactory. We refactored the biggest components and improved day by day the concept of VIPER inside the Redbooth iOS Team. I even developed a generator in Ruby <a rel="external" href="https://github.com/pepicrft/viper-module-generator">https://github.com/pepicrft/viper-module-generator</a> and I'm going to give a talk in the <strong>CodeMotion</strong> event.</li>
<li><strong>Cowboy, but sometimes</strong>: Working in a team where everything is planned, where you have an schedule of tasks that you have to follow during the week makes you loose your cowboy side. It's not bad when the company has a certain dimension (<em>you cannot be doing what you want because there are priorities</em>). However you shoudln't lost your Cowboy side because it keeps your motivation alive. I've sometimes received some pull of ears by my workmates for being more Cowboy than what I should.</li>
</ul>
<h2 id="change-of-pace">Change of pace</h2>
<p>It was difficult for me to take de decission, specially due to the previous points but I was very <strong>motivated with the new project</strong> and the idea behind it. The company is giving its first steps as a startup and it was a chance for me to learn about how to build a company from the scratch and work closed to the product (<em>at least more than what I did in Redbooth</em>). I'm going to have more flexibility now because I don't have a fixed space of work or office. I can work at home, from a Coworking space, from a coffee, or even from the world. I'm totally conscious that this is an adventure that I cannot miss. I have a lot of hope in the project and I'm going to do my best to do it a successful project and company to help a lot of users to get in shape and keep a good health.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Setup your iOS Projects for testing</title>
      <link>https://pepicrft.me/blog/setup-your-ios-projects-for-testing/</link>
      <guid>https://pepicrft.me/blog/setup-your-ios-projects-for-testing/</guid>
      <pubDate>Mon, 13 Oct 2014 12:00:00 +0000</pubDate>
      <description>Learn how to setup your iOS for testing using the most popular testing libraries and how to integrate your project tests in the development flow.</description>
      <content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>In other programming communities, like the Ruby one, developers are more aware of testing new components. Ensuring every component is tested <strong>is not common</strong> within the mobile appcommunity.</p>
<p>Fortunately, iOS developers have been working over the years to bring that culture to iOS too. The community is <strong>developing new libraries</strong> that use native ones allow you to write your tests with a fresh and more readable syntax. This has provided a big impulse and every day more and more developers ensure that expected behaviour in their apps is tested.</p>
<p>The <strong>Redbooth iOS Team</strong> we've been strongly influenced by the Ruby backend team and we decided to introduce testing into our development flow. Thanks to components like <em>Cocoapods</em>, <em>Schemes and targets</em> and some other tools, testing has become an essential part of development cycle.</p>
<h2 id="testing-flow">Testing flow</h2>
<p>Currently, depending on the type of test, the steps we follow are different:</p>
<ul>
<li><strong>Unit testing:</strong> We write unit tests when developing new features or controls. Our goal is to ensure the components behave according to expectations. Although we don't follow TDD at all times, we're trying to do so more and more. <em>Unit testing allow us to detect regressions and reduce QA costs</em>. 1. Tests are executed using a CI environment. 2. The CI integration reports the results to the Github PR. 3. The PR will be merged only when: - The implementation includes tests and they pass - It has more than one :+1: by the peer review. - <strong>Acceptance tests:</strong> In this case, tests are defined by the QA team. They use <a rel="external" href="http://appium.io/"><strong>appium.io</strong></a> for these tests which allows them to define the same suite of tests for Android and iOS in Ruby. It's important here to highlight the need of using <strong>accesibility tags</strong> because these tests make use of them to call different components in the app interface. When we have a new alpha version after some features introduced or bugs fixed: 1. We generate an <strong>alpha</strong> version and send it to the QA team using distribution tools like Hockeyapp. 2. QA runs Smoke and Acceptance tests in their environments. 3. When they pass we move the alpha to a <strong>beta</strong> version. Otherwise we fix the tests that didn't pass and repeat the process. - <strong>Snapshot testing:</strong> Regressions in design are not detectable using unit tests. Even if you add unit tests for UI properties (which we don't recommened). We have recently started using a library from Facebook, <a rel="external" href="https://github.com/facebook/ios-snapshot-test-case"><strong>iOS Snapshot Test Case</strong></a> and introduced it in the flow following the steps below: 1. Design team send us the designs of the new features 2. We implement them with their respective <strong>unit tests</strong> and <strong>snapshot tests</strong> generating snapshots. 3. We send the snapshots to the design team and wait for their confirmation. 4. Once confirmed, the implementation is <strong>ready</strong> and the snapshot/s generated will be valid while the designs don't change.</li>
</ul>
<h2 id="specta">Specta</h2>
<p>Our firsts tests were written using Kiwi. We find it a little bit outdated and introduces a lot of coupling with matchers and mocks. With the introduction of iOS 8 and the improvements in the XCTest framework we've seen that the Specta framework is becoming more and more active. After releasing the first beta with support for iOS 8 and after a lot of investigation we decided to move our tests to this library. We complemented it with the matcher <strong>Expecta</strong> and the library for mocking <strong>OCMock</strong>. I recommend reading <a rel="external" href="http://nshipster.com/unit-testing/">this article</a> about different alternatives for testing. There Matt compares all the alternatives and discusses their advantages and disadvantages.</p>
<blockquote>
<p>The main advantage of using Expecta over other matcher frameworks is that you do not have to specify the data types. Also, the syntax of Expecta matchers is much more readable and does not suffer from parenthesitis.</p>
</blockquote>
<p>Syntax in Specta + Expecta is more readable, friendly and easy to remember. The example below shows tests using <strong>OCMHamcrest</strong>:</p>
<pre><code>assertThat(@&quot;foo&quot;, is(equalTo(@&quot;foo&quot;)));
assertThatUnsignedInteger(foo, isNot(equalToUnsignedInteger(1)));
assertThatBool([bar isBar], is(equalToBool(YES)));
assertThatDouble(baz, is(equalToDouble(3.14159)));
</code></pre>
<p>Using <strong>Kiwi</strong></p>
<pre><code>[[@&quot;foo&quot; should] equal:@&quot;foo&quot;];
[[foo shouldNot] equal:theValue(1)];
[[[bar isBar] should] equal:theValue(YES)];
[[baz should] equal:theValue(3.14159)];
</code></pre>
<p>And finally <strong>Expecta</strong>:</p>
<pre><code>expect(@&quot;foo&quot;).to.equal(@&quot;foo&quot;); // `to` is a syntatic sugar and can be safely omitted.
expect(foo).notTo.equal(1);
expect([bar isBar]).to.equal(YES);
expect(baz).to.equal(3.14159);
</code></pre>
<h2 id="setup">Setup</h2>
<h3 id="setup-the-project-schemes-and-targets">Setup the project (schemes and targets)</h3>
<blockquote>
<p>A <strong>scheme</strong> represents a collection of targets that you work with together. It defines which targets are used when you choose various actions in Xcode (Run, Test, Profile, etc.)</p>
</blockquote>
<p>In our case we use schemes only for testing. We decided to leave the main scheme only for builds and archives, integrating only the <strong>pod libraries</strong> that our project uses and having the pods required for testing like Specta or OCMock in the testing scheme. The result is the following:</p>
<p>Where it's important set the scheme as <strong>Shared</strong> if you want to have it attached to your git repository.</p>
<p>With the <strong>schemes</strong> setup the next step is to define what <strong>targets</strong> we need.</p>
<blockquote>
<p>A <strong>target</strong> is an end product created by running "build" in Xcode. It might be an app, or a framework, or static library, or a unit test bundle. Whatever it is, it generally corresponds to a single item in the "built products" folder.</p>
</blockquote>
<p>In the <a rel="external" href="https://redbooth.com">Redbooth</a> app, apart form the main app target, we use one for <strong>Unit testing</strong> and another one for <strong>Snapshot testing</strong> as you can see in the screenshot below.</p>
<p>Notice in the screenshot that the project has configurations for <strong>Debug</strong> and <strong>Release</strong> where we set the configuration for each target and configuration. By default <strong>CocoaPods</strong> should do it automatically for you but in some cases it doesn't work properly. Be sure then that each configuration and XCode target has a corresponding generated pod config file.</p>
<p>Finally we have to select which targets are going to be built in our testing scheme. As we are going to use it only for testing we have to choose only this option in the targets. Moreover the order of the targets in that list should be the correct one regarding the dependencies between them. The firsts targets to be built should be the pod ones, then the application which components are going to be tested and later our testing targets. Remember:</p>
<ol>
<li><strong>Pod targets</strong> 2. <strong>Application targets</strong> 3. <strong>Testing targets</strong></li>
</ol>
<blockquote>
<p>Note: CocoaPods targets are not the same as XCode targets. Cocoapods targets are useful to group pods with an specific configuration. As you might have noticed their definitions but remember that <strong>they are not the same</strong> because it's a common misunderstanding when you are integrating your project with CocoaPods.</p>
</blockquote>
<h3 id="connect-cocoapods">Connect CocoaPods</h3>
<p>With the project setup the next step is to prepare the <strong>Podfile</strong> to integrate the testing libraries with our project targets. _If you haven't worked with CocoaPods before I recommend you to read about it here: <a rel="external" href="http://guides.cocoapods.org/_">http://guides.cocoapods.org/_</a>. Our Podfile has the following format:</p>
<pre><code>source &#39;https://github.com/CocoaPods/Specs.git&#39;
platform :ios, &#39;7.0&#39;

inhibit_all_warnings!

target :app do
 link_with &#39;Redbooth&#39;
 # Project pods
end

target :test do
 link_with &#39;UnitTests&#39;
 pod &#39;OCMock&#39;, &#39;~&gt; 3.1&#39;
 pod &#39;Specta&#39;, &#39;~&gt; 0.2&#39;
 pod &#39;Expecta&#39;, &#39;~&gt; 0.3&#39;

 target :snapshottest do
 link_with &#39;SnapshotTests&#39;
 pod &#39;FBSnapshotTestCase&#39;, &#39;~&gt; 1.2&#39;
 pod &#39;Expecta+Snapshots&#39;, &#39;~&gt; 1.2&#39;
 end
end
</code></pre>
<p>In order to have our pods organized we use <strong>Cocoapods</strong> targets. They are strongly related with our project targets but remember that they are not the same. To specify CocoaPods which XCode target should be integrated with we have to use the property <strong>link_with</strong>. The table below summarizes which Pods target is integrated with each Project target.</p>
<p>| Pods targets \ Project targets | Redbooth | UnitTests | SnapshotTests | | ------------------------------ | -------- | --------- | ------------- | | app | x | x | x | | test | | x | x | | snapshottest | | | x |</p>
<p>Execute <code>pod install</code> and wait until it integrates the pods into the different target.</p>
<p><strong>Note</strong>: We've noticed that in some cases, especially if you have been changing your Podfile a lot the integration might not be ok. If you try to compile the project after doing so you might run into problems:</p>
<ol>
<li>Check that <strong>Link Binary With Libraries</strong> section in <em>Build Phases</em> of each target contains only the <code>libPods-xxx.a</code> file of the CocoaPods target that you selected to be integrated there. 2. Check in the project <strong>configurations</strong> that each target has the proper pod config linked. 3. Finally ensure that in the scheme settings, build section, targets are listed there and in the proper order (mentioned previously)</li>
</ol>
<p>If everything is right you should be able to <strong>Run</strong> your application using the main target in any device and execute your <strong>Tests</strong> from the tests scheme.</p>
<h2 id="a-bit-about-snapshot-tests">A bit about snapshot tests</h2>
<p><img src="https://maniacdev.com/wp-content/uploads/2014/07/Snapshots.jpg" alt="snapshot-tests" /></p>
<p>Snapshot tests are not very common in the world of testing, however they are becoming more popular thanks overall to that Facebook's library. Since we started using it the number of regressions introduced in design has decreased and now the designers can check that the results <strong>match their expectations and desings</strong>.</p>
<p>Basically the snapshot tests consist of a definition for <strong>snapshots creation</strong> and then once it's checked that the snapshot is ok, the <strong>snapshot checking tests</strong> snapshots are stored in your project folder and they are used for future tests. If tests are executed and there's no incoherence between these images and the tested views, tests will pass but if something is detected the test won't pass giving you a <strong>command to be used with the software <a rel="external" href="http://www.kaleidoscopeapp.com/">Kaleidoscope</a></strong>. Take a look at the example below where we define the test for testing a header view and an example of failed test shown in Kaleidoscope. The failed example shows an animation with the introduced UI bug <em>(Someone changed the left margin and it was detected)</em></p>
<pre><code>#import &quot;TBHeaderView.h&quot;

SpecBegin(TBHeaderView)

describe(@&quot;header view&quot;, ^{
 it(@&quot;matches view&quot;, ^{
 TBHeaderView *view = [[TBHeaderView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
 [view setSectionName:@&quot;DuckTest&quot; sectionCount:60];
 if (SNAPSHOT_RECORDING) {
 expect(view).to.recordSnapshotNamed(@&quot;TBHeaderView&quot;);
 }
 else {
 expect(view).to.haveValidSnapshotNamed(@&quot;TBHeaderView&quot;);
 }
 });
});
SpecEnd
</code></pre>
<h2 id="next-steps">Next steps</h2>
<ul>
<li><strong>Continuous integration</strong>: Tests are great but how do you know wether someone's changes have broken them or not? This is where continuous integration plays an important role. Solutions like XCode Server, Travis CI or Jenkins should be taken into account to ensure nothing is broken. - <strong>Specta templates</strong>: I recommend you to install this XCode template <a rel="external" href="https://github.com/luiza-cicone/Specta-Templates-Xcode">https://github.com/luiza-cicone/Specta-Templates-Xcode</a> to create tests using that predefined structure. You can install it using <a rel="external" href="http://alcatraz.io/">Alcatraz</a>. - <strong>Snapshots for XCode</strong>: There's another plugin to check the results of the snapshot tests. You can install it using Alcatraz too. <a rel="external" href="https://github.com/orta/Snapshots">https://github.com/orta/Snapshots</a> - <strong>Test, test, test</strong>: Don't think testing is something useless. When you start having a big app with a lot of components interacting between them regressions could appear easily and with tests they would be detected before passing the app to the QA team.</li>
</ul>
<h2 id="documentation">Documentation</h2>
<ul>
<li><a rel="external" href="http://nshipster.com/unit-testing/"><strong>Unit Testing</strong></a>, by Matt - <a rel="external" href="http://robots.thoughtbot.com/test-driving-ios-a-primer"><strong>Test Driving iOS</strong></a>, Thoughbot - <a rel="external" href="http://appleprogramming.com/blog/2014/01/18/tdd-with-specta-and-expecta/"><strong>TDD With Specta and Expecta</strong></a>, by Apple Programming - <a rel="external" href="http://www.artandlogic.com/blog/2013/05/lightweight-bdd-for-ios-and-os-x/"><strong>Lightweight bdd for iOS and OSX</strong></a>, by Art &amp; Logic - <a rel="external" href="http://www.amazon.com/Test-Driven-iOS-Development-Developers-Library/dp/0321774183"><strong>Test-Drive iOS Development (Book)</strong></a>, by Graham Lee - <a rel="external" href="http://www.objc.io/issue-15/snapshot-testing.html"><strong>Snapshot testing</strong></a>, by objc.io</li>
</ul>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
