<?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: Monite</title>
    <description>The latest articles on DEV Community by Monite (@monite).</description>
    <link>https://dev.to/monite</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%2Forganization%2Fprofile_image%2F7706%2F782cf4d5-8eb5-49e8-bdd0-c70d8e62d742.jpg</url>
      <title>DEV Community: Monite</title>
      <link>https://dev.to/monite</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/monite"/>
    <language>en</language>
    <item>
      <title>API Versioning at Monite</title>
      <dc:creator>Stanislav Zmiev</dc:creator>
      <pubDate>Thu, 29 Aug 2024 11:49:59 +0000</pubDate>
      <link>https://dev.to/monite/api-versioning-at-monite-3ba3</link>
      <guid>https://dev.to/monite/api-versioning-at-monite-3ba3</guid>
      <description>&lt;p&gt;We all love to have shiny new tools but hate the chore of constantly updating them. This applies to anything: operating systems, apps, APIs, linux packages. It is painful when our code stops working because of an update and it is double the pain when the update was not even initiated by us.&lt;/p&gt;

&lt;p&gt;In web API development, you are constantly at risk of breaking your users' code with every new update. If your product is an API, then these updates will be terrifying every time. Monite's main products are our API and our white-label SDK. We are an API-first company so we take great care of keeping our API stable and easy to use. Hence the problem of &lt;a href="https://docs.monite.com/reference/versioning" rel="noopener noreferrer"&gt;breaking changes&lt;/a&gt; is near the top of our priority list.&lt;/p&gt;

&lt;p&gt;A common solution is to issue deprecation warnings to your clients and to release breaking changes rarely. Suddenly, your releases can now take months and some features have to stay hidden or even unmerged until each next release. This slows down your development and forces your users to update their integration every few months.&lt;/p&gt;

&lt;p&gt;If you make releases faster, your users are going to have to update their integration too often. If you lengthen the time between releases, you will move slower as a company. The more inconvenient you make it for users -- the more convenient it is going to be for you, and vice versa. This is certainly not an optimal scenario. We wanted to move at our own pace without breaking anything for existing clients which would be impossible with a regular deprecation approach. This is why we picked an alternative solution: &lt;strong&gt;API versioning&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is quite a simple idea: release any breaking changes at any time but hide them under a new API version. It grants you the best of both worlds: The users will not have their integrations routinely broken and you will be able to move at any speed you like. The users will migrate whenever they want -- free of any pressure.&lt;/p&gt;

&lt;p&gt;Considering the simplicity of the idea, it feels perfect for any company. That is what you would expect to read in a typical engineering blog. Sadly, it is not so simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beware of the price
&lt;/h2&gt;

&lt;p&gt;API versioning is hard, very hard. Its illusory simplicity quickly fades away once you begin implementing it. Sadly, the internet never really warns you as there are surprisingly few resources on the topic. The absolute majority of them argue about where to put the API version but only a few scarce articles attempt to answer: "How do we &lt;strong&gt;implement&lt;/strong&gt; it?". The most common ones are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;putting different versions of the same web application into separate deployments
&lt;/li&gt;
&lt;li&gt;copying single routes that have changed between versions
&lt;/li&gt;
&lt;li&gt;copying the entire versioned application for each version&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Separate deployments can get really expensive and hard to support, copying single routes does not scale very well to large changes, and copying the entire application creates so much extra code that you will start drowning in it after just a few versions.&lt;/p&gt;

&lt;p&gt;Even if you try to pick the cheapest one, the burden of versioning will catch up soon. At first, it will feel simple: add another schema here, another branch in business logic there, and duplicate a few routes at the end. But given enough versions your business logic will quickly become unmanageable, many of your developers will mistake application versions and API versions, and will start versioning the data within your database, and your application will become impossible to maintain.&lt;/p&gt;

&lt;p&gt;You might hope that you will never have more than two or three API versions at the same time; that you will be able to delete old versions every few months. It is true if you only support a small number of internal consumers. But clients outside of your organization will not enjoy the experience of being forced to upgrade every few months.&lt;/p&gt;

&lt;p&gt;API versioning can quickly become one of the most expensive parts of your infrastructure so it is critical to do diligent research beforehand. If you only support internal consumers, then you might have a simpler time with something like GraphQL but it can quickly get just as expensive as versioning.&lt;/p&gt;

&lt;p&gt;If you are a startup, it would be wise to postpone API versioning until the later stages of your development when you have resources to do it right. Until then, deprecations and &lt;a href="https://youtu.be/y6wXRMDtZd8" rel="noopener noreferrer"&gt;additive change strategy&lt;/a&gt; might suffice. Your API will not always look great but at least you will save a great deal of money by avoiding explicit versioning.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do we implement API versioning?
&lt;/h2&gt;

&lt;p&gt;After a few trials and many errors we were at the crossroads: our prior versioning approaches that we mentioned above were too expensive to maintain. As a result of our struggles, I devised the following list of requirements that would be required of a perfect versioning framework:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"&lt;em&gt;Maintaining a large number of versions is easy&lt;/em&gt;" to make sure that versioning does not slow down our feature development
&lt;/li&gt;
&lt;li&gt;"&lt;em&gt;Deleting old versions is easy&lt;/em&gt;" to make sure that we can clean up our code base without efforts
&lt;/li&gt;
&lt;li&gt;"&lt;em&gt;Creating new versions is not too easy&lt;/em&gt;" to make sure that our developers are still incentivized to try to solve problems without versions.
&lt;/li&gt;
&lt;li&gt;"&lt;em&gt;Maintaining a changelog between versions is easy&lt;/em&gt;" to make sure that both we and our clients can always be sure about the real differences between versions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sadly, there were little to no alternatives to our existing approaches. This is when a crazy idea came to my mind: what if we try and build something sophisticated, something perfect for the job -- something like &lt;a href="https://stripe.com/blog/api-versioning" rel="noopener noreferrer"&gt;Stripe's API versioning&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;As a result of countless experiments, we now have &lt;a href="https://github.com/zmievsa/cadwyn" rel="noopener noreferrer"&gt;Cadwyn&lt;/a&gt;: an open-source API versioning framework that not only implements Stripe's approach but significantly builds on top of it. We will be talking about its Fastapi and Pydantic implementation but the core principles are language and framework agnostic.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Cadwyn works
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Version Changes
&lt;/h4&gt;

&lt;p&gt;The problem of all other versioning approaches is that we are duplicating too much. Why would we duplicate the entire route, controller, or even application when only a tiny part of our contract got broken?&lt;/p&gt;

&lt;p&gt;With Cadwyn, whenever API maintainers need to create a new version, they apply the breaking changes to their latest schemas, models, and business logic. Then they create a version change -- a class that encapsulates all differences between the new version and a prior version.&lt;/p&gt;

&lt;p&gt;For example, let's say that previously our clients could create a user with an address but now we would like to allow them to specify multiple addresses instead of a single one. The version change would look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChangeUserAddressToAList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VersionChange&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Renamed `User.address` to `User.addresses` and &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;changed its type to an array of strings&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;instructions_to_migrate_to_previous_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;addresses&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;didnt_exist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nf"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;address&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;existed_as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@convert_request_to_next_version_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserCreateRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change_address_to_multiple_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;addresses&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;address&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

    &lt;span class="nd"&gt;@convert_response_to_previous_version_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserResource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change_addresses_to_single_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;address&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;addresses&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;instructions_to_migrate_to_previous_version are used by Cadwyn to generate code for older API versions of schemas and the two converter functions are the trick that allows us to maintain as many versions as we would like. The process looks like the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cadwyn converts all user requests from older API versions to the latest API version by using change_address_to_multiple_items converter, and pipes them to our business logic
&lt;/li&gt;
&lt;li&gt;Business logic, its API responses, and database models are always tailored to the latest API version (of course, it must still support old features even if they were dropped in new versions)
&lt;/li&gt;
&lt;li&gt;After business logic produces the response, Cadwyn converts it to the older API version that the client requester is currently on by using change_addresses_to_single_item converter.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After our API maintainers have created the version change, they need to add it to our VersionBundle to tell Cadwyn that this VersionChange will be included in some version:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="nc"&gt;VersionBundle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;ChangeUserAddressToAList&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;CollapseUserAvatarInfoIntoAnID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;MakeUserSurnameRequired&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's it: we have added a breaking change but our business logic only handles a single version -- latest. Even after we add dozens of API versions, our business logic will still be free from versioning logic, constant renaming, if's and data converters.&lt;/p&gt;

&lt;h4&gt;
  
  
  Version Chaining
&lt;/h4&gt;

&lt;p&gt;Version changes are dependent on the public interface of the API and we almost never add breaking changes into existing API versions. This means that once we have released the version – it will not be broken.&lt;/p&gt;

&lt;p&gt;Because version changes describe breaking changes within versions and there are no breaking changes within old versions, we can be sure that our version changes are completely immutable – they will never have a reason to change. Immutable entities are much easier to maintain than if they were a part of business logic because it is always evolving. Version changes are also applied one after another -- forming a chain of transformers between versions that can migrate any request to any newer version and any response to any older version.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19kqf9nscbgxhyn44acw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19kqf9nscbgxhyn44acw.png" alt="Diagram of how requests and responses flow through Cadwyn"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Side effects
&lt;/h4&gt;

&lt;p&gt;API contracts are much more complex than just schemas and fields. They consist of all endpoints, status codes, errors, error &lt;strong&gt;messages&lt;/strong&gt;, and even business logic behaviors. Cadwyn uses the same DSL we described above to handle endpoints and status codes but errors and business logic behaviors are a different story: they are impossible to describe using a DSL, they need to be embedded into business logic.&lt;/p&gt;

&lt;p&gt;This makes such version changes much more expensive to maintain than all others because they affect business logic. We call this property a "side effect" and we try to avoid them at all costs because of their maintenance burden. All version changes that want to modify business logic will need to be marked as having side effects. It will serve as a way to know which version changes are "dangerous":&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RequireCompanyAttachedForPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VersionChangeWithSideEffects&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User must now have a company_id in their account &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;if they want to make new payments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It will also allow API maintainers to check that the client request uses an API version that includes this side effect:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;RequireCompanyToBeAttachedForPayment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_applied&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br&gt;
    &lt;span class="nf"&gt;validate_company_id_is_attached&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  No silver bullets&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Cadwyn has many benefits: It greatly reduces the burden on our developers and can be integrated into our infrastructure to automatically generate the changelog and improve our API docs.&lt;/p&gt;

&lt;p&gt;However, the burden of versioning still exists and even a sophisticated framework is not a silver bullet. We do our best to only use API versioning when absolutely necessary. We also try to make our API correct on the first try by having a special "API Council". All significant API changes are reviewed there by our best developers, testers, and tech writers before any implementation gets moving.&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a href="https://twitter.com/brandur" rel="noopener noreferrer"&gt;Brandur Leach&lt;/a&gt; for his API versioning article at Stripe and for the help he extended to me when I implemented Cadwyn: it would not be possible without his help.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Measuring an engineering impact. Pyramid of needs for product engineers.</title>
      <dc:creator>Vadim</dc:creator>
      <pubDate>Thu, 22 Aug 2024 14:10:53 +0000</pubDate>
      <link>https://dev.to/monite/measuring-an-engineering-impact-pyramid-of-needs-for-product-engineers-35kc</link>
      <guid>https://dev.to/monite/measuring-an-engineering-impact-pyramid-of-needs-for-product-engineers-35kc</guid>
      <description>&lt;p&gt;Last time, &lt;a href="https://dev.to/monite/the-evolution-of-the-software-engineer-role-into-product-engineer-38fj"&gt;we discussed&lt;/a&gt; how the role of a software engineer has evolved into the role of a product engineer and what the fundamental differences between them are. Today, I'd like to delve into the work routine and understand the key principles of operating as a product engineer.&lt;/p&gt;

&lt;p&gt;Since the emphasis in this new role is on rapid iterations to gather feedback and validate your solution, it means we need specific tools to assess the code you release. When I talk about validation, I'm not referring to technical metrics, but rather how your solution impacts the overall business. Let's call it end-to-end (e2e) validation, encompassing the following points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Impact on fundamental technical metrics such as database load, server resource consumption, and browser memory usage.&lt;/li&gt;
&lt;li&gt;Impact on integration technical metrics, including the number of non-200 responses to users, increased response times for specific API endpoints, and a "laggy" interface.&lt;/li&gt;
&lt;li&gt;Influence on local product metrics, such as the number of users who started using a feature after an improvement (adoption level) or the number of users who consistently use it.&lt;/li&gt;
&lt;li&gt;Impact on business indicators - measured in the money generated by users utilizing the features you've worked on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we take another look at the points mentioned above, we'll find a common thread that unites them all - to measure impact, we need to "stay informed" about what's happening with the system in various dimensions. In the world of product development, there's a specific term for this - observability.&lt;/p&gt;

&lt;p&gt;Observability in the context of software development refers to the system or application's ability to be easily observed and analyzed. This involves collecting data about the application's operation, its state, and performance to ensure transparency and the ability to quickly detect and address issues.&lt;/p&gt;

&lt;p&gt;The list of previous points can be represented as an onion, where each ring is within the responsibility zone of different teams.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Few14ad1w72lfh6ejf2l3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Few14ad1w72lfh6ejf2l3.png" alt="Software observability onion" width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Level One: Engineering Metrics. Owners - Software Engineers.&lt;/li&gt;
&lt;li&gt;Level Two: Integration Metrics. Owners - Site Reliability Engineers (SRE).&lt;/li&gt;
&lt;li&gt;Level Three: Feature Metrics. Owners - Product Managers.&lt;/li&gt;
&lt;li&gt;Level Four: Business Metrics. Owners - Analytics Team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each level has its key metrics, and each team is responsible for its level in the onion, providing a comprehensive assessment of the impact on the product and business.&lt;/p&gt;

&lt;p&gt;For most modern companies, evaluating based on 1-2 of these points is quite commonplace. The more advanced ones try to assess changes against three. However, only A-players thoroughly assess all four parameters. Why is that? Because carrying out a detailed evaluation demands substantial effort, advanced skills in multiple areas, and smooth cooperation across various team departments. For very young startups, implementing such processes would be prohibitively costly, while the advantages would be minimal.&lt;/p&gt;

&lt;p&gt;In the early stages of product development, the basic shortcomings are usually clear, and all the low-hanging fruits are visible. However, as your solution matures and it's time to enhance or discover new growth areas, such a system becomes a primary tool in your arsenal if you don't want to move blindly forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Returning to engineering…
&lt;/h2&gt;

&lt;p&gt;All of this, of course, depends on how teams are organized within the company, but let's get back closer to our daily work routine. When working on a task, you're still writing code, there are no changes there. However, with such an approach, you need to think a bit further than just how to write code; you should also be interested in how your code works in production and, most importantly, how your code impacts the product.&lt;/p&gt;

&lt;p&gt;I like to envision this as a pyramid, something like Maslow's hierarchy but with an engineering twist. Each level becomes a concern only after we've managed to fill the previous one, and for success at each level, we'll need specific tools that best address the needs.&lt;/p&gt;

&lt;p&gt;So, we've written the code, initiated the deployment process, and now it's time to observe&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqukc5vft5k0yp5dizjj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqukc5vft5k0yp5dizjj.png" alt="Product engineer pyramid" width="800" height="776"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Is my code working? 🛠️
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Difficulty: Easy 🟢 
Owner: Developer 👨‍💻
Tools: Bugtracker 🐛
Evaluation time: up to 1 hour ⏲️
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bottommost level. Before evaluating further, you must ensure that your code fundamentally works. The primary metric is a binary answer: yes if your code somehow accomplishes its task, or no if it fails 100% of the time, even for the simplest user story without corner cases.&lt;/p&gt;

&lt;p&gt;Typically, simple bug trackers like Sentry or Bugsnag are used as tools. Evaluation time is usually less than an hour. Depending on the release process, validation can occur at various stages—some use QA department testing, others rely on team tests, and some may test independently directly on sandbox/production environments. These days there's nothing new about this, and hopefully, we all do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is my code working well? ✅
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Difficulty: Medium 🟡
Owner: Developer, but you'll need initial setup of integrations with 
tools typically falling on DevOps/SRE shoulders ⚙️
Tools: Log management systems, times-series databases 📉
Evaluation time: 10 minutes to 6 hours. ⌚
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After ensuring basic functionality, the next step is to assess how reliably our code is working and give it a quantitative evaluation. The primary metric here is the error/success rate.&lt;br&gt;
Tools for this can include logging systems like the ELK stack or Grafana, or more time-series-oriented tools such as Prometheus, Datadog, or AWS CloudWatch if you operate under high load. To assess this parameter, you need to ensure that your code logs information or sends metrics to the relevant system. Configuring dashboards to have a visual representation is also crucial.&lt;/p&gt;

&lt;p&gt;What's the ideal metric values to move to the next level? It all depends on the situation! For example, a billing system for processing orders on your site should strive for a success rate approaching 100%, while tasks related to unvalidated image classification or the use of an unreliable 3rd-party API may have a lower reliability level.&lt;/p&gt;

&lt;p&gt;Sometimes evaluation can be challenging, especially if you need to introduce a new feature to users and teach them how to use it. In such cases, you can manually test the main user scenario with different inputs and settings 5-10 times.&lt;/p&gt;

&lt;p&gt;Additionally, at this stage, automated alerts become your good friends. They send notifications if this metric starts deteriorating over time, allowing you to proactively respond to changes before your users become dissatisfied with the product&lt;/p&gt;

&lt;h2&gt;
  
  
  How does my code impact the system as a whole? 🌐
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Difficulty: Medium 🟡
Owner: DevOps or developer 🧑‍💻
Tools: Log management systems, times-series databases 📊 
Evaluation time: 10 minutes to 6 hours ⏳
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are numerous technical metrics reflecting the health of your service. Depending on the product, their criticality may vary, but your changes can easily lead to spikes in any of them. For example, using a database query in a loop without attention can significantly increase the number of database queries, loading an entire file into memory can spike server memory consumption, or synchronously calling a 3rd-party API that responds slowly can increase the average HTTP response time for your users.&lt;/p&gt;

&lt;p&gt;Most modern hosting or cloud providers cover these metrics out of the box. Many services, such as databases or queuing systems, also default to supporting data transmission to monitoring systems like Prometheus or OpenTelemetry. You need to put in some effort to start working with these, but the good news is that you only need to do it once for each tool.&lt;/p&gt;

&lt;p&gt;Evaluation time: In the best-case scenario, you can identify the issue immediately. More often, problems arise with an influx of traffic, so detailed logging becomes your best friend in investigation to quickly understand what exactly is leading to deteriorating metrics. Ideally, this can be caught during performance testing, but maintaining load testing for every change, especially in the development of new products, can be a challenging task.&lt;/p&gt;

&lt;p&gt;For example, in &lt;a href="https://monite.com/?utm_source=dev-to&amp;amp;utm_medium=blog&amp;amp;utm_campaign=product-engineer-impact" rel="noopener noreferrer"&gt;Monite&lt;/a&gt;, we use a set of multiple tools that support developers in collaboration with the DevOps team. For monitoring hardware metrics, such as database load, we use metrics exported to Prometheus. For a more detailed analysis of microservice performance, we have deep integration with Sentry. And for exploring end-to-end performance, we implement distributed tracing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does my code impact the success of a business feature? 📈
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Difficulty: Hard 🟠
Owner: Product Manager, Analyst 📈
Tools: Google Analytics, Amplitude, Data Warehouse 🔍
Evaluation time: A few days for designing the A/B test, and from
a few weeks to several months for data accumulation and drawing 
conclusions 📅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we've ensured that technical metrics are alright, we can move to the next level - assessing the impact of your changes at a local product level. Analytical tools such as Google Analytics or Amplitude can be helpful here.&lt;/p&gt;

&lt;p&gt;Let's consider a simple example - the checkout form on your service requires users to input their country in a strict format. Data show that the conversion to the next step is at 40%, and the simplest hypothesis is that users don't understand the expected input format, leading them to close the page after the first unsuccessful attempt. You decide to weaken the validation, and the conversion increases to 50%. However, you feel it's not enough, so you add autocomplete to the form, further increasing the conversion to 80%. This is the product impact of your changes.&lt;/p&gt;

&lt;p&gt;It might not sound too difficult, but when trying to implement this in practice, many questions arise. What if I have a multi-platform application? How do I measure the impact of each change on a feature when we release them simultaneously? How can we understand that it's your changes affecting metrics and not external factors? Most of these questions can be answered with one solution - A/B testing. Conducting clean A/B tests requires analytical skills and, more importantly, a significant volume of traffic to draw statistically significant conclusions. The latter is a major hurdle for small companies.&lt;/p&gt;

&lt;p&gt;Another reason I categorized this as “hard” is because such evaluation requires designing, bootstrapping, and implementing metrics for each feature of your product. As compensation, proudly use the "data-driven" badge on your resume.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does my code impact the success of the product? 🚀
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Difficulty: Insane 🔴
Owner: Product Manager, Analyst, Finance 🧑‍💼
Tools: Data warehouses, reporting tools, BI tools 💾
Evaluation time: from 1 month 🗓️
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If in the previous point you are examining how users behave when interacting with your feature, transitioning here shifts your focus from the feature to the user. Who is the user? What problem does your product solve for them? Where did they come from? What keeps them from leaving for competitors? You literally need to know everything about them. This requires significant investments in a data collection, analysis culture and data infrastructure.&lt;/p&gt;

&lt;p&gt;From an analytical standpoint, the complexity lies in establishing the correlation between key business metrics and local product metrics. You need to learn how changes, like increasing the form conversion rate by X%, will impact key business metrics (such as ARR, LTV, Churn rate, and any other metrics vital to your business). From a product standpoint, you need to understand not only your current users but also those contemplating using your product.&lt;/p&gt;




&lt;p&gt;Honestly, this goes beyond the direct responsibilities of an engineer, but I believe that if you consider yourself a product engineer, you should at least be curious about how effective the solutions you release are and how they influence the successes and failures of the business as a whole.&lt;/p&gt;

&lt;p&gt;How does your company measure the impact of engineering decisions on the product?&lt;/p&gt;

</description>
      <category>productengineering</category>
      <category>softwareengineering</category>
      <category>startup</category>
      <category>softwaredesign</category>
    </item>
    <item>
      <title>The Evolution of the Software Engineer Role into Product Engineer</title>
      <dc:creator>Vadim</dc:creator>
      <pubDate>Wed, 28 Feb 2024 13:44:51 +0000</pubDate>
      <link>https://dev.to/monite/the-evolution-of-the-software-engineer-role-into-product-engineer-38fj</link>
      <guid>https://dev.to/monite/the-evolution-of-the-software-engineer-role-into-product-engineer-38fj</guid>
      <description>&lt;p&gt;Over the past 10-20 years, software development approaches have undergone significant changes. What used to resemble the Wild West has now evolved into a vast ecosystem built from startups, accelerators, and venture funds. This transformation has inevitably influenced how companies structure their internal processes. Due to intense competition, the primary question for young companies has shifted from "how to build" to "what exactly to build." This has prioritized speed over high quality, emphasizing the velocity of hypothesis validation, market responsiveness, and adaptation to changes.&lt;/p&gt;

&lt;p&gt;We observe how lean and scrum methodologies have displaced the waterfall model, focusing on addressing bottlenecks that are crucial in the new realities. However, are there other ways to optimize the process?&lt;/p&gt;

&lt;h2&gt;
  
  
  Typical team structure
&lt;/h2&gt;

&lt;p&gt;Most modern development teams can be broadly categorized into two types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Conservative Teams: These teams typically consist of a few engineers led by an engineering team lead. The focus is on a more traditional hierarchy, where the team lead guides the technical aspects and decision-making.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8uznq50ju3wou70glt1w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8uznq50ju3wou70glt1w.png" alt="Conservative team" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cross-Functional Teams: These teams are more contemporary and are composed of a cross-functional mix. They include a product manager and a designer who are responsible for customer communication. The team is still led by an engineering team lead, and there are multiple developers working on tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ztti94w9jsfh689i16d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ztti94w9jsfh689i16d.png" alt="Cross-functional Team" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The choice between these models often depends on the nature of the project, the organizational culture, and the specific goals of the development effort.&lt;/p&gt;

&lt;p&gt;However, both of these approaches share a common drawback - all feedback from a large number of stakeholders goes through the Product Manager. The feedback is somewhat processed by the Product Manager, then passed on to the team or team lead. Specifications are written, requirements are decomposed, and the task is handed over to the developer... except for the details and business context. The developer works with a task that's already prepared and doesn't directly interact with the client. If they have questions, they ask the Product Owner or team lead, and either the questions are passed on or the team lead attempts to solve them based on their own knowledge. All of this resembles an attempt to play a game of Chinese whispers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2mr4qphh83fnmmjmlmn5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2mr4qphh83fnmmjmlmn5.png" alt="Development Chinese Whispers. Original taken from https://assertiveprogrammer.com/blog/chinesewhispers/" width="800" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the end of the sprint, developers submit their task, roll it out to production, and it turns out they did something completely different. The entire process has to be initiated again. What's wrong with this approach? Each link in the team becomes a bottleneck for task progress. Due to limited capacity of team members, answering questions and passing context can take days or even weeks, significantly increasing the feedback loop for your new product features.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbtjr2jf5klnol5z58kj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbtjr2jf5klnol5z58kj3.png" alt="Development Chinese Whispers 2. Original taken from https://assertiveprogrammer.com/blog/chinesewhispers/" width="800" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Is there a way to optimize this process? Certainly - by eliminating unnecessary links in the existing chain. That's how the role of a software engineer evolved into a product engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is this product engineer of yours?
&lt;/h2&gt;

&lt;p&gt;Product engineers possess a powerful combination of skills. They excel in communication, building strong relationships internally with colleagues and externally with customers. These strategic thinkers go beyond just completing tasks; they see their work as a key force driving towards a successful IPO. The most vital aspect is that product engineers deliver. They conceive, construct, and meticulously validate their work, ensuring that new features quickly reach customers.&lt;/p&gt;

&lt;p&gt;To illustrate how the feedback process changes with the new approach, you can refer to the following diagram&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8iemh0desffexg9yuaow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8iemh0desffexg9yuaow.png" alt="Product engineers team" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So let's consider the features of a product engineer's work and how they differ from a software engineer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measure of success&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software Engineer: Success criteria often revolve around the quality of the engineering system they develop.&lt;/li&gt;
&lt;li&gt;Product Engineer: Focuses on solving user problems. Success is not always about the most productive code or code covering the most corner cases. It's about writing code that best addresses user problems, closes the most popular use cases, and provides the maximum possible UX for end users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Scope of work&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software Engineer: Works based on ready specifications and tasks (for example in JIRA).&lt;/li&gt;
&lt;li&gt;Product Engineer: Concentrates on a user problem, usually described in the form of a user story.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Depth specialization&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software Engineer: Often has a clear specialization in frontend or backend development. For software engineers focused on technical excellence, having a specialization and deep technical expertise is vital.&lt;/li&gt;
&lt;li&gt;For a product engineer, it's crucial to balance speed and quality. They are often specialists without a strongly defined specialization in frontend or backend. They can contribute to any part of the product or are full-stack developers, following a T-shape or even W-shape approach. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Customer interaction&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software Engineer: Main sources of requirements and feedback are product owners or their immediate supervisors.&lt;/li&gt;
&lt;li&gt;Product Engineer: Emphasizes communication with users, involving both quantitative feedback through analytical systems and qualitative feedback through participation in customer development interviews to better understand user needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Development and delivery speed&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software Engineer: Can afford to solve technical problems that do not always directly impact end users.&lt;/li&gt;
&lt;li&gt;Product Engineer: Typically contributes to product development and drives shorter iterations, focused on obtaining feedback quickly from end users for their solutions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What are the requirements for the role and how to become successful?
&lt;/h2&gt;

&lt;p&gt;So, you've decided that you like this and want to try yourself in such a role. Should you just go and tell your boss about it? You can certainly try, but it doesn't always work. Transitioning to such a format usually requires changes in the overall company structure and internal processes, and not everyone is ready for such rearrangements. For larger companies with a strict and deep vertical structure, such a transition may prove more challenging than for horizontal companies or startups that are more aligned with them.&lt;/p&gt;

&lt;p&gt;If we look at the job market, a similar correlation is evident. For example, in a LinkedIn job search, where larger companies post vacancies, a search for &lt;code&gt;software engineer&lt;/code&gt; yields 143,146 job listings, while &lt;code&gt;product engineer&lt;/code&gt; results in 1,773, which is only 1.2% of the total number of job listings. However, if we examine platforms where engineers are hired by younger companies, such as &lt;a href="http://www.workatastartup.com"&gt;www.workatastartup.com&lt;/a&gt;, the distribution becomes much more interesting — 665 companies for &lt;code&gt;product engineer&lt;/code&gt; compared to 686 for &lt;code&gt;software engineer&lt;/code&gt; indicating a high demand for such specialists in young and growing companies.&lt;/p&gt;

&lt;p&gt;Since this role involves continuous learning across adjacent tracks, the company culture should be geared towards growth and open communication among employees with different skill sets. If you are already an established technical professional, you will need to enhance your understanding in areas like product management, UX design, and analytics to identify issues in your product and propose user-effective solutions.&lt;/p&gt;

&lt;p&gt;The next point may be a bit controversial, but I believe that to transition into the realm of product engineers, you should already be a software engineer with at least a middle+ or senior level. To address user problems, a developer must already have a well-developed technological worldview and experience to understand the pros and cons of specific solutions and make necessary trade-offs. The primary challenge in such a position should be product validation of the chosen solution, rather than writing the corresponding code.&lt;/p&gt;

&lt;p&gt;By the way, when we talk about UX, we don't always mean the interface. It is more about how the user interacts with your product. For example, being an API-first company at &lt;a href="//monite.com?utm_source=dev-to&amp;amp;utm_medium=blog&amp;amp;utm_campaign=product-engineer"&gt;Monite&lt;/a&gt;, 99.9% of user interactions with our product occur through the API. Therefore, we address this at the API level by adhering to industry standards, providing detailed documentation, and creating walk-through examples formatted in Postman that cover most user scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does this bring value to the company?
&lt;/h2&gt;

&lt;p&gt;Embracing a no-compromise approach, product engineering focuses on efficiently reducing communication noise. Forming small, agile teams leads to fewer meetings, rapid decision-making, and a streamlined feedback loop. By eliminating unnecessary layers of communication, product quality experiences a significant boost. When engineers have a comprehensive understanding and the authority to make decisions, the process becomes faster and more effective, preventing delays or errors.&lt;/p&gt;

&lt;p&gt;When I discuss this topic with employers unfamiliar with such an approach, there's often a certain level of skepticism for two main reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Developers have gained a reputation as technical geeks interested only in manipulating bits, optimizing algorithms, and scaling containers.&lt;/li&gt;
&lt;li&gt;The approach where an employee is expected to be involved in more than one direction is often perceived as a lack of focus and a stress-inducing factor related to work.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finally, I have a source to reference to refute these claims. In the &lt;a href="https://services.google.com/fh/files/misc/2023_final_report_sodr.pdf"&gt;DevOps report by Google released in 2023&lt;/a&gt;, there is a separate chapter dedicated to how a focus on users affects various team parameters. Among the findings, I would like to emphasize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams with a strong user focus experience a 40% higher organizational performance.&lt;/li&gt;
&lt;li&gt;Prioritizing user needs leads to a 20% higher job satisfaction.&lt;/li&gt;
&lt;li&gt;User-focused approaches significantly improve other metrics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvczl9rhzbe84dwewolq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvczl9rhzbe84dwewolq.png" alt="Metrics changes. Original taken from https://services.google.com/fh/files/misc/2023_final_report_sodr.pdf" width="800" height="1211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping-up
&lt;/h2&gt;

&lt;p&gt;Fundamental changes in the industry always impact the requirements for companies, which, in turn, influence approaches to development and the internal organization of teams. So, if, in addition to development, you are interested in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Growing along a non-technical track&lt;/li&gt;
&lt;li&gt;Gaining a better understanding of the domain you work in and the existing problems within it&lt;/li&gt;
&lt;li&gt;More closely aligning your efforts with the successes or failures of the company&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then perhaps now is the perfect time to be at the forefront of these changes and consider embracing a new role for yourself.&lt;/p&gt;

&lt;p&gt;If you prefer not to participate in this and feel more comfortable in the technical track, it doesn't mean you'll be left behind! Since all your teams are now focused on users and often do not pay full attention to engineering, there is a need for individuals who will address this aspect of your workflow. Therefore, roles such as architect or platform team (which I will revisit in future topics), providing a strong technological foundation for product engineers and preventing them from diverging too much, become even more crucial than before!&lt;/p&gt;




&lt;p&gt;In my blog, I still focus on approaches to work, team building in the early stages of company development, the role of a product engineer, and establishing a data-driven culture within a company. If these topics interest you, feel free to subscribe for me and other &lt;a href="https://dev.to/monite"&gt;Monite developers&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>productengineering</category>
      <category>career</category>
      <category>startup</category>
    </item>
    <item>
      <title>API-first Invoicing – A Guide to Simplifying Financial Document Generation</title>
      <dc:creator>Andrey Korchak</dc:creator>
      <pubDate>Wed, 29 Nov 2023 11:28:39 +0000</pubDate>
      <link>https://dev.to/monite/api-first-invoicing-a-guide-to-simplifying-financial-document-generation-3p1f</link>
      <guid>https://dev.to/monite/api-first-invoicing-a-guide-to-simplifying-financial-document-generation-3p1f</guid>
      <description>&lt;p&gt;Issuing invoices and other financial docs is something that rarely bothers tech teams. It’s something we all have to do, but there is no much value for customers in having access to financial documents. &lt;/p&gt;

&lt;p&gt;Building yet another invoicing feature in your application looks like a simple and extremely boring thing to work on. Most engineers put together a bunch of HTML-based templates, and a PDF rendering library and start spitting out a bunch of boring financial documents.&lt;/p&gt;

&lt;p&gt;Sometimes invoicing solutions come together as a part of payment services. Companies like Stripe supply their customers with pretty basic invoice generators integrated right into the payment gateway. That is a much simpler way to go, but it has disadvantages in terms of compliance in disadvantages. &lt;/p&gt;

&lt;p&gt;These two solutions are equally boring and wrong at the same time.&lt;/p&gt;

&lt;p&gt;First of all, invoices generated by your software system have to be compliant. Different countries and states have completely different understandings of what 'compliant' means. Some countries require valid business tax IDs to be present on every invoice. Some countries don't.&lt;br&gt;
Some countries require to put quite sophisticated VAT rates on invoices. Some countries don't. Some countries have a specific look at financial documents, with strict requirements for the position of elements, IDs, and codes on documents. Some countries don't.&lt;/p&gt;

&lt;p&gt;So most likely, if you just insert an HTML template into PDF render, you end up with an incompliant invoice in hand. What does 'incompliant' usually mean? it means 'loss of money'. Incorrect invoices may be not accepted by your/your customer's tax authorities, which leads to extra time and work spent on clarifying and re-doing financial paperwork. Missing compliant VAT information may lead to wrong VAT calculations which leads to extra taxes that must be paid to the government.&lt;/p&gt;

&lt;p&gt;The second problem is that often invoice-related business scenarios are more complex than we used to think. There is a whole universe of invoice-related documents that often are involved in the process of receiving money or making payments from your account. These are purchase orders, credit notes, and full or partial cancellation notes. And all of these docs often have to be exported into 3rd party accounting software.&lt;/p&gt;

&lt;p&gt;Both things, compliance, and different business cases, are boring, costly, and annoying to deal with. Especially if finances are not your main product and engineering expertise. That often happens in marketplaces, CRMs, and small-medium business management tools. In these software products, the main goal of the product team is to deliver features and customers and not to deal with annoying financial documents. But if you are not making invoices and other documents right, that will create frustration for your customers who have to deal with incompliant documents with missing VAT IDs (or God knows what else tax authorities wish to see on these PDF files).&lt;/p&gt;
&lt;h1&gt;
  
  
  Getting started
&lt;/h1&gt;

&lt;p&gt;In order to avoid the situation of re-writing the same financial features using different programming languages, we designed an API that provides all necessary functionality and designed to provide solid foundations for your apps.&lt;/p&gt;

&lt;p&gt;In short, Monite is like AWS for fintech, but instead of low-level services like servers and databases, Monite supplies users with high-level building blocks such as invoicing, payments, accounting, and many others. All building blocks can be connected to each other in all possible ways and they also can talk to each other. This leads us to API-level infrastructure which is able to provide a solid foundation for all your fintech ideas. &lt;/p&gt;

&lt;p&gt;The Monite API platform uses a few different layers to secure access to any stored data within the platform:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8kszwckvvem84qypvbex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8kszwckvvem84qypvbex.png" alt="Image description" width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Partner. A company that implements Monite in its app or platform. The development teams of Partners connect to the Monite API with admin-level access tokens. The admin tokens in this mandatory layer enable Partners to create and configure entities and access all resources of all entities they develop software for.&lt;/li&gt;
&lt;li&gt;Entity. A customer of a Partner – an entity – is either an organization or an individual. Each Partner develops for one or more entities. With the ID of an entity, it is possible to obtain root access to all resources related to this specific entity only.&lt;/li&gt;
&lt;li&gt;Entity user. The employees who work for an entity. This optional entity user access layer is for Partners who want to use Monite security for rapid development rather than build their own custom access control logic. Using the Monite API, Partners create customizable entity-level roles and permissions. Monite automatically monitors access policies for each API call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, Maria is an accountant at Beispiel GmbH and Beispiel GmbH uses the online banking of  Big Money Bank. Big Money Bank is a partner, Beispiel GmbH is an entity and Maria is an entity user.&lt;/p&gt;

&lt;p&gt;To start building your invoicing solution, the first thing you as an API partner need to do is to register your partner account on the &lt;a href="https://portal.sandbox.monite.com/signup"&gt;Monite Partner Portal.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then you have to create your project and get credentials for it.&lt;/p&gt;

&lt;p&gt;The API ID and secret need to be exchanged for an access token which is then used to authenticate the API calls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.sandbox.monite.com/v1/auth/token'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
        "grant_type": "client_credentials",
        "client_id": "28c10852-7e78-43cf-abfb-efeed1834963",
        "client_secret": "615b3cfa-646b-41d9-b768-521f09315ac5"
     }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Mapping your users to Monite
&lt;/h1&gt;

&lt;p&gt;Usually, Monite is used when a tech team wants to add a fintech feature to an existing software product. It means users, roles, and permissions are already implemented inside of that product. But in order to make invoicing work, we somehow need to connect that existing access management function of the parental product with Monite API.&lt;/p&gt;

&lt;p&gt;And in order to do that, we need to map existing users of our customers into Monite API and Monite will take care of all aspects of access control of invoicing feature.&lt;/p&gt;

&lt;p&gt;First,  we create an entity representing your customer. Let’s assume your software provides business services to  Bob Jones who lives in Berlin. Via following API call we connect Bob Jones with Monite.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.sandbox.monite.com/v1/entities'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer YOUR_PARTNER_TOKEN'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "type" : "individual",
    "email": "bob@example.com",
    "address" : {
        "country" : "DE",
        "city" : "Berlin",
        "state": "BE",
        "postal_code" : "10115",
        "line1" : "Flughafenstrasse 52"
    },
    "individual" : {
        "first_name" : "Bob",
        "last_name" : "Jones",
        "tax_id": "1234567890"
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Often multiple people operate business and they all have different permissions when we are talking about access to financial information. In order to separate different groups of people, you can create different roles with different permissions. For example, sales folks can only issue invoices, while CEO can do pretty much everything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.sandbox.monite.com/v1/roles'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Version: 2023-04-12'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Entity-Id: ENTITY_ID'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer ACCESS_TOKEN'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
      "name": "View payables",
      "permissions": {
        "objects": [
          {
            "object_type": "comment",
            "actions": [
              {
                "action_name": "read",
                "permission": "allowed"
              }
            ]
          },
          {
            "object_type": "payable",
            "actions": [
              {
                "action_name": "read",
                "permission": "allowed"
              }
            ]
          }
        ] 
      }
    }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then we put all things together and create a record for a person who works for Bob Jones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.sandbox.monite.com/v1/entity_users'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Version: 2023-04-12'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Entity-Id: ENTITY_ID'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer YOUR_PARTNER_TOKEN'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
       "login": "Gardner.Waelchi",
       "first_name": "Gardner",
       "last_name": "Waelchi",
       "role_id": "946141f3-ca01-44dc-b1a6-1024aa71f978",
       "email": "g.waelchi@example.com",
       "phone": "+15551234567"
     }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make API calls on behalf of an entity user, you need to use an access token of that user. To get this token, call &lt;code&gt;POST /auth/token&lt;/code&gt; with the following request body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.sandbox.monite.com/v1/auth/token'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Version: 2023-04-12'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
       "grant_type": "entity_user",
       "client_id": "2e0c68d6-00b7-447d-b26c-415bbcbfc026",
       "client_secret": "cf0de0bd-a59e-473f-a3dd-db5924bd8622",
       "entity_user_id": "0c76febf-aabb-451a-aabb-ea3b47689dc1"
     }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Invoices and account receivables
&lt;/h1&gt;

&lt;p&gt;All different invoice-related documents (such as cancellation notes and purchase orders) are part of a bigger concept which is called 'account receivables'. Monite API covers lots of different business cases related to AR and everything is available via API calls.&lt;/p&gt;

&lt;p&gt;In order to issue your first compliant invoice via API, you have to do some preparatory work.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, you have to dig into VAT rates. Monite manages VATs for you, but anyway you have to get connected to VAT rates API.&lt;/li&gt;
&lt;li&gt;Then you have to map your user’s counterparts to our system. In order to become exportable, every financial document has to refer to a specific counterpart which also will be exported into accounting solutions along with financial data. &lt;/li&gt;
&lt;li&gt;An invoice always contains information about line items such as goods and services, Every line item has to connect the valid title of service/good, price, VAT rate, and measurement units. Monite stores this information inside of API in order to make it reusable.&lt;/li&gt;
&lt;li&gt;Every compliant invoice also has to contain payment terms information. Payment terms define the amount of time one has to pay an invoice (for example, 30 days from the invoice issue date). The terms can optionally include discounts for early payments to motivate the customers to pay sooner than the due date. Without payment terms, the invoice may be considered as incompliant!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And after all their preparatory steps you can go forward and start issuing invoices.&lt;/p&gt;

&lt;h2&gt;
  
  
  VAT classes
&lt;/h2&gt;

&lt;p&gt;Monite maintains a database of VAT rates. API users can query the available rates via the API.&lt;/p&gt;

&lt;p&gt;Currently, Monite API provides VAT rates for the following countries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🇦🇴 Angola &lt;/li&gt;
&lt;li&gt;🇧🇪 Belgium&lt;/li&gt;
&lt;li&gt;🇧🇼 Botswana&lt;/li&gt;
&lt;li&gt;🇪🇪 Estonia&lt;/li&gt;
&lt;li&gt;🇸🇿 Eswatini&lt;/li&gt;
&lt;li&gt;🇫🇷 France &lt;/li&gt;
&lt;li&gt;🇩🇪 Germany&lt;/li&gt;
&lt;li&gt;🇮🇪 Ireland&lt;/li&gt;
&lt;li&gt;🇱🇸 Lesotho &lt;/li&gt;
&lt;li&gt;🇱🇷 Liberia &lt;/li&gt;
&lt;li&gt;🇲🇿 Mozambique &lt;/li&gt;
&lt;li&gt;🇳🇦 Namibia&lt;/li&gt;
&lt;li&gt;🇳🇱 Netherlands &lt;/li&gt;
&lt;li&gt;🇿🇦 South Africa&lt;/li&gt;
&lt;li&gt;🇪🇸 Spain &lt;/li&gt;
&lt;li&gt;🇦🇪 United Arab Emirates (UAE)&lt;/li&gt;
&lt;li&gt;🇬🇧 United Kingdom (UK) &lt;/li&gt;
&lt;li&gt;🇿🇼 Zimbabwe &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are constantly adding new countries, and please let us know if you don’t see VAT rates for some countries you want to support right now. Maintaining a valid database of actual VAT rates is a significant effort and that’s why we are doing this for you.&lt;/p&gt;

&lt;p&gt;You can get all available VAT rates using API call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; GET &lt;span class="s1"&gt;'https://api.sandbox.monite.com/v1/vat_rates?counterpart_id=3a9c5...48df'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Version: 2023-04-12'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Entity-Id: ENTITY_ID'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer ACCESS_TOKEN'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  &lt;strong&gt;Create and manage products&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;In order to make invoices right, your users need to specify products/services and measurement units for them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.sandbox.monite.com/v1/measure_units'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Version: 2023-04-12'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Entity-Id: ENTITY_ID'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer ACCESS_TOKEN'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
       "name": "kg",
       "description": "Kilogram"
     }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.sandbox.monite.com/v1/products'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Version: 2023-04-12'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Entity-Id: ENTITY_ID'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer YOUR_PARTNER_TOKEN'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
       "name": "Ice cream",
       "type": "product",
       "description": "A delicious vanilla ice cream",
       "price": {
         "currency": "EUR",
         "value": 1500
       },
       "measure_unit_id": "12188fc1-493d-48a7-aea8-382240dd7ce7",
       "smallest_amount": 1
     }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Counterparts
&lt;/h2&gt;

&lt;p&gt;Counterparts represent the suppliers and clients of an entity. They can be organizations or individuals. A counterpart must be created before you can create invoices, quotes, and other documents. That’s because in order to become exportable into accounting software, every financial document needs to be linked with a specific counterpart in the system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.sandbox.monite.com/v1/counterparts'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Version: 2023-04-12'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Entity-Id: ENTITY_ID'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer ACCESS_TOKEN'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
      "type": "organization",
      "organization": {
        "legal_name": "Acme Inc.",
        "is_vendor": false,
        "is_customer": true,
        "phone": "+4930774619876",
        "email": "acme@example.com",
        "registered_address": {
          "country": "DE",
          "city": "Berlin",
          "postal_code": "10119",
          "state": "BE",
          "line1": "Flughafenstrasse 52",
          "line2": "Additional address"
        }
      }
    }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Payment terms
&lt;/h1&gt;

&lt;p&gt;Payment terms define the amount of time one has to pay an invoice (for example, 30 days from the invoice issue date). The terms can optionally include discounts for early payments to motivate the customers to pay sooner than the due date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.sandbox.monite.com/v1/payment_terms'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Version: 2023-04-12'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Entity-Id: ENTITY_ID'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer ACCESS_TOKEN'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
       "name": "Net 30",
       "term_final": {
         "number_of_days": 30
       }
     }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Issuing an actual invoice
&lt;/h1&gt;

&lt;p&gt;And after all this preparatory work is done, you can finally issue an invoice on behalf of your user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.sandbox.monite.com/v1/receivables'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Version: 2023-04-12'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Monite-Entity-Id: ENTITY_ID'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer ACCESS_TOKEN'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
       "type": "invoice",
       "currency": "EUR",
       "counterpart_id": "0414f84c-b039-4203-b09b-e42b49245435",
       "line_items": [
         {
           "quantity": 1,
           "product_id": "8755c86a-d630-4920-b6fd-fd2917d87dfb",
           "vat_rate_id": "479155c3-0995-4689-a3cf-7482ea5132a9"
         }
       ],
       "payment_terms_id": "e2cbbb5f-15e6-4b22-a942-8f51b7a81118",
       "vat_exempt": false,
       "entity_vat_id_id": "cb6c1c38-fdae-48f8-8e51-2d50d116b882",
       "entity_bank_account_id": "3f548c1b-8f18-4021-bdd1-5624cca65c3e"
     }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  What next?
&lt;/h1&gt;

&lt;p&gt;Now you have a PDF document with all relevant financial data. But it’s just the beginning of the story. Invoices need to be delivered to recipients, then payments have to be accepted and matched against financial records. In some situations, people have to deal with recurring invoices and partially paid invoices, and all these cases need to be covered in invoicing products, otherwise, your invoicing solution will be half (or even quarter) backed. We covered these topics in &lt;a href="https://docs.monite.com/docs/ar-overview?utm_source=dev-to&amp;amp;utm_medium=blog&amp;amp;utm_campaign=api-first-invoicing"&gt;our tech documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The entire flow of API calls may seem a bit tricky for you. But there are ways to hide this complexity from your users. For example, VAT rates may be settled only once via a separate API call done in the background. Services and measurements can be also settled up only once if you are working, for example, on Upwork-like freelance platform, where people often produce invoices based on hours they spent working on projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  How API works under the hood
&lt;/h2&gt;

&lt;p&gt;All invoicing business flows are pretty much the same in different countries. Yes, there are differences in VAT rates, rules, and numbers, but we are talking, pretty much, about the same set of documents with the same set of properties. &lt;/p&gt;

&lt;p&gt;We identified regional aspects of invoicing and made them configurable via configuration options coming from our internal microservices and JSON configuration files. Compliance officers and keeping these configs up to date so end users always receive complaint invoices.&lt;/p&gt;

</description>
      <category>fintech</category>
      <category>api</category>
      <category>invoice</category>
    </item>
    <item>
      <title>Engineering Challenges in B2B and B2C Startups</title>
      <dc:creator>Vadim</dc:creator>
      <pubDate>Wed, 22 Nov 2023 09:07:53 +0000</pubDate>
      <link>https://dev.to/monite/engineering-challenges-in-b2b-and-b2c-startups-1lcd</link>
      <guid>https://dev.to/monite/engineering-challenges-in-b2b-and-b2c-startups-1lcd</guid>
      <description>&lt;p&gt;The internet is filled with articles comparing work cultures across different company types, especially in marketing or product management. But what about software developers? Do these differences impact them too? Absolutely! Understanding the nuances between B2B (Business-to-Business) and B2C (Business-to-Consumer) can be a game-changer. Each sector has its own unique set of characteristics, demands, and obstacles that significantly shape the work of software engineers.&lt;/p&gt;

&lt;p&gt;Before diving in, let's set the stage. I'll use "B2C" to describe products that engage directly with end-users. This includes not only consumer-focused applications but also B2B products with a low average ARPU, where the primary revenue stream comes from the self-serve customers segment. These are platforms like Miro and Zapier, catering to a broad range of users who can onboard independently. &lt;/p&gt;

&lt;p&gt;On the other hand, our B2B segment refers to enterprise-focused products. Such companies typically work with a smaller number of clients but with more substantial contracts, often in the tens of thousands, or hundreds of thousands of dollars.&lt;/p&gt;

&lt;p&gt;Throughout my career, I primarily worked in B2C companies, occasionally advising teams involved in B2B. However, after joining &lt;a href="http://monite.com/?utm_source=dev-to&amp;amp;utm_medium=blog&amp;amp;utm_campaign=engineering-challenges"&gt;Monite&lt;/a&gt;, I experienced the stark difference firsthand.&lt;/p&gt;

&lt;p&gt;Alright, let’s go step by step through the main differences, analyze where they come from, and explore the opportunities they open up for your professional growth.&lt;/p&gt;

&lt;h2&gt;
  
  
  In-depth specialization vs. broad accessibility
&lt;/h2&gt;

&lt;p&gt;In the B2B corner, you’re the tech wizard – called upon to solve specific challenges for major players. Corporate clients rely on you to provide robust solutions, sparing them the complexities of handling those issues themselves. &lt;/p&gt;

&lt;p&gt;Sounds exciting, right? But here’s the thing: you always need to be at the top of your game. Your business must meet the high standards set by your clients. If you’re dealing with financial data and payments, get ready to navigate intricate regulations across the countries they operate in. Managing credit card data? Compliance with PCI-DSS is non-negotiable. And when working with medical data, you’ll become well-acquainted with HIPAA. And that’s just the beginning…&lt;/p&gt;

&lt;p&gt;In the B2C space, your customers turn to your product for convenience or entertainment. They’re not looking for complex problem-solving; they want a user-friendly solution. While the B2C entry barrier is low, making it a popular choice, it's much like a bustling local cafe – lively but packed. While the vibe seems welcoming, brace yourself for fierce competition. Many are jostling for the spotlight in this vibrant arena.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stability and fault tolerance
&lt;/h2&gt;

&lt;p&gt;When a big client invests in your product with the expectation of saving their development team’s time and offloading certain tasks, any weaknesses on your part within their IT ecosystem can lead to a swift termination of your partnership. This applies not only to technical glitches, errors, and system failures but also to products that don't effectively meet their designated objectives.&lt;/p&gt;

&lt;p&gt;Each failure also impacts your client's reputation with their end-users, as it directly compromises the quality of service they provide. This, in turn, can negatively influence your standing within the industry.&lt;/p&gt;

&lt;p&gt;It’s also crucial to consider acquisition costs. Acquiring clients in the B2B sector is a resource-intensive and time-consuming task, demanding a personalized approach. So, when you lose a client, it's not just a hit to your wallet; it's hours of hard work down the drain and a chunk of your revenue gone.&lt;/p&gt;

&lt;p&gt;On the flip side, the B2C world is a bit more forgiving of minor glitches or even partial downtime. Here, clients usually use your product for straightforward tasks. Even if there's a small issue or a short downtime, it's not the end of the world. Why? Because the average sale is probably between $100–200, and you're catering to a much larger crowd. This time partial failure or temporary degradation of one of its functions has a less severe impact on your entire user base.&lt;/p&gt;

&lt;p&gt;But here's the thing: to really grow in the B2C space, you need a massive user base. And while there's a steady flow of users coming in and out, this model can handle a bit of client turnover.&lt;/p&gt;

&lt;p&gt;All of this means one thing: B2B products can't afford mistakes. That's why there's so much emphasis on making them fault-tolerant and thoroughly tested, way more than B2C products. As a result, variations emerge in the development processes. When working on a B2B product, you encounter extended release cycles, stricter Quality Assurance procedures, and daily encounters with terms like release management and zero bug policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  How working with customer feedback differs
&lt;/h2&gt;

&lt;p&gt;In the B2B world, you're often working with a client base that's in the tens or hundreds. This smaller number means you can get to know each client personally. Your products in this space are typically designed to weave seamlessly into a client's existing infrastructure, which means the integration process can get pretty detailed. It's not uncommon to find yourself giving technical advice to engineers from your top-tier clients, and sometimes, you might even grab a drink together.&lt;/p&gt;

&lt;p&gt;Within a B2B-focused company, you'll probably have several support tiers, each handling different levels of complexity. There might also be a specialized integration team. Their job? To offer deep technical support, help with integrating products, and sometimes even tweak the product to fit a particular client's needs.&lt;/p&gt;

&lt;p&gt;Switch over to the B2C side, and things look a bit different. With potentially thousands or millions of users, it's tough to have a personal connection with each one. Most of the feedback you'll get will be in the form of data: numbers, charts, and graphs in your analytics dashboard. Sure, every now and then, you might chat with a super-user or an influencer. But mostly, conversations about your user base shift from talking about individual users to discussing broader groups or segments.&lt;/p&gt;

&lt;p&gt;Because of this, B2C companies have a big appetite for product analytics. They need robust data engineering to gather, process, and make sense of heaps of data. This isn't just a numbers game; it's about making informed decisions based on a deep understanding of customer profiles and being able to measure how effective those decisions are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why rapid adaptation is important
&lt;/h2&gt;

&lt;p&gt;In the enterprise B2B space, it's common to see long-term contracts. The cost of integrating these solutions? Sky-high, especially when you compare it to B2C, where businesses often lean on subscription models or even offer their services for free. Given this landscape, it's crucial to keep a close watch on what your competitors are up to and stay in tune with market shifts. This is especially true if you're in a young industry where competition is fierce, and you don't want to miss out on attracting new clients.&lt;/p&gt;

&lt;p&gt;When it comes to product development in such an environment, the emphasis is on quick, short cycles aimed at fast delivery. You're probably not spending a ton of time drafting detailed tech documentation or plotting out product development for more than a few months in advance. &lt;/p&gt;

&lt;p&gt;To keep up this speed and swiftly test out different business ideas, many turn to agile approaches like Scrum. It's all about iterative feature development, and when exploring new product avenues, the MVP (Minimum Viable Product) strategy is often the go-to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step growth vs. gradual growth
&lt;/h2&gt;

&lt;p&gt;In the B2B space, the journey from customer interest to full integration can be a long one. This extended timeline often gives you a buffer to gear up for any unique demands a new client might bring. You can rally more developer manpower and fine-tune your infrastructure to cater to each new client's needs.&lt;/p&gt;

&lt;p&gt;On the flip side, when you're in the B2C game, a big focus is on how quickly a user can jump in and start using your product. With such a low barrier to entry, you might see spikes in user activity out of the blue. Maybe you rolled out a catchy ad that's gone viral, got a shoutout as the "product of the day" on Product Hunt, or perhaps it's just that time of the year when everyone's looking for what you offer. Suddenly, your user count could skyrocket. This unpredictability means you've got to build your system to be super flexible. It should be ready to scale up in a snap and adapt on the fly to whatever comes its way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;Beyond just meeting regulatory standards, it's crucial to sync up with your customers on security protocols. Today, a data breach can spell disaster for businesses big and small. However, big enterprise clients tend to put cybersecurity under the microscope before they even think about signing a contract or integrating your solution. They might ask you to secure certifications like ISO 27001, set up robust internal security guidelines, limit who can access production data, or even put your system through rigorous penetration tests.&lt;/p&gt;

&lt;p&gt;On the other hand, small to medium-sized businesses (SMBs) aren't usually as stringent about these security deep dives. Addressing basic concerns, like preventing SQL injections, often ticks the box for them. And if you're a budding company, you might find that tasks like updating software to patch vulnerabilities get pushed down the priority list, making way for more immediate business-driven goals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Brand visibility and recognition
&lt;/h2&gt;

&lt;p&gt;Even though you're diving deep into complex challenges and working under tough conditions, your hard work might fly under the radar for those outside your field. &lt;/p&gt;

&lt;p&gt;Your product often powers the big players from the shadows, without the general public getting a firsthand look. Contrast this with developing B2C tools or solutions for widespread SMB use. In those scenarios, explaining your latest project to friends and family is a breeze. &lt;/p&gt;

&lt;p&gt;Plus, there's the added perk of getting personal recognition for that cool new feature you helped bring to life.&lt;/p&gt;




&lt;h2&gt;
  
  
  Overall thoughts (or a conclusion of sorts)
&lt;/h2&gt;

&lt;p&gt;Launching a successful B2C company is no walk in the park. It demands a harmonious effort across every facet of the product. &lt;br&gt;
Here's a breakdown:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User acquisition: Draw in the "right" users without breaking the bank.&lt;/li&gt;
&lt;li&gt;Strategic planning: Choose the best paths forward for growth.&lt;/li&gt;
&lt;li&gt;Backlog prioritization: Ensure you're always showing impressive month-over-month growth.&lt;/li&gt;
&lt;li&gt;User support: Keep existing users happy and engaged.&lt;/li&gt;
&lt;li&gt;Engineering: Never lose sight of the technical side of your product.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given the fierce competition in the B2C space, this all comes with a hefty dose of uncertainty. This unpredictability can make venture capitalists wary of investing. If your leadership team isn't packed with industry bigwigs, securing substantial early-stage investment can be an uphill battle. With funds spread thin, it's tough to give every aspect of product development the attention it deserves.&lt;/p&gt;

&lt;p&gt;At this juncture, zeroing in on a product-market fit is paramount. B2C startups are more prone to shifts in direction compared to their B2B counterparts, which usually have a clearer picture of their target audience and the problems they're addressing.&lt;/p&gt;

&lt;p&gt;Budget constraints and the potential for sudden shifts in direction mean it's often unwise to pour too much into engineering. You'll likely be working with a tight budget, focusing only on the essentials to roll out the next product version swiftly for another round of testing. This environment is ripe for tales of quick adaptation, problem-solving on the fly, and product building.&lt;/p&gt;

&lt;p&gt;However, B2B startups present a different picture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They often have a clearer idea of client pain points.&lt;/li&gt;
&lt;li&gt;Initial customer acquisition can be smoother, thanks to founders' connections or direct sales efforts.&lt;/li&gt;
&lt;li&gt;The uncertainty is generally less, but the depth of knowledge required about the domain and product is greater.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, if you're aiming to be a specialist in a niche area and prefer a more stable work environment (though priorities might still shift), B2B startups could be your calling.&lt;/p&gt;

&lt;p&gt;Whether you're venturing into B2C or B2B, both paths come with their unique challenges and rewards. It's all about finding the right fit for your skills, passion, and the kind of challenges you're eager to tackle.&lt;/p&gt;

&lt;p&gt;In my blog, I mostly focus on approaches to work, team building in the early stages of company development, the role of a product engineer, and establishing a data-driven culture within a company. If these topics interest you, feel free to subscribe for me and other &lt;a href="https://dev.to/monite"&gt;Monite developers&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>startup</category>
      <category>career</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
