<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>sglavoie.com – Tag: BSc</title><link>https://www.sglavoie.com/tags/bsc/</link><description>Posts and writings by Sébastien Lavoie. Customization setups and articles on productivity for developers who like minimalism.</description><language>en</language><atom:link href="https://www.sglavoie.com/tags/bsc/feed.xml" rel="self" type="application/rss+xml"/><lastBuildDate>Sun, 30 Jul 2023 18:44:00 -0600</lastBuildDate><item><title>Building a task planner with React Native: an academic journey</title><link>https://www.sglavoie.com/posts/building-task-planner-react-native/</link><description>After having built a somewhat original habit tracker, I was keen on coming up with a solution to a much more common problem: task management. This is the story of how I built a task planner with React Native, explored from an academic perspective first and foremost.</description><content:encoded>&lt;hr&gt;
&lt;h2 id="preamble"&gt;Preamble&lt;/h2&gt;
&lt;p&gt;For my last assignment in a &lt;a href="https://www.london.ac.uk/courses/computer-science"&gt;BSc in Computer Science at the University of London&lt;/a&gt;, I decided to get involved in the world of task management to tackle one of the most common challenges usually offered to programmers, but with a twist based on scientific evidence. The result ended up being a cross-platform mobile application built with React Native, named ProductiviDo. Due to intellectual property concerns, I will not be able to share the source code of the application, but I hope you will nonetheless find joy in reading about the process of building it through the lens of the report I submitted for the assignment. For a complete list of references and appendices in context, please refer to &lt;a href="https://www.sglavoie.com/files/posts/0039_productivido/productivido.pdf"&gt;the original report&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0039_productivido/app_icon.png"
 alt="App icon ProductiviDo"
 loading="lazy"
 decoding="async" width="1280" height="720"/&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-introduction"&gt;1 Introduction&lt;/h2&gt;
&lt;p&gt;The world needs a new kind of task manager, just like &lt;strong&gt;ProductiviDo&lt;/strong&gt;, which comes to life through the &amp;ldquo;&lt;em&gt;task manager mobile app&lt;/em&gt;&amp;rdquo; template provided for the Mobile Development module taught at Goldsmiths, University of London.&lt;/p&gt;
&lt;h2 id="11-inspiration-the-main-contenders"&gt;1.1 Inspiration: the main contenders&lt;/h2&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/inspiration.png"&gt;
 &lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/inspiration.png" alt="Overview of the main task-management apps that inspired ProductiviDo" class="max-size-img-post" width="3377" height="1202" loading="lazy" decoding="async"&gt;
 &lt;/a&gt;
 &lt;figcaption&gt;Inspiration.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;There are a few wonderful products that deliver a good experience. Desirable features range from filters, labels and reminders to custom views and breadcrumbs. With &lt;strong&gt;Todoist&lt;/strong&gt;, tasks can be quickly captured and will be added to an &amp;ldquo;&lt;em&gt;Inbox&lt;/em&gt;&amp;rdquo; section. Once categorized, tasks are organized into projects, sections and sub-tasks.&lt;/p&gt;
&lt;p&gt;Although &lt;strong&gt;Todoist&lt;/strong&gt; recently added a board view, &lt;strong&gt;ClickUp&lt;/strong&gt; takes it to the next level by labelling columns. In &lt;strong&gt;ClickUp&lt;/strong&gt;, tasks are organized into multiple levels of hierarchies, down to task dependency, where sub-tasks depend on parent tasks.&lt;/p&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/clickup-overview.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/clickup-overview.png" alt="clickup overview" class="max-size-img-post"&gt;&lt;/a&gt;
 &lt;figcaption&gt;ClickUp overview.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Trello&lt;/strong&gt; takes an entirely different approach, where planning happens by moving cards onto different columns horizontally and re-ordering them vertically. Even though it has a concept of workspaces which is a group of boards, all the organization of a project usually takes place within a single board which contains multiple columns, each containing multiple cards.&lt;/p&gt;
&lt;p&gt;Planning in &lt;strong&gt;Airtable&lt;/strong&gt; is much more freestyle with a spreadsheet-like system. There is a Gantt view in the paid plan to visualize tasks over time. Using &lt;strong&gt;Airtable&lt;/strong&gt; feels like interacting directly with a SQL database with its heavily grid-focused appearance.&lt;/p&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/airtable-project.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/airtable-project.png" alt="airtable project" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Airtable project.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Finally, &lt;strong&gt;Asana&lt;/strong&gt; shines mostly within a team setting and mainly works with the core concept of projects, which themselves can contain tasks, sub-tasks and even sub-projects.&lt;/p&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/asana-calendar.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/asana-calendar.png" alt="asana calendar" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Asana calendar.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="12-drawbacks-of-existing-solutions"&gt;1.2 Drawbacks of existing solutions&lt;/h2&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/drawbacks.png"&gt;
 &lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/drawbacks.png" alt="Comparison chart summarizing the main drawbacks of competing task-management apps" class="max-size-img-post" width="3377" height="1202" loading="lazy" decoding="async"&gt;
 &lt;/a&gt;
 &lt;figcaption&gt;Drawbacks.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;There are usability issues across all these mobile apps (and others) for different reasons. Most popular task managers have a limited search functionality, making it hard to find what one needs quickly unless a good organizational system has been consciously put in place beforehand. Crucially, such applications do not address the fact that unimportant tasks accumulate over time and provide no system to focus on what matters to avoid the fate of having &amp;ldquo;&lt;em&gt;41% of to-do items [&amp;hellip;] never completed&lt;/em&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;A second point worth mentioning is that a calendar integration is not a core feature deeply integrated into these apps. For instance, &lt;strong&gt;Todoist&lt;/strong&gt; offers a 2-way sync with Google Calendar, but tags, labels, priorities and areas of responsibilities are not shown nor taken into account in the calendar. Some task managers will provide their own built-in set of calendar features that partially solve the problem of being able to navigate a complete schedule in a breeze. However, none of these applications really allow efficient scheduling within the calendar. Some allow the user to add or modify events in the calendar, but this remains a slow process working with reduced functionality.&lt;/p&gt;
&lt;p&gt;With regards to organization, all these applications are well-suited to manage tasks but when it comes to &amp;ldquo;&lt;em&gt;time boxing&lt;/em&gt;&amp;rdquo; or &amp;ldquo;&lt;em&gt;time blocking&lt;/em&gt;&amp;rdquo;, they will show every single task in the calendar view. This is impractical at scale as it quickly becomes overwhelming with dense information, a setup encouraging fragmented work and multitasking. Fragmented work caused by context switching has been shown to have a negative impact on productivity and on output quality while multitasking will lead to &amp;ldquo;&lt;em&gt;experiencing more stress, higher frustration, time pressure and effort&lt;/em&gt;&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="13-market-overview"&gt;1.3 Market overview&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;ProductiviDo&lt;/strong&gt; will target in its first iteration Google Calendar because this product can be consumed from a plethora of desktop and mobile applications and there are about 4.3 billion Google users. Once data is integrated into Google Calendar, it can be consumed by different applications such as Apple Calendar, Zoom, Slack or other Google products, including Google Docs.&lt;/p&gt;
&lt;p&gt;The number of smartphone users will increase by almost 23% over the next 5 years, forecasting more than a doubling over a 10-year period (2016–2026). Task management software is going upwards of USD$5 billion in market size, the CAGR —&lt;em&gt;compound annual growth rate&lt;/em&gt;— is hovering around 14% and continuously growing. Combining supply and demand, we can see that both are expected to increase drastically over the coming years and that task managers fall into a category of growth market, which is desirable as it clearly indicates there is room for new rivals in the field: this is distinctly the case given that the task management world is still dominated by a few big players, many products have retired over the years (which unsaturates the market) and considering that &lt;strong&gt;ProductiviDo&lt;/strong&gt; solves a real problem —that of staying on top of a growing list of commitments— with an innovative solution not yet implemented elsewhere.&lt;/p&gt;
&lt;h2 id="14-motivation"&gt;1.4 Motivation&lt;/h2&gt;
&lt;p&gt;One reason why &lt;strong&gt;ProductiviDo&lt;/strong&gt; will shine is because calendars are still under-appreciated in existing task managers, yet all major task manager applications integrate them in one way or another. It has been shown through many studies that calendars save time, improve productivity, reduce stress and make it simpler to batch similar activities. Plus, they can be consumed in a myriad of ways with their Application Programming Interfaces (APIs). The problem with using only a calendar without a task manager is that they are inconvenient when dealing with many events or tasks. On the other hand, relying only on task managers makes it difficult to appreciate how useful calendars are when it comes to visualizing one&amp;rsquo;s schedule from different perspectives such as a weekly or monthly view. Regarding &lt;strong&gt;ProductiviDo&lt;/strong&gt; as a task manager and not only a calendar integration, it will distinguish itself by allowing users to quickly and efficiently record their routine activities. This is because it has been shown that these occupy a good amount of time even for productive people and there is currently no application that really implements a direct solution to this.&lt;/p&gt;
&lt;p&gt;Intelligent prioritization is essential, yet difficult to achieve with existing products. Beyond capturing tasks and categorizing them, this application will feature a prioritization system that will help users focus on their most high-leverage activities with the help of custom sorting algorithms as advocated by Edmond Lau in his book &lt;em&gt;The Effective Engineer&lt;/em&gt;. These will take into consideration aspects such as urgency and importance — in the spirit of the Eisenhower Matrix — as well as deadlines to calculate the impact that completing a task will have. Importantly, the priority matrix is adapted to account for other needed facets, such as when other people are involved in the task dependency chain (delegatees), an adaptation of the &amp;ldquo;&lt;em&gt;fit&lt;/em&gt;&amp;rdquo; variable from the Sung Diagram, which is an extension of the Eisenhower Matrix.&lt;/p&gt;
&lt;p&gt;The application will benefit users by providing a built-in planning system that will make it easier to follow a successful schedule. This goes hand in hand with findings illustrating how, in the absence of a mindful review process, users will want to focus on small or unimportant tasks to release dopamine even though they know what would bring them the best outcomes, a real productivity threat leading to a decrease in output and an increase in completion time. Therefore, by offering a system that will encourage users to take better decisions and visualize evidently their highest-leverage tasks in a familiar and useful fashion, &lt;strong&gt;ProductiviDo&lt;/strong&gt; will carve its place in the market by solving unmet needs.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="2-literature-review"&gt;2 Literature review&lt;/h2&gt;
&lt;h2 id="21-previous-work"&gt;2.1 Previous work&lt;/h2&gt;
&lt;p&gt;As alluded to in section 1.1, the current work found inspiration in well-established task management software. There are numerous alternatives available on the market: only the most well-known and relevant ones for this project will be covered. Evaluating such products in depth goes beyond the scope of this report: key points will be highlighted to justify the need for a new solution.&lt;/p&gt;
&lt;h2 id="211-todoist"&gt;2.1.1 Todoist&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Todoist&lt;/strong&gt; is one of the most popular task management software, with over 20 million users. It is a web-based application that allows users to create tasks, organize them into projects, and assign them to specific dates. It also features a priority system that allows users to sort tasks by importance, and a reminder system that will notify users of upcoming tasks. While &lt;strong&gt;Todoist&lt;/strong&gt; is a very popular solution, it has some shortcomings. Its design is arguably polished, yet its dark theme lacks contrast, recurring tasks don&amp;rsquo;t show immediately on which schedule they recur and tasks with comments or attachments are difficult to locate. Other functional deficiencies include the fact that the &amp;ldquo;Upcoming&amp;rdquo; view shows all tasks from all projects as a large, single list of items without allowing filtering or that the app has a concept of &amp;ldquo;due date&amp;rdquo; with no &amp;ldquo;start date&amp;rdquo; such that duration is not taken into account nor can be visually represented meaningfully in a calendar. Equally relevant when comparing to what &lt;strong&gt;ProductiviDo&lt;/strong&gt; will offer is the fact that there is no way to apply &amp;ldquo;time boxing&amp;rdquo; as there is no calendar view and only a functionally limited Google Calendar integration, task filtering is not intuitive due to the custom query language syntax used by the app and there is no easy way to find recurring or routine tasks without setting up a custom labelling system on one&amp;rsquo;s own.&lt;/p&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/todoist-upcoming-view.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/todoist-upcoming-view.png" alt="todoist upcoming view" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Todoist upcoming view.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="212-trello"&gt;2.1.2 Trello&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Trello&lt;/strong&gt; lies on the other end of the feature creep spectrum when compared to &lt;strong&gt;ClickUp&lt;/strong&gt; and can be seen as possessing an even more basic set of capabilities than &lt;strong&gt;Todoist&lt;/strong&gt;. With its simple and uncluttered drag &amp;amp; drop interface, &lt;strong&gt;Trello&lt;/strong&gt; is much more intuitive than a more sophisticated and flexible option such as &lt;code&gt;Todo.txt&lt;/code&gt; which can be technically extended at will and can be operated from the command-line on a desktop computer or from a multitude of third-party applications on mobile devices. &lt;strong&gt;Trello&lt;/strong&gt;&amp;rsquo;s simplicity comes at a cost, however: it is not uncommon to lose track of &amp;ldquo;cards&amp;rdquo; because one must swipe horizontally in order to navigate the UI; and very little information fits on the screen at once, where only a fraction of a &amp;ldquo;board&amp;rdquo; with up to a few &amp;ldquo;cards&amp;rdquo; is shown. There is a copious amount of calendar integrations available for &lt;strong&gt;Trello&lt;/strong&gt;, yet the core of the issue that &lt;strong&gt;ProductiviDo&lt;/strong&gt; aims to address remains unsolved: the app&amp;rsquo;s metadata is not accessible from Google Calendar (e.g., priority, area of work, task status, etc.) and the app does not provide a way to visualize the user&amp;rsquo;s tasks in a convenient calendar view as it only &amp;ldquo;&lt;em&gt;displays all cards with due dates by month&lt;/em&gt;&amp;rdquo; and only when using one of its paid feature, called &amp;ldquo;Power Ups&amp;rdquo;.&lt;/p&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/trello-boards.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/trello-boards.png" alt="trello boards" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Trello boards.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="22-contributions-from-the-literature-and-gaps-being-filled"&gt;2.2 Contributions from the literature and gaps being filled&lt;/h2&gt;
&lt;h3 id="221-initial-design-justifications"&gt;2.2.1 Initial design justifications&lt;/h3&gt;
&lt;p&gt;Amongst a panoply of scientific papers on the subject of task management, the quintessential work of Bellotti et al. serves as an excellent entrypoint listing a set of design requirements to be expected in an efficiently conceived task manager. Of particular relevance to the creation of &lt;strong&gt;ProductiviDo&lt;/strong&gt; are the needs for the app to be &amp;ldquo;&lt;em&gt;instantly on&lt;/em&gt;&amp;rdquo; with the option to have &amp;ldquo;&lt;em&gt;no formal task description&lt;/em&gt;&amp;rdquo; and a &amp;ldquo;&lt;em&gt;mechanism for handling stale to-dos of low importance&lt;/em&gt;&amp;rdquo;. The authors highlight that the main issue is &amp;ldquo;&lt;em&gt;making sure that the important tasks get done&lt;/em&gt;&amp;rdquo;, which led to further research being exposed on the topic of prioritization matrices. The authors also advocate for task states, location, social relations, notes and time constraints to be captured, all of which are taken into account in the design. In a more recent study looking at the importance of prioritizing tasks, further evidence suggested that a prioritization model should be adopted (e.g., HI/LO, CARVER or Carpenter) in a task management system, pointing at the Eisenhower Matrix as a useful framework to use for this very purpose. Other less formal alternatives such as the RICE or ICE frameworks have also been reported to be used with success and could be adapted to this project with their scoring model.&lt;/p&gt;
&lt;p&gt;Another aspect which served to inform the overall direction to take is the well-known fact that humans do not work optimally when multi-tasking as this leads to a high cognitive load in keeping track of different areas of focus or projects. Fragmentation of information in one&amp;rsquo;s work —which occurs when multitasking— is a problem because people won&amp;rsquo;t remember where to find the information. Applying this idea of fragmentation to the digital world, it only makes sense that offering too many ways to store and retrieve data (such as with &lt;strong&gt;ClickUp&lt;/strong&gt;) is counterproductive. Furthermore, the ability to customize the UI is a double-edged sword because &amp;ldquo;&lt;em&gt;users make mistakes and create building blocks with unintended consequences&lt;/em&gt;&amp;rdquo;. Indeed, if the user interface is cluttered or offers too many bells and whistles, managing the global context of one&amp;rsquo;s tasks becomes difficult and one inevitably encounters obstacles when trying to juggle with multiple actions at once, because &amp;ldquo;&lt;em&gt;prospective memory is fallible&lt;/em&gt;&amp;rdquo;. Hence, simplicity is key to a good task manager (which certainly helps to explain &lt;strong&gt;Todoist&lt;/strong&gt;&amp;rsquo;s wild success). While simplification is part of the gamified model —Habitica being one example of a product incorporating many elements of gamification— this model suffers from the &amp;ldquo;&lt;em&gt;undifferentiated use of rewards&lt;/em&gt;&amp;rdquo;, leads to &amp;ldquo;&lt;em&gt;punishments for productivity&lt;/em&gt;&amp;rdquo;, to &amp;ldquo;&lt;em&gt;feeling of not being taken seriously&lt;/em&gt;&amp;rdquo; and cause &amp;ldquo;&lt;em&gt;negative anticipation&lt;/em&gt;&amp;rdquo;. Moreover, &amp;ldquo;&lt;em&gt;people found their standard task manager simpler to use&lt;/em&gt;&amp;rdquo; and the integration of extrinsic motivational factors such as a reward system &amp;ldquo;&lt;em&gt;would not excite them to continue being immersed in a gamification application&lt;/em&gt;&amp;rdquo;. While this form of motivation does not appear to be effective in goal attainment, the literature concludes that &amp;ldquo;&lt;em&gt;valuing extrinsic goals [&amp;hellip;] does not seem to increase our happiness, but attaining those goals does&lt;/em&gt;&amp;rdquo;, adding that giving weight to intrinsic goals (such as personal growth, loving relationships and physical health) and achieving them is a better way to increase happiness. As long as a task manager nourishes intrinsic motivation, it is likely to be effective in helping people to achieve their goals while maintaining optimal psychological health.&lt;/p&gt;
&lt;p&gt;Other approaches were considered, notably the &amp;ldquo;&lt;em&gt;Binary Priority List&lt;/em&gt;&amp;rdquo; due to its simplicity when it comes to comparing two elements (such as tasks). However, it lacks flexibility and becomes inefficient as more and more tasks are added because —unlike the famous binary search algorithm— this algorithm requires human intervention to classify tasks, which becomes burdensome faster than &lt;code&gt;O(log n)&lt;/code&gt;. The literature on gamification also linked to sources that revealed solutions to solving procrastination, a self-regulation failure that gamified systems sought to minimize to no avail, which led to identifying a desirable core component of the application: implementation intentions. These can be integrated into the &amp;ldquo;mental flexibility&amp;rdquo; facet of &amp;ldquo;planfulness&amp;rdquo; —through a technique known as &amp;ldquo;mental contrasting with implementation intentions&amp;rdquo; (MCII)— along with temporal orientation and cognitive strategies, all of which improve goal outcomes.&lt;/p&gt;
&lt;h3 id="222-implementation-intentions"&gt;2.2.2 Implementation intentions&lt;/h3&gt;
&lt;p&gt;Implementation intentions have shown their effectiveness in helping people to achieve their goals, the real purpose behind using task managers in the first place. The idea is to create a plan of action for a specific goal, which is then followed by a specific time and place. The plan must be broken down into a series of steps, which are written down in a way that is easy to remember using so-called &amp;ldquo;if–then plans&amp;rdquo;. The specific formulation of such plans &amp;ldquo;&lt;em&gt;produce much more favorable and reliable outcomes than broad intentions to pursue a goal&lt;/em&gt;&amp;rdquo;. Findings from Bieleke et al. show that implementation intentions are also useful when planning one&amp;rsquo;s work because they help &amp;ldquo;&lt;em&gt;evaluate information from a certain perspective&lt;/em&gt;&amp;rdquo; —which can be verbally recommended to users so they adopt a &amp;ldquo;&lt;em&gt;certain processing style (e.g., deliberative thought) or perspective (e.g., neutral observer)&lt;/em&gt;&amp;rdquo;. Their research also highlight the high potential of implementation intentions in reviewing tasks because &amp;ldquo;&lt;em&gt;participants can strategically adopt a reflective mode of information processing that helps them make more sophisticated decisions when facing uncertainty&lt;/em&gt;&amp;rdquo;. Other studies show that such &amp;ldquo;&lt;em&gt;plans to deliberate can be used to increase the likelihood of deliberation and thereby the effective processing of newly available information&lt;/em&gt;&amp;rdquo;, which further supports the benefits of implementation intentions with regards to planning. To make the planning stage more effective, research also &amp;ldquo;&lt;em&gt;indicates that having plans that focus on overcoming obstacles are important for maintaining progress and staying on track with one&amp;rsquo;s goals&lt;/em&gt;&amp;rdquo;, so this aspect will also be featured when creating tasks in the &lt;strong&gt;&amp;ldquo;Inscribe&amp;rdquo;&lt;/strong&gt; step described in section 2.3.1. Once planning has been done, implementation intentions will also prove useful to take action towards accomplishing one&amp;rsquo;s goals because they lead to &amp;ldquo;&lt;em&gt;automatic action initiation without further conscious intent&lt;/em&gt;&amp;rdquo; —surprisingly and encouragingly, even in participants suffering from mild to moderate depression. While this is obviously beneficial during the initial stages of a project or task to overcome procrastination, it is equally important to re-evaluate one&amp;rsquo;s course of action because sticking to a plan stubbornly &amp;ldquo;&lt;em&gt;can hinder overall goal performance by causing one to overlook alternative opportunities for achievement&lt;/em&gt;&amp;rdquo;, amongst other negative consequences. This explains why &lt;strong&gt;ProductiviDo&lt;/strong&gt; encompasses a &lt;strong&gt;&amp;ldquo;Review&amp;rdquo;&lt;/strong&gt; step which deals with this particular problem and more, described in section 2.3.4.&lt;/p&gt;
&lt;p&gt;While this self-regulation technique can be applied successfully in the context of a task manager, it bears mentioning that it is not a panacea as it suffers from some limitations, one of which being that &amp;ldquo;&lt;em&gt;formulating multiple implementation intentions is ineffective when changing unwanted behavior [&amp;hellip;] due to interference in the enacting phase of the planning process&lt;/em&gt;&amp;rdquo;. In other words, multiple implementation intentions can compete for attention, which makes one lose focus. To drastically mitigate this issue, &lt;strong&gt;ProductiviDo&lt;/strong&gt; dedicates an entire step to &lt;strong&gt;&amp;ldquo;Focus&amp;rdquo;&lt;/strong&gt;, which is described in more detail in section 2.3.3. The &lt;strong&gt;&amp;ldquo;Review&amp;rdquo;&lt;/strong&gt; step will help with reducing the number of tasks one has to juggle with while there will be a &lt;strong&gt;&amp;ldquo;Prioritize&amp;rdquo;&lt;/strong&gt; step (described in section 2.3.2) to help users decide which tasks to focus on before they get conveniently extracted in the &lt;strong&gt;&amp;ldquo;Focus&amp;rdquo;&lt;/strong&gt; step.&lt;/p&gt;
&lt;h3 id="223-calendars-planning--scheduling"&gt;2.2.3 Calendars, planning &amp;amp; scheduling&lt;/h3&gt;
&lt;p&gt;Section 1.4 introduced some of the core benefits of using calendars for planning and scheduling, yet scientific examination supplies a treasure trove of additional findings justifying their use alongside a task manager. A study exploring the use of a personal calendar discovered that most interviewees prefer a weekly view to aid with &amp;ldquo;&lt;em&gt;opportunistic rehearsal&lt;/em&gt;&amp;rdquo;, a fact that sits well with the need for a reviewing system such as the one proposed in section 2.3.4 as well as the realization that a simple list or Kanban presentation is helpful but not sufficient to get a clear overview of one&amp;rsquo;s schedule at a glance. The same study made it clear that most users rely on their calendar to store efficiently certain types of information such as the date (97%), time (96%), location (93%) and purpose (69%). Quite convincingly, participants also used their calendar for &amp;ldquo;&lt;em&gt;tentative event scheduling&lt;/em&gt;&amp;rdquo;, revealing the need to empty their mind to stay on top of their duties, a need addressed with the &lt;strong&gt;&amp;ldquo;Inscribe&amp;rdquo;&lt;/strong&gt; step referred to earlier. This study also emphasized the fact that calendars can be viewed on the web from most devices or even printed for offline reference. Finally, this paper also found that a majority of users (63%) reported using reminders and alarms with the help of their calendar.&lt;/p&gt;
&lt;p&gt;Even though almost two thirds of working professional consider using a calendar application to be very important in their workflow, it was also found in another study that &amp;ldquo;&lt;em&gt;it is inconvenient to schedule on calendar apps&lt;/em&gt;&amp;rdquo;, which supports the use of task managers for that specific necessity since they can alter tasks brilliantly and speedily. Calendars are not necessarily the best tactic when it comes to scheduling all kinds of activities either. Indeed, &amp;ldquo;&lt;em&gt;when consumers schedule their leisure, they may inadvertently reduce their utility for the activity&lt;/em&gt;&amp;rdquo;. With this type of activity, the authors divulge that &amp;ldquo;&lt;em&gt;roughly scheduling (i.e., without pre-specified times)&lt;/em&gt;&amp;rdquo; constitutes a practical alternative. This results in effective scheduling when tasks are entered via a task manager and synced with Google Calendar since blocks of activities can still be displayed in the calendar view without the added burden of specifying a strict duration for each event.&lt;/p&gt;
&lt;p&gt;There are some use cases that simply are not well suited for task managers, such as synchronizing events from Gmail (i.e., capturing tasks from different sources), setting reminders on appointments scheduled by third parties (where the primary source of truth must remain the calendar itself) or sharing a schedule with groups across the G suite applications with the help of smart suggestions coming from Google users&amp;rsquo; data which is not entirely available to external applications.&lt;/p&gt;
&lt;h2 id="23-the-four-pillars-forming-a-new-approach-evaluating-their-effectiveness"&gt;2.3 The four pillars forming a new approach: evaluating their effectiveness&lt;/h2&gt;
&lt;h3 id="231-inscribe"&gt;2.3.1 Inscribe&lt;/h3&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/inscribe.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/inscribe.png" alt="inscribe screen" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Inscribe screen.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;ProductiviDo&lt;/strong&gt; features four core components to help tackle one&amp;rsquo;s work skillfully, the first of which being all about jotting down tasks, a demonstration of the &amp;ldquo;generation effect&amp;rdquo; which assists with remembering information better. At this stage of the process, the idea is to record any potential future action that is required while being fully aware of the impact that such action will have on one&amp;rsquo;s life, benefitting at once from reducing one&amp;rsquo;s cognitive load by storing or discarding thoughts that do not require immediate response. &amp;ldquo;Inscribing&amp;rdquo; in this application is an intentional step demanding a certain level of mindfulness and acts as a precursor to the use of implementation intentions as it similarly &amp;ldquo;&lt;em&gt;serves an important self-regulatory function&lt;/em&gt;&amp;rdquo; according to a study on mindfulness done at the University of Rochester. A 2020 study from Bieleke and Keller found that &amp;ldquo;&lt;em&gt;opportunity-focused plans are especially important for initial progress towards the goal&lt;/em&gt;&amp;rdquo;, therefore this step ensures —through questioning the user&amp;rsquo;s aspirations— that the task is indeed a priority and that it is not just a distraction by evaluating its &amp;ldquo;leverage&amp;rdquo;, a notion introduced in section 1.4.&lt;/p&gt;
&lt;h3 id="232-prioritize"&gt;2.3.2 Prioritize&lt;/h3&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/prioritize.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/prioritize.png" alt="Prioritize screen" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Prioritize screen.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;There is substantial evidence to establish that the concept of a &amp;ldquo;master list&amp;rdquo; has been popularized and has found multiple concrete applications (e.g., as a list of relevant jobs held by an applicant, as an Excel spreadsheet keeping track of crucial information at a high-level, in some jurisdictions in the legal world, etc.), including as a way to manage tasks, an idea also sprouting from Edmond Lau&amp;rsquo;s work. In the context of task management systems, a master list manifests itself as a centralized location where all tasks are accessible once they have been &amp;ldquo;inscribed&amp;rdquo;. With &lt;strong&gt;ProductiviDo&lt;/strong&gt;, &amp;ldquo;prioritizing&amp;rdquo; is a transient state: it is about handling a database of data to be referenced later when progress must be undertaken on specific tasks. It is a digital space separate from the current areas of focus (presented in the following step in section 2.3.3) used to find the next priorities to work on, where filters are available to that end (see section 3 for the technical details). As defended by Bellotti&amp;rsquo;s research as a set of desirable features, the &lt;strong&gt;&amp;ldquo;Prioritize&amp;rdquo;&lt;/strong&gt; step offers the &amp;ldquo;&lt;em&gt;ability to sort by importance and deadlines&lt;/em&gt;&amp;rdquo; as well as a &amp;ldquo;&lt;em&gt;smart prioritization&lt;/em&gt;&amp;rdquo; of tasks by default, where the most important ones will flow to the top of the list, ready to be acted upon. Because tasks listed in the &lt;strong&gt;&amp;ldquo;Prioritize&amp;rdquo;&lt;/strong&gt; step are forcibly distinct from those listed in the &lt;strong&gt;&amp;ldquo;Focus&amp;rdquo;&lt;/strong&gt; step as they are mutually exclusive, this intermediate step helps to reduce the number of tasks shown in the schedule, improving one&amp;rsquo;s perceived control of time, busyness and stress.&lt;/p&gt;
&lt;h3 id="233-focus"&gt;2.3.3 Focus&lt;/h3&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/focus.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/focus.png" alt="focus screen" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Focus screen.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Once there are prioritized tasks in the application defined in terms of implementation intentions, science dictates that there is a need to &amp;ldquo;&lt;em&gt;support the viewing of entire task vistas, but also allow different perspectives for different kinds of planning&lt;/em&gt;&amp;rdquo; and for &amp;ldquo;&lt;em&gt;top priority items to be made apparent&lt;/em&gt;&amp;rdquo;. It is also known that setting clear goals eliminates intrusive thoughts and that &amp;ldquo;&lt;em&gt;commitment to a later behavior was linked to reduced rather increased strain on mental resources&lt;/em&gt;&amp;rdquo;. For these reasons, the &lt;strong&gt;&amp;ldquo;Focus&amp;rdquo;&lt;/strong&gt; step is a crucial component of the application. This component has the additional benefit of mitigating the problem uncovered in section 2.2.2 about the lesser efficacy of having multiple implementation intentions at once because it helps to recall all the high-leverage tasks in a filtered version of the master list (i.e., the current working list), leading to the observation of the Zeigarnik Effect which states that &amp;ldquo;&lt;em&gt;an activity that has been interrupted may be more readily recalled&lt;/em&gt;&amp;rdquo;. In addition, seeing a list of promises to oneself in the form of MCIIs &amp;ldquo;&lt;em&gt;seems to facilitate behavior change even when there is an initial reluctance to engage in the targeted behavior&lt;/em&gt;&amp;rdquo;. Even more benefits from MCIIs include &amp;ldquo;&lt;em&gt;sustained task value and higher persistence&lt;/em&gt;&amp;rdquo;, two aspects that contribute to goal achievement and, consequently, to turning a task manager into an efficacious product.&lt;/p&gt;
&lt;h3 id="234-review"&gt;2.3.4 Review&lt;/h3&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/review.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/review.png" alt="review screen" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Review screen.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;At this point, a working list of tasks exists to &lt;strong&gt;&amp;ldquo;Focus&amp;rdquo;&lt;/strong&gt; and a backlog of work remains to &lt;strong&gt;&amp;ldquo;Prioritize&amp;rdquo;&lt;/strong&gt;, yet not all labor should be brought to fruition as initially planned. Life circumstances change and &amp;ldquo;&lt;em&gt;plans to deliberate can be used to increase the likelihood of deliberation and thereby the effective processing of newly available information&lt;/em&gt;&amp;rdquo;, which can help eliminate or update tasks that are no longer considered important or relevant enough given an ever-changing environmental context. A paper on making informed scheduling decisions also noted that &amp;ldquo;&lt;em&gt;self-monitoring and self-reflection often affect behavior, and this change typically goes in the desired direction of improvement&lt;/em&gt;&amp;rdquo;. These findings can be applied practically by creating plans focusing on overcoming obstacles to make sustained progress, allowing one to ponder every major decision during the journey. A 2021 study on task management tools proposed to break complex tasks into smaller chunks (using a sophisticated approach with dependency graphs), an idea that can auspiciously be employed in a simpler way by breaking down a larger unit of work into smaller ones, which can be done during the information-gathering phase (i.e. the &lt;strong&gt;&amp;ldquo;Inscribe&amp;rdquo;&lt;/strong&gt; step) as well as during the reviewing phase with existing units of work, which is known as &amp;ldquo;compartmentalization&amp;rdquo;. This self-reflection process can also contribute to one&amp;rsquo;s well-being by providing written cues to recollect positive images from past accomplishments. Looking towards the future, cueing the users to imagine positive outcomes and encouraging them to restructure their priorities can equally evoke optimism and improve life satisfaction while inspiring them to live according to their personal values. After all, a &amp;ldquo;&lt;em&gt;person who sets up life and its routines to avoid inner conflict between goals is better off in the sense that he or she ends up feeling fewer bad emotional states and is generally happier&lt;/em&gt;&amp;rdquo;.&lt;/p&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/review-later.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/review-later.png" alt="review screen with later filter applied" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Review screen, showing a filter being applied.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id="3-design"&gt;3 Design&lt;/h2&gt;
&lt;h2 id="31-domain-and-target-audience"&gt;3.1 Domain and target audience&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;ProductiviDo&lt;/strong&gt; is a task management system staying clear of project management and time management, geared towards being a capture and review tool leaving notifications and scheduling to external systems, primarily to Google Calendar in these first product iterations. As such, the target audience is represented by conscientious people desiring to optimize their productivity with a tool discouraging multitasking, who don&amp;rsquo;t mind hand holding to achieve their goals — willing to trade off flexibility in exchange for a more rigid system backed by science —, expecting a simple set of essential features for a distraction-free environment to get things done and wanting to manage their own set of personal tasks (as this product is not designed with teams or businesses in mind).&lt;/p&gt;
&lt;p&gt;Explicitly supported users include people who want to follow a useful system without having to build it from scratch (e.g., setting up projects, tags, custom priorities, etc.) as well as those who need to keep track of tasks involving others with basic functionality (via Google Calendar and filters in the application). The application will not cater to those who want to rely mainly on desktop applications (because the core of the application is mobile only), nor to those who want to use a calendar other than Google Calendar (which is the only calendar undeniably supported in this version) or those who are looking for a solution integrating into other applications, since there will be no publicly accessible API at first to make this possible.&lt;/p&gt;
&lt;h2 id="32-design-decisions-and-principles"&gt;3.2 Design decisions and principles&lt;/h2&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/figma_design.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/figma_design.png" alt="Designing and wireframing in Figma" class="max-size-img-post"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Designing and wireframing in Figma.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Section 2 abstractly laid out the foundation for the core ideas being implemented in the application meeting
the needs of the target audience. Concretely, a few design principles listed in &amp;ldquo;The Pocket Universal
Principles of Design&amp;rdquo; inform how the application has been thought out, markedly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The 80/20 rule: &amp;ldquo;&lt;em&gt;80 percent of a product&amp;rsquo;s usage involves 20 percent of its features&lt;/em&gt;&amp;rdquo;, which is true with &lt;strong&gt;ProductiviDo&lt;/strong&gt; where users will spend most of their time focusing on the work they have to accomplish;&lt;/li&gt;
&lt;li&gt;Chunking: &amp;ldquo;&lt;em&gt;Chunk information when people are required to recall and retain information&lt;/em&gt;&amp;rdquo;, where each task will display the most important information to contextualize work;&lt;/li&gt;
&lt;li&gt;Constraint: &amp;ldquo;&lt;em&gt;Limiting the actions that can be performed to simplify use and prevent error&lt;/em&gt;&amp;rdquo;, where each screen will have a single function with a premedidated lack of customization;&lt;/li&gt;
&lt;li&gt;Five Hat Racks: the five ways in which information can be organized (i.e., category, time, location, alphabet, and continuum), all of which are supported by &lt;strong&gt;ProductiviDo&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;Form follows function: &amp;ldquo;&lt;em&gt;Aesthetic considerations should be secondary to functional considerations&lt;/em&gt;&amp;rdquo;, where the application maximizes the functionality available on each screen while taking into consideration the primary interactions needed at each step, regardless of the visual impact these decisions have;&lt;/li&gt;
&lt;li&gt;Garbage in, garbage out: &amp;ldquo;&lt;em&gt;Make it impossible to store bad data types&lt;/em&gt;&amp;rdquo;, where the application will not accept invalid inputs on any field that could jeopardize the integrity of the data;&lt;/li&gt;
&lt;li&gt;Nudges: &amp;ldquo;&lt;em&gt;smart defaults, clear feedback, aligned incentives, structured choices, and visible goals&lt;/em&gt;&amp;rdquo;, where the app makes the purpose of each interaction crystal clear;&lt;/li&gt;
&lt;li&gt;Progressive disclosure: &amp;ldquo;&lt;em&gt;A method of managing complexity, in which only necessary or requested information is displayed&lt;/em&gt;&amp;rdquo;, where filters are selectively shown to match the intent of each screen and where optional fields are hidden away by default until they are needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is noteworthy that calendar integration will be optional and that the application will remain fully functional without relying on external calendars for maximum convenience, especially while users are offline. Even though this work underlined the usefulness of calendars when used as companions for task managers, one of the primary goals of a task manager is to be available at all times regardless of internet connectivity so that users can access their list of priorities and get work done: requiring an active connection and access to a calendar via sign-on before being able to do any work would break the principle of least astonishment in this type of application.&lt;/p&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/prioritize-wireframes.png"&gt;
 &lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/prioritize-wireframes.png" alt="Some of the original wireframes for the Prioritize screen" class="max-size-img-post" width="6193" height="4383" loading="lazy" decoding="async"&gt;
 &lt;/a&gt;
 &lt;figcaption&gt;Some of the original wireframes for the &lt;strong&gt;Prioritize&lt;/strong&gt; screen.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="33-structure-of-the-application"&gt;3.3 Structure of the application&lt;/h2&gt;
&lt;p&gt;The application is structured in such a way that each screen has a single function and that the user is guided through the process of adding, editing, and reviewing tasks4. The application is designed to be as simple as possible, with a minimalistic interface and a limited number of interactions to keep the user focused on the task at hand. Technically, it is arranged according to a pyramid schematic architecture, where the &amp;ldquo;hub&amp;rdquo; is the hamburger menu which links to all other pages and where all the sub-pages can go back to the &amp;ldquo;hub&amp;rdquo;. In this architecture, the tab navigation at the bottom of the screen lists the core sub-pages which are always accessible and can lead back to the hub as needed so that the user does not need to remember how to get from one screen to another, since they are all identified with both a recognizable icon and text label.&lt;/p&gt;
&lt;p&gt;The application is structured in a way that makes it easy to add, edit, and review tasks, with the following screens:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Inscribe&lt;/strong&gt;: Looking at the tab bar (bottom part of the wireframes) from left to right, this is the first screen meant to be easily accessible and also the first step that is part of the process of managing tasks by carefully adding them to the system;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prioritize&lt;/strong&gt;: this is the screen responsible for displaying the list of tasks that have been added to &lt;strong&gt;ProductiviDo&lt;/strong&gt; in the first step (&lt;strong&gt;Inscribe&lt;/strong&gt;) but still require planning (i.e., they represent the tasks to prioritize);&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Focus&lt;/strong&gt;: Once the tasks have been prioritized from the previous screen (&lt;strong&gt;Prioritize&lt;/strong&gt;), they are ready to be scheduled and worked on, which is the purpose of this screen — it displays the current working list of tasks in a digestible format;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review&lt;/strong&gt;: Periodically (daily, weekly, etc.), the application will ask the user to review the tasks that remain to be completed to ensure that they are still relevant and that they are still a priority.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/edit-task.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/edit-task.png" alt="edit task screen" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Edit task screen.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;These core screens are accessible at all times from the tab bar to allow for easy navigation between them. The application will also have a few other screens that are not part of the core workflow but that are still important for the user experience:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;About&lt;/strong&gt;: This screen will display information about the application, such as the purpose behind each aspect as well as the version number;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Help&lt;/strong&gt;: There will be a help system embedded in this screen to help users understand how to use the application and how to get the most out of it, which will be fully searchable;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recycle bin&lt;/strong&gt;: Sometimes, tasks will be added to &lt;strong&gt;ProductiviDo&lt;/strong&gt; by mistake or they will be completed before they are scheduled. This screen will allow the user to review and restore these tasks if they are still relevant;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accomplishments&lt;/strong&gt;: This screen will display a list of tasks that have been completed and will allow the user to review them and reflect on their accomplishments;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Settings&lt;/strong&gt;: This screen will allow the user to customize the application to their liking, such as changing the theme, determining default values on new tasks, etc.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/about.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/about.png" alt="about screen" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;About screen.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;These secondary screens are accessible from each core screen in the top-right corner to toggle the presence of a &amp;ldquo;drawer&amp;rdquo; menu. The menu can also be revealed by swiping from right to left on the screen. The menu will be hidden by default to keep the interface as clean as possible and to avoid cluttering it with unnecessary information. The menu will be revealed by default on the first launch of the application to help users discover the features available to them.&lt;/p&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/menu.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/menu.png" alt="Menu screen" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Menu screen.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="34-libraries-and-services"&gt;3.4 Libraries and services&lt;/h2&gt;
&lt;p&gt;At a high level, the application will be built using React Native to support both Android and iOS platforms.
In terms of software user-facing dependencies, the application will use the following libraries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;react-native-async-storage/async-storage&lt;/code&gt;: The application will use this library to store data
locally on the device;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;react-native-community/datetimepicker&lt;/code&gt;: This library will be used to display the date and time
pickers;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;React Navigation&lt;/code&gt;: This library will be used to implement the navigation system;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Redux&lt;/code&gt;: This library will be used to manage the state of the application;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NativeBase&lt;/code&gt;: it will be used to implement the user interface;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;redux-persist&lt;/code&gt;: This library will be used to persist the state of the application locally on the device;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;redux-thunk&lt;/code&gt;: This library will be used to implement asynchronous actions in the application;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;react-native-collapsible&lt;/code&gt;: This library will be used to implement all the collapsible sections to
provide progressive disclosure;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;react-native-extended-stylesheet&lt;/code&gt;: This library will be used to implement the theming system;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nandorojo/anchor&lt;/code&gt;: This library will be used to implement the anchor system so that users can jump
from one section to another in the help system.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The application will also use the following libraries to support the development process:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Eslint&lt;/code&gt;: This library will be used to enforce a consistent coding style;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Babel&lt;/code&gt;: This library will be used to transpile the code to support older versions of JavaScript;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Jest&lt;/code&gt;: This library will be used to implement unit tests;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;react-native-testing-library&lt;/code&gt;: This library will be used to implement integration tests;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;react-native-dotenv&lt;/code&gt;: This library will be used to manage environment variables;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;react-test-renderer&lt;/code&gt;: This library will be used to implement snapshot tests;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TypeScript&lt;/code&gt;: It will ensure type checking is available app-wide and reduce the number of bugs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the backend side, the application will make use mainly of the following services:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Firebase&lt;/code&gt;: This service will be used to implement the authentication system needed to deal with
Google accounts as an optional add-on;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Google Calendar&lt;/code&gt;: This service will be used to implement the calendar system;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SQLite&lt;/code&gt;: It will be used to implement the database system locally and will be backed up to the cloud.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/db_schema.png"&gt;
 &lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/db_schema.png" alt="Database schema behind ProductiviDo" class="max-size-img-post" width="2824" height="1196" loading="lazy" decoding="async"&gt;
 &lt;/a&gt;
 &lt;figcaption&gt;Showing the database design behind ProductiviDo.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="35-plan-of-work"&gt;3.5 Plan of work&lt;/h2&gt;
&lt;p&gt;In a nutshell, the plan of work will be followed as shown below:&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0039_productivido/gantt_chart.png"
 alt="Gantt Chart"
 loading="lazy"
 decoding="async" width="1512" height="1319"/&gt;
&lt;/p&gt;
&lt;h2 id="36-testing-and-evaluation"&gt;3.6 Testing and evaluation&lt;/h2&gt;
&lt;p&gt;The project will be tested primarily using the following methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unit tests&lt;/strong&gt;: Unit tests will be implemented to ensure that each component of the application works as expected. These tests will be implemented using &lt;code&gt;Jest&lt;/code&gt; and &lt;code&gt;react-test-renderer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration tests&lt;/strong&gt;: Integration tests will be implemented to ensure that the application works as expected when all the components are combined. These tests will be implemented using the apt &lt;code&gt;react-native-testing-library&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User and usability testing&lt;/strong&gt;: User testing will be implemented to ensure that the application is easy to use and that it meets the needs of the users. These tests will be implemented using a combination of user interviews and surveys.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance, load and stress testing&lt;/strong&gt;: Performance testing will be implemented to ensure that the application is fast and responsive. These tests will be performed by simulating the presence of a large number of tasks and events.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security testing&lt;/strong&gt;: Security testing will be implemented to ensure that the application is secure, most definitely when it comes to protecting user&amp;rsquo;s data in the cloud to avoid data breaches.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regression testing&lt;/strong&gt;: Regression testing will be implemented to ensure that the application does not break when new features are added, using a mixture of automated &lt;code&gt;git bisect&lt;/code&gt; scripts to locate anomalies and by automatically running test suites with Git pre-commit hooks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compatibility testing&lt;/strong&gt;: Compatibility testing will be implemented to ensure that the application works on all the supported platforms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessibility testing&lt;/strong&gt;: Accessibility testing will be implemented to ensure that the application is accessible to all users.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="4-implementation"&gt;4 Implementation&lt;/h2&gt;
&lt;h2 id="41-overview"&gt;4.1 Overview&lt;/h2&gt;
&lt;p&gt;At its core, &lt;strong&gt;ProductiviDo&lt;/strong&gt; aims to provide a system that facilitates &amp;ldquo;getting things done&amp;rdquo; in the manner of the famously successful productivity system GTD, created and shared with millions of people by David Allen. The system is based on the following principles, worth expanding on as it bears strong resemblance with the final design of the application:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Capture&lt;/strong&gt;: All tasks and events should be captured in a single place, so that they can be easily accessed and managed. This is achieved with the &lt;strong&gt;&amp;ldquo;Inscribe&amp;rdquo;&lt;/strong&gt; screen, the first step in the &lt;strong&gt;ProductiviDo&lt;/strong&gt; system.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clarify&lt;/strong&gt;: All tasks and events should be clarified, so that they can be easily understood and prioritized. This is achieved in the &lt;strong&gt;&amp;ldquo;Inscribe&amp;rdquo;&lt;/strong&gt; screen, where the user can add a description to the task or event along with necessary metadata to help classify and prioritize the data being added.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Organize&lt;/strong&gt;: All tasks and events should be organized, so that they can be easily accessed and managed. While this GTD step does not map directly to a step in &lt;strong&gt;ProductiviDo&lt;/strong&gt;, the &lt;strong&gt;&amp;ldquo;Focus&amp;rdquo;&lt;/strong&gt; screen serves a similar purpose in that it allows the user to organize tasks and events into a list of immediately actionable items that are easy to reference.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reflect&lt;/strong&gt;: All tasks and events should be reflected upon, so that they can be easily understood and prioritized. With &lt;strong&gt;ProductiviDo&lt;/strong&gt;, this is done in the &lt;strong&gt;&amp;ldquo;Review&amp;rdquo;&lt;/strong&gt; screen, which invites users to review tasks logically according to their deadline, priority, an&lt;strong&gt;d other meta&lt;/strong&gt;data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Engage&lt;/strong&gt;: All tasks and events should be engaged with, so that they can be easily accessed and managed. &lt;strong&gt;ProductiviDo&lt;/strong&gt; deals with this GTD step in a simpler way via the &lt;strong&gt;&amp;ldquo;Prioritize&amp;rdquo;&lt;/strong&gt; screen and the &lt;strong&gt;&amp;ldquo;Focus&amp;rdquo;&lt;/strong&gt; screen, which allow users to prioritize tasks and events and then focus on the most important ones.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="42-features-implemented-a-visual-tour"&gt;4.2 Features implemented: a visual tour&lt;/h2&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/quick-actions.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/quick-actions.png" alt="Quick actions screen" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Quick actions.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The application has the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Add a task&lt;/strong&gt;: The user can add tasks by navigating to the &lt;strong&gt;&amp;ldquo;Inscribe&amp;rdquo;&lt;/strong&gt; screen and filling in the required fields. The user can also add a deadline date and time, a duration, a location, a priority to the task and so on. By choosing the type of task as &amp;ldquo;&lt;strong&gt;Calendar&lt;/strong&gt;&amp;rdquo; and filling in the required fields, the task will be added to the user&amp;rsquo;s Google Calendar. This screen hides any navbar and tab bar to maximize the screen real estate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prioritize a task&lt;/strong&gt;: The user can prioritize tasks by navigating to the &lt;strong&gt;&amp;ldquo;Prioritize&amp;rdquo;&lt;/strong&gt;, where filtering options are available to help the user find the task to prioritize. The main task action that can be performed on this screen is to &amp;ldquo;focus&amp;rdquo; a task, effectively moving it to the &lt;strong&gt;&amp;ldquo;Focus&amp;rdquo;&lt;/strong&gt; screen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Focus on a task&lt;/strong&gt;: The user can focus on a task by navigating to the &lt;strong&gt;&amp;ldquo;Focus&amp;rdquo;&lt;/strong&gt; screen, where the user can see a list of tasks that are immediately actionable. The user can also filter the tasks to focus on. The main action that can be performed on this screen is to &amp;ldquo;complete&amp;rdquo; a task, effectively moving it to the &amp;ldquo;Accomplishments&amp;rdquo; screen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review tasks&lt;/strong&gt;: The user can review tasks by navigating to the &lt;strong&gt;&amp;ldquo;Review&amp;rdquo;&lt;/strong&gt; screen, where the user can see a list of tasks that are overdue, due soon (e.g., today, tomorrow, this week), due later (e.g., next week, next month, next year) as well as tasks that are &amp;ldquo;old&amp;rdquo; (i.e., tasks that have been added to the system more than a month ago relative to today&amp;rsquo;s date but have not been worked on yet). This screen features &amp;ldquo;&lt;em&gt;quick actions&lt;/em&gt;&amp;rdquo; that are relevant to the tasks being reviewed. These actions provide the ability to reschedule a task, update its current state (i.e., move it from and to the Prioritize and Focus screens) and to delete a task without having to open the task details screen to edit it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filter tasks to review&lt;/strong&gt;: The user can filter tasks to review by navigating to the &lt;strong&gt;&amp;ldquo;Review&amp;rdquo;&lt;/strong&gt; screen and selecting the filter options. The user can filter tasks by one of the categories &amp;ldquo;&lt;strong&gt;Overdue&lt;/strong&gt;&amp;rdquo;, &amp;ldquo;&lt;strong&gt;Soon&lt;/strong&gt;&amp;rdquo;, &amp;ldquo;&lt;strong&gt;Later&lt;/strong&gt;&amp;rdquo;, &amp;ldquo;&lt;strong&gt;Old&lt;/strong&gt;&amp;rdquo; and by all of these at once when no filters are applied.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Edit task details&lt;/strong&gt;: Once a task has been added to the system, it can be edited from any of the main screens (i.e., &lt;strong&gt;&amp;ldquo;Prioritize&amp;rdquo;&lt;/strong&gt;, &lt;strong&gt;&amp;ldquo;Focus&amp;rdquo;&lt;/strong&gt;, &lt;strong&gt;&amp;ldquo;Review&amp;rdquo;&lt;/strong&gt;). The user can edit all the same properties as when adding a task as well as add new ones not present when the task was added. When a task is of type &amp;ldquo;Calendar&amp;rdquo;, its related details will also be updated on the user&amp;rsquo;s Google Calendar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;About screen&lt;/strong&gt;: while the About screen does not provide any functionality related to tasks, it allows users to learn more about the application. The screen includes a link to the application&amp;rsquo;s website, a link to a dynamic feedback form to help &lt;strong&gt;ProductiviDo&lt;/strong&gt; become a better fit for its users, an email address to contact the developers (which opens the default email client on the user&amp;rsquo;s device) and other less frequently accessed information, including a link to the GitHub repository of the project and a list of open source libraries used to create the product.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Help screen&lt;/strong&gt;: the application has been designed to avoid relying on documentation in order to be used. However, the Help screen is a useful resource for users who want to learn more about the concepts involved in the application. It describes possible workflows and guides users through the application&amp;rsquo;s main screens so they will be able to use it even more effectively.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recycle bin screen&lt;/strong&gt;: &lt;strong&gt;ProductiviDo&lt;/strong&gt; makes it very easy to access and manage tasks that have been deleted by the user. The Recycle bin screen allows users to restore deleted tasks (which are sent back to the Prioritize screen for the next round of prioritization) or to permanently delete them by emptying the recycle bin.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accomplishments screen&lt;/strong&gt;: While the Recycle bin holds all deleted tasks, the Accomplishments screen holds all tasks that have been completed by the user from the Focus screen. The Accomplishments screen is a great way to keep track of the user&amp;rsquo;s progress and to celebrate the user&amp;rsquo;s accomplishments, yet it also allows removing completed tasks from the system if the user wishes to do so.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Settings screen&lt;/strong&gt;: The Settings provided by &lt;strong&gt;ProductiviDo&lt;/strong&gt; allow users to customize the application to their needs in a basic way — and all settings are persisted across reboots of the application or device. There is a dark mode available to protect the users&amp;rsquo; eyes from screen brightness. Other settings include the ability to set default behaviours on new tasks, set the increment in minutes to be shown in the time picker, set a different locale to represent dates and times and some more options to toggle the display of certain elements in the application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filters&lt;/strong&gt;: What &lt;strong&gt;ProductiviDo&lt;/strong&gt; lacks in customizations, it makes up for in filters. The application allows users to filter tasks by type, status, priority, deadline date, deadline time, duration, location and more. The filters are applied in real-time, so the user can see the results of the filters as they are being applied. The filters can be applied to any of the main screens (i.e., &lt;strong&gt;&amp;ldquo;Prioritize&amp;rdquo;&lt;/strong&gt;, &lt;strong&gt;&amp;ldquo;Focus&amp;rdquo;&lt;/strong&gt;, &lt;strong&gt;&amp;ldquo;Review&amp;rdquo;&lt;/strong&gt;) and can be combined to create more precise filters.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Google Calendar&lt;/strong&gt;: One of the key tenets of &lt;strong&gt;ProductiviDo&lt;/strong&gt; is to make it easy for users to manage their tasks and to have a visual window into their schedule, which is achieved by integrating with the user&amp;rsquo;s primary calendar on Google Calendar. The application allows users to connect their Google Calendar account to &lt;strong&gt;ProductiviDo&lt;/strong&gt; and to create calendar events from new or existing tasks. At the same time, this functionality remains entirely optional: users can choose to never opt in to the Google Calendar integration and can disconnect their Google account at any time, which will prevent any synchronization from happening between &lt;strong&gt;ProductiviDo&lt;/strong&gt; and Google Calendar.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/settings.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/settings.png" alt="settings screen" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Settings screen.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/dark-mode.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/dark-mode.png" alt="dark mode screen" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Dark mode.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="43-techniques-and-methods"&gt;4.3 Techniques and methods&lt;/h2&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0039_productivido/help.png"&gt;&lt;img src="https://www.sglavoie.com/images/posts/0039_productivido/help.png" alt="help screen" style="max-width: 500px"&gt;&lt;/a&gt;
 &lt;figcaption&gt;Help screen.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Beyond the libraries mentioned in section 3.4, the actual implementation of the application happened in the following way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;React Native bare workflow&lt;/strong&gt;: The application was developed using the React Native bare workflow, which allows for the use of native code in the application. This was necessary to implement the Google Calendar integration, which was not possible using the Expo workflow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State management&lt;/strong&gt;: The application was architected in such a way that React Context was used to avoid &amp;ldquo;&lt;em&gt;props drilling&lt;/em&gt;&amp;rdquo; and to provide a global state to the application, using data coming from the SQLite database loaded at launch. All context that does not require persistence is managed by React Context, while the rest of the state (e.g., settings) is managed by Redux Toolkit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TypeScript&lt;/strong&gt;: The app was developed using TypeScript, a typed superset of JavaScript that compiles to plain JavaScript. TypeScript was used to ensure type safety and to provide a better developer experience with autocomplete and other features that help developers write code with fewer errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React Navigation&lt;/strong&gt;: The navigation between screens uses a combination of stack and tab navigation, with the main screens being accessible through the tab navigation and the rest of the screens being accessible through the stack navigation. Additionally, a drawer navigation is used to provide access to all secondary screens via the traditional &amp;ldquo;hamburger&amp;rdquo; menu.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NativeBase&lt;/strong&gt;: This library was used to provide a consistent look and feel to the application and get access to components that are not available in React Native. Many of its components were put to use in the application, including &lt;code&gt;Actionsheet&lt;/code&gt;, &lt;code&gt;AlertDialog&lt;/code&gt;, &lt;code&gt;Badge&lt;/code&gt;, &lt;code&gt;FlatList&lt;/code&gt;, &lt;code&gt;Modal&lt;/code&gt;, &lt;code&gt;Switch&lt;/code&gt; and &lt;code&gt;Transitions&lt;/code&gt; to name a few.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Google Calendar API&lt;/strong&gt;: The application uses the Google Calendar API to allow users to connect their Google Calendar account to &lt;strong&gt;ProductiviDo&lt;/strong&gt; and to create calendar events from new or existing tasks. The API is used to create new events, to update existing events and to delete events. The API is also used to retrieve the user&amp;rsquo;s primary calendar and to retrieve the list of calendars available to the user.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQLite&lt;/strong&gt;: The application uses SQLite to store all data locally on the device. The application uses the expo-sqlite library to interact with the SQLite database. The database is initialized at launch and is updated whenever the user makes changes to the data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Form validation&lt;/strong&gt;: The application uses the yup library to validate forms and to provide error messages to the user. Coupled with &lt;code&gt;formik&lt;/code&gt;, the library provides a great way to validate forms and to provide a consistent experience to the user.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom hooks and functional components&lt;/strong&gt;: This project explicitly embraces new React features such as custom hooks and functional components. The application uses custom hooks to encapsulate logic for all the main screens. The application also uses functional components to avoid the use of class components, which are considered legacy in React.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="5-evaluation-results-and-discussion"&gt;5 Evaluation: results and discussion&lt;/h2&gt;
&lt;h2 id="51-successes"&gt;5.1 Successes&lt;/h2&gt;
&lt;h3 id="511-planning-and-execution"&gt;5.1.1 Planning and execution&lt;/h3&gt;
&lt;p&gt;Extensive research and preparation went into the project before writing a single line of production code. A multitude of potential implementations and concepts were explored in great details and the idea of the final product was refined from a very early stage, leading to a more focused development of the todo application. Because there existed a tangible vision of the desired outcome, it made it much simpler to define the database schema and the React context needed throughout the application to pass adequate data structures around. On a related note, doing all this work upfront helped to avoid wasting time learning libraries that would not entirely meet the needs of the application and to stop contemplating features that would not fit within the constraints of the chosen concept.&lt;/p&gt;
&lt;p&gt;Another decision that proved to be quite useful was to postpone dealing with complicated services till much later during development. For instance, storing mock data as simple JSON allowed for quick iterations during development without having to manually add tasks one by one by using the application itself to do so. Once it came time to integrate database functionality, data was first stored as a temporary in-memory database for fast read/write speeds (because the task view, filtering and sorting was not optimized yet) and it was later persisted to disk. Likewise, external services (e.g., Firebase and Google Calendar) were only integrated until the internal application design was set in stone. Performance optimizations were favorably delayed until most of the logic was implemented, which gave ample time to test and refine the design, productively steering clear of premature optimization due to the changing nature of the application still being validated and tested by beta users.&lt;/p&gt;
&lt;h3 id="512-functionality-achieved"&gt;5.1.2 Functionality achieved&lt;/h3&gt;
&lt;p&gt;One concept that served the final design well was a direct application of Fitt&amp;rsquo;s law, which states that &amp;ldquo;&lt;em&gt;the time required to touch a target is a function of the target size and the distance to the target&lt;/em&gt;&amp;rdquo;, meaning that it is important to keep controls close and large when speed or accuracy matters. As a concrete demonstration of this law, tasks can be added with the touch of a single button in the &lt;strong&gt;&amp;ldquo;Inscribe&amp;rdquo;&lt;/strong&gt; button located in the tab bar, making it frictionless for users to add tasks and events to the application. This meets the need of being &amp;ldquo;&lt;em&gt;always on&lt;/em&gt;&amp;rdquo;, especially since all data is accessible locally without the need for an internet connection, allowing users to quickly get their priorities out of their mind and onto a digital device to allow for proper referencing later on. Other critical interactions such as focusing tasks and completing them can be done by tapping on a large icon next to each task.&lt;/p&gt;
&lt;p&gt;The application allows visualizing all tasks at once in the &lt;strong&gt;&amp;ldquo;Prioritize&amp;rdquo;&lt;/strong&gt; screen, which contains all necessary filters in order to make filtering and sorting through a growing list of incoming data not only feasible but also simple and practical. Indeed, the lack of hierarchical organization in the information architecture is absolutely intentional. This design decision allows flexibility with the use of filters without incurring a cognitive cost to understand how information is organized. As long as users are diligent with the metadata they input in the application (as they should if they wish to accomplish their goals), they will be able to easily find the information they need in the &lt;strong&gt;&amp;ldquo;Prioritize&amp;rdquo;&lt;/strong&gt; screen. Excluding the hierarchical access to information, all other aspects of information architecture (location, alphabet, time, category) are available as filters to the users.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;&amp;ldquo;Focus&amp;rdquo;&lt;/strong&gt; screen intuitively lets users know which tasks are most important to work on at any given time, sorting them by deadline, priority and other metadata, making the data &amp;ldquo;&lt;em&gt;always actionable&lt;/em&gt;&amp;rdquo;. Since focused tasks are isolated from the rest of the data, users are able to focus on the task at hand without being distracted by other tasks. On this screen, users are able to complete tasks, which effectively disappear from the task list and are kept in the &amp;ldquo;&lt;strong&gt;Accomplishments&lt;/strong&gt;&amp;rdquo; screen for later retrieval. This is a way to keep track of tasks that have been completed, which is a feature that is not available in the Google Calendar application and which complements its functionality very well. Additionally, this screen allows users to &amp;ldquo;restore&amp;rdquo; tasks, which performs the opposite action. Notably, it will prevent mistakes by letting users undo their actions; it will also allow users to review tasks and events that have been deleted and to permanently delete them as needed. This feature is not available in the Google Calendar application and contributes to making &lt;strong&gt;ProductiviDo&lt;/strong&gt; a useful ally in this case so that events can be restored to the calendar view. The final active step required to use &lt;strong&gt;ProductiviDo&lt;/strong&gt; effectively, found in the &lt;strong&gt;&amp;ldquo;Review&amp;rdquo;&lt;/strong&gt; screen, provides complimentary functionality to that found in most modern calendar applica&lt;strong&gt;tions. While&lt;/strong&gt; a calendar is useful to get a sense of upcoming events, a review system is needed to stay on top of one&amp;rsquo;s priorities to make sure that time-insensitive yet important events do not slip through the cracks. The &lt;strong&gt;&amp;ldquo;Review&amp;rdquo;&lt;/strong&gt; screen is a way to make sure that users are not only aware of the tasks and events they ha&lt;strong&gt;ve scheduled&lt;/strong&gt;, but also of the tasks and events that they have not scheduled but are important to them. Furthermore, reviewing one&amp;rsquo;s work periodically in an automatic way allows for better planning and will make sure that longstanding tasks are either updated, prioritized, delegated or removed.&lt;/p&gt;
&lt;h2 id="52-failures-and-limitations"&gt;5.2 Failures and limitations&lt;/h2&gt;
&lt;p&gt;The following points of failures are discussed in more details in section 6.2, where solutions for brighter times ahead are pictured.&lt;/p&gt;
&lt;h3 id="521-google-calendar-integration"&gt;5.2.1 Google Calendar integration&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;ProductiviDo&lt;/strong&gt; solves real-world issues related to task management and scheduling in a robust manner, yet it does so partially. One major caveat to the current implementation is that it supports only Google Calendar, which severely limits the potential market the application can tap into. Because only Google Calendar was taken into account during this project, it is highly likely that the application will not be able to support other calendar applications without a major overhaul of the codebase. The application was thought to be a companion to Google Calendar from the ground up, which means that while it integrates seamlessly with it, it creates tight coupling between the two applications. There are in fact more issues to delve into when it comes to Google Calendar. In particular, full synchronization of tasks and events is not supported in a scalable way. For one, Google Calendar API&amp;rsquo;s daily and monthly rates are limited: instead of calling that API on every little detail being updated in a task, the application should really try its best to batch requests so that heavy users will not be penalized if they happen to trigger many updates in their calendar or if Google decides to lower the number of requests that can be processed in a given amount of time. Another pitfall is that the application does not support recurring tasks as originally intended due to lack of human resources, which is a feature that is available in the Google Calendar application. While it is technically possible to implement this feature, more context would need to be stored in the application to avoid duplication of tasks in the database and to allow recurring tasks to be reset to their original state or updated as desired, all of which would need to communicate with the Google Calendar API in an efficient way. There is, at the moment, no task tracking facility: a completed task is simply removed from the list of tasks by updating its status in the database. This is a considerable limitation, since it prevents users from creating tasks that are recurring, such as weekly meetings or monthly bills.&lt;/p&gt;
&lt;h3 id="522-unit-testing"&gt;5.2.2 Unit testing&lt;/h3&gt;
&lt;p&gt;One clear oversight in the development process was the lack of unit testing. While the application was profusely tested in a manual way, it would have been much more efficient to have had a suite of unit tests that would have allowed for a more sturdy and scalable application. &lt;strong&gt;ProductiviDo&lt;/strong&gt; comprises a few essential unit tests regarding the Google Calendar integration, but it is nowhere near the level of testing that would be required to ensure that the application is robust and that it will not break in the future. Amongst some of the types of tests that should have been implemented are unit tests for the database, unit tests for the application&amp;rsquo;s business logic, snapshot testing and testing of asynchronous API calls through mocking. In hindsight, the reason more tests did not make it into the final application is that the development process was not agile enough to allow for the time required to write unit tests and there have been too many side experiments that have taken priority over the core functionality of the application. Of equal relevance is the fact that unanticipated issues have arisen during the development process, which have required more time and effort to be spent on fixing them rather than on writing unit tests. It is also important to keep in mind that unit testing is not a one-time activity: it should be done continuously throughout the development process, more akin to the test-driven development (TDD) workflow. Failing in that department was a major setback for the application, since it will make it harder to maintain and to scale in the future and it likely contributed to the fact that more time was spent on debugging than was necessary.&lt;/p&gt;
&lt;h3 id="523-advanced-features-powered-by-ai"&gt;5.2.3 Advanced features powered by AI&lt;/h3&gt;
&lt;p&gt;Besides the issues already raised in this section, there are a few other features that would have optimized the user experience, but which were not implemented due to lack of time as otherwise the scope of the project would have fallen appreciably out of reasonable proportions. For instance, the application does not support batch editing of tasks, which is a feature that is available in many other task managers in one form or another. It also does not support location-based notifications, which would have been useful to send reminders to users based on their location. The application does not make use of advancements in machine learning: learning users&amp;rsquo; preferences over time to provide helpful shortcuts when creating new tasks could have been a fantastic time saver. &lt;strong&gt;ProductiviDo&lt;/strong&gt; could have stored task templates such that creating recurring tasks would be faster and more intuitive by providing logical default values based on what the algorithm thinks is going to be needed next. Similarly, the app could add locations, people, and other properties to tasks once it figures out that certain actions only happen in given locations or with the same people repeatedly. Yet another feature that would have proven handy would be to provide time-based notifications based on predictions from past data derived from tracking user movements and time taken to complete specific types of tasks. For instance, if a user has a task that is due at 9:00 AM, the app could send a notification to the user&amp;rsquo;s phone at 8:45 AM if the user is at home, but at 8:30 AM if the user is at work once the travel time could reliably be estimated from prior activities.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="6-conclusion"&gt;6 Conclusion&lt;/h2&gt;
&lt;h2 id="61-salient-takeaways"&gt;6.1 Salient takeaways&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;ProductiviDo&lt;/strong&gt; set out to fathom the needs of the modern-day, demanding user and to provide a novel solution to the problem of task management and scheduling. The application was designed from the start to work alongside Google Calendar, which is a popular calendar application that is used by many millions of people around the world. The application was designed to be a simple and intuitive task manager that would allow users to create tasks and events, to schedule them, and to track their progress. While there is room for improvement, &lt;strong&gt;ProductiviDo&lt;/strong&gt; goes far beyond a proof of concept or &amp;ldquo;&lt;em&gt;Goldilocks Quality&lt;/em&gt;&amp;rdquo; and shows how it can be used by anyone who wants to manage their tasks and schedule more efficiently, as it relies on strong scientific foundations that were dispersed throughout this work as convincing evidence backing up such a claim.&lt;/p&gt;
&lt;p&gt;One of the key takeaways from this work is that despite a crowded task management digital market, innovation can take place by taking inspiration from different fields and by applying them to the problem at hand. In the case of &lt;strong&gt;ProductiviDo&lt;/strong&gt;, the needs of business users and productivity seekers alike were distilled into an almost mechanical process, where the application flow is extremely simple and strives to put forward in a visually sensible manner all the required functionality to get work done without friction: this meant taking a few assumptions about users for granted, knowingly reducing the user base to better serve those who will resonate with the offering.&lt;/p&gt;
&lt;p&gt;There are a few dominant players in the industry, albeit niches are still well underserved. Almost every software application out there in this space endeavors to serve customers in a very generic way, but it could be flourishingly argued that a task manager could be designed to serve a specific industry. For instance, a task manager for a construction company could be designed to be more intuitive for construction workers, who are not necessarily computer savvy, and could be designed to be more efficient for project managers, who are likely to be more tech-savvy. The same could be said for a task manager for a law firm, a task manager for a restaurant, or a task manager for a school. The possibilities are endless, and the key is to understand the needs of the users and to design the application to be as intuitive as possible. Even though &amp;ldquo;task templates&amp;rdquo; can, up to a point, be used to achieve this, nothing competes with a well-designed application that is tailored to the needs of a well-known target audience. Such applications will by definition be adopted within a given niche and will dispense unique value to the users. A generic task manager may be suitable for simple projects and may require fiddling around with the settings to get it to work for a specific use case, but a task manager dedicated to culinary chefs will natively understand and care for concepts such as &amp;ldquo;ingredients&amp;rdquo; and &amp;ldquo;recipes&amp;rdquo;, which will be baked into the product (no pun intended).&lt;/p&gt;
&lt;h2 id="62-improvements-and-future-research"&gt;6.2 Improvements and future research&lt;/h2&gt;
&lt;p&gt;Even though Google users abound, using exclusively Google Calendar as an calendar integration is not a universal solution. In the future, it would be interesting to explore the possibility of integrating other calendar applications such as Apple Calendar, Outlook, and others. This would allow users to use the application with their preferred calendar application and would also allow for a more seamless integration with the calendar application, which would be a great benefit to users.&lt;/p&gt;
&lt;p&gt;Expanding on the notion of &amp;ldquo;delegatees&amp;rdquo; explored in this project, a task manager with built-in collaboration would be welcome to further satisfy the needs of business users. This is because a calendar can become social and collaborative by itself, and it is not uncommon for colleagues or friends to share their calendars with others. This is especially true for business users, who often need to coordinate their activities with other members of their team. It would certainly not be far-fetched to have business teams be formed and given access to their shared task assignments and calendars. This would allow for a more efficient and transparent way of working together, and it would also allow for a more efficient way of tracking the progress of a project and would pave the way to generating insightful analytics dashboards, another place where machine learning would shine by finding patterns and making it possible to optimize overlapping schedules and projects based on people&amp;rsquo;s availability, area of expertise and so on.&lt;/p&gt;
&lt;p&gt;Recent reports have shown that job creation and entrepreneurship is at its highest peak and that the United States of America is leading the way in terms of new business creation, with literally millions of companies being born each year. This is a great sign for the economy and it shows numerous opportunities in the business world when considering task managers embarking on a journey to become a collaborative platform for teams and businesses within a specific line of work. In the meantime, &lt;strong&gt;ProductiviDo&lt;/strong&gt; comes to the rescue of the millions of people who are looking for simplicity and intuitiveness in a task manager to get their work done with less technological grinding.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="demo-of-the-app"&gt;Demo of the app&lt;/h2&gt;
&lt;div class="youtube youtube-16x9"&gt;
&lt;iframe src="https://www.youtube.com/embed/l_5JRL1UDzY" allowfullscreen seamless frameBorder="0"&gt;&lt;/iframe&gt;
&lt;/div&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Sun, 30 Jul 2023 18:44:00 -0600</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/building-task-planner-react-native/</guid><category>learnings</category><category>bsc</category><category>lessons</category><category>mobile-dev</category><category>react-native</category></item><item><title>Reviewing the process of building a first React Native application</title><link>https://www.sglavoie.com/posts/reviewing-the-process-of-building-a-first-react-native-application/</link><description>Working with new technologies can be exciting and insightful at the same time! At least, this is what I would like to believe after having dedicated a couple of weeks to this project…</description><content:encoded>&lt;hr&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the context of an assignment as part of a BSc in computer science, I had to come up with a React Native application. Specifically, I chose to build an app to help make and break habits through the use of a solid system that&amp;rsquo;s backed by science, which is presented through a large excerpt that accompanied the end result. It helps people to consistently stick to habits until they become an intrinsic part of their routine. Moreover, it helps to maintain an actual routine and to build a sense of accountability and capability in oneself, because big successes come from small steps taken in the right direction time and time again.&lt;/p&gt;
&lt;p&gt;Instead of giving dopaminergic hits like other apps which strive to reward their users in one way or another for completing their tasks and goals or generating anxiety around items not being completed, this app focuses on giving full control to the user with a proven system to turn their habits into automated behaviours with ease. That was the idea, at least.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/app_icon.png"
 alt="App icon Routinizator"
 loading="lazy"
 decoding="async" width="1280" height="720"/&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="concept-development"&gt;Concept development&lt;/h2&gt;
&lt;h2 id="the-origin"&gt;The origin&lt;/h2&gt;
&lt;p&gt;The idea for this application came from listening to the Huberman Lab podcast from Dr. Andrew Huberman in an episode entitled &lt;a href="https://hubermanlab.com/the-science-of-making-and-breaking-habits"&gt;The science of making &amp;amp; breaking habits&lt;/a&gt;. Starting from this excellent learning resource, further literature was devoured to inform the final concept, most notably &lt;a href="https://www.annualreviews.org/doi/abs/10.1146/annurev-psych-122414-033417"&gt;Psychology of Habit from the Annual Review of Psychology&lt;/a&gt; and &lt;a href="https://journals.sagepub.com/doi/full/10.1177/1539449219876877"&gt;Intervention to Modify Habits: A Scoping Review&lt;/a&gt; published in Sage Journals.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/typography.png"
 alt="Typography"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="time-restrictions"&gt;Time restrictions&lt;/h2&gt;
&lt;p&gt;It was entirely feasible to come up with a simpler concept that would be doable in roughly 10 weeks. Like many popular applications on the market today, it is expected that new features will be added after the official release date once additional and valuable feedback is received from users. The core idea can and will be implemented in this short time frame. After all, this application can pivot towards a simpler presentation should there be a need to and as the &lt;a href="https://en.wikipedia.org/wiki/Zen_of_Python"&gt;Zen of Python&lt;/a&gt; says: &lt;em&gt;&amp;ldquo;Simple is better than complex&amp;rdquo;&lt;/em&gt;.
Niceties could be added to the user interface should time allow: however the initial development will focus on a narrower set of features so that the roadmap can be successfully followed and the final product delivered in a timely manner.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/ui_elements.png"
 alt="UI elements"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="main-concern-during-development"&gt;Main concern during development&lt;/h2&gt;
&lt;p&gt;A bad implementation of the system could mean that flexibility could be lost at the cost of ease of development. In other words, due to a strict, looming deadline, some shortcuts could be considered to cut corners in the underlying logic of the application to save time without affecting the quality of the product from the user&amp;rsquo;s perspective. Nonetheless, this could lead to more headache down the road when it becomes necessary to refactor the application in order to satisfy the need for a more modular approach, which would simplify further development.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/screens.png"
 alt="Screens"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="wireframing"&gt;Wireframing&lt;/h2&gt;
&lt;p&gt;Low-fidely as well as high-fidelity wireframes were created using &lt;a href="https://www.figma.com"&gt;Figma&lt;/a&gt;. An exhaustive presentation of the final application was included in an appendix, depicting the logo, the color palette, the typography used, a list of the UI elements and a complete and faithful display of all the screens. Technically, the high-fidelity wireframes were designed using &lt;a href="https://help.figma.com/hc/en-us/articles/360038662654-Guide-to-components-in-Figma"&gt;Figma components&lt;/a&gt; and placed inside &amp;ldquo;frames&amp;rdquo; to export a PDF. Most UI elements were hand-drawn, except for a few free icons taken from the &lt;a href="https://material.io/design"&gt;Material Design community&lt;/a&gt;. Numerous user flow diagrams were included to illustrate how the wireframing took shape once the logic to navigate between screens was determined.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/welcome.png"
 alt="Welcome screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="user-feedback"&gt;User feedback&lt;/h2&gt;
&lt;p&gt;User feedback was critical to the success of this project. Users helped refine certain visual aspects, such as making sure there was enough padding between the different elements by testing with devices using a smaller screen.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/frequency_execution_early.png"
 alt="Frequency execution early"
 loading="lazy"
 decoding="async" width="595" height="486"/&gt;
&lt;/p&gt;
&lt;h2 id="improvements-to-the-original-design"&gt;Improvements to the original design&lt;/h2&gt;
&lt;p&gt;Other notable improvements included redesigning the user flow when creating a new programme so that it would be easier to follow. Instead of dealing with multiple habits at once, the slightly updated design made it possible to fully complete the cycle when adding a new habit. Similarly, once habits were added, the newer flow to tackle habit stacks made it simpler to navigate back to the main screen to confirm the selection of habits and to review the programme as a whole.&lt;/p&gt;
&lt;p&gt;Without users inquiring about having a satellite view in the map, there wouldn&amp;rsquo;t have been any option to toggle the style of the map either. This became a needed addition in places where roads are sparse while the terrain remains easily recognizable.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/about.png"
 alt="About screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="prototyping"&gt;Prototyping&lt;/h2&gt;
&lt;h2 id="early-iterations"&gt;Early iterations&lt;/h2&gt;
&lt;p&gt;While shaping the initial application alongside both wireframing and concept sketching, a few iterations of the different screens were designed from scratch. General ideas and concepts were discussed and analyzed to fit with the goal of creating a mindful habit tracker while taking into consideration hard requirements such as the time available for the development cycles.&lt;/p&gt;
&lt;p&gt;The application started with a strong focus on accountability. However, it was quickly realized that the technical stack would need to be more ample and would necessarily require a higher budget to fund the use of online services to store a database of &lt;em&gt;&amp;ldquo;habit contracts&amp;rdquo;&lt;/em&gt; that users would create and optionally make public on their own. Needless to say, the single developer involved in the creation of this application did not have the resources nor the willingness to deal with legal issues that would arise from managing such personal information.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/iteration_1_flow.png"
 alt="Iteration 1 flow"
 loading="lazy"
 decoding="async" width="595" height="842"/&gt;
&lt;/p&gt;
&lt;h2 id="privacy-concerns"&gt;Privacy concerns&lt;/h2&gt;
&lt;p&gt;Additionally, there would not have been the easy possibility of making accessible all the data from a habit contract since personally identifiable information such as location, accountability partner names and so on would be revealed to the world. For these reasons and many more, the set of features relating to accountability was removed from the application to ensure that user privacy would be dealt with properly at this scale of operation.&lt;/p&gt;
&lt;p&gt;In this regard, to avoid any potential issue with privacy, no data whatsoever is stored remotely. &lt;a href="https://github.com/react-native-async-storage/async-storage"&gt;React Native Async Storage&lt;/a&gt; was used to store data locally on users&amp;rsquo; devices, even removing the need for an internet connection (except for the need to find the user location and set an address, which is an optional step when creating a programme).&lt;/p&gt;
&lt;p&gt;To make use of the async storage, &lt;a href="https://redux-toolkit.js.org"&gt;Redux Toolkit&lt;/a&gt; was used to deal with all the state management and is responsible for dispatching actions throughout the application. Importantly, users do not need to leave the application open at all times since &lt;a href="https://github.com/rt2zz/redux-persist"&gt;Redux Persist&lt;/a&gt; was used to store Redux data to the async storage and to rehydrate it when the application is re-opened.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/iteration_4_flow.png"
 alt="Iteration 4 flow"
 loading="lazy"
 decoding="async" width="595" height="468"/&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="development"&gt;Development&lt;/h2&gt;
&lt;p&gt;As we can now attest, a lot happened before developing the actual application, but this fact did not make the development itself less interesting to narrate! In a little over two months, this React Native application started from nothing and grew to a fully-fledged product.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/new_dashboard.png"
 alt="New programme dashboard"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="initial-setup"&gt;Initial setup&lt;/h2&gt;
&lt;p&gt;The initial steps taken were all about setting up the project correctly with most of its JavaScript dependencies, beginning with a &lt;code&gt;.gitignore&lt;/code&gt; file to prevent adding secrets and other unneeded artifacts to the project, an &lt;code&gt;app.json&lt;/code&gt; to define the metadata required to publish an application with &lt;a href="https://expo.dev"&gt;Expo&lt;/a&gt; and a &lt;code&gt;package.json&lt;/code&gt; listing all the major dependencies to be installed with &lt;a href="https://yarnpkg.com"&gt;Yarn&lt;/a&gt; in this case. Secondly, &lt;a href="https://github.com/infinitered/reactotron"&gt;Reactotron&lt;/a&gt; was set up with Redux to provide access to the application state in real time. Strict mode was then enabled to help avoid bad programming practices and third-party libraries were silenced with React Native&amp;rsquo;s &lt;code&gt;LogBox&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/remove_habit.png"
 alt="Remove habit screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="state-management"&gt;State management&lt;/h2&gt;
&lt;p&gt;Once the basic setup was in place, Redux Persist was added to work with React Native Async Storage. Then, the testing setup was integrated into the project before adding any screen to the application using &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt; configured with mockAsyncStorage to avoid issues with the persistent storage while testing. Despite barebone Redux being useful on its own, &lt;a href="https://redux-toolkit.js.org/tutorials/quick-start"&gt;Redux Toolkit provides some useful utilities and shortcuts&lt;/a&gt; that were taken advantage of, including &lt;code&gt;createSlice&lt;/code&gt; to easily &amp;ldquo;slice&amp;rdquo; parts of the state to retrieve and store information in isolation, &lt;code&gt;combineReducers&lt;/code&gt; to list all the slices of state in the same &amp;ldquo;root reducer&amp;rdquo;, and &lt;code&gt;configureStore&lt;/code&gt; to connect the persistent storage to the Redux store and set up access to the store itself in the rest of the application.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/cues.png"
 alt="Cues screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="styling-the-app"&gt;Styling the app&lt;/h2&gt;
&lt;p&gt;Before adding logic to the project, &lt;a href="https://github.com/vitalets/react-native-extended-stylesheet"&gt;react-native-extended-stylesheet&lt;/a&gt; was used to add functionality to the way the styling could be done by having the ability to reference variables, do calculations inside CSS fragments, etc. Styles were set globally right from the start to avoid code duplication and where deemed useful, some screens had specific stylings applied exclusively to them from separate files.&lt;/p&gt;
&lt;p&gt;As a next step, the general structure of the app was set up with a status bar and a &lt;code&gt;SafeAreaView&lt;/code&gt; component to make sure that rendering happened within safe limits on the screen. In order to style the application and render different screens, &lt;a href="https://reactnavigation.org/"&gt;React Navigation&lt;/a&gt; was used to make the navigation possible and to initially render a fixed screen at a time while it was being designed based off the high-fidelity wireframes. One by one, the screens were designed with all the buttons in the right place and some dummy content to render all the different UI elements. This led to using a multitude of third-party libraries, including notably &lt;a href="https://github.com/react-native-maps/react-native-maps"&gt;react-native-maps&lt;/a&gt; to work with native maps on both Android and iOS devices.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/location.png"
 alt="Location screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="premature-refactoring"&gt;Premature refactoring&lt;/h2&gt;
&lt;p&gt;With the screens in place, the code was re-arranged to allow for better flexibility while developing. New directories for components were created, and the smallest components of all were extracted from the larger ones to start splitting concerns and have specific destinations to receive parts of the states via Redux selectors.&lt;/p&gt;
&lt;p&gt;Global styles were then cleaned up considerably and local styles were mostly eliminated as they were being re-used elsewhere without notice. At this point, without yet having anything useful to demonstrate, users reviewed where the application was going and suggested possible improvements while it was still easy to move UI elements around without breaking anything.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/frequency_execution.png"
 alt="Frequency execution screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="adding-navigation"&gt;Adding navigation&lt;/h2&gt;
&lt;p&gt;Once all the screens were designed and ready to include programmatic logic, the screens were then linked together so that the user could &amp;ndash;without doing anything useful yet&amp;ndash; navigate from one page to another. After that, a menu was included in the top-left corner to navigate to specific pages from anywhere within the app. This behaviour was later customized so that some pages would show the &amp;ldquo;back button&amp;rdquo; (a chevron icon pointing to the left) to make going back to the previous screen easier than scrolling to the bottom of a longer page. On top of this, some screens received a special treatment where the menu is hidden entirely, such as when deleting a programme from the app. While not strictly required, this made it obvious to the user that they should focus on the content of that particular screen.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/programme_specs.png"
 alt="Programme specs screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="customizing-ui-elements"&gt;Customizing UI elements&lt;/h2&gt;
&lt;p&gt;At this stage, the application was ready to receive its final touch-ups to look as polished as the expected product. This included getting our hands on &lt;a href="https://github.com/WrathChaos/react-native-bouncy-checkbox"&gt;React Native Bouncy Checkbox&lt;/a&gt; to give a more joyful feel to the most boring parts of the application and using &lt;a href="https://github.com/react-native-datetimepicker/datetimepicker"&gt;React Native DateTimePicker&lt;/a&gt; to input the time of the day in a more meaningful and straightforward way.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/habit_stacks.png"
 alt="Habit stacks screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="setting-up-simple-states"&gt;Setting up simple states&lt;/h2&gt;
&lt;p&gt;Using the &lt;code&gt;useState&lt;/code&gt; hook from React and &lt;code&gt;useDispatch&lt;/code&gt; from Redux, basic states were set up to toggle the styles of buttons and to allow basic interactivity, such as expanding and collapsing sections of the user interface. Using some dummy content in the Redux store, other simple events were taken care of, for example removing a habit, creating a new habit and so on. With the basic logic and states in place, more complex flows were added, such as the need to loop through habits to display them as &amp;ldquo;habit stacks&amp;rdquo; or looping through the days in a programme to display three phases for each day, each phase containing possibly multiple stacks of habits and each habit being a self-contained source of data with a table displayed with &lt;a href="https://github.com/Purii/react-native-tableview-simple"&gt;react-native-tableview-simple&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/habit_review.png"
 alt="Habit review screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="testing-on-different-platforms"&gt;Testing on different platforms&lt;/h2&gt;
&lt;p&gt;Although admittedly a bit late in the process, the application was then tested fully on Android and in the Expo website. Trading off speed of development for the inconvenience of guaranteeing a pixel-perfect application at each step was most definitely worth it since very few changes were required in the end, this being the main idea behind using something like React Native in the first place so that code can be written once and for all. Despite all these promises, some issues related to dependencies were faced with big, red messages showing an alarmingly large list of errors in the Expo Snack interface. Thankfully, it was only a matter of upgrading locally to match the latest SDK available at the time from Expo (v46.0.0).&lt;/p&gt;
&lt;p&gt;There were some minor issues observed on different platforms which were fixed on the development machine using simulators. For instance, the map view was somewhat laggy on iOS originally, so instead of moving the marker around on the map, it was decided to leave it fix on top of the center of the map with a greater &lt;code&gt;zIndex&lt;/code&gt; to make it visible at all times in order to have only the map view to re-render each time the map was moved. On Android, the time picker was a bit fiddly to work with and so to circumvent the problematic situation, the picker would be shown once automatically to the user when the related screen was opened, removing the need to display a space for the picker on screen and instead having it fill out the screen in the style of a modal.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/habit_contract.png"
 alt="Habit contract review screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="improving-the-developer-experience-with-redux"&gt;Improving the developer experience with Redux&lt;/h2&gt;
&lt;p&gt;Reactotron was useful in the beginning but started to crash very often at this point of the development. After un-starring the project on GitHub and starring &lt;a href="https://github.com/jhen0409/react-native-debugger"&gt;React Native Debugger&lt;/a&gt; instead, things were smooth again. Reactotron required messing a little bit with the testing setup by removing everything related to it first, then React Native Debugger made it all simple again thanks to its seamless integration with Redux which does not need to be injected as middleware when configuring the Redux store.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/programme_progress.png"
 alt="Programme in progress screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="refactoring-again"&gt;Refactoring again&lt;/h2&gt;
&lt;p&gt;Now that most of the logic was implemented, smaller components were created from the monstrous ones created thus far. In most instances, components were already existing on their own but they were all positioned in the same file without being prefixed with the keyword &lt;code&gt;export&lt;/code&gt;. Equally important, all &lt;a href="https://eslint.org/"&gt;ESLint&lt;/a&gt; warnings were cleared up one after the other to avoid re-renders and unused bits of code. Because Expo tends to be picky with missing import statements, &lt;code&gt;import React from ‘react'&lt;/code&gt; was carefully added to almost every file in the project where it was needed.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/delete_programme.png"
 alt="Delete programme screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="last-minute-cleanup"&gt;Last-minute cleanup&lt;/h2&gt;
&lt;p&gt;Finally, once the application was usable and the source code a little more pretty, import statements were grouped by categories, warnings from third-party libraries were silenced with &lt;code&gt;LogBox&lt;/code&gt;, spacing around paragraphs was reviewed and optimized and the app was scrutinized once again to look for the presence of bugs.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/completed_programme.png"
 alt="Completed programme screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="unit-testing"&gt;Unit testing&lt;/h2&gt;
&lt;h2 id="navigating"&gt;Navigating&lt;/h2&gt;
&lt;p&gt;While the development took place, testing happened all along. The first couple of tests to be included in the test suite were added while validating that navigation occurred correctly between screens. At once, tests were also added when creating the screens to make sure that they would render consistently in the UI by creating snapshots with Jest.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/iteration_6_flow.png"
 alt="Iteration 6 flowchart"
 loading="lazy"
 decoding="async" width="595" height="740"/&gt;
&lt;/p&gt;
&lt;h2 id="utility-functions"&gt;Utility functions&lt;/h2&gt;
&lt;p&gt;More concrete unit testing happened with the utility functions being called by the actions from the Redux store. Because these functions define what happens when an action is dispatched with Redux, there is a lot of potential for bugs to creep in. To make debugging less painful in these cases, dummy and minimal states were set up as part of the unit tests to check for inconsistencies against the input value and the expected one. While Jest offers a complete range of features, the matchers used most often from this library were &lt;code&gt;toBe&lt;/code&gt; to check for exact values (e.g., Boolean and numbers) and &lt;code&gt;toEqual&lt;/code&gt; to assert a deep equality on objects and arrays. Mock functions were set up with Reactotron, but that need went away when the developer migrated to a more stable piece of software (i.e, React Native Debugger).&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/early_new_programme.png"
 alt="Early new programme"
 loading="lazy"
 decoding="async" width="595" height="842"/&gt;
&lt;/p&gt;
&lt;h2 id="database--asynchronous-code"&gt;Database &amp;amp; asynchronous code&lt;/h2&gt;
&lt;p&gt;In the future, should this application be deployed to the cloud, there will be a need to use setup and teardown functionality against a database and to add tests for asynchronous calls. This was not required for the present version of the application, which focuses on allowing users to be as independent as possible from the Internet while respecting their privacy.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/later_new_programme_flow.png"
 alt="Later new programme flow"
 loading="lazy"
 decoding="async" width="595" height="842"/&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="evaluation"&gt;Evaluation&lt;/h2&gt;
&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;All in all, despite a strict deadline and few (more truthfully, close to none) monetary resources, it was possible to deliver a working solution to a tangible problem, namely that of increasing productivity by knowing what is most valued in one&amp;rsquo;s life circumstances. While the application can be considered feature-complete, it could be the beginning of a long journey towards sharing an application that has real potential to improve people&amp;rsquo;s lives by solving a problem that is hard to pinpoint without enough awareness.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/new_programme.png"
 alt="New programme screen"
 loading="lazy"
 decoding="async" width="595" height="843"/&gt;
&lt;/p&gt;
&lt;h2 id="technical-aspects"&gt;Technical aspects&lt;/h2&gt;
&lt;p&gt;On the technical side of things, it would have been preferable to split the state in a more logical way right from the beginning. Even though a general idea of the state was drawn inside an IDE by creating a JSON object to represent the schema to be adhered to, the state was allowed to mutate along the way, which caused issues by having to move reducers around and by having to update the selectors to look at a different hierarchy of the state. By contemplating the real meaning of a Redux &amp;ldquo;slice&amp;rdquo; in which the state is meant to be entirely independent from other slices of the state, it makes it obvious that some types of object will remain independent while others will eventually require to communicate with their siblings. Thinking this logic through before starting to make things happen in the UI is, in hindsight, a fruitful endeavour.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/new_programme_flow.png"
 alt="New programme flow"
 loading="lazy"
 decoding="async" width="595" height="378"/&gt;
&lt;/p&gt;
&lt;h2 id="communicational-aspects"&gt;Communicational aspects&lt;/h2&gt;
&lt;p&gt;On the soft skills side, a mistake was made by not sharing the original concept with users sooner. Although the final product would likely resemble what it ended up being, interactivity in the application could have been designed better regarding some aspects. For example, the component responsible for displaying the frequency of execution could very well become an actual calendar. Designed in a compact way, a calendar surely would be more familiar to most users instead of having a list that needs to be scrolled into view. Functionally speaking, ticking a box in a calendar-like view would be exactly equivalent to checking off a box next to a row item in a list, but the presentation would be more familiar to most users and, quite understandably, more intuitive too.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0035_building_first_react_native_application/finish_flow.png"
 alt="Finish flow"
 loading="lazy"
 decoding="async" width="595" height="842"/&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="demo-of-the-app"&gt;Demo of the app&lt;/h2&gt;
&lt;div class="youtube youtube-16x9"&gt;
&lt;iframe src="https://www.youtube.com/embed/d9PAO_Ehza4" allowfullscreen seamless frameBorder="0"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="resources-and-references"&gt;Resources and references&lt;/h2&gt;
&lt;p&gt;If you like this type and format of content, you might also enjoy &lt;a href="https://www.sglavoie.com/posts/building-task-planner-react-native/"&gt;a follow-up story about building a task planner&lt;/a&gt;, also brought to life with the help of React Native!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.annualreviews.org/doi/abs/10.1146/annurev-psych-122414-033417"&gt;Annual Reviews, Psychology of Habit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eslint.org/"&gt;ESLint, Find and fix problems in your JavaScript code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://expo.dev"&gt;Expo, Make any app. Run it everywhere&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.figma.com/hc/en-us/articles/360038662654-Guide-to-components-in-Figma"&gt;Figma, Guide to components in Figma&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.figma.com"&gt;Figma, Nothing great is made alone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hubermanlab.com/the-science-of-making-and-breaking-habits"&gt;Huberman Lab, THE SCIENCE OF MAKING &amp;amp; BREAKING HABITS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jestjs.io"&gt;Jest, Delightful JavaScript Testing Framework with a focus on simplicity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://material.io/design"&gt;Material Design, Create intuitive and beautiful products with Material Design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/react-native-async-storage/async-storage"&gt;React Native Async Storage, An asynchronous, persistent, key-value storage system for React Native&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/WrathChaos/react-native-bouncy-checkbox"&gt;React Native Bouncy Checkbox - Fully customizable animated bouncy checkbox for React Native&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/react-native-datetimepicker/datetimepicker"&gt;React Native DateTimePicker - React Native date &amp;amp; time picker com- ponent for iOS, Android and Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jhen0409/react-native-debugger"&gt;React Native Debugger - The standalone app based on official debugger of React Native, and includes React Inspector / Redux DevTools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reactnavigation.org/"&gt;React Navigation - Routing and navigation for Expo and React Native apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vitalets/react-native-extended-stylesheet"&gt;react-native-extended-stylesheet - Extended StyleSheets for React Native&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/react-native-maps/react-native-maps"&gt;react-native-maps - React Native Mapview component for iOS + Android&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Purii/react-native-tableview-simple"&gt;react-native-tableview-simple - Flexible and lightweight React Native component for UITableView made with pure CSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/infinitered/reactotron"&gt;Reactotron - A desktop app for inspecting your React JS and React Native projects. macOS, Linux, and Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rt2zz/redux-persist"&gt;Redux Persist, Persist and rehydrate a redux store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://redux-toolkit.js.org/tutorials/quick-start"&gt;Redux Toolkit, Redux Toolkit Quick Start&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://redux-toolkit.js.org"&gt;Redux Toolkit, The official, opinionated, batteries-included toolset for efficient Redux development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://journals.sagepub.com/doi/full/10.1177/1539449219876877"&gt;Sage Journals, Intervention to Modify Habits: A Scoping Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Zen_of_Python"&gt;Wikipedia, Zen of Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://yarnpkg.com"&gt;Yarn, Safe, stable, reproducible projects&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Sat, 04 Mar 2023 12:41:00 -0600</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/reviewing-the-process-of-building-a-first-react-native-application/</guid><category>learnings</category><category>bsc</category><category>lessons</category><category>mobile-dev</category><category>react-native</category></item><item><title>Building the next Facebook in a couple of weeks (as a humble experiment)</title><link>https://www.sglavoie.com/posts/building-the-next-facebook-in-a-couple-of-weeks-as-a-humble-experiment/</link><description>To spice things up, I am posting a reformatted version of the report I wrote for a web development assignment done during the last year of a computer science degree at the undergraduate level. Facebook should remain a dominant social media platform for a little while longer…</description><content:encoded>&lt;hr&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The following is a report that was part of a project I delivered during my BSc in computer science, reformatted from LaTeX to Markdown. While not being utterly interesting (unfortunately, the source code cannot be freely published due to the nature of the work&amp;hellip;), it gives a glimpse of my thought process while building this Django website. I have learnt a few lessons from it and maybe, with some imagination, you might too :). To read a nicely formatted version of this article, you can refer to the &lt;a href="https://www.sglavoie.com/files/posts/0032_building_the_next_Facebook_in_a_couple_of_weeks_as_a_humble_experiment/report.pdf"&gt;original report&lt;/a&gt; instead.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="meeting-the-requirements"&gt;Meeting the requirements&lt;/h2&gt;
&lt;p&gt;In order to meet all the requirements when building this application, a few different techniques, strategies and concepts were put to good use. Firstly, all &lt;a href="https://www.djangoproject.com/"&gt;Django&lt;/a&gt; views are class-based and rely on &lt;a href="https://www.django-rest-framework.org/"&gt;Django REST Framework&lt;/a&gt; to reduce the boilerplate needed to write the views. One such (simple) view is shown below:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;python&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Profiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;APIView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;Used when listing all profiles at once.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# allow everyone to see all basic profiles&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;permission_classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;IsOwnerOrReadOnly&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;profiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;-id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;serializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ProfileSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;many&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;All views in turn rely on serializers to parse incoming data and to transform it into appropriate structures that can be used internally by Django. Some serializers are obviously more complex than others, but for demonstration purposes and for the sake of brevity, an example of a class-based serializer is reproduced here:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;python&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserPublicSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;Serializer the User model to get back user information that can
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; safely be shared around in the application to other users.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# We need easy access to the profile image when listing all profiles&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# at once&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;profile_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SerializerMethodField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;profile_image&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_profile_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userprofile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The actual implementation details for signals, forms, URLs, other views and components can be explored in the source code submission provided with this report.&lt;/p&gt;
&lt;p&gt;When it comes to version control, Git was used religiously with GitHub to host a private repository. The &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/"&gt;Conventional Commits specification&lt;/a&gt; was followed to help create meaningful commit messages.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0032_building_the_next_Facebook_in_a_couple_of_weeks_as_a_humble_experiment/commits.png"
 alt="Git log extract"
 loading="lazy"
 decoding="async" width="1110" height="800"/&gt;
&lt;/p&gt;
&lt;p&gt;Defensive coding strategies were used, both in Python and in JavaScript. In the backend, exceptions were raised directly where no appropriate actions could be taken:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;python&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;clean_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;Verify that the email is available.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cleaned_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;email&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;query_set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;query_set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;email is taken&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In the views, conditional statements were sprinkled everywhere where necessary to avoid expansive computations (e.g., processing a profile image when the request is invalid) and to return early from functions:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;python&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Profile not found!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_404_NOT_FOUND&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;You do not have the required permissions &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;to update this profile!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_401_UNAUTHORIZED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;serializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ProfileUpdateSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;many&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;On the frontend, a kindred approach was used to assemble robust requests:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;javascript&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REACT_APP_API_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;/auth/jwt/verify/`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;token_not_valid&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AUTHENTICATED_SUCCESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AUTHENTICATED_FAIL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AUTHENTICATED_FAIL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With security in mind, views were by default protected and accessible only to authenticated users unless a statement such as the following allows all users to read an endpoint:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;python&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;permission_classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;IsOwnerOrReadOnly&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Requirements were also exceeded by using advanced techniques and tools: &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt;, &lt;a href="https://docs.docker.com/compose/"&gt;Docker Compose&lt;/a&gt;, &lt;a href="https://python-poetry.org/"&gt;Poetry&lt;/a&gt;, &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt;, &lt;a href="https://redux.js.org/"&gt;Redux&lt;/a&gt;, &lt;a href="https://mui.com/"&gt;Material UI&lt;/a&gt; as well as setting up an SMTP backend to send emails to users were some of the additions made to the project to prove this claim &amp;ndash; these will be covered in more details in later sections of this report.&lt;/p&gt;
&lt;p&gt;While being a simple application considering time constraints and budget, the solution brings some novelty to the table, making it a valid application that is production-ready while also serving as an excellent prototype for a much bigger project. Some interesting features not commonly found elsewhere include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Being able to chat in real-time with all users of the platform in a time-sensitive context in a way that supports high concurrency with &lt;a href="https://channels.readthedocs.io/en/stable/"&gt;Django Channels&lt;/a&gt; and &lt;a href="https://redis.io/"&gt;Redis&lt;/a&gt;. In other words, messages disappear automatically after a specified delay, making for a special chat room where one lives in the moment.&lt;/li&gt;
&lt;li&gt;The application allows users to easily follow others to then be able to quickly search through their posts by filtering them. The added tweak resides in the fact that all posts are given &amp;ldquo;total points&amp;rdquo; without &amp;ldquo;up&amp;rdquo; or &amp;ldquo;down&amp;rdquo; counts being disclosed directly.&lt;/li&gt;
&lt;li&gt;Posts can be hidden at any time by users yet remain viewable by showing the author as being anonymous.&lt;/li&gt;
&lt;li&gt;The colourful profile list view allows filtering of all the profiles at once by name and shows distinctive information about users, such as the list of people they follow or the list of people who are following them as a non-obstrusive modal (Material UI pop-up).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As will be discussed in the section &lt;a href="#state-of-the-art-in-web-development"&gt;State of the art in web development&lt;/a&gt;, this solution follows best practices and aims to represent the state of the art, both in terms of technical execution and in the contemporary look of the final product, which is brought into the spotlight in the following figures.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="running-the-application"&gt;Running the application&lt;/h2&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0032_building_the_next_Facebook_in_a_couple_of_weeks_as_a_humble_experiment/demo1.png"
 alt="Homepage feed and left navigation in the student social network demo"
 loading="lazy"
 decoding="async" width="2349" height="622"/&gt;
&lt;/p&gt;
&lt;h2 id="installing-and-running-the-web-application"&gt;Installing and running the web application&lt;/h2&gt;
&lt;h3 id="accessing-user-accounts"&gt;Accessing user accounts&lt;/h3&gt;
&lt;p&gt;All accounts are registered with the same password: &lt;code&gt;pass1234&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To log in, simply use one of the following email addresses:&lt;/p&gt;
&lt;div class="code-block code-block--wrap"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;admin admin@gmail.com (superuser for Django admin)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Andrea andrea@gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Bob uol.grader@gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Hider hider@gmail.com (hidden profile)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Mia mamamia@gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Suliman suliman@gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Tuan tuan@gmail.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you set the &lt;code&gt;SEND_ACTIVATION_EMAIL&lt;/code&gt; setting to &lt;code&gt;True&lt;/code&gt; in the configuration file &lt;code&gt;socialnetwork/settings.py&lt;/code&gt;, emails will be sent from the account &lt;code&gt;uol.grader@gmail.com&lt;/code&gt;, which is a real account created to manage emails for this application.&lt;/p&gt;
&lt;h3 id="running-locally"&gt;Running locally&lt;/h3&gt;
&lt;h4 id="backend"&gt;Backend&lt;/h4&gt;
&lt;p&gt;To avoid a layer of abstraction as setting up Redis on some systems may be more difficult, Django&amp;rsquo;s backend is used for the channels by default. Should you require to use Redis instead, please follow the instructions in &lt;code&gt;settings.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;python&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;CHANNEL_LAYERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;BACKEND&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;channels.layers.InMemoryChannelLayer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# To use Redis locally, please comment the above line and uncomment the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# following two dicts:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CHANNEL_LAYERS = {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# &amp;#34;default&amp;#34;: {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# &amp;#34;BACKEND&amp;#34;: &amp;#34;channels_redis.core.RedisChannelLayer&amp;#34;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# &amp;#34;CONFIG&amp;#34;: {&amp;#34;hosts&amp;#34;: [(&amp;#34;redis&amp;#34;, 6379)]},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# }&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# }&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CACHES = {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# &amp;#34;default&amp;#34;: {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# &amp;#34;BACKEND&amp;#34;: &amp;#34;django_redis.cache.RedisCache&amp;#34;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# &amp;#34;LOCATION&amp;#34;: [(&amp;#34;redis&amp;#34;, 6379)],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# &amp;#34;OPTIONS&amp;#34;: {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# &amp;#34;CLIENT_CLASS&amp;#34;: &amp;#34;django_redis.client.DefaultClient&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# },&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# }&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then, a simple way to get Redis running would be to launch it with Docker:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -d -p 6379:6379 redis&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Moving on to installing Django and the rest of the dependencies for the backend:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; backend
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Activate a virtual environment, e.g.:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 -m venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Install dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install -r requirements.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Run the server on port 8000 with existing data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python manage.py runserver&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Dependencies can also be installed with Poetry thanks to the provided files &lt;code&gt;pyproject.toml&lt;/code&gt; and &lt;code&gt;poetry.lock&lt;/code&gt; with the following command:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;poetry install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To keep the Docker image simple, &lt;code&gt;pip&lt;/code&gt; is used to install the requirements, although beware that Poetry&amp;rsquo;s dependency resolver will be more predictable in a production application.&lt;/p&gt;
&lt;h4 id="frontend"&gt;Frontend&lt;/h4&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; frontend
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Install dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm install
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Run the server on port 3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm run start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Access the application at &lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="using-docker"&gt;Using Docker&lt;/h4&gt;
&lt;p&gt;A &lt;code&gt;docker-compose.yaml&lt;/code&gt; has been prepared to launch all the required parts at once (Redis, Django and React).&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose build
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose up -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Some other useful commands:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose down
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose logs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose ps -a&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This container could be set up to run in a cloud infrastructure such as Google Cloud Platform inside a virtual machine. This setup goes above and beyond what was taught in this module, though, therefore resources were not allocated to the actual deployment.&lt;/p&gt;
&lt;h3 id="local-deployment"&gt;Local deployment&lt;/h3&gt;
&lt;p&gt;An alternative to the (costly and unfunded) deployment on GCP can be done on a local machine, using Docker to containerize the application and a service like Cloudflare Tunnel to allow traffic from the external world to reach the application, effectively converting the machine into a server.&lt;/p&gt;
&lt;h4 id="summary-of-the-steps-needed-to-deploy-locally"&gt;Summary of the steps needed to deploy locally&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Buy/use a domain name and configure its DNS with Cloudflare.&lt;/li&gt;
&lt;li&gt;Update Django&amp;rsquo;s &lt;code&gt;settings.py&lt;/code&gt; to allow the domain name to reach the Django application &amp;ndash; avoiding CORS issue when localhost:3000 tries to connect to localhost:8000 using that domain &amp;ndash; (i.e. &lt;code&gt;ALLOWED_HOSTS&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Install the CLI tool &lt;code&gt;cloudflared&lt;/code&gt;, log in to your Cloudflare account with &lt;code&gt;cloudflared tunnel login&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create a new tunnel: &lt;code&gt;cloudflared tunnel create test-tunnel&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Route that tunnel: &lt;code&gt;cloudflared tunnel route dns &amp;lt;T&amp;gt; &amp;lt;N&amp;gt;&lt;/code&gt;, where &lt;code&gt;&amp;lt;N&amp;gt;&lt;/code&gt; is the web address to use as a sub-domain and &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt; is the tunnel ID.&lt;/li&gt;
&lt;li&gt;Add this sub-domain to the DNS management console in the Cloudflare dashboard.&lt;/li&gt;
&lt;li&gt;Configure Cloudflare to use the web application:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block code-block--wrap"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# ~/.cloudflared/config.yml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;url: http://localhost:3000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tunnel: SOME_ID_GIVEN_BY_CLOUDFLARE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;credentials-file: ~/.cloudflared/SOME_ID_GIVEN_BY_CLOUDFLARE.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Finally, run the tunnel with &lt;code&gt;cloudflared tunnel run&lt;/code&gt; and go to the configured website at its subdomain (e.g., &lt;code&gt;name.domain.com&lt;/code&gt;).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="functionality-implemented"&gt;Functionality implemented&lt;/h2&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0032_building_the_next_Facebook_in_a_couple_of_weeks_as_a_humble_experiment/demo2.png"
 alt="Profile page with user details and activity in the student social network demo"
 loading="lazy"
 decoding="async" width="2336" height="430"/&gt;
&lt;/p&gt;
&lt;p&gt;This application implements all the necessary functionality at the account management level with Djoser. In effect, users can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sign up for a new account;&lt;/li&gt;
&lt;li&gt;Activate their account via email upon creation (this behaviour is disabled by default for convenience but can be reactivated as mentioned earlier);&lt;/li&gt;
&lt;li&gt;Reset their password via email;&lt;/li&gt;
&lt;li&gt;Log into their account;&lt;/li&gt;
&lt;li&gt;Change their displayed name;&lt;/li&gt;
&lt;li&gt;Make their profile hidden to other users;&lt;/li&gt;
&lt;li&gt;Log out from their account;&lt;/li&gt;
&lt;li&gt;Delete their account permanently by validating their password.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;User profiles provide the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Number of followers as well as a complete list of followers shown;&lt;/li&gt;
&lt;li&gt;Number of people that a user is following as well as a complete list of these people;&lt;/li&gt;
&lt;li&gt;Number of points a user has &amp;ldquo;given&amp;rdquo; to posts they like;&lt;/li&gt;
&lt;li&gt;Number of points a user has &amp;ldquo;taken&amp;rdquo; from posts they dislike;&lt;/li&gt;
&lt;li&gt;Where the user is located;&lt;/li&gt;
&lt;li&gt;Each user can display a biography;&lt;/li&gt;
&lt;li&gt;The date at which a user joined the social network;&lt;/li&gt;
&lt;li&gt;The latest date at which the user updated their profile;&lt;/li&gt;
&lt;li&gt;A &amp;ldquo;status&amp;rdquo; field to prominently feature a statement, which is also shown in the profile listing;&lt;/li&gt;
&lt;li&gt;A list of posts written by the user, where the owner can create new posts, delete, edit or hide existing posts so they are no longer displayed publicly in their profile nor in the list of public posts;&lt;/li&gt;
&lt;li&gt;An image gallery the user has uploaded, where the owner can add or remove pictures;&lt;/li&gt;
&lt;li&gt;The ability for each user to delete their account, effectively cascading a delete of their interactions in the application such as their posts, profile image, etc.;&lt;/li&gt;
&lt;li&gt;Users can edit the information they share with others;&lt;/li&gt;
&lt;li&gt;To avoid profile pictures slowing down navigation &amp;ndash; most notably in the profile list view &amp;ndash; all images are automatically resized to maximum 300 by 300 pixels when a user uploads a new image;&lt;/li&gt;
&lt;li&gt;Finally, users can also hide their profile entirely &amp;ndash; doing so will then mark all their posts as being anonymous and they will not be reachable by any other user of the network.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Following the &amp;ldquo;profile&amp;rdquo; view, the &amp;ldquo;profile list&amp;rdquo; view (linked with the text &amp;ldquo;&lt;strong&gt;Meet&lt;/strong&gt;&amp;rdquo; in the navigation bar) shows all public profiles with most of the information users share. To view the details of a profile (such as a birth date and the date of the last edit of a user), it is necessary to be authenticated, otherwise unauthenticated users will be redirected back to the &amp;ldquo;profile list&amp;rdquo; view and an error alert will be flashed. Additionally, the number of followers and people users are following are displayed right from the list view and allow to click to retrieve a complete list of people who are followed. The different icons shown on this page really pop out: the more followers a user has, the bigger the number of people shown in the actual icon representation; also, an icon indicating a value of &amp;ldquo;0&amp;rdquo; is slightly greyed out for readability and to let users know they won&amp;rsquo;t be able to interact with these icons.&lt;/p&gt;
&lt;p&gt;As a distinctive mark of interest, everything belonging to a user is marked with a fingerprint icon: when a user views their own profile or posts, they will be able to quickly identify that this information is theirs as long as they are logged in.&lt;/p&gt;
&lt;p&gt;Posts implement a basic editing view and allow their author to hide them. Furthermore, posts receive and lose points based on the opinions of users in the network and will end up with positive or negative scores, similar to what &lt;a href="https://www.reddit.com/"&gt;Reddit&lt;/a&gt; and &lt;a href="https://stackoverflow.com/"&gt;Stack Overflow&lt;/a&gt; have done but without splitting the count in either direction.&lt;/p&gt;
&lt;p&gt;The &amp;ldquo;&lt;strong&gt;Read&lt;/strong&gt;&amp;rdquo; page &amp;ndash; to be found in the navigation bar &amp;ndash; shows posts from people users follow at the top, allowing to filter the content of posts based on their interests. The total number of points is shown next to each post entry. As a section section on that page, users have the ability to see a list of public posts as well as search for keywords of interest, just like in the first section just described.&lt;/p&gt;
&lt;p&gt;On any page that gets longer than 500 pixels when scrolling down, there will be a little arrow icon allowing users to swiftly glide to the top of the page.&lt;/p&gt;
&lt;p&gt;When clicking on the avatar icon displayed in the top-right corner of the application, a &amp;ldquo;drawer&amp;rdquo; (in &lt;a href="https://mui.com/"&gt;Material UI&lt;/a&gt;&amp;rsquo;s terms) will open to allow users to quickly jump to their profile and to log out of the application.&lt;/p&gt;
&lt;p&gt;Behind the scenes, administrators and superusers can be created with full privileges to modify and delete other accounts. These special accounts will be hidden by default from the public-facing frontend, although their profile can later be made public and used as any other account on the website.&lt;/p&gt;
&lt;p&gt;Last but not least, there is a public chat room where all users of the application can go to have a spontaneous discussion. In fact, the web application is programmed to automatically discard messages that are older than 20 seconds (by default), allowing users to share special moments that are very much unique and time-limited while avoiding being overwhelmed by content. In the event that a constant flow of messages might be entering the chat room at a given time, users will still have the ability to scroll up in the view (assuming they read fast enough). If they do not scroll up, the view will always focus on the latest incoming message so their attention span will be maintained on this very moment. Every time a user reloads the page or goes somewhere else in the application, the content of the chat window will disappear on purpose, because good discussions are meant to happen in real-time on this website. Users will not be distracted by anything else other than a little avatar icon and people&amp;rsquo;s names so they can know at a glance who is interacting with them&amp;hellip; but they will need to have a good memory to remember everything. After all, the idea behind this chat application really is to exchange some good thoughts in the moment. What lives on is only the memory of time well spent with others.&lt;/p&gt;
&lt;p&gt;At the API level, users can interact with the application directly via API endpoints, provided they send their authentication token should a view have a requirement in this regard. These endpoints are listed succinctly below, but a file &lt;code&gt;openapi-schema.yml&lt;/code&gt; has been provided in the &lt;code&gt;backend&lt;/code&gt; directory for a complete reference.&lt;/p&gt;
&lt;div class="code-block code-block--wrap"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;accounts/ profiles/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;accounts/ profiles/&amp;lt;int:user_id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;accounts/ profiles/&amp;lt;int:user_id&amp;gt;/image
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;accounts/ profiles/&amp;lt;int:pk&amp;gt;/followers
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;accounts/ profiles/&amp;lt;int:pk&amp;gt;/followers/add
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;accounts/ profiles/&amp;lt;int:pk&amp;gt;/followers/remove
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;accounts/ profiles/gallery/add
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;accounts/ profiles/gallery/remove/&amp;lt;int:gallery_pk&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;accounts/ ^media/(?P&amp;lt;path&amp;gt;.*)$
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;api/ posts/&amp;lt;int:pk&amp;gt;/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;api/ posts/author/&amp;lt;int:pk&amp;gt;/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;api/ posts/&amp;lt;int:pk&amp;gt;/up/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;api/ posts/&amp;lt;int:pk&amp;gt;/down/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;api/ posts/&amp;lt;int:pk&amp;gt;/pointsby/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;api/ posts/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="executing-the-unit-tests"&gt;Executing the unit tests&lt;/h2&gt;
&lt;p&gt;To run the unit tests, it is a matter of activating a virtual environment (as described in the section &lt;a href="#running-locally"&gt;Running locally&lt;/a&gt;) and using the built-in &lt;code&gt;test&lt;/code&gt; command provided by Django in the following manner, which must be run from within the &lt;code&gt;backend&lt;/code&gt; directory:&lt;/p&gt;
&lt;div class="code-block" data-prompted&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="code-block__prompt"&gt;$ &lt;/span&gt;python manage.py &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Found &lt;span class="m"&gt;119&lt;/span&gt; test&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Creating &lt;span class="nb"&gt;test&lt;/span&gt; database &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;System check identified no issues &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; silenced&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;..............................................................
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Ran &lt;span class="m"&gt;119&lt;/span&gt; tests in 0.584s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;OK
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Destroying &lt;span class="nb"&gt;test&lt;/span&gt; database &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="logical-approach"&gt;Logical approach&lt;/h2&gt;
&lt;h2 id="frontend-framework-react"&gt;Frontend framework: React&lt;/h2&gt;
&lt;p&gt;The application was designed with the goal in mind of having a modern frontend framework relying on an excellent CSS framework to provide icons and other components. Speaking of components, React was chosen for its strong focus on designing small components that can be reused. Taking advantage of this approach, some components such as the &amp;ldquo;profile intro&amp;rdquo; (the box showing the main information regarding a user profile) are literally displayed on different pages, such as when viewing a single profile or when viewing a list of profiles.&lt;/p&gt;
&lt;p&gt;Similarly, a &amp;ldquo;post&amp;rdquo; entry represents the exact same React component when viewed in isolation or when browsing for many more posts. When search bars are used, these share the same characteristics and behaviors across the page while managing a different state.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0032_building_the_next_Facebook_in_a_couple_of_weeks_as_a_humble_experiment/demo3.png"
 alt="Course discovery page with cards and filters in the student social network demo"
 loading="lazy"
 decoding="async" width="1897" height="1649"/&gt;
&lt;/p&gt;
&lt;h2 id="react-components-and-icons-material-ui"&gt;React components and icons: Material UI&lt;/h2&gt;
&lt;p&gt;On the design side, the presentation of the website was made much more consistent with the help of Material UI, which provides many ready-made React components. The whole application was built around the concept of adding building blocks from Material UI such as a &amp;ldquo;&lt;code&gt;box&lt;/code&gt;&amp;rdquo;, &amp;ldquo;&lt;code&gt;button&lt;/code&gt;&amp;rdquo; or &amp;ldquo;&lt;code&gt;typography&lt;/code&gt;&amp;rdquo; to guarantee that all aspects of the application look homogeneous and with the same modern style.&lt;/p&gt;
&lt;p&gt;Components such as a &amp;ldquo;&lt;code&gt;drawer&lt;/code&gt;&amp;rdquo; and a &amp;ldquo;&lt;code&gt;navbar&lt;/code&gt;&amp;rdquo; really sped up development and were expected to be used extensively right from the start.&lt;/p&gt;
&lt;h2 id="api-django-rest-framework"&gt;API: Django Rest Framework&lt;/h2&gt;
&lt;p&gt;Since the use of Django was mandatory for the backend part of this work, Django REST framework was an ideal choice considering the need for an API to be directly accessible to end-users and to benefit from an easy-to-use toolkit to build an API that can be accessed from React without breaking a sweat.&lt;/p&gt;
&lt;p&gt;Django REST Framework simplifies data serialization and even allows dealing with nested serialization in a straightforward way. Because it comes with powerful features for authentication and permission management, it was also a great option for this specific use case which depend easily on these sets of features which would arguably be very complex, error-prone and time consuming to implement manually.&lt;/p&gt;
&lt;h2 id="user-management-djoser"&gt;User management: Djoser&lt;/h2&gt;
&lt;p&gt;Beyond Django&amp;rsquo;s default user management system, there was a desire to extend the default behaviour, for instance to use an email address instead of a username to authenticate users. Djoser makes these changes and much more a lot more simple, adding easy management of logins, logouts, password confirmation resets, activation emails and so forth.&lt;/p&gt;
&lt;p&gt;By leveraging Django&amp;rsquo;s built-in features with Djoser, the user model can be extended with ease and flexibility.&lt;/p&gt;
&lt;h2 id="asynchronous-communication"&gt;Asynchronous communication&lt;/h2&gt;
&lt;p&gt;To build the chat application, Channels and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API"&gt;WebSocket&lt;/a&gt; were considered as one of the best combination of libraries because they are simple to use and allow high concurrency to be possible. Channels makes it easy to create an asynchronous WebSocket consumer to deal with many users connecting to possibly many different groups: it is therefore an ideal option for a growing social network.&lt;/p&gt;
&lt;p&gt;The WebSocket library in JavaScript is then used to communicate with Channels via the WebSockets technology, sending and receiving messages with additional payload to extend the functionality of the chat application.&lt;/p&gt;
&lt;h2 id="deployment-docker-cloudflare-tunnel"&gt;Deployment: Docker, Cloudflare Tunnel&lt;/h2&gt;
&lt;p&gt;To deploy an application to production, Docker Compose is a robust and reliable solution, especially for this use case where different microservices can be pieced together seamlessly, sharing resources across a single network on different ports.&lt;/p&gt;
&lt;p&gt;Docker makes it possible to containerize parts of the application (i.e., the backend, frontend and in-memory cache database) to be run potentially on many virtual machines in the cloud and Docker Compose makes the process of orchestring an application such as this one much more accessible than configure web servers from start to finish.&lt;/p&gt;
&lt;p&gt;Poetry, a package and dependencies management system for Python, allows requirements to be pinned to specific versions and ensures reproducibility is achieved, which is critically important when it comes to deploying to production. Its dependencies resolver is much more reliable when the exactitude of a list of requirements must be met.&lt;/p&gt;
&lt;p&gt;In terms of deploying a real application on a small scale, &lt;a href="https://www.cloudflare.com/products/tunnel/"&gt;Cloudflare Tunnel&lt;/a&gt; was also considered as it is useful to share prototypes during development and to instantly deploy a local server. Furthermore, it can work hand in hand with Docker Compose and Poetry since a container can be run in the background and the application can be exposed on multiple ports locally without having to configure firewalls.&lt;/p&gt;
&lt;p&gt;Because &lt;code&gt;pip&lt;/code&gt; is traditionally used in the Python world to manage requirements, the command &lt;code&gt;pip freeze&lt;/code&gt; was used to generate a standard list of pinned dependencies, although for an actual deployment to production, an open source alternative like Poetry would likely be preferable.&lt;/p&gt;
&lt;h2 id="formatting-prettier-black-vulture-pylint"&gt;Formatting: Prettier, Black, Vulture, Pylint&lt;/h2&gt;
&lt;p&gt;While code formatting is of utmost importance for readability, it is also a tremendous waste of time to try to do it manually. For this reason, multiple tools were used to aid with this gargantuan task. &lt;a href="https://prettier.io/"&gt;Prettier&lt;/a&gt; was used on the frontend side to format everything related to JavaScript and CSS.&lt;/p&gt;
&lt;p&gt;On the backend side, &lt;a href="https://black.readthedocs.io/en/stable/"&gt;Black&lt;/a&gt; was the primary formatter used. Its use was complemented with &lt;a href="https://pylint.pycqa.org/en/latest/"&gt;Pylint&lt;/a&gt;, which helps to clean up and refactor the code by finding hard-to-spot warnings, such as unnecessary return statements or the use of more complex expressions when an equivalent such as a list comprehension could be used.&lt;/p&gt;
&lt;p&gt;Finally, to keep the code tidy and alive, &lt;a href="https://github.com/jendrikseipp/vulture"&gt;Vulture&lt;/a&gt; was used to find &amp;ldquo;dead&amp;rdquo; code not in used anywhere else. Even if code is well formatted, code that is not needed become a liability. In the source code world, less really is more.&lt;/p&gt;
&lt;h2 id="api-calls-axios"&gt;API calls: Axios&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://axios-http.com/"&gt;Axios&lt;/a&gt; JavaScript library was used for the attractiveness and flexibility of its API. Because it supports fully the Promise API and allow making asynchronous calls with the async/await syntax, it makes for a good tool to communicate with the backend. It has extensive documentation and excellent support on various web platforms including GitHub, which is an important consideration when thinking about deploying an application in the real world.&lt;/p&gt;
&lt;p&gt;There are new and shiny technological options all the time, but a battle-tested software like Axios remain a competent tool apt for the job.&lt;/p&gt;
&lt;h2 id="state-management-redux-and-immer"&gt;State management: Redux and Immer&lt;/h2&gt;
&lt;p&gt;Despite the Context API from React being powerful and easy to use, Redux and &lt;a href="https://immerjs.github.io/immer/"&gt;Immer&lt;/a&gt; really make dealing with state management a breeze. Redux on its own is one of the best in its category to provide state management at scale: its documentation is also fantastic and detailed and its popularity on Stack Overflow is only a plus in its favour should there be a need to fix issues while using it (because there will inevitably be such a need). The Redux workflow with actions being dispatched with types makes sense and adding new features is very fast without having to change existing pieces of states when combining reducers.&lt;/p&gt;
&lt;p&gt;One possible drawback of using plain Redux to manage the store is that states can be mutated and unexpected consequences may ensue. For this reason, Immer was included so that dealing with a Redux store is stripped down to a direct object assignment, where Immer takes care of updating items and even nested items as needed.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="design-and-implementation-decisions"&gt;Design and implementation decisions&lt;/h2&gt;
&lt;p&gt;Because deployment with Docker was a primordial concern, the application was built with a backend that is completely decoupled from a frontend. In fact, with just a little bit of ingenuity, Django could be swapped entirely with another web framework as long as the same endpoints are provided to the frontend with the necessary technologies (such as web sockets) being implemented. In a similar way, the frontend, which is built primarily with React, could be upgraded to another popular alternative such as Vue.js. This gives flexibility and should there be a greater need for optimization once the social network takes off for a real spin, there is the possibility to bundle React with Django by building minimized versions of the assets and shipping everything as a Docker container that can be run on powerful machines in the cloud.&lt;/p&gt;
&lt;p&gt;Beyond this original concern, more concrete decisions were taken. For instance, Django signals were used to simplify how user profiles are created. Instead of allowing users to create a profile from their user account, the experience was unified by transparently automating this process whenever a user account is created such that it is attached to a newly created profile associated with it. Leaving the option to the end-user of manually creating a profile could be confusing at best and lead to unexpected results at worst, where user accounts and user profiles IDs become out of sync, which is a nice side-effect of having them created as well as deleted at the same time.&lt;/p&gt;
&lt;p&gt;From the start, Djoser was chosen to override specific built-in functions performed by Django and to facilitate email management. To integrate Djoser with the administrative bits of the application &amp;ndash; namely, the Django admin interface &amp;ndash; Django forms were used to customize how users are to be registered as well as superusers and staff accounts. By overriding the user creation, it is now possible to update parts of the process with simple configuration variables implemented by Djoser, such as forcing users to retype their passwords or not.&lt;/p&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0032_building_the_next_Facebook_in_a_couple_of_weeks_as_a_humble_experiment/demo4.png"
 alt="Real-time chat view from the student social network demo"
 loading="lazy"
 decoding="async" width="2338" height="1010"/&gt;
&lt;/p&gt;
&lt;p&gt;With Django models, the base model became a &lt;code&gt;UserAccount&lt;/code&gt;, which allow users to join the network. However, the functionality related to account management is kept separate from other features of the application by interfacing with the accounts using a &lt;code&gt;UserProfile&lt;/code&gt; model on which a &lt;strong&gt;user&lt;/strong&gt; field exist. In turn, this model integrates other parts of the models, such as many-to-many relationships with followers and a gallery image model, which is also linked as a many-to-many relationship. Another part of the application implements a &lt;code&gt;Post&lt;/code&gt; model where the &lt;strong&gt;author&lt;/strong&gt; field corresponds to a &lt;code&gt;UserAccount&lt;/code&gt;, effectively linking a different part of the application to the user accounts. Again, a &lt;code&gt;Post&lt;/code&gt; then interfaces with other models to take points into account, which are also linked to user profiles.&lt;/p&gt;
&lt;p&gt;To manage all kinds of POST requests as well as to guarantee that models communicate as expected between each other, serializers using Django REST framework features were used in the process. These generally use a &lt;code&gt;SerializerMethodField&lt;/code&gt; to define more complex behaviors, such as getting all non-hidden followers for a single profile.&lt;/p&gt;
&lt;p&gt;Views were implemented with DRF &lt;code&gt;APIView&lt;/code&gt;, bridging the gap between a RESTful API and the ability to define simple views using methods like &lt;strong&gt;get&lt;/strong&gt; and &lt;strong&gt;delete&lt;/strong&gt;. Views rely on serializers and specify a &lt;code&gt;permission_classes&lt;/code&gt; list of custom values, which were implemented separately in a &lt;code&gt;permissions.py&lt;/code&gt; file. This allows customizing the default behavior so that by default all views require authentication unless explicitly stated otherwise by these permission classes. This is also more secure, preventing users from inadvertently being able to access what should have been protected resources.&lt;/p&gt;
&lt;p&gt;In terms of API definition, simplicity was key: every endpoint regarding authentication is accessed under &lt;code&gt;/auth&lt;/code&gt; while our specific implementation of user accounts is accessed under &lt;code&gt;/accounts&lt;/code&gt;. Additionally, all endpoints to deal with user posts are to be found with an endpoint starting with &lt;code&gt;/posts&lt;/code&gt;. Finally, there is another set of endpoints to work with profiles, these being accessible under &lt;code&gt;/profiles&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The Django chat application, due to its asynchronous nature, uses different technologies behind the scenes, including notably WebSockets. Channels was chosen to implement this portion because it extends Django&amp;rsquo;s capabilities beyond HTTP and is ideally suited for chat applications like the one being built as part of this social network.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="evaluation-of-the-final-product"&gt;Evaluation of the final product&lt;/h2&gt;
&lt;h2 id="what-worked-well"&gt;What worked well&lt;/h2&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0032_building_the_next_Facebook_in_a_couple_of_weeks_as_a_humble_experiment/demo5.png"
 alt="Notifications and activity panel from the student social network demo"
 loading="lazy"
 decoding="async" width="2338" height="1170"/&gt;
&lt;/p&gt;
&lt;p&gt;Opting for React made for a flexible framework that behaves extremely well with Django. React has complete documentation and extensive support offered on different medium, making it ideal for a robust and complex web application. Coupled with Material UI, the frontend aspect of the work was taken care of and didn&amp;rsquo;t need particular attention when developing. For any basic functionality that was not available out of the box in JavaScript, the Lodash library was used to make object comparisons and such much more readable and understandable when multiple conditions were being evaluated in a JSX expression, often with ternary operators.&lt;/p&gt;
&lt;p&gt;The state was managed beautifully with Redux and the Redux Devtools web browser extension, allowing for rapid iterations and feedback where debugging would otherwise become very cumbersome. The &lt;code&gt;useState&lt;/code&gt; hook was used profusely to separate concerns as well.&lt;/p&gt;
&lt;p&gt;Keeping with React, the application was divided into logical sections that made it easy to add new features. Small components were created for different parts of the application, Redux actions and reducers were stored in their respective directories, containers and other higher-order components were given a special place in the frontend hierarchy, utility functions were well organized and accessible, pages and custom hooks also had their own place to reside.&lt;/p&gt;
&lt;p&gt;Deploying with Docker remained a clean process, where a single &lt;code&gt;Dockerfile&lt;/code&gt; was created to power the backend and another &lt;code&gt;Dockerfile&lt;/code&gt; added for the frontend. Finally, all these instructions were put together with a readable &lt;code&gt;docker-compose.yaml&lt;/code&gt; file, which purpose was to join all the different containers in a single place and to allow adding more microservices, such as Redis. Postgres was not used in this version for practical reasons when sharing the source code of the web application with others, but only a few steps would need to be taken to update Django&amp;rsquo;s settings file as well as pulling from DockerHub a suitable image to run Postgres.&lt;/p&gt;
&lt;p&gt;Testing with Django went particularly well: the documentation had a clear guide about testing and any aspect of the application &amp;ndash; serializers, views, models, forms, consumers, signals and so on &amp;ndash; were tested according to the Django standards, leading to a whopping total of 119 passing unit tests, which are to be found inside a &lt;code&gt;tests&lt;/code&gt; directory inside each Django application within the project.&lt;/p&gt;
&lt;h2 id="what-could-have-been-improved"&gt;What could have been improved&lt;/h2&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0032_building_the_next_Facebook_in_a_couple_of_weeks_as_a_humble_experiment/demo6.png"
 alt="Mobile-friendly view of the student social network demo"
 loading="lazy"
 decoding="async" width="2338" height="966"/&gt;
&lt;/p&gt;
&lt;p&gt;Planning of the technical stack could have gone much better. During the experimentation phase in the early steps of this project, good portions of functionality were implemented using Django templates without any frontend framework, except for the CSS framework Bootstrap. Features such as user notifications, personal messaging between two users with the ability to use different &amp;ldquo;inboxes&amp;rdquo; and &amp;ldquo;threads&amp;rdquo; was a very good selling point of the first version of this web application. Alas, due to time constraints, these useful additions were left behind (preserved with a Git history) but did not manage to make it to the final product. It would have been much more productive to take a closer look at the panoply of requirements to be implemented from the very beginning and determining the best fit as early as possible to avoid rewriting code from one framework to another.&lt;/p&gt;
&lt;p&gt;Although Redux was a lifesaver in many circumstances, it was also a hurdle in terms of productivity because of its complexity and different moving parts. Being more careful to not use Redux at all costs everywhere possible, dispatching updates in the application would surely be simplified with the Context API using pure React or even some &lt;code&gt;useEffect&lt;/code&gt; hooks, which were used profusely with good results. Immer was also introduced a bit later in the thought process when dealing with nested JSON objects. Although it made the remaining development easier, it was also probably a red flag meaning that the Redux store could have been simplified into smaller reducers where different selectors could access parts of the store that wouldn&amp;rsquo;t need to be nested objects. This may also indicate a flaw in the way models were implemented, but most likely there were errors made when dispatching messages in a part of the Redux store that really should belong somewhere else. In concrete terms, dispatching an event regarding users inside the &amp;ldquo;user&amp;rdquo; reducer was probably more complicated than simply dealing with all notifications in a different reducer. In actuality, this led to some dispatch actions that did more than one thing, which is not ideal when thinking about the concept of separation of concerns.&lt;/p&gt;
&lt;p&gt;Although this is not perceptible in the final product, Django migrations were at times a pain to work with. This is because the models weren&amp;rsquo;t thought through very well at the beginning and despite the iterative process being an inherent part of software development, iterating over models in Django definitely counts as an exception to the rule where clearly defined models will not cause migrations to break or need to be modified in any way. It would have been more productive to produce well-designed diagrams, depicting the architecture of the application as well as the complete schema of the database to avoid surprises down the road.&lt;/p&gt;
&lt;h2 id="state-of-the-art-in-web-development"&gt;State of the art in web development&lt;/h2&gt;
&lt;p&gt;&lt;img
 src="https://www.sglavoie.com/images/posts/0032_building_the_next_Facebook_in_a_couple_of_weeks_as_a_humble_experiment/source_code.png"
 alt="Source code overview for the student social network project"
 loading="lazy"
 decoding="async" width="718" height="1656"/&gt;
&lt;/p&gt;
&lt;p&gt;On a technical aspect, many parts of this web application conform to modern web standards. The latest stable release versions of libraries were used whenever convenient and/or possible. This non-exhaustive list would include, at the time of this writing, React 17.0.2, Redux 4.1.2, WebSocket 1.0.34 and Material UI 5.5.0 for the frontend. On the backend, Django 4.0.3, Channels 3.0.4, Djoser 2.1.0 and Redis 4.2.0 were used.&lt;/p&gt;
&lt;p&gt;When dealing with dependencies, Poetry was used with great benefit to make sure that Docker containers could be deployed reliably. Using Docker and Docker Compose was another touch that was added since most contemporary software will ship with a Docker solution for convenience. An excellent example in this regard would be PlantUML, a Java-based application to generate diagrams from textual descriptions that can be deployed in only a few seconds via Docker, launching a local server with the full capabilities offered by the piece of software in question. Nowadays, with Docker containers being more secure and very fitting for a deployment to the cloud at most big technology companies, it really is a best practice adopted by good software teams to work with containerized versions of their products.&lt;/p&gt;
&lt;p&gt;The wider community was consulted in an effort to bring the maximum quality possible to the end result. Concretely, advice was taken from prominent figures in the web development world, including &lt;a href="https://www.dennisivy.com/"&gt;Dennis Ivanov&lt;/a&gt; and &lt;a href="https://laithharb.com/"&gt;Laith Harb&lt;/a&gt;, both Django and React experts and &lt;a href="https://coreyms.com/"&gt;Corey Schafer&lt;/a&gt;, an accomplished software developer from the Python world. &lt;a href="https://nigelpoulton.com/"&gt;Nigel Poulton&lt;/a&gt; &amp;ndash; author of Docker Deep Dive &amp;ndash; served as a good reference for the deployment part. &lt;a href="https://realpython.com/"&gt;Real Python&lt;/a&gt; was a godsend with its in-depth articles, for instance about debugging code with Pdb. Less well-known yet high-quality content producers inspired work with Djoser and the implementation of user posts, including &lt;a href="https://www.youtube.com/channel/UCf_Y89gbkB1bJGkmqiQIAnQ"&gt;Bryan Dunn&lt;/a&gt; and &lt;a href="https://www.legionscript.com/"&gt;Legion Script&lt;/a&gt;. &lt;a href="https://www.cloudflare.com/"&gt;Cloudflare&lt;/a&gt; was also one of the best resources used to deploy a secure web server locally and to learn about JSON web tokens and their use specifically with Python. Needless to say, the official documentation from each major framework and tool was referenced all way through, many names which are going to sound familiar by now &amp;ndash; Django REST Framework, React, Redux, Immer.js, Django, Djoser, Channels, etc.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="demo-of-the-app"&gt;Demo of the app&lt;/h2&gt;
&lt;div class="youtube youtube-16x9"&gt;
&lt;iframe src="https://www.youtube.com/embed/LFJfL2ejhAU" allowfullscreen seamless frameBorder="0"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="resources-and-references"&gt;Resources and references&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://axios-http.com/"&gt;Axios&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://black.readthedocs.io/en/stable/"&gt;Black&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/channel/UCf_Y89gbkB1bJGkmqiQIAnQ"&gt;Bryan Dunn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cloudflare.com/products/tunnel/"&gt;Cloudflare Tunnel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cloudflare.com/"&gt;Cloudflare&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.conventionalcommits.org/en/v1.0.0/"&gt;Conventional Commits specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://coreyms.com/"&gt;Corey Schafer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dennisivy.com/"&gt;Dennis Ivanov&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://channels.readthedocs.io/en/stable/"&gt;Django Channels&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.django-rest-framework.org/"&gt;Django REST Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.djangoproject.com/"&gt;Django&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/compose/"&gt;Docker Compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://immerjs.github.io/immer/"&gt;Immer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://laithharb.com/"&gt;Laith Harb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.legionscript.com/"&gt;Legion Script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mui.com/"&gt;Material UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nigelpoulton.com/"&gt;Nigel Poulton&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://python-poetry.org/"&gt;Poetry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://prettier.io/"&gt;Prettier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pylint.pycqa.org/en/latest/"&gt;Pylint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/"&gt;Real Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/"&gt;Reddit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://redis.io/"&gt;Redis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://redux.js.org/"&gt;Redux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/"&gt;Stack Overflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jendrikseipp/vulture"&gt;Vulture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API"&gt;WebSocket&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Fri, 14 Oct 2022 18:49:00 -0500</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/building-the-next-facebook-in-a-couple-of-weeks-as-a-humble-experiment/</guid><category>learnings</category><category>bsc</category><category>django</category><category>lessons</category><category>python</category></item></channel></rss>