Categories
CS 462

Blog Post #3 – Wrapping Up

My senior project journey has been a very interesting experience. I would say that our most difficult journey would be losing two out of our five team members. My team handled these losses pretty well, but we had to make some sacrifices on the parts of the project we wanted to work on to fill in the missing pieces. Personally, I took the initiative to develop these missing components, ensuring they were completed to a high standard and remained accessible for the rest of the team.

The hardest chunk to fill in was the project’s machine learning / AI aspect. One of the main goals of our project was to use computer vision to somehow create a self-driving car. We were not given any constraints or tips for this, just more of an end goal. Initially, we planned to have many advanced features that sounded cool on paper, but we ended up constraining our scope due to the difficulty of implementing some of those features. We had been planning on using reinforcement learning to control our vehicle for a while, but we recently found out that it would not be that feasible to implement in this project.

I chose this project because I thought working with a gaming engine built with the Rust programming language would be cool. We were also given a list of areas we could focus on for the project. One of these areas was graphics shaders, which I was looking forward to. Unfortunately, once the project was underway, I was told that our focus was now autonomous driving, which is interesting but not something I would have picked myself. On top of that, I have not seen a single company that uses Rust or Bevy for game development, as most of them use Unity or Unreal. While I can still put this on my resume, it may not be as impactful as a shader project would have been or creating a game in one of the more popular engines.

Categories
CS 462

Blog Post #2 – Technologies

Virtually everything that is being used in our senior project is new to everyone in our group. The main thing, Bevy, is a game engine that is written in Rust. The cool thing about Bevy is that it is entirely open-source, which means anyone can contribute to it. While the engine is by far the most developed Rust game engine, it still lacks some features that all other big game engines have, like an editor or official tutorials. Nonetheless, we are making some good progress even with these limitations.

One of my favorite parts about working with Bevy is the fact that it is written in and uses Rust. In the grand scheme of things, I am still new to coding. This means it can be easy for someone like me to make small mistakes that can be a big problem for the stability of a program. Rust is a language that helps prevent many of these minor issues by checking everything at compile time. While it sometimes makes developing an application a little slower, once something I write in Rust works, it continues to work.

Due to Bevy still being pretty new, if I could start over, I think that I would do a project in either Unreal Engine or Unity. One of the main points of working on this project is to help build my resume, and I still have yet to find one job listing that lists Bevy as a nice to have. However, Bevy uses an ECS or Entity Component System, which is something Unreal Engine is slowly adapting to. Who knows? Once it gets more complete, I have a feeling Bevy will be a strong contender in the game engine space, especially since there are no licensing fees.

Categories
CS 462

The Hidden Implications of Clean Code

Since the start of my programming career, I have always found it satisfying to rewrite my code in a way that does the same thing but is easier to understand. So, one might assume I am an avid supporter of “clean code,” which is actually not the case. There are quite a few benefits to writing clean code, but there are also some downsides that people forget to talk about.

Good Practices of Clean Code

Starting with the benefits of clean code, there are a few tactics one can use to make their code easier to read without much effort:

Avoid Deep Nesting

Every time you nest something that is one extra step the person reading your code has to keep in their mind. If possible, try to collapse nested structures into one level. If the code has already been executed beyond a certain point, then the previous code no longer needs to be taken into consideration.

Bad Example:

javafunction calculateTaxes(user, cart) {
    if (!isMaintenancePeriod) {
        if (user.isAuthenticated) {
            if (user.isAuthorized) {
                if (cart.total > 0) {
                    // Deep nested logic
                }
            }
        }
    }
}

Better Approach:

javafunction calculateTaxes(user, cart) {
    if (isMaintenancePeriod) return null;
    if (!isValidUser(user)) return null;
    if (!isValidCart(cart)) return null;
    
    return calculateRegionalTax(user, cart);
}

Eliminate Code Duplication

While I do not think you have to extract everything, especially if you are only using it once, you should try to extract logic into reusable functions. By centralizing repeated logic, you can make code more maintainable.

Use Meaningful Names

Some programmers find coming up with good names challenging, but this does not mean we should give up entirely. When naming variables, you should at least use descriptive names that clearly convey purpose and intent. This makes code more self-documenting and can eliminate the need for some comments.

Bad Example:

pythondef calc(a, b):
    res = 0
    tmp = a
    for i in range(b):
        res += tmp
    return res

Better Example:

pythondef multiply(multiplicand, multiplier):
    product = 0
    currentValue = multiplicand
    for count in range(multiplier):
        product += currentValue
    return product

Where the Problems Start

I do not think clean code is a bad idea, but I have a few issues with it.

First, not everyone agrees on what “clean code” means. Does it mean having very short functions? Does it require continuously extracting functions to make them more abstract? Do functions really have to only do one thing? The answer to these questions, and many more, will change depending on who you ask.

Now, there are a few things I do not like that are sometimes considered “clean code.” First, the idea to keep functions extremely short (2-4 lines) is impractical and can lead to fragmented, hard-to-follow code. Excessive function granularity makes code harder to follow by forcing readers to jump between tiny functions.

Another issue is that premature optimization of code flexibility can lead to it becoming unnecessarily complex. I have noticed that writing clean code sometimes leads to over-engineering and feature overload. If you follow something like the DRY principle 100% of the time, it can lead to over-abstraction and hard-to-maintain code. People spend so much time turning a simple program into a framework-like program when they could have used the time better somewhere else.

I recently read an article that discussed some of the issues with “clean code,” specifically Robert C. Martin’s Clean Code book, more in-depth. The book itself is already pretty outdated, but it is an interesting article.

When Clean Code Is Worse

Here is a video that talks about how clean code principles can significantly hurt performance: “Clean” Code, Horrible Performance

In short, this video talks about and gives examples of how common “clean code” principles can impact software performance. One of the examples the YouTuber gave was using polymorphism over switch statements and hiding internal implementations, which can make code 15-24 times slower since it requires more cycles. Now, there are languages like Rust that let you do zero-cost abstractions, but that is not the case with many languages. The video goes into more advanced options, which significantly improved performance but broke even more “clean code” rules.

Now, clean code is not necessarily a bad thing, but one should not blindly follow these rules without considering their significant performance implications.