From afece502c6538beeeec76beae075c11b95e2b1ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adri=C3=A1n=20Oliva?= <adrian.oliva@cimat.mx>
Date: Mon, 5 Jun 2023 22:07:57 -0600
Subject: New post!

Not so weekly essay.
---
 _posts/2023-05-29-weekly-essay-5.md | 350 ++++++++++++++++++++++++++++++++++++
 1 file changed, 350 insertions(+)
 create mode 100644 _posts/2023-05-29-weekly-essay-5.md

(limited to '_posts')

diff --git a/_posts/2023-05-29-weekly-essay-5.md b/_posts/2023-05-29-weekly-essay-5.md
new file mode 100644
index 0000000..1a8aee3
--- /dev/null
+++ b/_posts/2023-05-29-weekly-essay-5.md
@@ -0,0 +1,350 @@
+---
+title: To-Do App
+categories: [Weekly Essay]
+tags: []
+# math: true
+---
+
+After a long time since the last post, we're back! Let's try to explain our
+latest project: _A To-Do App_.
+
+You can see the complete code on my personal Git page or in my GitHub account.
+
+|                 Personal Git Page                  |                           GitHub                           |
+| :------------------------------------------------: | :--------------------------------------------------------: |
+| [Front End](https://cgit.hisiste.com/ToDo-App-FE/) | [Front End](https://github.com/Hisiste/ToDo-App-Front-End) |
+| [Back End](https://cgit.hisiste.com/ToDo-App-BE/)  |  [Back End](https://github.com/Hisiste/ToDo-App-Back-End)  |
+
+## Goals and Requirements
+
+As the name implies, this project is about creating and managing to-dos. We have
+the following functional requirements for this app:
+
+-   [x] Create a "to-do" specifying the name, a priority, and possibly a due
+        date.
+-   [x] Ability to edit name, priority and due date for existing "to-do" tasks.
+    -   Being able to specify a due date or clear the due date (because you may
+        not be interested in when to finish that "to-do").
+-   [x] Being able to filter "to-dos" specifying the name (or part of the name),
+        the priority and if they are done/undone.
+-   [x] Being able to sort the "to-do’s" by priority and/or due date.
+    -   For example, be able to sort items where their due date is soon and sort
+        them also by priority to see what tasks are more urgent or less urgent.
+-   [x] Mark "to-do’s" as done (clicking in a checkbox) or to undo a "to-do".
+    -   The undone functionality is just there if there is a mistake. :D
+-   [x] Since it is possible that you can have a lot of "to-dos" there's the
+        need to paginate the list of "to-dos".
+-   [x] Ability to know, in average, the time between creation and done for all
+        "to-dos". This should be shown in general for all done "to-dos" and
+        also grouped by priority.
+    -   This could be a metric to measure performance.
+
+The project was separated into two projects: The _Front End_ part and the _Back
+End_ part. Each part has its own details and technologies. Let's discuss all of
+them.
+
+### The Front End
+
+We'll follow this markup to design the app:
+
+![](/assets/posts_assets/2023-05-29-weekly-essay-5/UX-UI-markup.png)
+
+1. Search/Filtering Controls.
+2. New To Do Button. This should open a modal to type the "to-do" data.
+3. Priority column should show in the header the classic up and down arrows to
+   allow the user to sort.
+4. Due date column should show in the header the classic up and own arrows to
+   allow the user to sort.
+5. Action column to show actions (links/buttons) to allow the user to delete or
+   edit a "to-do".
+    - To Edit is ok to show a modal similar to the one to create a "to-do".
+6. Pagination control. Showing the pages, its number and the next
+   and previous page is enough.
+7. Area to show the metrics.
+
+We're restricted to use the following technologies for this project:
+
+-   JavaScript.
+-   ReactJS.
+-   Redux.
+
+Neither of which I've used before. So this will be an interesting project.
+
+### The Back End
+
+This is further broken into two parts: the _model_ and the _API_. The _model_ is
+the information we're storing for every to-do. The _API_ will be our connection
+between the Front End and the Back End. Let's detail the requirements for each
+part.
+
+#### Model
+
+Every to-do should have:
+
+-   ID. This could be a number or string or a combination. Must be unique.
+-   Text (required). Max length is 120 chars.
+-   A due date (optional).
+-   Done/undone flag.
+-   A done date. When the "to-do" is marked as done this date is set.
+-   Priority (required). Options: High, Medium and Low.
+-   Creation date.
+
+#### API
+
+-   A GET endpoint (/todos) to list "to-dos".
+    -   **Include pagination. Pages should be of 10 elements.**
+-   Sort by priority and/or due date.
+-   Filter by:
+    -   The name or part of the name.
+    -   Done/Undone.
+    -   Priority.
+-   A POST endpoint (/todos) to create "to-dos".
+    -   Validations included.
+-   A PUT endpoint (/todos/{id}) to update the "to-do" name, due date
+    and/or priority.
+    -   Validations included.
+-   A POST endpoint (/todos/{id}/done) to mark "to-do" as done.
+    -   This should update the "done date" property.
+    -   If "to-do" is already done nothing should happen (no error returned).
+-   A PUT endpoint (/todos/{id}/undone) to mark "to-do" as undone.
+    -   If "to-do" is already undone nothing should happen.
+    -   If "to-do" is done, this should clear the done date.
+
+Finally, we're restricted to using the following technologies:
+
+-   Java.
+-   Maven.
+-   Spring Boot.
+
+And again, none of which I have experience. Oh, boy.
+
+## What I have learned
+
+A LOT. Not only have I learned enough of each technology to (barely) make a
+functional To-Do App from almost scratch in less than 3 weeks, but we're
+restricted to **NOT** use a database. At first, I thought "well, I don't know
+anything about databases either, so this is something one technology less to
+learn." Later I finally understood that this requirement:
+
+> No need to use a database by now, storing data could be in memory using Java
+> Collections, and it is ok if data is lost when the application is
+> shutdown. But they are asking you to design the persistent layer such that it
+> will be somehow easy to switch from in-memory implementation to a database
+> implementation.
+
+will cause me a lot of trouble. Well, not that much trouble, but things would
+have been smoother if we're allowed to use databases. (Or at least that was my
+conclusion.)
+
+So, without further ado, let's summarize everything I've learned during this
+whole new project:
+
+### Front End
+
+To use [_Redux_](https://redux.js.org/), we have to understand key-concepts
+like:
+
+Functional Programming : Decomposing a problem into a bunch of small and
+reusable pieces.
+
+Higher Order Functions : A function that takes a function as an argument and/or
+returns a function.
+
+Pure Functions : Where a function with the same arguments yield the same
+outputs. No external behavior should alter the output.
+
+And little more.
+
+Redux was heavily used at first. Creating the store and developing the reducers
+to store all to-dos was my first move. Not the best, but my first. I learned
+about [Bootstrap](https://getbootstrap.com/) and used it to create the UX/UI.
+Buttons, a table for the to-dos, containers with borders, and very messy **but
+functional** forms for adding a new to-do, editing a to-do and filtering through
+to-dos. Every time a reducer worked, I celebrated it. It wasn't very difficult
+to make them work, but it was an achievement for me, a math student who
+specialized solely on Python.
+
+I realized that JavaScript wasn't that much different from C++, but where
+everything is a class and objects are mutable. ~~And when something failed,
+`undefined` was returned instead of an error... Why?~~
+
+[React](https://react.dev/) was a breeze of fresh air and something easy to
+pick-up. It has its funny quirks like using `className` instead of `class`, the
+style needs to be defined as a JSON object and not a string, or that inside a
+loop, every new item needs to have a key, but they weren't serious problems.
+
+I always had Google opened (well, it was Bing, but you get the point). Every
+time I was stuck or lost, I tried to Google it. StackOverflow was my savior most
+of the time, but not always. Even _Googling_ can be seen as a skill. Let me tell
+you a funny story on why I said this:
+
+Because I was too into Bootstrap, I searched for a date-picker input using
+Bootstrap. After a long search, I stumbled upon a
+[**Bootstrap date-picker**](https://github.com/uxsolutions/bootstrap-datepicker)
+plugin developed by [**uxsolutions**](https://github.com/uxsolutions). I really
+thought it was the only (actively developed) solution and I forced it into my
+project. (See commit
+[163398](https://cgit.hisiste.com/ToDo-App-FE/commit/?id=163398f68444d278eb83543ba9798a6441c8af9f)
+([same but on GitHub](https://github.com/Hisiste/ToDo-App-Front-End/commit/163398f68444d278eb83543ba9798a6441c8af9f)).)
+**TWO** days later and after having LOTS of troubles with `onChange`, I just
+found out that I could have used HTML5's date input. By just doing
+
+```html
+<input type="date" />
+```
+
+ALL of my problems with date picking suddenly vanished. You can even see part of
+my frustration on commit
+[3d4a58](https://cgit.hisiste.com/ToDo-App-FE/commit/?id=3d4a589e5dc8f97a5fe94f5f8f42b97f2b6c7b52)
+([GitHub link](https://github.com/Hisiste/ToDo-App-Front-End/commit/3d4a589e5dc8f97a5fe94f5f8f42b97f2b6c7b52)).
+I attribute this problem to me trying to solve and forcing myself to solve
+everything with Bootstrap. I thought (and still think) that it is a very cool
+library, but it cannot do everything.
+
+### Back End
+
+Working on the Back End was something else. I felt a little more restricted
+using Java than using JavaScript. But at the end, Spring Boot helped me in
+simplifying the API creation. Like, a lot. I felt really happy and relieved when
+my first API call worked instantly. It was just a "Hello World!", but after
+seeing how simple it was to write it, I was calmer than when I started this
+project.
+
+{: file="Main.java"}
+
+```java
+@SpringBootApplication
+@RestController
+public class Main {
+    public static void main(String[] args) {
+        SpringApplication.run(Main.class, args);
+    }
+
+    // GET request on page `http://localhost:9090/greet`.
+    // Returns the string "Hello world!".
+    @GetMapping("/greet")
+    public String greet() {
+        return "Hello world!";
+    }
+}
+```
+
+As simple as that! I was happy... Until the "database" came along.
+
+Apparently, after setting up a database and linking it with the back end, all I
+had to do was:
+
+{: file="ToDosRepository.java"}
+
+```java
+public interface ToDosRepository extends JpaRepository<ToDos, Integer>{}
+```
+
+`ToDosRepository` would have been our database variable, `ToDos` is our class
+[model](#model), and `Integer` is the data type of our ID. The database would
+have functions like `findAll`, `save`, `deleteById` and many more. But because
+we're restricted to not use a database, WE HAD to implement those functions by
+ourselves. So we had to do something like this:
+
+{: file="ToDosRepository.java"}
+
+```java
+public class ToDosRepository implements JpaRepository<ToDos, Integer> {
+    List<ToDos> todos;
+
+    // Constructor
+    public ToDosRepository() {
+        this.todos = new ArrayList<>();
+    }
+
+    // Return all to-dos.
+    @Override  // <- We HAVE to write our own implementations.
+    public List<ToDos> findAll() {
+        return this.todos;
+    }
+
+    // Sort and return all to-dos.
+    @Override
+    public List<ToDos> findAll(Sort sort) {
+        // Figure out how to use the Sort class. >:3
+    }
+
+    // We HAVE to override EVERY function that JpaRepository offers. Even if
+    // we won't need it. (You can always return `null` as a solution.)
+}
+```
+
+Notice how instead of an _interface_, we have created a _class_, and instead of
+_extending_ the **JpaRepository**, we're _implementing_ it.
+
+The "database" took me way longer than I've expected. But at the end I made it
+work. Somehow. There were hiccups here and there, like when I tried to pass a
+request body to a GET request, just to then find out that this is a bad
+practice. At the end, there were no major "blockers" in this project.
+
+### Connecting both projects
+
+I HAD to run and implement this as fast as possible. Time was not on my side and
+the connection wasn't as smooth as I wanted to. For this part, I used
+[Axios](https://axios-http.com/) on the Front End. This library allowed me to
+make HTTP requests to the Back End. These were my major takeaways from this:
+
+-   Discovered about a `'Access-Control-Allow-Origin' header` problem and found
+    about CORS Policy.[^CORS] At the end the problem was fixed by making the
+    Back End (port 9090) allow requests from the Front End (port 8080).
+
+    ```java
+    @SpringBootApplication
+    @RestController
+    @RequestMapping()
+    public class Main {
+        // Edit this origin and set where the Front End is allocated.
+        private static final String allowed_origin = "http://localhost:8080/";
+
+        // ...
+
+        // Get all to dos.
+        @CrossOrigin(origins=allowed_origin)  // <- Allow HTTP request.
+        @GetMapping("/todos")
+        public List<ToDos> getToDos() {
+            return toDosRepository.findAll();
+        }
+    }
+    ```
+
+    Every request had to have the `@CrossOrigin(origins=allowed_origin)` line in
+    order for the Front End to successfully make the HTTP request.
+
+-   Apparently the GET requests should not have a body.[^GET] Although `curl`
+    CAN send a body on GET requests, Axios doesn't support it.
+
+-   Filters, sorting, pagination and more can be done pretty quickly on the Back
+    End. It is bad practice to do this stuff in the Front End. ~~There goes work
+    to waste. D:~~
+
+-   APIs are a GREAT way to connect projects, each written in their own
+    languages, having their own frameworks and their own databases.
+
+## Conclusion
+
+This project was a fun ride. Full of new technologies, new ways of creating
+applications and turning theory into practice. I celebrated each personal
+milestone, from deploying the whole app to writing my first API call. It's not
+hard to write code in a new programming language, but it's hard to write clean
+code. My app works (I hope), but the code is most likely a complete mess with
+lots of bad practices that I don't know about. The only way to get better at it
+is to **practice**. Keep practicing, learning and trying new and challenging
+things.
+
+---
+
+## Footnotes
+
+[^CORS]:
+    To know more about this issue, see commit
+    [5fccbc](https://cgit.hisiste.com/ToDo-App-BE/commit/src/main/java/com/encora?id=5fccbca45f7ad6837f46b4f5967c06c85e588e8c)
+    ([GitHub](https://github.com/Hisiste/ToDo-App-Back-End/commit/5fccbca45f7ad6837f46b4f5967c06c85e588e8c))
+
+[^GET]:
+    See the following link for more information:
+    [[StackOverflow] HTTP GET with request body](https://stackoverflow.com/a/983458).
-- 
cgit v1.2.3