aboutsummaryrefslogtreecommitdiff
path: root/_posts/2023-05-29-weekly-essay-5.md
blob: 1a8aee35bc41ecb4e190e2f0e718ab0fee4a7dea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
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).