Reflection HW 4

1. UI

I struggled a lot with figuring out how to make your login state persistent between refreshes and closing tabs, because even if the server knew user x was logged in, the UI would not reflect that.

2. Login endpoint

I struggled the most with cookies and server configuration; I just kept getting really strange bugs that required changes to the configuration of various things that took hours to figure out. Also some things like the pm2 package stopped working, which had me desperate because I didn’t know what could possibly be wrong, and then a couple days later without me doing anything started working just fine. I guess you just have to embrace the jank sometimes.

3. Security Audit

My app is (most probably) not vulnerable to XSS attacks because of the added security headers by helmet, same-origin policy, http-only cookies, server-side schema/type validation, and react built-in security features.

I think the app is safe from CSRF attacks because the backend API only accepts requests coming from the same site (orangeblossom.xyz). If I clicked a link in maliciouswebsite.com with a DELETE request, for example, the server would reject it. I’m sure there are ways of getting around that, but there is this baseline of protection at least.

I added rate limiting to my application code with express-rate-limit, and I KNOW it works because I accidentally got locked out of my own app for a bit because of it. I also had to change the headers for the content security policy because the browser was complaining, which means an extra layer of protection against XSS attacks and packet sniffing.

Reflection HW 3

1. UI

I integrated the book and author editing into the table displaying the data: There is a delete button in each row that will delete the data when clicked, if possible (for example, you still can’t delete an author that still has books related to them). Book and author editing is done by simply double clicking on each cell on the table and editing it. Certain parameters, such as ID, cannot be edited.

I chose the design I did because of its simplicity on the user-end. Do you want to edit books and authors? Simply double click, and type. If anything incorrect is inputted, it will simply revert to its original state and not “commit” any of the changes to the database. Do you wanna delete a row? Just click the button. I will probably for the next assignment get rid of the “add book” and “add author” pages and create something to integrate that functionality inside the same table so that the user does not have to keep changing pages.

I did struggle with the DataGrid API since it was quite complex, but it provided such a clean solution to all the problems that it was worth it to stick to it. As a side note, I did eliminate the filtering functionality that I had done previously for hw2, because the component already implemented sorting and filtering in a much cleaner and better way.

2. Material UI

The only tricky part was the table because I had to build everything from scratch and rethink all of the logic. Everything else was pretty smooth and simple, no issues.

3. Editing Endpoint

It was honestly pretty easy, since the implementation was very similar to the POST endpoints. Having those done correctly beforehand was extremely useful.

Reflection HW 2

1. Design

I didn’t make any changes to the back-end except for changing the api routes by adding /api (for example, /books → /api/books). I don’t think I’d structure it any differently at the moment.

I didn’t really perform client side validation for my post requests because I thought it was kind of unnecessary, since from the client side there are very few type errors that can happen, and those are immediately caught by the back-end validation. It’s true that adding that validation would add an extra layer of protection, and it would make it easier to display more accurate/useful error messages. However, for an app as small and simple as this, it’s not that useful.

2. React

I thought I was going to have many more issues than I did. The development process was very straight-forward and I thankfully didn’t hit any walls. The only tricky thing was manipulating the state of the books list when filtering by various parameters.

I felt like the role of types was less significant than in the back-end, and were more annoying to use. Especially since it was very difficult to make TypeScript happy when it came to setting the state for genres, publication years, etc.

I had to resort generally to using basic strings and numbers instead of, for example, my “genres” type, because it would just complain and complain, and the work needed to make the errors disappear was unnecessary considering that there is already pretty solid server-side validation in place. (I don’t think I had to use “any” at any point though, at least deliberately).

Nevertheless, I do believe that using TypeScript improved the development experience by a lot and the benefits outweighed the annoyances by a lot.

3. Experience

I enjoyed writing the front-end with React so much more. Granted, I had worked with it a couple of times before so I didn’t go in completely blind. But honestly, now I would have a very hard time enjoying going back to plain JavaScript. Front-end frameworks just automate and take care of so many of the mundane, repetitive and annoying things that, while they may not be necessary for smaller projects, it makes working with the front-end so much more fun and quick.

Reflection HW 1

1. Coding

I honestly spent a pretty long time on this assignment. I can’t remember exactly how many hours, but adding everything up I’d estimate around 17h, give or take. In general, I felt like I had a very balanced development experience, I wouldn’t say that I spent an unreasonable amount of time on anything in particular. After the initial struggle with the SQLite3 installation, configuration was not an issue at all.

Typescript was really interesting to use, and while figuring out all the types as I went was a little bit new, it helped me a lot to understand more deeply what exactly are the shapes of all the objects I was manipulating, as well as Express requests and responses, which were a bit magical to me before.

I’ll touch on testing further down in the reflection, but it was a very positive experience, something I didn't really expect given my past experiences with testing.

There were times where, after having been coding for a while, I struggled to solve some nasty issues I was having while debugging my tests and request handlers. As cliché as it sounds, what helped was leaving and coming back to it the next day. I really have to thank the past me for the good time management, because leaving everything until the very end would have been a total nightmare. I really did enjoy the assignment, since there was the right amount of guidance, the right amount of time to complete it, and the right amount of difficulty so that someone more experienced wouldn’t think of it as trivial, while being a valuable learning experience for someone more inexperienced (such as myself).

2. TypeScript

Typescript helped me to deal with a lot of the confusion that comes with not exactly knowing the return types of certain functions, and preventing many bugs before they even appear. For example, when querying the database, or making axios requests, it helped me realize that I had to access a certain attribute to view the data I actually wanted, or that it was actually given to me in the form of a list even if it only consisted of a single element, which saved me a lot of pain and aimless debugging time, since regular Javascript would have for sure allowed me to do many stupid things.

However, there are some times where type checking everything can be unnecessary, and finding the right type for something minuscule can be time consuming. I found Error object typings especially confusing and hard to fully understand, as well as the types for the zod library functions, which I decided to exclude because they cluttered the code too much and I figured that since they already served to validate my other Typescript types and schemas, validating the validation felt a bit overkill.

I realized one of the limitations of Typescript when I hit a wall while trying to validate the types of (POST) request objects at runtime. Figuring out that I had to use a separate schema validation library like zod was really cool, because I had heard about it in class but didn’t really understand until that moment why they are useful.

3. Testing

The first step for me was designing the API on pen and paper: all the endpoints, what they would return, the types each would accept and return, the database schema (which remained largely unchanged except ids and pub_year which I changed to numbers instead of text/strings), and the overall functionality. Once I had that clear, I wrote a list of all the tests that I would need to test all the functionality, as well as handle the main errors that I figured would pop up from a user perspective.

From that mindset, developing the pre-written test cases one by one was what drove the whole development process. I tackled one at a time and would write the code needed until I was able to make it pass. If I thought of another feature (such as full-support for query strings in the uri) I would create a test name for it and comment it out until I was ready to tackle it.

I had never used tests for web development, and that, coupled with typescript, made me noticeably more confident in my code because I knew that it worked, why, and that it would return the appropriate errors when things did not match up. I genuinely thought it was going to be a pain to write tests, and never expected to actually like it, so that was a nice surprise. I got some pretty annoying bugs because I forgot to use the await keyword in a couple database calls and axios requests, and tests played a major part in me being able to narrow down the reason without going completely insane.

I feel like I’ll continue with this general framework for my next projects, creating and then developing tests for the features that I want to develop, and the actions that a user could take, without getting lost in the details.