<?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: Siddhant Goel</title>
    <description>The latest articles on DEV Community by Siddhant Goel (@siddhantgoel).</description>
    <link>https://dev.to/siddhantgoel</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%2F329259%2F201f7dad-6f6f-4af2-8f65-d45ebf529390.jpg</url>
      <title>DEV Community: Siddhant Goel</title>
      <link>https://dev.to/siddhantgoel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/siddhantgoel"/>
    <language>en</language>
    <item>
      <title>Why you should choose Starlette for your next SaaS</title>
      <dc:creator>Siddhant Goel</dc:creator>
      <pubDate>Mon, 22 Aug 2022 16:27:36 +0000</pubDate>
      <link>https://dev.to/siddhantgoel/why-you-should-choose-starlette-for-your-next-saas-3eln</link>
      <guid>https://dev.to/siddhantgoel/why-you-should-choose-starlette-for-your-next-saas-3eln</guid>
      <description>&lt;p&gt;&lt;a href="https://www.starlette.io/" rel="noopener noreferrer"&gt;Starlette&lt;/a&gt; is a relatively recent entrant to the world of Python web frameworks, particularly if you compare it to the more established ones like Django, Flask, etc.&lt;/p&gt;

&lt;p&gt;In this post, I'd like to make the case that in spite of its recency, it brings so much to the table that you should give it a serious consideration if you're starting a new project today.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Starlette is asynchronous by default
&lt;/h2&gt;

&lt;p&gt;Asynchronous programming is not new by any means. But mainline Python support for high-level asynchronous primitives can definitely be considered recent.&lt;/p&gt;

&lt;p&gt;To be fair, Python has had the &lt;a href="https://docs.python.org/3/library/asyncore.html" rel="noopener noreferrer"&gt;asyncore&lt;/a&gt; module for years (decades?) now, which enabled asynchronous programming at a rather lower level. However, with the introduction of &lt;a href="https://docs.python.org/3/library/asyncio.html" rel="noopener noreferrer"&gt;asyncio&lt;/a&gt;, writing asynchronous code in Python has gotten a lot more approachable and popular.&lt;/p&gt;

&lt;p&gt;Starlette builds on top of all this and gives you an asynchronous &lt;strong&gt;web toolkit&lt;/strong&gt;. When you're building a SaaS, this can enable a ton of use cases that are usually not possible with synchronous web servers because of the (different) concurrency model they're running under.&lt;/p&gt;

&lt;p&gt;Here are two examples:&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 Serving multiple requests in parallel
&lt;/h3&gt;

&lt;p&gt;Assume that your SaaS application is starting to gain traction. At some point, you may need the ability to serve multiple users in parallel.&lt;/p&gt;

&lt;p&gt;With conventional WSGI-based synchronous web servers, you can serve multiple requests at the same time by running &lt;em&gt;more&lt;/em&gt; backend processes. If on the other hand your application is built on top of an asynchronous framework, you can achieve a lot more within a single process. This is because each individual process can utilize the CPU time more efficiently by allowing context-switches while performing I/O.&lt;/p&gt;

&lt;p&gt;As always, it's hard to make generalizations in software. The same applies here. A lot of these performance aspects depend on the individual characteristics of &lt;em&gt;your&lt;/em&gt; application. Regardless, trying to figure out if any specific aspects of your application can benefit from the asynchronous concurrency model can be worth a shot.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.2. Making network calls without affecting other requests
&lt;/h3&gt;

&lt;p&gt;In user-facing web applications, there are often use cases where you want to make network calls over the Internet as part of serving a user's HTTP request. Calling out external APIs, for instance an email delivery service, is a good example.&lt;/p&gt;

&lt;p&gt;Performing such actions inside the main thread of a synchronous web application will block the entire application until the network call finishes. In an asynchronous application, the server is free to switch context to do something else as long as the first context is busy with (network) I/O.&lt;/p&gt;

&lt;p&gt;This means that if there's a situation where the server is processing two user requests and the first one makes a network call, the server can switch to processing the second request &lt;em&gt;while&lt;/em&gt; the first request is waiting for the network call to finish. How neat is that?!&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Starlette gives you very high performance
&lt;/h2&gt;

&lt;p&gt;The recommended mode to run Starlette applications is under &lt;a href="https://www.uvicorn.org/" rel="noopener noreferrer"&gt;Uvicorn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Uvicorn is an ASGI server implementation written in Python. ASGI, short for Asynchronous Server Gateway Interface, provides a standard interface between asynchronous Python web servers, frameworks, and applications. Uvicorn is one of the fastest implementations of the ASGI interface and pushes &lt;em&gt;hard&lt;/em&gt; on performance.&lt;/p&gt;

&lt;p&gt;From their homepage:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ASGI should help enable an ecosystem of Python web frameworks that are highly competitive against Node and Go in terms of achieving high throughput in IO-bound contexts. It also provides support for HTTP/2 and WebSockets, which cannot be handled by WSGI.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Installing Uvicorn using &lt;code&gt;pip install uvicorn[standard]&lt;/code&gt; will replace (if possible) the standard library's async event loop with &lt;code&gt;uvloop&lt;/code&gt; which is an event loop written in Cython (which in turn is a superset of Python that compiles down to &lt;em&gt;fast&lt;/em&gt; C code).&lt;/p&gt;

&lt;p&gt;There is a lot to unpack here which will mostly be a digression from what we're talking about. The gist of it all is that Starlette combined with Uvicorn is &lt;em&gt;fast&lt;/em&gt;. Their documentation refers the readers to &lt;a href="https://www.techempower.com/benchmarks/#section=data-r17&amp;amp;hw=ph&amp;amp;test=fortune&amp;amp;l=zijzen-1" rel="noopener noreferrer"&gt;this performance benchmark&lt;/a&gt; which shows that this combination is indeed one of the fastest combinations available in the Python ecosystem, serving slightly more than 71,000 requests per second.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The API is minimal but solid
&lt;/h2&gt;

&lt;p&gt;One of the hallmarks of well-built APIs is that you can intuit where things are going to be. In my experience working with Starlette, that certainly seems to be the case here.&lt;/p&gt;

&lt;p&gt;The overall API that Starlette gives you is very intuitive. The main entry point is a &lt;code&gt;Starlette&lt;/code&gt; object which accepts URL routes and the associated handlers as initialization parameters (amongst other parameters). This already makes up for a major chunk of your application. The rest of the code - things like database access, template rendering, authentication, etc. - is organized neatly into distinct modules that you can import.&lt;/p&gt;

&lt;p&gt;For instance, if I want to have my application behave differently depending on configuration variables, &lt;code&gt;starlette.config&lt;/code&gt; is the package I need to look into. Different kinds of HTTP response classes are available under&lt;br&gt;
&lt;code&gt;starlette.responses&lt;/code&gt;. Similarly, the authentication utilities are bundled inside &lt;code&gt;starlette.authentication&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;I hope that through this article I could give you a sense of the simplicity and power that Starlette has to offer. If you're looking to build a SaaS using Starlette, we offer an industry-standard &lt;a href="https://geniepy.com" rel="noopener noreferrer"&gt;boilerplate&lt;/a&gt; to kick-start your&lt;br&gt;
application. Alternatively if you'd like to learn more about Starlette, &lt;a href="https://www.starlette.io/" rel="noopener noreferrer"&gt;their documentation&lt;/a&gt; is an excellent resource to peruse.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@jeremythomasphoto" rel="noopener noreferrer"&gt;Jeremy Thomas&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/stars" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>saas</category>
      <category>starlette</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How you can track your personal finances using Python 🐍</title>
      <dc:creator>Siddhant Goel</dc:creator>
      <pubDate>Sat, 09 Oct 2021 16:52:25 +0000</pubDate>
      <link>https://dev.to/siddhantgoel/how-you-can-track-your-personal-finances-using-python-k5d</link>
      <guid>https://dev.to/siddhantgoel/how-you-can-track-your-personal-finances-using-python-k5d</guid>
      <description>&lt;p&gt;In this post, I'd like to describe how you can track your personal finances using a workflow that is highly focused on data privacy, is 100% self-hosted, and uses only the Python ecosystem.&lt;/p&gt;

&lt;p&gt;I'm also secretly hoping that some of you find this interesting enough to explore it in &lt;a href="https://personalfinancespython.com" rel="noopener noreferrer"&gt;more detail&lt;/a&gt;. 🙂&lt;/p&gt;




&lt;p&gt;We all know that money is important. Having money buys us freedom and lack of money is stressful. So how do we know whether we're doing good on that front?&lt;/p&gt;

&lt;p&gt;The answer is simple: we track our money.&lt;/p&gt;

&lt;p&gt;We keep an eye on how much money is coming in to our accounts, how much is going out, and when and how often those events are happening. We keep an eye out on trends, what are the recurring expenses, how many of those are necessary, so on and so forth.&lt;/p&gt;

&lt;p&gt;There's a good chance that you're doing this already. There are plenty of off-the-shelf solutions one can pick from for this purpose. There are mobile and SaaS apps that can connect to all your bank accounts, import all your financial transactions, and show you consolidated data.&lt;/p&gt;

&lt;p&gt;Not that there's anything particularly wrong with such apps. I'm instead of the opinion that my financial data (from across all my bank accounts) is something &lt;strong&gt;only I&lt;/strong&gt; should have consolidated access to. Financial data is one of the most privata data I own. So limiting the possible attack vectors sounds to me like an obvious choice.&lt;/p&gt;

&lt;p&gt;If you're out searching for such software and limit your search to open-source only solutions, you're most likely going to come across &lt;a href="https://plaintextaccounting.org" rel="noopener noreferrer"&gt;Plain Text Accounting&lt;/a&gt;, which is something I'll describe in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Big (and Quick) picture
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TL:DR&lt;/strong&gt;: Maintaining &lt;a href="https://en.wikipedia.org/wiki/Double-entry_bookkeeping" rel="noopener noreferrer"&gt;double-entry accounting&lt;/a&gt; based records of your financial transactions in plain-text files is the way to go.&lt;/p&gt;

&lt;p&gt;Double-entry accounting is a great way to track your finances. In this system, the flow of money between accounts is represented using transactions. You can think of a transaction as an "entry" of sorts that talks about a specific instance of money flowing between accounts. In most cases, transactions are composed of two "legs", where one leg is the &lt;strong&gt;credit&lt;/strong&gt; side and the other one is the &lt;strong&gt;debit&lt;/strong&gt; side.&lt;/p&gt;

&lt;p&gt;One of the most important rules of double-entry accounting is that the sum of the amounts of the individual legs in a transaction must be zero. A transaction is said to be "balanced" if this rule is satisfied.&lt;/p&gt;

&lt;p&gt;Here's a sample transaction to help you visualize this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2021-01-01 * "AMAZON.DE"
    Assets:MyBank    -42.00 EUR
    Expenses:Amazon   42.00 EUR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This transaction represents an Amazon purchase I made where the money was deducted from one of my accounts (called &lt;code&gt;Assets:MyBank&lt;/code&gt;) and added to an Amazon expense account.&lt;/p&gt;

&lt;p&gt;A collection of such transactions is what makes up your financial ledger.&lt;/p&gt;

&lt;h2&gt;
  
  
  Double-entry Accounting ♥️ Python = Beancount
&lt;/h2&gt;

&lt;p&gt;The Python ecosystem contains a really neat package called &lt;a href="https://pypi.org/project/beancount" rel="noopener noreferrer"&gt;Beancount&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Beancount is a command-line implementation of the double-entry accounting system that works on top of plain-text files. It mainly provides the following three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;basic primitives for working with money (eg. data structures like Accounts, Transactions, Postings, etc.)&lt;/li&gt;
&lt;li&gt;a language specification for defining financial transactions in a plain-text format (the snippet I showed earlier is valid Beancount code)&lt;/li&gt;
&lt;li&gt;command-line scripts that tie everything together&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As with most Python packages, getting started is as easy as creating a virtual environment and running &lt;code&gt;pip install beancount&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does the ledger look like?
&lt;/h2&gt;

&lt;p&gt;I wrote earlier that one of the main things that Beancount provides is a language specification for defining financial transactions in a plain-text format.&lt;/p&gt;

&lt;p&gt;What does this format look like? Here's a quick example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;option "title" "Alice"
option "operating_currency" "EUR"

; Accounts
2021-01-01 open Assets:MyBank:Checking
2021-01-01 open Expenses:Rent

2021-01-01 * "Landlord" "Thanks for the rent"
    Assets:MyBank:Checking     -1000.00 EUR
    Expenses:Rent               1000.00 EUR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What you see here is a very basic financial ledger of an imaginary person.&lt;/p&gt;

&lt;p&gt;In the first few lines we specify some metadata. Then we open (initialize) two Accounts. And the last three lines define a transaction where rent was deducted from one of those accounts and debited to the other one.&lt;/p&gt;

&lt;p&gt;Note that the account names don't always have to correspond one-to-one to real-world accounts. You can define as many accounts as you like, each for a specific purpose. For instance, you can have one account to track your supermarket expenses, one for rent, one for Netflix, so on and so forth.&lt;/p&gt;

&lt;p&gt;As I said, this is a very basic example. Real-world ledger files tend to be much longer.&lt;/p&gt;

&lt;p&gt;For instance, at the time of this writing my personal &lt;code&gt;.beancount&lt;/code&gt; file contains close to 21,000 lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/Work/finances main ❯ &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; goel.beancount
20996 goel.beancount
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How does the data flow?
&lt;/h2&gt;

&lt;p&gt;I hope that at this point you have a basic understanding of Beancount and double-entry accounting. In this section, I'll quickly run you through how data flows in such a system.&lt;/p&gt;

&lt;p&gt;The core idea with Beancount is that the user is responsible for storing all their financial transactions inside their &lt;code&gt;.beancount&lt;/code&gt; file. This file acts as the single source of truth for all your financial data from all your banks.&lt;/p&gt;

&lt;p&gt;So how do your transactions from your bank(s) end up in this file? In a series of three simple steps:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Download transactions from your bank
&lt;/h3&gt;

&lt;p&gt;Almost every bank allows you to export your data in some form. You should be able to log in to your bank's website, select a timeframe, and download all the transactions in a given file format. This usually tends to be CSV, but you can also download a PDF or sometimes an &lt;a href="https://en.wikipedia.org/wiki/Open_Financial_Exchange" rel="noopener noreferrer"&gt;OFX&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;This is the first step in a Beancount-driven workflow: download all your original data to your machine.&lt;/p&gt;

&lt;p&gt;Note that ideally this should be something that Python can parse without much ceremony. For instance, if I would have the choice between CSV and PDF, I would most likely pick a CSV download. Not because Python cannot parse PDF data (because &lt;a href="https://pypi.org/search/?q=pdf" rel="noopener noreferrer"&gt;it can&lt;/a&gt;) but because CSV is a much simpler data format than PDF.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Convert transactions to the Beancount format
&lt;/h3&gt;

&lt;p&gt;The next step is to take these CSV files and convert this data into a format that Beancount understands.&lt;/p&gt;

&lt;p&gt;Beancount provides an &lt;a href="https://beancount.github.io/docs/importing_external_data.html" rel="noopener noreferrer"&gt;importer framework&lt;/a&gt; to help with this process. Importers are Python programs which take a source file (eg. the downloaded CSV), parse it, and convert the data into data structures that Beancount provides. A text representation of these data structures is what makes up your personal ledger.&lt;/p&gt;

&lt;p&gt;Now, obviously Beancount does not know about all the banks on the planet and what their CSV exports look like and how they should be parsed. This is where the Python developer inside you can shine.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Importer&lt;/code&gt; classes shipped with Beancount are more like protocols. The base class is literally called &lt;code&gt;ImporterProtocol&lt;/code&gt;. They define method signatures and leave the implementation up to you. This way, you can inherit the base &lt;code&gt;ImporterProtocol&lt;/code&gt; class for your own importer, override the relevant methods, and let Beancount know of the existence of these importer classes using a configuration file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;beancount.ingest.importer&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ImporterProtocol&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;convert_to_beancount_data_structs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Implement me!
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyBankImporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ImporterProtocol&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;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Read and parse the file and convert the original data into Beancount
        data structures
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;convert_to_beancount_data_structs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on what banks you have accounts with, you can define multiple such importer classes and let Beancount know of their existence in a configuration file. Everything else will be handled for you automatically using the command line scripts included in Beancount.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Balance the transactions
&lt;/h3&gt;

&lt;p&gt;The next step is also the most fun part (at least I find it fun).&lt;/p&gt;

&lt;p&gt;We take the output of the previous step, pipe everything over to our &lt;code&gt;.beancount&lt;/code&gt; file, and "balance" transactions.&lt;/p&gt;

&lt;p&gt;Recall that the flow of money in double-entry accounting is represented using transactions involving at least two accounts. When you download CSVs from your bank, each line in that CSV represents money that's either incoming or outgoing. That's only one leg of a transaction (credit or debit). It's up to us to provide the other leg.&lt;/p&gt;

&lt;p&gt;This act is called "balancing".&lt;/p&gt;

&lt;p&gt;For instance, assume that the output of the previous step was the following transaction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2021-01-01 * "Landlord" "Thanks for the rent"
    Assets:MyBank:Checking    -1000.00 EUR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The total amount of the legs in this transaction does not yet sum to zero. It's up to us to balance it.&lt;/p&gt;

&lt;p&gt;Balancing involves figuring out what the transaction is about and assigning it an equal and opposite leg. In this case we can see that this transaction has to do with us paying rent. So the second leg should clearly contain the &lt;code&gt;Expenses:Rent&lt;/code&gt; account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2021-01-01 * "Landlord" "Thanks for the rent"
    Assets:MyBank:Checking     -1000.00 EUR
    Expenses:Rent               1000.00 EUR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This process of balancing is something we do for all the transactions, so that the entire ledger can be marked as balanced.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. That's it!
&lt;/h3&gt;

&lt;p&gt;That's basically it. Those three steps, performed at regular intervals of time, should ensure that your &lt;code&gt;.beancount&lt;/code&gt; data contains all your financial transactions and is in good shape.&lt;/p&gt;

&lt;p&gt;I prefer doing this every month. So on the first Sunday of every month, I prepare a fresh cup of coffee, download all the CSV files, run them through my importers, and balance all the unbalanced transactions.&lt;/p&gt;

&lt;p&gt;You might think that this is too much work. I have to admit that I had a similar thought when I started out.&lt;/p&gt;

&lt;p&gt;In my experience so far, it has been the exact opposite. The entire process has never taken me more than 45 minutes to finish. Considering that I do this once a month, the time investment seems more than fair. And the added benefit is that by balancing these transactions by hand, I get a fairly good idea of what was happening in my accounts in the previous month.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualization
&lt;/h2&gt;

&lt;p&gt;So far we talked about entering data into the system.&lt;/p&gt;

&lt;p&gt;The real power of personal accounting software is in showing you insights from that data. In this section I'll quickly walk you through the two tools I end up using the most: &lt;code&gt;bean-query&lt;/code&gt; and Fava.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;bean-query&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;bean-query&lt;/code&gt; is a command line utility shipped with Beancount that lets you run SQL-ish queries on your financial data. The query language is specific to Beancount. But if you're familiar with SQL, you'll feel right at home with &lt;code&gt;bean-query&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's an example run from my own data where I want to know how much I spent on public transport in the last three years, grouped by the year:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;beancount&amp;gt; SELECT \
        year, SUM(number) AS total \
        WHERE account ~ 'Expenses:PublicTransport' AND year &amp;gt;= 2019 \
        GROUP BY year;
year total 
---- ------
2019 672.60
2020 328.02
2021  30.50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first column in the output contains the year and the second one contains the total amount of money that I spent buying public transport tickets.&lt;/p&gt;

&lt;p&gt;Side note: I've been working remote since 2016, but it's pretty clear from those numbers when the COVID-lockdown hit my town the most.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Fava
&lt;/h3&gt;

&lt;p&gt;Fava is a community-maintained web interface for Beancount. At its core it's a Flask application which reads your &lt;code&gt;.beancount&lt;/code&gt; file and provides all sorts of visualizations you'll find useful.&lt;/p&gt;

&lt;p&gt;Here's a screenshot of one of the reports that Fava can generate for you:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://beancount.github.io/fava/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.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%2Ff3rsllig7te8exoyyep9.png" alt="Beancount Fava" width="800" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are multiple reports built-in, for instance balance sheet, income statement, document browser (another neat feature of Beancount where you can attach documents (eg. invoices) to transactions), and more. &lt;em&gt;And&lt;/em&gt; you can filter all the data using timeframes.&lt;/p&gt;

&lt;p&gt;There is an online demo at this URL in case you'd like to get a feel for it: &lt;a href="https://fava.pythonanywhere.com/" rel="noopener noreferrer"&gt;https://fava.pythonanywhere.com/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Between Fava and &lt;code&gt;bean-query&lt;/code&gt;, I use Fava the most. I feel that the visualizations provided by Fava give me a really good sense of almost all the financial insights I'm looking for.&lt;/p&gt;

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

&lt;p&gt;That was it! Congratulations for making it this far! I hope this article was able to interest you in this privacy-focused way of tracking personal finances.&lt;/p&gt;

&lt;p&gt;If you're interested in learning more, you should consider buying an ebook I wrote on this topic titled &lt;a href="https://personalfinancespython.com" rel="noopener noreferrer"&gt;Tracking Personal Finances using Python&lt;/a&gt;. In this&lt;br&gt;
ebook, I explain the concepts mentioned above in detail to help you build your own personalized multi-banking application using Python.&lt;/p&gt;

&lt;p&gt;Beancount and Double Entry Accounting can be slightly confusing to folks who are just starting out. So this ebook is my attempt at lowering the barrier to entry.&lt;/p&gt;

&lt;p&gt;And if you have questions about any of this, feel free to reach out to me on &lt;a href="https://twitter.com/siddhantgoel" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>python</category>
      <category>finance</category>
      <category>money</category>
      <category>flask</category>
    </item>
  </channel>
</rss>
