<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Building an events app from scratch]]></title><description><![CDATA[Building an events app from scratch]]></description><link>https://blog.alexnorgaard.dk</link><generator>RSS for Node</generator><lastBuildDate>Mon, 13 Apr 2026 07:23:03 GMT</lastBuildDate><atom:link href="https://blog.alexnorgaard.dk/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Building an Events Application: Querying events and indexing with GIN]]></title><description><![CDATA[In my last blog post we explored how to expose a simple API using the Echo Go framework and GORM ORM. We also took a look at how I wanted to represent an event in the database, including using tags and geolocation for search and filtering purposes. G...]]></description><link>https://blog.alexnorgaard.dk/building-an-events-application-querying-events-and-indexing-with-gin</link><guid isPermaLink="true">https://blog.alexnorgaard.dk/building-an-events-application-querying-events-and-indexing-with-gin</guid><category><![CDATA[PostgreSQL]]></category><category><![CDATA[query-optimization]]></category><category><![CDATA[GINIndex]]></category><category><![CDATA[golang]]></category><category><![CDATA[Echo framework]]></category><category><![CDATA[full text search]]></category><category><![CDATA[development]]></category><category><![CDATA[Developer]]></category><category><![CDATA[indexing]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Application Development]]></category><category><![CDATA[gorm]]></category><category><![CDATA[APIs]]></category><category><![CDATA[Golang developer]]></category><category><![CDATA[echo-web-framework]]></category><dc:creator><![CDATA[Alexander Arlund Nørgaard]]></dc:creator><pubDate>Sun, 03 Nov 2024 16:17:05 GMT</pubDate><content:encoded><![CDATA[<p>In my last blog post we explored how to expose a simple API using the Echo Go framework and GORM ORM. We also took a look at how I wanted to represent an event in the database, including using tags and geolocation for search and filtering purposes. Great! But how should the data actually be queried when the end user is searching for events? In this post I’m going to discuss my thought process and approach to best find a match to a users search criteria.</p>
<h4 id="heading-title-and-tags">Title and tags</h4>
<p>You may remember from my last blog post that I chose to have column on the Events db table named tags. My initial thinking has been that most people either would want to search on the title of the event, or some other metadata about the event. I chose to go with tags as people are used to adding these to their posts on social media, and would be comfortable using them to add searchable values to their events.<br />The next question then, is how should these tags be represented in the database? I need the tags to be easily searchable, with fast querying in the database, and I need every event to be able to hold several tags. One solution would be to have a tags table with a column that holds a string value that is the tag, and a tag ID. Then have a through table that points to a tag and an event in the same row, to register which events hold which tags. However, this would require expensive joins to query for specific tags. A successful application, holding thousands of searchable events, would make for some inefficient querying this way.<br />So I need locality of the tags, and I need to be able to index said tags as effectively as possible. Because I don’t need tags to be normalised in the database (I don’t care about aggregation, etc), I can hold all of the tags in a single column on each entry.</p>
<p>PostgreSQL has an index type which helps immensely with lookups in arrays called GIN (Generalized inverted index). GIN works really well on JSONB, array types and full text search. It is really effective in speeding up searches on these data types in a way that B-tree indexes cannot, and is especially effective if you are using the <code>@&gt;</code> operator. It does come with the added cost of extra overhead on writes, but as I expect that there will be considerably many more searches for events than events being created or updated, I am okay with this overhead. There are also ways to mitigate some of the overhead.<br />Defining the column on the events table in go, using GORM looks like this:</p>
<pre><code class="lang-go">Tags         pq.StringArray <span class="hljs-string">`gorm:"type:text[];index:tags_idx,type:GIN"`</span>
</code></pre>
<p>Here we tell GORM about the datatype using <code>pq.StringArray</code> and define the column to be a text array with <code>type:text[]</code>. I then specify the index as well as the indexing type using <code>index:tags_idx,type:GIN</code>.</p>
<p>The title is more simply defined:</p>
<pre><code class="lang-go">Title        <span class="hljs-keyword">string</span>         <span class="hljs-string">`gorm:"not null"`</span>
</code></pre>
<h4 id="heading-querying-events">Querying events</h4>
<p>So now that we have defined our tags and title column, we can look at querying events. Having in mind that a user will be writing their search criteria in a single search bar, it becomes apparent that we need to make our lookups using the same values for both title and tags. This means that the words written in a search could either be a list of tags or an event title. To facilitate this, the words need to be both comma separated for the tags and with spaces for the title. Assuming that the api takes a list of words delimited by commas in the query parameters, we can query the database like so:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> EventSearchItemDTO <span class="hljs-keyword">struct</span> {
    ID               uuid.UUID <span class="hljs-string">`json:"id"`</span>
    Title            <span class="hljs-keyword">string</span>    <span class="hljs-string">`json:"title"`</span>
    FormattedAddress <span class="hljs-keyword">string</span>    <span class="hljs-string">`json:"address"`</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(es *EventStore)</span> <span class="hljs-title">Get</span><span class="hljs-params">(c echo.Context)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-keyword">var</span> events = []EventSearchItemDTO{}
    <span class="hljs-keyword">var</span> result *gorm.DB

    params := c.QueryParams()
    tags := params.Get(<span class="hljs-string">"tags"</span>)
    title := strings.ReplaceAll(tags, <span class="hljs-string">","</span>, <span class="hljs-string">" "</span>)
    <span class="hljs-comment">//ILIKE makes the LIKE case insensitive</span>
    result = es.db.Model(&amp;model.Event{}).Where(<span class="hljs-string">"tags @&gt; ? OR title ILIKE ?"</span>, <span class="hljs-string">"{"</span>+tags+<span class="hljs-string">"}"</span>, <span class="hljs-string">"%"</span>+title+<span class="hljs-string">"%"</span>).Select(<span class="hljs-string">"id, title, formatted_address"</span>).Find(&amp;events)

    <span class="hljs-keyword">if</span> result.Error != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> c.String(http.StatusNotFound, <span class="hljs-string">"Not Found"</span>)
    }
    <span class="hljs-keyword">return</span> c.JSON(http.StatusOK, events)
}
</code></pre>
<p>The resulting database query, searching for “cool party” looks like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">id</span>, title, formatted_address <span class="hljs-keyword">FROM</span> <span class="hljs-string">"events"</span> <span class="hljs-keyword">WHERE</span> tags @&gt; <span class="hljs-string">'{cool,party}'</span> <span class="hljs-keyword">OR</span> title <span class="hljs-keyword">ILIKE</span> <span class="hljs-string">'%cool party%'</span>
</code></pre>
<p>A thing to note, is that I’m currently calling the search criteria for tags, and then deducting the title search criteria from that, changing commas to spaces. Since it’s both things we’re searching for, the query parameter should probably not be named tags.</p>
<h4 id="heading-improvements">Improvements</h4>
<p>Currently, searching for event title is not exactly efficient. If a user misspells a word or uses other derivatives of it (for example writing days instead of day), they would not get a hit on an event that would otherwise be a match. So we need a better search functionality for the title. But what about getting hits on some text in the description of the event? Maybe the person even wants to search for events on a specific address?<br />One potential solution is to add an extra column in the database that converts all relevant columns into a <code>tsvector</code> for full-text search. This brings a new set of complications though. The tags that I have implemented do not need to be searched for derivatives, making them unsuitable for <code>tsvector</code> search. Full text search also means that we have to think about settings weights on values in order to determine the most relevant matches and displaying them first.<br />An alternative I have been thinking about, is getting rid of the tags, and using categories for filtering instead, and combining it with full text search on all columns. If you have any input or suggestions I would love to hear from you in the comments.</p>
<h4 id="heading-final-thoughts">Final thoughts</h4>
<p>In this post, we explored how to query events using a combination of tags and event titles, leveraging GIN indexing and the less complicated <code>ILIKE</code> operator. We also discussed alternative approaches to enhance search functionality. If you find these problems interesting or want to learn more about full text search, I recommend checking out pganalyze’s article <a target="_blank" href="https://pganalyze.com/blog/gin-index">Understanding Postgres GIN Indexes</a>.<br />Another method to sort results by relevance is to consider the proximity of the event to the user. In my next post, I will discuss how to perform distance calculations directly in PostgreSQL.<br />You can access my code and review it in detail on my <a target="_blank" href="https://github.com/alexnorgaard/eventsapp">GitHub repo</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Building an Events Application: Kickstarting Development with Echo and GORM in Go]]></title><description><![CDATA[In my previous blog post “Choosing the right tools,” I decided to develop the events application using the Echo web framework for Golang and GORM for database querying. In this post, we will begin developing the API for the events application. But fi...]]></description><link>https://blog.alexnorgaard.dk/building-an-events-application-kickstarting-development-with-echo-and-gorm-in-go</link><guid isPermaLink="true">https://blog.alexnorgaard.dk/building-an-events-application-kickstarting-development-with-echo-and-gorm-in-go</guid><category><![CDATA[echo-web-framework]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[golang]]></category><category><![CDATA[Golang developer]]></category><category><![CDATA[Golang Web Framework]]></category><category><![CDATA[Echo framework]]></category><category><![CDATA[gorm]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[development]]></category><category><![CDATA[events]]></category><category><![CDATA[Application Development]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[APIs]]></category><dc:creator><![CDATA[Alexander Arlund Nørgaard]]></dc:creator><pubDate>Tue, 24 Sep 2024 14:32:17 GMT</pubDate><content:encoded><![CDATA[<p>In my previous blog post “Choosing the right tools,” I decided to develop the events application using the Echo web framework for Golang and GORM for database querying. In this post, we will begin developing the API for the events application. But first, let's quickly review some of my design choices.</p>
<h4 id="heading-the-model">The Model</h4>
<p>I want to expose a simple API that tracks events - public and private - as well as users and the events they have created and/or are attending. Simple as that. I do, however, want to start off by focusing on the events part, so let’s take a look at what I want an “event” to entail:</p>
<ul>
<li><p>Title</p>
</li>
<li><p>Description</p>
</li>
<li><p>A banner/image</p>
</li>
<li><p>Start datetime</p>
</li>
<li><p>End datetime</p>
</li>
<li><p>Address</p>
</li>
<li><p>Geolocation for distance calculation purposes</p>
</li>
</ul>
<p>Pretty simple.</p>
<p>We need to be able to hold a little more information about the event though.</p>
<ul>
<li><p>The event should have one or more owners</p>
</li>
<li><p>Users should be able to subscribe to an event - Both as attending and non-attending</p>
</li>
<li><p>For search and filtering purposes the owner of an event should be able to add tags</p>
</li>
<li><p>The owner should be able to make the event private, making it invisible to the public</p>
</li>
<li><p>The owner should be able to disable the event - effectively cancelling it</p>
</li>
</ul>
<p>With GORM you define a database table as a go struct. Representing the table would therefore look something like this:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> model

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"time"</span>

    <span class="hljs-string">"github.com/codingsince1985/geo-golang"</span>
    <span class="hljs-string">"github.com/lib/pq"</span>
)

<span class="hljs-keyword">type</span> Event <span class="hljs-keyword">struct</span> {
    Model
    Title            <span class="hljs-keyword">string</span>         <span class="hljs-string">`gorm:"not null;index:title_idx,type:GIN"`</span>
    Description      <span class="hljs-keyword">string</span>         <span class="hljs-string">`gorm:"default:NULL"`</span>
    Banner_url       <span class="hljs-keyword">string</span>         <span class="hljs-string">`gorm:"default:NULL"`</span>
    Owners           []User         <span class="hljs-string">`gorm:"many2many:event_owners"`</span>
    Is_private_event <span class="hljs-keyword">bool</span>           <span class="hljs-string">`gorm:"default:false"`</span>
    Time_start       time.Time      <span class="hljs-string">`gorm:"required"`</span>
    Time_end         time.Time      <span class="hljs-string">`gorm:"default:NULL;check:time_end &gt; time_start"`</span>
    Address          *geo.Address   <span class="hljs-string">`gorm:"embedded"`</span>
    Geolocation      *geo.Location  <span class="hljs-string">`gorm:"embedded"`</span>
    Tags             pq.StringArray <span class="hljs-string">`gorm:"type:text[];index:tags_idx,type:GIN"`</span>
    Is_enabled       <span class="hljs-keyword">bool</span>           <span class="hljs-string">`gorm:"default:true"`</span>
    Subscribers      []User         <span class="hljs-string">`gorm:"many2many:event_subscribers"`</span>
}
</code></pre>
<p>Notice the tags for each field in the struct, which start with "gorm:". GORM’s migrate functionality interprets these tags and applies them as constraints on the corresponding database columns when creating the table. This allows us to define a database table using just Go code. Pay attention to the Address and Geolocation fields, as well as the Tags field. The Address and Geolocation types refer to structs from the imported package geo-golang, a geocode package. The Address struct includes fields like "Street" and "HouseNumber", and by using the gorm tag "embedded", we instruct GORM to include all fields in the struct as individual columns in the database table. The Location struct contains fields for latitude and longitude.</p>
<p>One downside of using embedded structs is the inability to apply database constraints or other tags to individual fields, which can make them challenging to work with. In such cases, you might prefer to define the structs yourself instead of importing them from external packages.</p>
<p>The Tags field is a little different. I need to be able to hold several tags across several events and still be able to query them fast. I chose to use a StringArray with GIN indexing, a choice I will elaborate on in a future post about searching and filtering events and writing the appropriate queries.</p>
<p>The Subscribers field is defined as a many-to-many relation with the though-table being called “event_subscribers”. This is a simple solution, and I want to define my own table in the future, so it can hold information such as attending/not attending/maybe attending, and whether the user wants to receive updates about the event they subscribed to. For now, we will define it this way.</p>
<p>You might have noticed the Model field in the beginning of the <em>Event</em> struct. The struct is inheriting from the Model struct, which I have defined in a different file in the same package. The struct holds a unique ID for the row as well as some metadata. GORM has it’s own model struct which you would normally inherit, but it has it’s limitations and, as discussed earlier, I cannot use struct tags on those fields as it is a struct imported from an external package. The gorm.Model looks as such:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Model <span class="hljs-keyword">struct</span> {
    ID        <span class="hljs-keyword">uint</span> <span class="hljs-string">`gorm:"primarykey"`</span>
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt DeletedAt <span class="hljs-string">`gorm:"index"`</span>
}
</code></pre>
<p>I do not wish to use unsigned integers as the ID for the database tables, as UUID enables you to uniquely identifying any row in any table. It also makes it near impossible to guess an ID. Therefore I have defined my own base model:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> model

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"database/sql"</span>
    <span class="hljs-string">"time"</span>

    <span class="hljs-string">"github.com/google/uuid"</span>
)

<span class="hljs-keyword">type</span> Model <span class="hljs-keyword">struct</span> {
    ID        uuid.UUID    <span class="hljs-string">`gorm:"&lt;-:create;type:uuid;primary_key;default:uuid_generate_v4()" param:"id" validate:"omitempty,uuid4"`</span>
    CreatedAt time.Time    <span class="hljs-string">`gorm:"autoCreateTime:milli"`</span>
    UpdatedAt time.Time    <span class="hljs-string">`gorm:"autoUpdateTime:milli"`</span>
    DeletedAt sql.NullTime <span class="hljs-string">`gorm:"index"`</span>
}
</code></pre>
<p>Here I make sure a new row always has a UUID generated when first created, as well as other tags for validation and linking it to the request parameter “id”. I also made sure to explicitly define how I want time to be stored in the rows. Specifically in milliseconds. I am going to go into more detail about other struct tags than gorm in a later post.</p>
<h4 id="heading-creating-the-endpoints">Creating the endpoints</h4>
<p>Now let’s have a look at how to expose an api as simply as possible using Echo.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">//Connect to db and return a db object</span>
    db, err := dbmodule.Connect()
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-built_in">panic</span>(err)
    }
    <span class="hljs-comment">//Migrate the registered structs</span>
    dbmodule.Migrate(db)
    <span class="hljs-comment">//Create an instance of echo </span>
    e := echo.New()
    <span class="hljs-comment">//Define routing</span>
    v1 := e.Group(<span class="hljs-string">"/v1"</span>)
    event := v1.Group(<span class="hljs-string">"/event"</span>)
    event.POST(<span class="hljs-string">"/"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c echo.Context)</span> <span class="hljs-title">error</span></span> {
        <span class="hljs-comment">//Create event logic</span>
    })
    event.GET(<span class="hljs-string">"/"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c echo.Context)</span> <span class="hljs-title">error</span></span> {
        <span class="hljs-comment">//Get event logic</span>
    })
    event.GET(<span class="hljs-string">"/:id"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c echo.Context)</span> <span class="hljs-title">error</span></span> {
        <span class="hljs-comment">//Get event by id logic</span>
    })
    event.PUT(<span class="hljs-string">"/:id"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c echo.Context)</span> <span class="hljs-title">error</span></span> {
        <span class="hljs-comment">//Update event logic</span>
    })
    event.POST(<span class="hljs-string">"/:id/image"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c echo.Context)</span> <span class="hljs-title">error</span></span> {
        <span class="hljs-comment">//Upload image to event logic</span>
    })
    event.DELETE(<span class="hljs-string">"/:id"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c echo.Context)</span> <span class="hljs-title">error</span></span> {
        <span class="hljs-comment">//Delete event logic</span>
    })

    e.Logger.Fatal(e.Start(<span class="hljs-string">":1323"</span>))
}
</code></pre>
<p>When run, this should be enough to create an Echo server which listens on port 1323. I have boiled it down quite a bit from my actual implementation. As you can see this does not show how I handle the database connection nor the migration. I doesn’t show my implementation of each endpoint, and I register the routes differently. However, this should be enough to get the ball rolling.</p>
<h4 id="heading-final-thoughts">Final thoughts</h4>
<p>We have looked at how we can use Go structs with tags to represent tables with GORM. We have also had a brief look at how we can expose an api very quickly, using Echo framework. Some of the code shown above has been simplified to keep the initial definition of the system as simple as possible. For instance, the Event struct in my actual implementation includes more tags for validation and binding purposes. I have also implemented automatic TLS certification and request validation, among other features.<br />You can access my code and review it in detail on my <a target="_blank" href="https://github.com/alexnorgaard/eventsapp">GitHub repo</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Building an Events Application: Choosing the right tools]]></title><description><![CDATA[So much water has flowed under the bridge since my last blog post. Mind you that I have been working quite a lot on this project, I just didn't get around to write about it. So, let's pick up where we left off!
In my last post I talked about some of ...]]></description><link>https://blog.alexnorgaard.dk/building-an-events-application-choosing-the-right-tools</link><guid isPermaLink="true">https://blog.alexnorgaard.dk/building-an-events-application-choosing-the-right-tools</guid><category><![CDATA[golang]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[Golang web development]]></category><category><![CDATA[Echo framework]]></category><category><![CDATA[development]]></category><category><![CDATA[APIs]]></category><category><![CDATA[ORM (Object-Relational Mapping)]]></category><category><![CDATA[PostGIS]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[app development]]></category><dc:creator><![CDATA[Alexander Arlund Nørgaard]]></dc:creator><pubDate>Wed, 11 Sep 2024 10:59:44 GMT</pubDate><content:encoded><![CDATA[<p>So much water has flowed under the bridge since my last blog post. Mind you that I have been working quite a lot on this project, I just didn't get around to write about it. So, let's pick up where we left off!</p>
<p>In my last post I talked about some of the requirements of the application and the fact that I really wanted to try to build the server side in Golang. Some of the things that I had in mind was to see if there were any appropriate frameworks out there for making a simple REST API. I also wanted to find an ORM that was simple to use and mature enough that more complicated queries wouldn't be a problem. Simply because I am lazy, and don't want to write my queries in SQL.</p>
<h4 id="heading-the-framework">The framework</h4>
<p>Looking into the possible web frameworks for exposing a REST API I ended up looking primarily at Gin and Echo. Gin is a lightweight framework with focus on performance, and especially its HTTP router and error handling are intriguing. It also has a built in JSON validator. Echo, on the other hand, is even more minimalist than Gin, and while it does not have a built in JSON validator, they do recommend the same one used by Gin. The router is also based on <a target="_blank" href="http://en.wikipedia.org/wiki/Radix_tree">radix tree</a>, just like Gin's. What excites me the most about Echo though, is its built in ability to bind incoming request data to a struct, as well as the context-based request handling.<br />If you take a look at the documentation for each framework, you will find that the documentation for Gin is very sparse. They do have a large community around the framework, but that is not going to cut it for me. While Echo's documentation is far from as good as it can get, it is still a whole lot better that of Gin. Furthermore, from what I can read on various forums online, it seems like there is a little too much magic going on behind the curtains with Gin, which makes it really hard to understand what is going on under the hood. For all of these reasons I decided to give Echo a try.</p>
<h4 id="heading-the-orm">The ORM</h4>
<p>As I mentioned earlier I want to use an ORM for my database queries. There are a few different options out there, all of them with different approaches. The ones I looked into are SQLBoiler, GORM and ent.<br />Ent seems to be an ORM that focuses primarily on representing database schemas as graph structures, which is great if you want to expose an API with query languages such as GraphQL. This is not the approach I want to take. My focus will be on making a simple REST API for my application to use.<br />SQLBoiler is more interesting in my opinion. It takes a database-first approach, meaning that it generates code from the schemas in your database. This means that it can create optimised code that is specific to your database. However, this also means that each time you make a change to your database schemas, you have to regenerate the code. I do have a rough idea of the structure of the schemas, but I am in no way confident that they aren't going to change over time, and they might even change quite often.<br />GORM seems to me to be a much more traditional ORM, especially for someone coming from Django. It takes a code-first approach, meaning that you define your database schemas by defining them as structs. It seems to be relatively user friendly, and it has OK documentation and a large community behind it. It also allows you to write raw SQL, should the ORM fall short in some cases, and you can define column constraints with tags on the struct.</p>
<p>I ended up going with GORM, because it is easy to get started with the schema definition, and wanted something relatively close to what I already know. I also don't see myself needing to do any graph traversals in this project.<br />Working on the project, I have found the ORM to be a little difficult to work with, but it might also be a learning curve thing. I'll get more into this in a later post.</p>
<h4 id="heading-the-database">The database</h4>
<p>Looking at most of my needs and requirements, I could probably choose any old RDBMS. Especially because GORM has drivers for most of them. I do however have one very specific requirement.<br />When I defined the requirements in my previous blog post, I told you that the user should be able to find events near them. Defining what is nearby means knowing the location of the user, knowing the location of a given event (Both of them located in latitude and longitude), and calculating the distance between the two points.<br />We could choose to just store the latitude and longitude of an event in the database, query all events that match the search criteria made by the user, make the distance calculations in Go, sort the events by distance and discard the ones that are too far away, or limit by an arbitrary number. To me this seems like a waste of resources, and I would much rather that the database could make the distance calculations and return a result that has already been filtered and ordered, ready to return to the user.</p>
<p>So how do I get a database to make these calculations? I looked into possible solutions and other people who had the same problem and came across PostGIS. PostGIS is an extension for PostgreSQL that allows you to store, index and query geospatial data. I looked a little further at the documentation, and it turns out that making the calculations directly in the query is relatively straight forward. BINGO!<br />Because of this, my choice naturally fell on using PostgreSQL as my RDBMS for the project.</p>
<h4 id="heading-final-thoughts">Final thoughts</h4>
<p>Looking into the feasibility of using Go for my REST API, we have explored different options for frameworks, ORMs and RDBMS's. I chose to go with Echo web framework, GORM and PostgreSQL. I have since I made my choices been completely submerged in learning these new technologies, and coding away. I had forgotten just how much fun it is to build something from scratch. The process has also made me realise just how complete a framework Django is. It really does come with batteries included!<br />In the coming blog posts I'm going to write about my initial thoughts of programming in Go, show you some of the code I've written so far, and talk about the challenges and intricacies of the technologies I've decided to work with. Strap in, it's going to be a hell of a ride!</p>
]]></content:encoded></item><item><title><![CDATA[Building an Events Application: Requirements and discussion of choice of technologies]]></title><description><![CDATA[Right! In my previous post I talked about my project of creating an events application as an alternative to facebook events. In this article we will discuss user- and performance requirements, and talk briefly about possible technologies to use for t...]]></description><link>https://blog.alexnorgaard.dk/building-an-events-application-requirements-and-discussion-of-choice-of-technologies</link><guid isPermaLink="true">https://blog.alexnorgaard.dk/building-an-events-application-requirements-and-discussion-of-choice-of-technologies</guid><category><![CDATA[Programming Blogs]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[app development]]></category><category><![CDATA[Application Development]]></category><dc:creator><![CDATA[Alexander Arlund Nørgaard]]></dc:creator><pubDate>Thu, 11 Jul 2024 11:41:40 GMT</pubDate><content:encoded><![CDATA[<p>Right! In my previous post I talked about my project of creating an events application as an alternative to facebook events. In this article we will discuss user- and performance requirements, and talk briefly about possible technologies to use for the project. So what do I actually want to the application to do and not do? Time to get down to brass tacks here.</p>
<p>The events application should be able to:</p>
<ul>
<li><strong>Have users using SSO (Single Sign On)</strong></li>
</ul>
<ul>
<li><p><strong>Create new public events</strong>:</p>
<ul>
<li><p>Have an event title</p>
</li>
<li><p>A text description of the event in question</p>
</li>
<li><p>Include photos for banner <s>as well as in the description</s> (upload)</p>
<ul>
<li>The photos in the description on top of the ability to have one as a banner opens up for customisability of the event page, which for now I am going to limit in the interest of time-saving. The event page should have text fields for headline and body.</li>
</ul>
</li>
<li><p>Hold a time range for the event</p>
</li>
<li><p>Hold an address/geolocation</p>
</li>
<li><p>Have one or more owners of an event</p>
</li>
<li><p>Add tags to event</p>
</li>
<li><p>Make event private (Not shown on search)</p>
</li>
</ul>
</li>
<li><p><strong>Interact with events:</strong></p>
<ul>
<li><p>Subscription to events (push-messages for event updates, cancellation, etc.)</p>
</li>
<li><p>Add attendance to event (Automatic subscription)</p>
</li>
<li><p>Add event to your phones calendar</p>
<ul>
<li>Make change to calendar in case of changes to time or location or in case of cancellation (Push message with prompt to change)</li>
</ul>
</li>
<li><p>Suggest changes to event if user is not the owner</p>
</li>
<li><p>Share the event with other people via link (Also the way to invite people to private events)</p>
</li>
<li><p>Show event on a map (potentially opened in google maps)</p>
</li>
<li><p>Add comments to events (Future editions)</p>
</li>
</ul>
</li>
<li><p><strong>Find events:</strong></p>
<ul>
<li><p>Search for events</p>
</li>
<li><p>Filter events using tags</p>
</li>
<li><p>Filter events using time (Think "events today")</p>
</li>
<li><p>Filter events using geolocation</p>
<ul>
<li>Adjust maximum distance</li>
</ul>
</li>
<li><p>Show events near the user on list (using filters if any)</p>
</li>
<li><p>Show events near the user with pins on a map (using filters if any)</p>
</li>
<li><p>Favorite an event (With potential subscription)</p>
</li>
</ul>
</li>
</ul>
<p>Now for the sake of granulation, and nut cluttering the minimum viable product (MVP) I am going to cut out SSO and the features it enables, and save it for the next iteration of the app. This means that attendance and favorite events will not be in the MVP as well as event ownership. However, I still want to pick a framework for developing the api which have dedicated libraries for easy implementation of SSO.</p>
<h2 id="heading-system-requirements">System requirements</h2>
<p>Now that we have looked into the user requirements, let's have a look into what this means for the requirements of the system. As I have previously stated in my initial blog post, I want to make a phone and web application that interacts with the backend through an API. Therefore I am going to split the requirements into server side requirements and client side requirements.</p>
<h3 id="heading-server-side-requirements">Server side requirements</h3>
<p>So what do these user requirements tell us about the requirements of the server side application?<br />There are a few things we can reasonably deduct:</p>
<ul>
<li><p>The application is primarily a simple CRUD application, and there will not be large amounts of heavy computing involved</p>
</li>
<li><p>There will be more people looking for events in their vicinity than people creating these events, which means that there is going to be considerably more reads to the database than writes</p>
</li>
<li><p>Events will be filtered and found using geolocation, timestamps as well as tags. This means that we will have to use a data-model that can store and <strong>effectively</strong> search in such datatypes. Especially geospatial search could prove to be a bit tricky.</p>
</li>
<li><p>The system should be able to store and easily look up high resolution images for rendering on the events</p>
</li>
</ul>
<h3 id="heading-client-side-requirements">Client side requirements</h3>
<p>The client should:</p>
<ul>
<li><p>Be able access the users geolocation</p>
</li>
<li><p>Have easy access to use of maps - Preferably google maps, as this is what most users customarily use and thus has the interface they know the best.</p>
</li>
<li><p>Be able to push messages to the user</p>
</li>
<li><p>Have the ability to make changes to said event in users phone, if granted access</p>
</li>
</ul>
<h3 id="heading-performance-requirements">Performance requirements</h3>
<p>Taking into consideration that this project is chiefly aimed at smartphone users, we can make some general requirements that boil down to user experience:  </p>
<ul>
<li>It should not take more than two seconds from searching/filtering events until a result is displayed on the client application</li>
</ul>
<p>When it comes down to the server side application, we can be relatively lax as this is a hobby project, which is more about learning new technologies and honing my skills, than it is about amassing a huge user base. However, if the project should for some reason become popular, it would be prudent to design the system with scalability in mind. For now, let's stick to some simple and not overly ambitious requirements:</p>
<ul>
<li><p>The system should be able to handle that api requests are replied to within two seconds, for up to 100 requests per second. Let's say that this should be the case for the 95th percentile of all requests.</p>
</li>
<li><p>A maximum of 2000 simultaneous sessions at a time.</p>
</li>
<li><p>Zero downtime is not necessary. For now, new features can be introduced at night time, although error handling should be handled with a type of middleware. Error handling and response to end user on failure is a whole beast on its own, which should definitely be touched upon later in the process.</p>
</li>
</ul>
<p>Have I forgotten anything when writing down the requirements for the project? Definitely! For now we are going to head on to the next thing, but I will revisit the requirements in a later blog post or cheat a little and add the requirements in this post as they appear 😉</p>
<h2 id="heading-choosing-the-technologies"><strong>Choosing the technologies</strong></h2>
<p>It's time for the difficult part. Actually picking which programming languages and technologies to use! As I mentioned in my previous blog post I am looking to learn new languages and technologies, and maybe brushing up on things that I have previously worked with. But I have been working with the python framework Django the past three years, and the more I think about what the application should be capable of, the more I think that Django is a great choice for the backend part of the project. It has a great framework for quickly exposing an API called django REST framework, it has built in user management, a really well made ORM, and an API for modelling with geospatial data! It also has a great template language for the frontend part based on Jinja2 called Templates, if one wants to use it for that part as well. Did I mention that it comes with built in admin site that can be customised and used as a backoffice?<br />But no, damnit! I am only doing this project not just to show my capabilities and my thought process, but to learn something new as well. A language that I have been wanting to try out for a while is Golang. So does it even make sense to make the server side part using Go? In my next post we're going to have a look at how feasible this actually is. I'm not going to go into details about Go as a language, but rather if there are any frameworks and libraries that can help me build the application so I can prevent having to build everything from scratch, thus completely exploding the scope of this project.</p>
]]></content:encoded></item><item><title><![CDATA[Starting Out: Building an Events Application]]></title><description><![CDATA[The motivation
I have long been pissed at facebook. Partly because it keeps people, including myself, in an infinite death scroll whenever they decide to open the app. But primarily my problem with facebook is that it still have a few features which ...]]></description><link>https://blog.alexnorgaard.dk/starting-out-building-an-events-application</link><guid isPermaLink="true">https://blog.alexnorgaard.dk/starting-out-building-an-events-application</guid><category><![CDATA[development]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Alexander Arlund Nørgaard]]></dc:creator><pubDate>Tue, 28 May 2024 13:17:31 GMT</pubDate><content:encoded><![CDATA[<h3 id="heading-the-motivation">The motivation</h3>
<p>I have long been pissed at facebook. Partly because it keeps people, including myself, in an infinite death scroll whenever they decide to open the app. But primarily my problem with facebook is that it still have a few features which no one have managed to do better, or at least have not been successful in poaching the users to their proprietary platform. This in turn forces people, such as myself, to stick with facebook even though they don't particularly enjoy using the platform. I am talking about groups and events. Now, I am aware that there are alternatives out there - <a target="_blank" href="http://groups.io">groups.io</a> and eventbrite are good examples. However, I want to start a project to challenge myself to learn languages and technologies I have either not used before, or just want to get more practice using, and I am bringing you along for the ride!</p>
<h3 id="heading-the-concept">The concept</h3>
<p>I want to build an application for events. This is not supposed to be an app for companies and people who want to manage their events, but rather an app for finding public events near the user and creating private events for friends and family.<br />The purpose is to make it as easy and simple as possible to find, filter and plan attendance to any event in your vicinity, or even plan ahead when travelling.</p>
<h3 id="heading-choosing-the-technologies">Choosing the technologies</h3>
<p>Hey, that sounds really cool, Alexander! What technologies are you going to use for your application? I'm really glad you asked! The answer is that we're about to find out together. To make it easier to select the appropriate technologies, first we should look at some general requirements and scope of the project, which will be the extend of this article. Once we have a better understanding of the extend of the project we will define the business and user requirements. When we have these we can deduct what is required of the system, choose our technologies and create the appropriate system design. Let's get into it.</p>
<h4 id="heading-scope">Scope</h4>
<p>The project is limited by the fact that I am only one person working on the project, and the focus is to build something that is realistically finished. Therefore it is important to limit the features and complexity of the system. I still want this application to work across both iOS, android and as a web application. Therefore it could be beneficial to choose a cross-platform technology for the UI part of the application. If not, the application should be easily portable into other platforms. Realistically, most people would get the greatest benefit from using their smartphones for the functionality of the app, so this should be prioritised.</p>
<p>For server-side, I want to make an exposed api which can handle users, and create, read, update and delete events (CRUD), including geotagging, tags and other meta data about events. The server-side should be kept simple with as low complexity as possible. It should also be hosted on a suitable cloud service because I don't want to deal with the hassle and unreliability of having a server rack in my closet.</p>
<p>There are many frameworks out there intended for getting started easy with your api, all of which include varying amounts of of boilerplate code. In order to choose the right framework, we need to consider our needs and requirements, such as performance, built-in features and third party libraries, documentation and support. Keep in mind that, as I have mentioned, I am going to choose frameworks and technologies/languages that I have not used before or want more experience with.</p>
<h4 id="heading-ui">UI</h4>
<p>The UI technology used should either be easy to port to iOS and android, be cross-platform by nature, or be a hybrid web app, as most people would have most use of it on their phone (Think of finding an exhibition "near you"). I am not going to develop a native application for iOS and one for Android because of time and resource constraints.</p>
<p>The UI will be a simple search/filter page for finding events near the user, and should integrate a map for plotting the events, and making the overview better for the user.</p>
]]></content:encoded></item></channel></rss>