Lessons Learned from a Project-based Course on Software Engineering

After today’s FSE exam, it officially wraps up my experience in the course Foundations of Software Engineering. As the most important course, or the “bread-and-butter” of the Software Engineering program, I thought I’d summarize what I learned from taking the course, both in terms of the technical and the non-technical aspects.

Background in FSE

The course, titled as “Foundations of Software Engineering”,supposedly teaches the students the fundamentals of the subject. In my opinion, it mostly fulfills this objective because it takes a very hands-on approach. According to the course information website, students will learn to “iteratively define requirements, and architect, design, implement, integrate, test, and deploy a solution”.

To learn those things, we worked as a team to build an emergency situation networking application, which is basically an application that uses standard web technologies. The most important things here are 1) working as a team, and 2) iterately building the application in a pseudo-real-world setting where requirements are defined and we should deliver accordingly.

What makes the course unconventional to me is the following:

  1. More focus on soft skills
  2. Requirements are a somewhat ambiguous (will come back to it later), and
  3. Strong focus on team work and communication.

In fact, the effort that went into the development of the course was well documented in this paper by the professors.

In terms of the “foundations” of software engineering that we learned, they span across engineering methods (e.g., iterative, LEAN, agile, SCRUM, kanban, etc.), design patterns, architectural styles, technical debt, and requirement engineering, and so on.

Non-technical Lessons

These are the lessons I learned from working with people from different backgrounds and working styles.

1. Work distribution

Work distribution across team members can be a difficult. Most of the time, we should optimize and maximize everyone’s strength, and allocate the appropriate tasks. However, it has two downsides: 1) It can lead to a person being hyper-focused on just a single aspect of the project all the time and not learning about others’ work, and 2) inbalance of work distribution depending on the nature of the task (some tasks might be heavy on the frontend, for example).

To solve the above issues, learning and adaptation is important. Thus, one must actively take initiatives if he/she wants to get something useful out of the experience. However, to avoid overloading, concerns should be communicated clearly.

2. Follow the Instructions

Surprisingly, following instructions is supposed to be straightforward: when creating design documents with UML diagrams, for example, all we need to do is to follow the proper format. However, people tend to not follow the instructions carefully (me included sometimes) and it has led to unnecessary wastes of time. This is particularlly important when we deal with project requirements. If the use case is defined in a way by the user, we should build our product based on that requirement; we should NOT build it how we like it.

3. Make Friends

This is possibly the best thing about this course - I genuinely enjoyed the way how they teamed us up. It “forces” different people who did not knew each other to work together. It makes the graduate community feel tighter and neater. I enjoyed spending time with my folks, and I feel fortunate knowing them.

Technical Lessons

These lessons concern the technical aspects of the projects, such as tooling and design.

1. Static Analysis

In a big project where the majority of the code is written in JavaScript, you want to “help your tools help you” by using static analysis tools. We adopted TypeScript from the beginning. The main reason is that the code itself is self-documenting, and its integration with VSCode is superb. By stating types, most exceptions are caught at compile-time. Null exceptions are rare at run-time. It did take a while to learn for some of us, but since it’s a superset of JavaScript, a person can learn it incrementally.

2. Importance of Design

None of us are as capable as a software architect, so the design of our project was not ideal. However, we did come to the realization early on: consistent implementation depends on a good design. In our case, we used the Factory Method pattern for our core business logic. This allows anyone who comes onboard to implement the logic in a way that is guaranteed to work and be compatible. On the other hand, when we learn something new in class, we’d better carry it out in the real world by practicing it.

Conclusion

Overall, FSE was a valuable experience to me as someone who has done multiple internships. It was not a perfect experience, but making new friends alone has made it worth my time!