<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Patrik</title>
    <description>The latest articles on DEV Community by Patrik (@iselind).</description>
    <link>https://dev.to/iselind</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F25661%2F7f8b7d3d-ea5e-44de-a70a-ff136194cc58.jpg</url>
      <title>DEV Community: Patrik</title>
      <link>https://dev.to/iselind</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iselind"/>
    <language>en</language>
    <item>
      <title>Rethinking Exception Handling in APIs: Design for Clarity, Not Convenience</title>
      <dc:creator>Patrik</dc:creator>
      <pubDate>Sun, 20 Apr 2025 07:43:36 +0000</pubDate>
      <link>https://dev.to/iselind/rethinking-exception-handling-in-apis-design-for-clarity-not-convenience-1hjb</link>
      <guid>https://dev.to/iselind/rethinking-exception-handling-in-apis-design-for-clarity-not-convenience-1hjb</guid>
      <description>&lt;p&gt;Many projects—especially APIs—tend to lean too heavily on exceptions, often treating them as a lazy shortcut to communicating failure. I've encountered too many APIs where exceptions escape into the wild or worse, are dumped wholesale into responses. This approach might be convenient for the developer, but it creates a nightmare for API consumers.&lt;/p&gt;

&lt;p&gt;In a well-designed API, exceptions should never escape unhandled. They should be caught and translated into meaningful, informative responses. While exceptions are indeed useful during development and debugging, they are rarely intended for end users or external systems.&lt;/p&gt;

&lt;p&gt;That doesn’t mean we hide everything behind a vague 500 error. Quite the opposite. A well-crafted response can be clear and helpful without exposing raw internals. Think about what exception &lt;em&gt;type&lt;/em&gt; occurred, and use that as a cue to shape your response. But don’t return something like: "We got exception: NullPointerException". Instead, use the exception to inform your API logic and produce a clean, actionable response.&lt;/p&gt;

&lt;p&gt;The problem is that most exceptions only carry a message—usually something meant for internal developers. That message isn’t appropriate for API consumers. But what if we enriched exceptions so they carried more useful, structured information?&lt;/p&gt;

&lt;h2&gt;
  
  
  Enriching Exceptions
&lt;/h2&gt;

&lt;p&gt;This is absolutely achievable. Yes, it takes a shift in mindset, and it might mean creating some supporting structures, but the payoff is significant. Let's go through some examples of what might be achieved.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dual Messages
&lt;/h3&gt;

&lt;p&gt;Enhance your exceptions to include two messages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One for internal diagnostics (e.g., logs).&lt;/li&gt;
&lt;li&gt;One tailored for the external consumer (e.g., API response).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This separation ensures that developers have the information they need without confusing or overwhelming the API consumer. It also helps prevent accidental leaks of sensitive or overly technical details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Context Flag
&lt;/h3&gt;

&lt;p&gt;Add a simple boolean flag indicating whether the error is due to the consumer (e.g., bad request) or internal server logic. This tiny addition can guide how the API responds and what information is revealed.&lt;/p&gt;

&lt;p&gt;For example, the tailored message meant for external consumers might be included in the response if the context flag indicates a bad request. In contrast, if the issue is internal, exposing that message might be unhelpful—or even misleading—for the requester. The flag becomes a simple yet powerful mechanism for deciding what gets communicated and when.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Result
&lt;/h3&gt;

&lt;p&gt;By implementing just these two small changes, you can radically improve your API's user experience. Instead of cryptic error codes or raw stack traces, your consumers get clear, relevant, and actionable responses—without sacrificing internal visibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Implementation Example
&lt;/h2&gt;

&lt;p&gt;Let's imagine a super class. Something along these lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ServiceGeneratedException extends Exception {
  private String internalMessage;
  private String externalMessage;
  private boolean causedByExternal;

  public ServiceGeneratedException(String internal, String external, boolean causedByExternal) {
    this.internalMessage = internal;
    this.externalMessage = external;
    this.causedByExternal = causedByExternal;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there we can make two subclasses, one for each case for &lt;code&gt;causedByExternal&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class InternalException extends ServiceGeneratedException {
  public InternalException(String internal, String external) {
    super(internal, external, false);
  }
}

public class ExternalException extends ServiceGeneratedException {
  public ExternalException(String internal, String external) {
    super(internal, external, true);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All your exceptions should inherit from one of these two classes.&lt;/p&gt;

&lt;p&gt;This might not look like much at first, but it demonstrates how deliberate changes can lead to impactful improvements.&amp;amp;##x20;&lt;/p&gt;

&lt;p&gt;Having these classes provide the opportunity to create more useful responses. We can provide those responses in various formats based on the headers provided. We would have the same data presented in whichever format the requester supports.&lt;/p&gt;

&lt;p&gt;What we need is a method that can convert a &lt;code&gt;ServiceGeneratedException&lt;/code&gt; to a response body, and then serialize that response into a format that the requester supports. One way to achieve this would be to add something like &lt;code&gt;String toResponse(Set&amp;lt;DataFormat&amp;gt; supportedFormats)&lt;/code&gt; to &lt;code&gt;ServiceGeneratedException&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;DataFormat&lt;/code&gt; here is an enum with entries for &lt;code&gt;JSON&lt;/code&gt;, &lt;code&gt;Yaml&lt;/code&gt;, &lt;code&gt;XML&lt;/code&gt;, and whichever other format you might support. The set &lt;code&gt;supportedFormats&lt;/code&gt; is the translation of which formats the requester supports in the response which is found in the request headers.&lt;/p&gt;

&lt;p&gt;Here's a simplified implementation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public String toResponse(Set&amp;lt;DataFormat&amp;gt; supportedFormats) {
  DataFormat format = findFormatWeCanProduce(supportedFormats)

  // Create a basic response object
  Map&amp;lt;String, Object&amp;gt; response = new HashMap&amp;lt;&amp;gt;();
  response.put("error", this.causedByExternal ? this.externalMessage : "An unexpected error occurred.");
  response.put("type", this.causedByExternal ? "external" : "internal");
  // Other data that could be provided:
  // - Correlation ID
  // - Trace ID
  // - A GUID for this particular issue, making it easier to find it later in the logs.
  //   Just make sure the GUID shows up in the logs as well!

  // Serialize the response to the preferred format
  switch (format) {
    case JSON:
      return JsonSerializer.serialize(response);
    case XML:
      return XmlSerializer.serialize(response);
    case Yaml:
      return YamlSerializer.serialize(response);
    default:
      return JsonSerializer.serialize(response); // fallback
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A quick word on &lt;code&gt;findFormatWeCanProduce&lt;/code&gt;: we assume it selects the first mutually supported format from the set provided. This keeps things simple and pragmatic. If you want to take this further, you could return a strategy object responsible solely for serializing the response body. For example, it might serialize into JSON, XML, or YAML, and potentially include format-specific metadata such as MIME types—relevant in protocols like HTTP.&lt;/p&gt;

&lt;p&gt;Separately, the &lt;code&gt;toResponse&lt;/code&gt; method itself could delegate to another strategy object tasked with constructing the complete response. This object would be responsible for wrapping the serialized body in whatever envelope is appropriate for the communication protocol, including headers, status codes, and similar metadata. This design helps decouple concerns: one strategy focuses on how data is formatted, and the other on how that formatted data is packaged and delivered within the specific context of a given protocol.&lt;/p&gt;

&lt;p&gt;Have you noticed that none of the implementation so far is specific to any one specific communication protocol? This can be used just as well in HTTP, gRPC, RabbitMQ, GraphQL, or whatever! And without affecting your internal implementation to any significant degree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts: Designing with the Consumer in Mind
&lt;/h2&gt;

&lt;p&gt;Exception handling shouldn't be an afterthought. The API is the contract you offer your consumers—not the exceptions themselves. While exceptions can be wrapped into the API’s response, they must be filtered, reformatted, and made useful. Just because an exception message makes sense to you as the developer doesn't mean it will make any sense to your consumers. Design your error responses with the same care and intention as your successful ones.&lt;/p&gt;

</description>
      <category>softwaredesign</category>
      <category>errors</category>
      <category>api</category>
    </item>
    <item>
      <title>What Is a Tech Lead (And Why It Doesn’t Have to Be a Person)</title>
      <dc:creator>Patrik</dc:creator>
      <pubDate>Fri, 18 Apr 2025 15:03:00 +0000</pubDate>
      <link>https://dev.to/iselind/what-is-a-tech-lead-and-why-it-doesnt-have-to-be-a-person-1e7i</link>
      <guid>https://dev.to/iselind/what-is-a-tech-lead-and-why-it-doesnt-have-to-be-a-person-1e7i</guid>
      <description>&lt;p&gt;In the evolving landscape of software development, the role of the tech lead is both crucial and, at times, contentious. Companies vary widely in how they define, implement, or even avoid this role altogether. Whether a company is building software products for its own use or delivering solutions for clients, the tech lead function plays a pivotal role in steering technical direction, facilitating collaboration, and ensuring quality. However, the execution of this role can differ significantly.&lt;/p&gt;

&lt;h1&gt;
  
  
  Clarifying the Tech Lead vs. Architect Roles
&lt;/h1&gt;

&lt;p&gt;A common point of confusion in software organizations is the distinction between the tech lead and the architect. While there can be overlap, their focuses are typically different. A tech lead is primarily concerned with the &lt;em&gt;how&lt;/em&gt;—how the team approaches implementation, how the codebase is structured, how best practices are applied, and how the team collaborates effectively.&lt;/p&gt;

&lt;p&gt;In contrast, an architect tends to focus more on the &lt;em&gt;what&lt;/em&gt;—what systems need to be built, what technologies should be adopted, and what high-level decisions shape the overall architecture. Both roles are essential and ideally work in tandem, with the architect providing a broad, strategic view and the tech lead translating that vision into actionable execution.&lt;/p&gt;

&lt;p&gt;It's important not to view the roles as isolated or siloed. They are interdependent and constantly shape each other's work, as well as the broader technical landscape. For instance, architects often rely on input from tech leads to identify when a necessary component or system—the &lt;em&gt;what&lt;/em&gt;—is missing or undefined. In turn, architects can clarify or refine that &lt;em&gt;what&lt;/em&gt;, enabling the tech lead to move forward effectively with the &lt;em&gt;how&lt;/em&gt;. Likewise, architects may influence tech leads by introducing new architectural principles or constraints—such as adopting a microservices approach or enforcing data privacy layers—which directly shape how tech leads approach implementation, tooling, and team workflows.&lt;/p&gt;

&lt;h1&gt;
  
  
  Diverging Models: Centralized vs. Distributed Leadership
&lt;/h1&gt;

&lt;p&gt;Some organizations designate a specific individual as the tech lead. This person often acts as a bridge between developers, product managers, and other stakeholders. They help define technical strategies, make architectural decisions, and mentor team members. Their presence can provide clarity and cohesion, especially in complex projects where alignment is essential. That individual tech lead might also focus on a specific product area, which means that in organizations with multiple product areas, several tech leads may exist concurrently, each guiding their respective domain. In such cases, coordination between tech leads becomes essential—not only to avoid inconsistencies across products but also to create shared solutions and standards that deliver value greater than the sum of their parts.&lt;/p&gt;

&lt;p&gt;That same need for coordination exists in organizations where the tech lead role is distributed among senior developers. Even without a single point of leadership, aligning technical direction across teams ensures cohesion, reduces duplication, and enables collective progress.&lt;/p&gt;

&lt;p&gt;Other companies choose to flatten their team structures, removing the formal tech lead role in favor of a more democratized approach. Decision-making responsibilities are shared among senior engineers, or delegated to ad hoc working groups. This model can enhance a sense of ownership and encourage diverse viewpoints, but may also introduce ambiguity, inconsistencies between teams, and slow decision-making.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tech Lead is a Function, Not a Title
&lt;/h1&gt;

&lt;p&gt;It is essential to understand that tech leadership is not necessarily tied to a specific individual or title. In some cases, the tech lead function may be fulfilled by a rotating role, a group of engineers, or even a forum that facilitates consensus-based decisions. What matters is not the format, but the function: guiding the team in technical matters, promoting best practices, and fostering alignment.&lt;/p&gt;

&lt;p&gt;This functional view emphasizes that leadership should not be about exerting authority. Instead, it should focus on influence—building trust, articulating sound reasoning, and encouraging consensus. For instance, when introducing coding guidelines, a tech lead (or group fulfilling that role) should strive to involve the team, gather input, and reach a shared understanding. This approach not only ensures better adoption but also strengthens team cohesion.&lt;/p&gt;

&lt;h1&gt;
  
  
  Enabling Consistency and Automation
&lt;/h1&gt;

&lt;p&gt;Software organizations often operate in environments full of inconsistencies—differing approaches to the same problem, fragmented tooling, and ad hoc processes. A key responsibility of tech leadership is to reduce these inconsistencies and guide teams toward a shared approach. This consistency is not just about aesthetics or preferences; it is foundational to enabling automation. When teams follow consistent patterns and conventions, opportunities arise to automate repetitive tasks, streamline workflows, and eliminate manual, error-prone processes.&lt;/p&gt;

&lt;p&gt;Automation, in turn, frees developers to focus on higher-value work—solving novel problems, refining user experience, and improving system resilience—rather than spending time on tedious or mundane tasks. By championing consistency and supporting automation, tech leads help create an environment where teams can move faster, build more reliably, and enjoy their work more.&lt;/p&gt;

&lt;h1&gt;
  
  
  Influence Over Authority
&lt;/h1&gt;

&lt;p&gt;The most effective tech leads are those who lead by example and who earn the respect of their peers through competence, empathy, and clear communication. They recognize that their role is to enable the team, not to control it. In this light, their true power lies in influence rather than authority.&lt;/p&gt;

&lt;p&gt;When the tech lead role is seen as a facilitator rather than a ruler, it opens up space for more inclusive and adaptive decision-making. This is especially important in fast-paced environments where technology and requirements evolve rapidly. Teams need to feel empowered to contribute ideas and challenge assumptions without fear of hierarchy.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Whether formalized or fluid, individual or collective, the tech lead function remains a cornerstone of successful software development. Companies should carefully consider how best to structure this role within their context, balancing the need for direction with the benefits of shared ownership. Above all, they should remember that effective leadership is less about titles and more about the value delivered through influence, collaboration, and thoughtful guidance.&lt;/p&gt;

&lt;p&gt;What does tech leadership look like in your org?&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>softwareengineering</category>
      <category>teamwork</category>
      <category>devculture</category>
    </item>
    <item>
      <title>Hi, I'm Patrik</title>
      <dc:creator>Patrik</dc:creator>
      <pubDate>Thu, 13 Jul 2017 14:42:24 +0000</pubDate>
      <link>https://dev.to/iselind/hi-im-patrik</link>
      <guid>https://dev.to/iselind/hi-im-patrik</guid>
      <description>&lt;p&gt;I have been coding for 15 years.&lt;/p&gt;

&lt;p&gt;You can find me on GitHub as &lt;a href="https://github.com/iselind" rel="noopener noreferrer"&gt;iselind&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I live in Lund, Sweden.&lt;/p&gt;

&lt;p&gt;I work for Axis Communications AB&lt;/p&gt;

&lt;p&gt;I mostly program in these languages: C, Python, Go.&lt;/p&gt;

&lt;p&gt;I am currently learning more about machine learning.&lt;/p&gt;

&lt;p&gt;Nice to meet you.&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
