<?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: Ivan Levenhagen</title>
    <description>The latest articles on DEV Community by Ivan Levenhagen (@eckzzo).</description>
    <link>https://dev.to/eckzzo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F936069%2F111f2c65-b6cc-45ae-b5e6-fa8004d867f7.gif</url>
      <title>DEV Community: Ivan Levenhagen</title>
      <link>https://dev.to/eckzzo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eckzzo"/>
    <language>en</language>
    <item>
      <title>What do we look in a Software Engineer</title>
      <dc:creator>Ivan Levenhagen</dc:creator>
      <pubDate>Mon, 18 Dec 2023 18:32:25 +0000</pubDate>
      <link>https://dev.to/woovi/what-do-we-look-in-a-software-engineer-470b</link>
      <guid>https://dev.to/woovi/what-do-we-look-in-a-software-engineer-470b</guid>
      <description>&lt;p&gt;In my experience as a software engineer, I've found that excelling in problem-solving demands skills beyond coding. Effective communication, initiative, and ownership are essential. In this article I share on what I seek when evaluating potential software engineers for our team, and the practical skills I think are needed for success. So what are these skills, and why I think they are so important for success?&lt;/p&gt;

&lt;p&gt;Communication is fundamental for a good software engineer. Our work isn't just about technical skills; it's also about explaining our ideas and solutions clearly. If you can't explain your solution well, it might mean you don't fully understand what you're doing, or proposing.&lt;/p&gt;

&lt;p&gt;In our hiring process, we keep our code challenges as simple and open-ended as possible. This allows the candidates to show their problem solving skills, and also is an opportunity for them to explore something new, whether it's a new technology or a concept they may be unfamiliar with.&lt;/p&gt;

&lt;p&gt;Ownership also shows how well a candidate documents their work, and how much they care for it. Similarly, writing articles and sharing them publicly is a great way to demonstrate ownership. It can offer insights into their processes, the obstacles they tackled, and the lessons they learned. Being willing to document and share not only benefits the community but also shows a sense of pride in the work.&lt;/p&gt;

&lt;p&gt;In conclusion, I think that being a good software engineer, goes beyond technical skills. Clear communication, initiative, and ownership are just as important. Communicating your ideas, taking the initiative of proposing innovative solutions and having ownership of your work, is what truly makes someone excel.&lt;/p&gt;




&lt;p&gt;If you want to work in a startup in its early stages, This  is your chance. &lt;a href="https://woovi.com/jobs/"&gt;Apply today!&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://woovi.com/"&gt;Woovi&lt;/a&gt; is a Startup that enables shoppers to pay as they please. To make this possible, Woovi provides instant payment solutions for merchants to accept orders.&lt;/p&gt;

&lt;p&gt;If you want to work with us, we are &lt;a href="https://woovi.com/jobs/"&gt;hiring&lt;/a&gt;!&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@chrislawton?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash"&gt;Chris Lawton&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/assorted-color-lear-hanging-decor-5IHz5WhosQE?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Using Conditional Put to Solve MongoDB Concurrency Issues</title>
      <dc:creator>Ivan Levenhagen</dc:creator>
      <pubDate>Mon, 02 Oct 2023 12:26:19 +0000</pubDate>
      <link>https://dev.to/woovi/using-conditional-put-to-solve-mongodb-concurrency-issues-405a</link>
      <guid>https://dev.to/woovi/using-conditional-put-to-solve-mongodb-concurrency-issues-405a</guid>
      <description>&lt;p&gt;When building applications, handling concurrency issues is a critical aspect of ensuring data integrity. MongoDB lacks an API for conditional expressions in inserts, a feature that is standard in databases such as DynamoDB, making dealing with concurrency harder. How can we effectively manage situations where multiple entities attempt to write to the database simultaneously, potentially compromising data integrity? In this article, we will explore three strategies to address this challenge: FIFO Queues, Distributed Locks, and our main focus, Conditional Put.&lt;/p&gt;

&lt;p&gt;Concurrency issues occur when multiple entities attempt to write to the database simultaneously. This can lead to conflicting writes, potentially compromising data integrity. Guaranteeing that only a single entity will be able to write on a database given a condition, is crucial for some systems.&lt;/p&gt;

&lt;p&gt;To address this issue, there are a few strategies we can use. In this post, we will go through three of them: FIFO Queues, Distributed Locks, and our main focus, Conditional Put.&lt;/p&gt;

&lt;p&gt;Before diving into possible solutions, we need to identify our problem. Our scenario is the following: We're building an application where Users can request Races which can be accepted by Drivers. We will focus on the User requesting Races part. Our goal is that a User shouldn't be able to request two Races at the same time.&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%2Ff7b7hkkl24hgwqh0ahvg.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%2Ff7b7hkkl24hgwqh0ahvg.png" alt="Initial Data Modeling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that this is an extremely simplified version of the data modeling. The focus of this post isn't the data modeling but how to solve a problem like the one presented.&lt;/p&gt;

&lt;p&gt;Now that we have our 'schema' and problem, let's talk about how we can approach to solve it.&lt;/p&gt;

&lt;h2&gt;
  
  
  FIFO Queues
&lt;/h2&gt;

&lt;p&gt;FIFO stands for 'First In First Out'. In our case, it would be a message queue without any concurrency, guaranteeing that all the requested writes would be always tried in the order they were requested. We can just add a check if the item already exists. In a way, we can say that FIFO Queues would guarantee that there wouldn't be any concurrent attempts at writing on our database.&lt;/p&gt;

&lt;p&gt;The problem with this solution is scaling. Imagine we have thousands of operations being realized at the same time; a single queue wouldn't be very fast to handle it. This could result in a poor user experience due to latency. The advantage is that it is very simple to implement, especially if you already have a message queue system implemented in your application. All you would need to do is create a new queue for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Distributed Lock
&lt;/h2&gt;

&lt;p&gt;Distributed Locks would be a more robust solution to our problem. In a Distributed Lock system, the system distributes tokens to consumers. We add a lock to our process and check if the consumer has a valid token. If not, we just return an error. This would allow us to still run concurrent processes; we could have only a single valid token available at a time for a User, per race requested. Whichever request acquires the lock first, wins the token and can write to the database.&lt;/p&gt;

&lt;p&gt;This is a pretty robust solution, and it would also scale nicely. The problem with Distributed Lock systems is that they are very complex. Going deeper into them would be a subject for another article, or possibly even several more. Another point to consider is that you most likely would be introducing a new layer to your application, maybe something like Redis or possibly a more robust locking system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conditional Put
&lt;/h2&gt;

&lt;p&gt;This is the main focus of this post, and probably why you're here. While MongoDB has a conditional expression system for updates with the $cond operator, it doesn't have one for inserts, which is where our problem lies. But that doesn't mean it's not possible to make Conditional Puts in it; we just need to be a bit more creative.&lt;/p&gt;

&lt;p&gt;We can solve our problem by adding a new field to our Race model, which we will call conditionId. This field will be an ObjectId with a unique constraint attached to it.&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%2Fwg8fwxi0yyvnqpn1ao9m.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%2Fwg8fwxi0yyvnqpn1ao9m.png" alt="Updated Data Modeling with Condition Id"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So what is this id? What is it going to reference? This is where we get creative; this id will be the id of the last race requested by the user. Due to the unique constraint we added to the field, we can guarantee that only a single document will exist with it; all other attempts will fail at the database level.&lt;/p&gt;

&lt;p&gt;Here's some pseudo code of how our logic would look:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;raceConditionIdGet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lastRace&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Race&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;lastRace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;raceCreate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;conditionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;raceConditionIdGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;race&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Race&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;conditionId&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;race&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;race&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you may think, what if this is the User's first Race? There won't be a valid conditionId, so what do we use? In this case, we can use the User's own id.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;raceConditionIdGet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lastRace&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Race&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;lastRace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;lastRace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&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;You can see that our conditionId acts very similar to the idea of the Distributed Lock token; the advantage is that we didn't introduce any new system to our codebase. But just like any other solution, it has trade-offs. While storage is cheap, does it make sense to save this id? What if we have multiple conditions? Would it be a good idea to just keep saving new ids, maybe even repeated ones in the same document?&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Just like pretty much any other problem like this one, there is not actually a right answer; it all depends on your context. If you already have a message queue system implemented and are not expecting a lot of demand, the queue system will work just fine for you. You may (probably) be building something way more complex than our contained example, so the distributed lock may make more sense for you. &lt;/p&gt;




&lt;p&gt;If you want to work in a startup in its early stages, This  is your chance. &lt;a href="https://woovi.com/jobs/" rel="noopener noreferrer"&gt;Apply today!&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://woovi.com/" rel="noopener noreferrer"&gt;Woovi&lt;/a&gt; is a Startup that enables shoppers to pay as they please. To make this possible, Woovi provides instant payment solutions for merchants to accept orders.&lt;/p&gt;

&lt;p&gt;If you want to work with us, we are &lt;a href="https://woovi.com/jobs/" rel="noopener noreferrer"&gt;hiring&lt;/a&gt;!&lt;/p&gt;




</description>
    </item>
    <item>
      <title>Learn, Decide, Grow</title>
      <dc:creator>Ivan Levenhagen</dc:creator>
      <pubDate>Fri, 16 Jun 2023 15:07:44 +0000</pubDate>
      <link>https://dev.to/woovi/learn-decide-grow-2hc2</link>
      <guid>https://dev.to/woovi/learn-decide-grow-2hc2</guid>
      <description>&lt;p&gt;Working in a rapidly growing startup like Woovi requires you to adapt quickly to the market and customer demands. This environment often demands rapid decision-making. Being able to make decisions quickly, learn from them, and course-correct is crucial for us.&lt;/p&gt;

&lt;p&gt;To make things easier, we document every single type of decision we take, showing both the tradeoffs of different approaches, and what we have learned from them. This way we take away some of the cognitive load, by making a map of our past mistakes.&lt;/p&gt;

&lt;p&gt;For example one of the documented decisions we have is &lt;code&gt;When to create a new Component&lt;/code&gt;. With a pretty small document we managed to save a lot of time from future decisions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7wL6BpNk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/swd09dh6aslao7bh9uxg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7wL6BpNk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/swd09dh6aslao7bh9uxg.png" alt="Image description" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But while this helps in a lot of cases, everyday at Woovi we're presented with new challenges. These unexpected situations might seem daunting as they often necessitate quick decisions in the face of uncertainty.&lt;/p&gt;

&lt;p&gt;To be able to move quickly in these scenarios, you need to understand and accept that not every decision you make will be the best one at first. Getting things right, especially on the first try, is extremely hard, if not impossible.&lt;/p&gt;

&lt;p&gt;It's better that you fail as fast as possible and learn from it, rather than avoiding decisions due to fear of failing. Rather than seeing it as a failure, see it as an opportunity to learn, see what went wrong, and why, share with your team your discoveries. This mindset of 'failing forward' not only accelerates personal growth but also drives the evolution of our team and the entire organization.&lt;/p&gt;




&lt;p&gt;If you want to work in a startup in its early stages, This  is your chance. &lt;a href="https://woovi.com/jobs/"&gt;Apply today!&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://woovi.com/"&gt;Woovi&lt;/a&gt; is a Startup that enables shoppers to pay as they please. To make this possible, Woovi provides instant payment solutions for merchants to accept orders.&lt;/p&gt;

&lt;p&gt;If you want to work with us, we are &lt;a href="https://woovi.com/jobs/"&gt;hiring&lt;/a&gt;!&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@pinewatt?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;pine  watt&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/dUbKcgu0zjw?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>startup</category>
      <category>softwareengineering</category>
      <category>programming</category>
    </item>
    <item>
      <title>Double Entry for Developers</title>
      <dc:creator>Ivan Levenhagen</dc:creator>
      <pubDate>Fri, 31 Mar 2023 19:03:20 +0000</pubDate>
      <link>https://dev.to/woovi/double-entry-for-developers-2mcb</link>
      <guid>https://dev.to/woovi/double-entry-for-developers-2mcb</guid>
      <description>&lt;p&gt;At Woovi, ensuring the accuracy of our numbers is crucial. Even the slightest mistake can cause irreparable damage. For this reason, we have a robust ledger system at our core.&lt;/p&gt;

&lt;p&gt;If at any point in your career you find yourself working in a place that deals with numbers, you will undoubtedly come across the terms &lt;strong&gt;Double Entry Accounting&lt;/strong&gt; and &lt;strong&gt;Ledger&lt;/strong&gt;. But what exactly do they mean?&lt;/p&gt;

&lt;p&gt;A ledger refers to the Book of Accounts, which is responsible for keeping track of all transactions. The accounts represent the 'where' of the debit or credit event.&lt;/p&gt;

&lt;p&gt;One of the biggest misconceptions surrounding ledgers is the idea that all the accounts within a ledger are bank accounts. This is not true. While a bank account may use a ledger to keep track of its numbers, the ledger itself does not specifically concern bank accounts. Accounts within a ledger can be used to track virtually anything you want.&lt;/p&gt;

&lt;p&gt;Another common misconception lies in the notion of double entry. Double entry transactions do not necessarily mean that there will always be exactly two entries within a transaction. Rather, it means that there will always be &lt;strong&gt;at least&lt;/strong&gt; one Credit and one Debit within it. As long as the sum of credits and debits inside the transaction matches, it follows the rules of double entry accounting.&lt;/p&gt;

&lt;p&gt;There is not a single correct way of representing something on a ledger; it all depends on your wants and needs. Let's look at how you can represent the same transaction in multiple ways using this example:&lt;/p&gt;

&lt;p&gt;Suppose we have a lemonade stand in front of a shop. To let us stay on the sidewalk, this shop charges us 10% of each lemonade we sell, and we charge USD 300.00 for each drink. Yes, our lemonade is &lt;strong&gt;that&lt;/strong&gt; good. So, how can we represent the sale of a drink on the ledger?&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%2Ff3gbujy1ec7gp4pvirwx.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%2Ff3gbujy1ec7gp4pvirwx.png" alt="Image description"&gt;&lt;/a&gt;&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%2Fuwwh7j8rfe7b7edjujsl.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%2Fuwwh7j8rfe7b7edjujsl.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both of these methods are correct ways to represent the sale of the drink on the ledger. It's all about what we want and need. Does it make sense for us to record the fees being paid by us separately? Will this number be useful for us in the future? It all depends on what and how you want to use the ledger.&lt;/p&gt;

&lt;p&gt;Note that we have no mention of banks here. We have an account that tracks our earnings, one that tracks the small shop earnings, and one to represent the buyer. Do you want to know your earnings by customer? Create an account for each of them! Accounts on the ledger are nothing special; they're just another row on a database.&lt;/p&gt;




&lt;p&gt;If you want to work in a startup in its early stages, This  is your chance. &lt;a href="https://woovi.com/jobs/" rel="noopener noreferrer"&gt;Apply today!&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://woovi.com/" rel="noopener noreferrer"&gt;Woovi&lt;/a&gt; is a Startup that enables shoppers to pay as they please. To make this possible, Woovi provides instant payment solutions for merchants to accept orders.&lt;/p&gt;

&lt;p&gt;If you want to work with us, we are &lt;a href="https://woovi.com/jobs/" rel="noopener noreferrer"&gt;hiring&lt;/a&gt;!&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/pt-br/@rodlong?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Rod Long&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/JB5YCqOXV1o?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Making Good Pull Requests</title>
      <dc:creator>Ivan Levenhagen</dc:creator>
      <pubDate>Tue, 14 Mar 2023 13:37:38 +0000</pubDate>
      <link>https://dev.to/woovi/making-good-pull-requests-1md4</link>
      <guid>https://dev.to/woovi/making-good-pull-requests-1md4</guid>
      <description>&lt;p&gt;At Woovi we have a culture that every dev should review all pull requests, due to that it's crucial that we follow good practices to make the reviewing process easier, and also give context on what we're working on.&lt;/p&gt;

&lt;p&gt;A good pull request have a few characteristics to it, you can have more rules depending on the culture you're trying to nurture, but you should always try to follow these points:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small / Atomic​&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One pull request should be responsible for a singular change when possible, this not only makes it easier to review, but it lowers the chances of introducing bugs to the code base.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linked Issue​&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ideally every pull request should have an issue linked on it. This makes it easier to track what's being done on the issue, improve the documentation of changes, and also makes reviewing it easier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tests​&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Regardless of how small a change is, almost all pull requests should have a test attached to it. Having tests for even small changes and bug fixes is important so we don't introduce the same bug on the codebase again. It's important that the tests are in the same pull request as the changes, not only it makes it easier to review the changes, it also makes it easier to review the tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prints​&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your pull request makes a visual change, it's important to always attach a print to it. It makes sure that everyone can easily see the change you made.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Should You Do Before Making a Pull Request?​
&lt;/h2&gt;

&lt;p&gt;Before making a new pull request, you should make sure that the code you wrote is ready for merge, here's a few steps you can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the tests you wrote, or any associated with the pieces you're changing.&lt;/li&gt;
&lt;li&gt;If your tests generated any snapshots, make sure to guarantee the snapshots are correct.&lt;/li&gt;
&lt;li&gt;Run any commands that will generate code, like for example i18n and make sure to do the needed changes after running them.&lt;/li&gt;
&lt;li&gt;Update any snapshots needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Should You do After Making a Pull Request?​
&lt;/h2&gt;

&lt;p&gt;Your work doesn't end when you finish publishing your changes, after actually making the pull request you should also try to follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Review your own code&lt;/li&gt;
&lt;li&gt;Respond to comments and feedback the team gives you&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Any feedback given in the pull request should be considered, when someone gives feedback on a pull request it means that they thought and properly reviewed your code, if you disagree with a point, make sure to respond with your own arguments. Feedback is &lt;strong&gt;not&lt;/strong&gt; an attack on your work, so make sure to always respond to any feedback given. If you're thinking you're not getting constructive feedback, make sure to let it clear to team how you'd like feedback to be given.&lt;/p&gt;

&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bad Pull Request&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X6qfaiT7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbz5zl396xnhn5qozjlu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X6qfaiT7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbz5zl396xnhn5qozjlu.png" alt="Image Showing a Bad Pull Request" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good Pull Request&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NoO3kYuG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ykaaeghvm85v3j8yy2g8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NoO3kYuG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ykaaeghvm85v3j8yy2g8.png" alt="Image Showing a Good Pull Request" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you want to work in a startup in its early stages, This  is your chance. &lt;a href="https://woovi.com/jobs/"&gt;Apply today!&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://woovi.com/"&gt;Woovi&lt;/a&gt; is a Startup that enables shoppers to pay as they please. To make this possible, Woovi provides instant payment solutions for merchants to accept orders.&lt;/p&gt;

&lt;p&gt;If you want to work with us, we are &lt;a href="https://woovi.com/jobs/"&gt;hiring&lt;/a&gt;!&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@coleito?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Cole Keister&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/xMMh-VFGL9M?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Adapter Pattern: Adapting Data from the Outside World</title>
      <dc:creator>Ivan Levenhagen</dc:creator>
      <pubDate>Mon, 13 Feb 2023 20:53:29 +0000</pubDate>
      <link>https://dev.to/woovi/adapting-data-from-the-outside-world-474c</link>
      <guid>https://dev.to/woovi/adapting-data-from-the-outside-world-474c</guid>
      <description>&lt;p&gt;Often while building applications we consume data from outside services, and even save parts of it on our end. A very common mistake is adapting your architecture for these services, what you should do instead is &lt;strong&gt;adapt their data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On Woovi our application communicates with various different applications from the outside world, also known as 3rd party apps. These applications have their own data modeling and doesn't always fit ours, so we must &lt;strong&gt;adapt their data&lt;/strong&gt; to fit &lt;strong&gt;ours&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This approach have some benefits, such as decoupling. For example if we consume a email provider and then decide to change to another one in the future, rather than restructuring our architecture to fit the new provider, all we would need to do is create a new adapter and everything should stay working.&lt;/p&gt;

&lt;p&gt;Another benefit is that it lets us not only learn from others modeling, we can try to evolve them to what we believe is the correct approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Adapter Pattern​
&lt;/h2&gt;

&lt;p&gt;When consuming data from third party, before saving it to our database, we always run it through an adapter function. This function job is to accept a payload and return a payload for our structure, to avoid losing data, you can choose to save the original payload on a metadata field or something similar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an Adapter Function
&lt;/h2&gt;

&lt;p&gt;Creating an Adapter Function is pretty simple, using a very contrived example, let's say we want consume a API for geo location, and save the latitude and longitude that it returns in our database.&lt;/p&gt;

&lt;p&gt;In our data, we decided that both the latitude and longitude will be different fields, but when calling this api, it returns both values inside an array instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;latLong: [40.689247, -74.044502]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rather than altering our modeling to also accept an array, all we need to do is adapt this field to ours:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const latLongApiToLocation = (payload) =&amp;gt; ({
  latitude: payload.latLong[0],
  longitude: payload.latLong[1],
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this is extremely simple, it makes the data &lt;strong&gt;ours&lt;/strong&gt; and we're not dependent of this API, all we would need to do to replace it is create another of these functions, while maintaining the data in the structure we believe in.&lt;/p&gt;




&lt;p&gt;If you want to work in a startup in its early stages, This  is your chance. &lt;a href="https://woovi.com/jobs/" rel="noopener noreferrer"&gt;Apply today!&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://woovi.com/" rel="noopener noreferrer"&gt;Woovi&lt;/a&gt; is a Startup that enables shoppers to pay as they please. To make this possible, Woovi provides instant payment solutions for merchants to accept orders.&lt;/p&gt;

&lt;p&gt;If you want to work with us, we are &lt;a href="https://woovi.com/jobs/" rel="noopener noreferrer"&gt;hiring&lt;/a&gt;!&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@alexkixa?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Alexandre Debiève&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/gZdFwcCbXf4?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>announcement</category>
      <category>devto</category>
    </item>
    <item>
      <title>You (most likely) don't need to optimize React</title>
      <dc:creator>Ivan Levenhagen</dc:creator>
      <pubDate>Thu, 06 Oct 2022 16:18:48 +0000</pubDate>
      <link>https://dev.to/woovi/you-most-likely-dont-need-to-optimize-react-43h2</link>
      <guid>https://dev.to/woovi/you-most-likely-dont-need-to-optimize-react-43h2</guid>
      <description>&lt;p&gt;One of the biggest pitfalls in software development is early optimization, we always want our code to run as fast as possible and try to squeeze every single drop out of it. But going through this process too early can do more harm than good.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.woovi.com"&gt;Woovi&lt;/a&gt; is a Startup that enables shoppers to pay as they like. To make this possible, Woovi provides instant payment solutions for merchants to accept orders.&lt;/p&gt;

&lt;p&gt;The most common mistake in React projects is the use of the &lt;code&gt;useCallback&lt;/code&gt; and &lt;code&gt;useMemo&lt;/code&gt; hooks, you (most likely) don't need to use these hooks, let's take a look how &lt;code&gt;useMemo&lt;/code&gt; works to understand why.&lt;/p&gt;

&lt;p&gt;So, what does &lt;code&gt;useMemo&lt;/code&gt; do? It accepts two parameters, a &lt;code&gt;Callback&lt;/code&gt; and an array of dependencies, and returns the return of this callback. The dependency array is used so &lt;code&gt;useMemo&lt;/code&gt; can track if this value is &lt;strong&gt;stale&lt;/strong&gt;, if the dependencies values changes, this mean we have to calculate the value again.&lt;/p&gt;

&lt;p&gt;Now, all of this sounds amazing, so why don't we just &lt;code&gt;useMemo&lt;/code&gt; everywhere? Let's take at this &lt;strong&gt;very&lt;/strong&gt; contrived example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const fruits = ['apple, 'banana', 'orange']
const initialFruit = useMemo(() =&amp;gt; fruits.find(item =&amp;gt; item === 'orange'), [])
const [fruit, setFruit] = useState(initialFruit)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While it's great that we're not running the .find on every render, we have to ask ourselves, is it worth it? &lt;code&gt;useMemo&lt;/code&gt; itself is &lt;strong&gt;more&lt;/strong&gt; code it isn't completely free to use, we added more complexity to our code which makes it harder to maintain. React is fast, you don't need to optimize every single thing, what's expensive in React is committing changes to the DOM not a simple calculation.&lt;/p&gt;

&lt;p&gt;So when should I optimize React? It's actually very easy to know. If you're asking yourself this question, you don't need it. When the time comes that performance is a problem on your code, you'll know it.&lt;/p&gt;

&lt;p&gt;Focus your time creating new features for your application, not optimizing code that you probably don't even need to.&lt;/p&gt;

&lt;p&gt;If you want to work with us, we are &lt;a href="https://woovi.com/jobs/"&gt;hiring&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
