Category Archives: CS-343

Learning How Architecture Patterns Shape Reliable Software

For my first blog, I read “Software Architecture Patterns” from the ByteByteGo blog. The post explains what architecture patterns are, why they exist, and how they help developers organize software systems that scale and remain maintainable. It outlines several common patterns such as layered, event-driven, microservices, client server, and micro kernel, describing their main structures and the problems they solve. The article emphasizes that architecture is not about strict rules but about creating a structure that supports clarity, reliability, and growth.

The author shows how the layered pattern divides applications into presentation, business, and data layers, useful for simple or monolithic systems. Event driven architectures handle asynchronous communication, making them ideal for systems that must respond quickly to different events. Microservices split large systems into smaller, independent services that can be developed, deployed, and scaled separately. Client server architecture remains a foundation for most web applications, while micro kernel focuses on extensibility, often used in plugins or modular software.

I chose this blog because it connects directly with what we are learning in CS-343 about design principles, maintainability, and system organization. It presents architecture patterns as practical solutions rather than abstract theories. The visuals and examples in the article made complex ideas clear. Reading it helped me understand that the architecture pattern chosen for a project directly affects performance, scalability, and how teams collaborate.

What stood out to me is the focus on trade offs. Each pattern has strengths and weaknesses depending on the project’s goals. For instance, microservices improve flexibility but increase deployment complexity. Layered systems are easier to start with but can slow down change if dependencies grow too tightly coupled. This reinforced the importance of balancing simplicity, independence, and maintainability, key themes from our class discussions about SOLID and GRASP principles.

From this reading, I learned that good architecture is about creating boundaries that protect core business logic while allowing technology and frameworks to evolve. I plan to apply this by practicing modular design in future projects and thinking more critically before deciding on an architecture. Understanding patterns like microservices or event-driven systems will help me reason about trade offs when I design APIs or backend structures.

Overall, ByteByteGo’s article strengthened my understanding of architecture as the backbone of sustainable software. It made clear that design patterns are not only about writing code but about shaping how software grows over time.

Link: https://www.thoughtworks.com/en-us/insights/blog/architecture/demystify-software-architecture-patterns

From the blog CS@Worcester – Harley Philippe's Tech Journal by Harley Philippe and used with permission of the author. All other rights reserved by the author.

From Inheritance to Strategy: Lessons from the Duck Simulator

One of the primary obstacles in software design is ensuring that code remains easy to maintain and extend. Initially, inheritance seems like the clear answerplacing shared code in a superclass and allowing subclasses to override as necessary. However, as demonstrated in the classic Duck Simulator example, relying solely on inheritance can result in fragile designs.

From Inheritance to Strategy

In the first version of the Duck Simulator, all ducks derived from a base Duck class. This approach worked until we introduced unique ducks like RubberDuck (which squeaks instead of quacking and cannot fly) and DecoyDuck (which does neither). Suddenly, we found ourselves needing to override or disable inherited methods, leading to duplication and design issues such as viscosity and fragility. Transitioning to interfaces helped to declutter the design, but it also required us to replicate code across similar ducks. The true breakthrough arrived with the Strategy Pattern,

We extracted behaviors like flying and quacking into separate classes (FlyWithWings, FlyNoWay, Quack, Squeak, MuteQuack). Now, ducks possess behaviors rather than inheriting them. These behaviors can be altered at runtime, and new ones can be introduced without changing existing code. This transition underscored the principle of favoring composition over inheritance and illustrated the Open-Closed Principle: code is open for extension but closed for modification.

Design Principles in Action

The exercise reinforced several essential principles: High Cohesion: Each behavior class excels at a single task. Low Coupling: Ducks are indifferent to how they fly or quack, only that they can delegate to a behavior. Encapsulate What Varies: Changes in behavior are contained, not dispersed across subclasses. Collectively, these factors enhance the design’s flexibility and maintainability.

UML: Clearly Communicating Design

We also engaged in the practice of illustrating designs through UML diagrams. In contrast to code, UML offers a higher-level representation that clarifies relationships: Associations (for instance, a Student possessing a schedule of Course objects). Multiplicity (for example, a student may enroll in 0–6 courses). Inheritance and interfaces (such as Faculty extending Employee and implementing HasCourseSchedule). Tools like PlantUML enable us to create these diagrams in Markdown, facilitating easy adjustments and sharing.

Key Takeaways

Relying solely on inheritance frequently results in fragile designs. The Strategy Pattern addresses this issue by encapsulating behavior and employing composition. Guiding principles such as High Cohesion, Low Coupling, and Open-Closed promote cleaner designs. UML diagrams provide us with a common language to convey and analyze code. What began as a straightforward duck simulator evolved into an insightful lesson on the significance of design patterns. By embracing the Strategy Pattern and utilizing UML for design modeling, we discovered how to construct systems that are not only functional but also resilient, adaptable, and easy to maintain.

From the blog CS@Worcester – MY_BLOG_ by Serah Matovu and used with permission of the author. All other rights reserved by the author.

Polymorphism in Object-Oriented Programming

Polymorphism was one of those programming words that used to sound scary the first time I ever heard of it. It literally means “many forms” but in OOP, it’s not as scary-sounding as it is. It’s basically when the same method or function can be something different based on what object it’s being called from. As soon as I started reading over some examples, it made a lot more sense.

Think of it like this: an individual might be a class student, a home sibling, and maybe a work employee. Same person, various role depending on context. In programming, polymorphism enables us to do one thing with one function that changes its behavior depending on the object.

There are two main forms of polymorphism. Compile-time polymorphism (or static) is solved before the program ever runs. That generally happens with method overloading, where you have multiple versions on the same method name with different parameters. The compiler figures out which one to invoke. Operator overloading is another example, like using “+” for numbers and strings too.

Then there is runtime polymorphism (dynamic), resolved as the program is running. That is what happens with method overriding. A case in point is a parent class Shape that has a method draw(). Subclasses such as Circle and Square override draw() to do something else. When you call draw(), the program picks one that matches the actual object.

First of all, I used to confuse this with inheritance. They definitely go hand in hand, but they are not one and the same. Inheritance is when you are copying another class’s code. Polymorphism is when you have the same method name but have different action.

A lot of people also think that using polymorphism, especially the runtime kind, makes programs really slow. I used to believe that too, but it turns out that’s not really the case anymore. Modern compilers are built to handle this kind of thing quickly with tricks like virtual tables, so the performance hit is tiny. The trade-off is worth it because you get cleaner code and way more flexibility, so worrying about speed here feels kind of outdated.

I’ve read about this and it struck me how many times I’ve made my own code overly complicated. In Java, for example, I used to create a whole bunch of methods with unique names when I could have done overloading. I also blocked overriding in subclasses because I believed that it would be slow. Now I know that not just is that fine, it’s the correct thing to do most of the time.

In the future, I’d like to use polymorphism more intentionally, especially in my Android applications. It’ll be a tremendous assistance if new functionality is introduced in the future because I won’t need to begin anew. That, to me, is the beauty of OOP, it’s not just about making things function, but making them simpler to maintain and extend in the long run.

Resources:

https://www.cincom.com/blog/smalltalk/polymorphism-in-object-oriented-programming/

From the blog Maria Delia by Maria Delia and used with permission of the author. All other rights reserved by the author.

Why Polymorphism is so Important in Programming

Polymorphism is one of those terms you hear in Computer Science that sounds confusing at first and overly complicated, until you find out you’ve probably been using it this whole time. “Polymorphism in Programming” by Johnathan Johnson is a great blog detailing exactly what it is and how it works. It gives a nice clear definition that’s easy to understand and then lists out the different types you’ll encounter along your programming journey.

Polymorphism is essentially just a process that can perform multiple tasks depending on the context of the situation. There are many forms of polymorphism as well such as Subtype (Runtime), Ad hoc (Compile-time), Parametric (Overloading), and Coercion (Casting). I won’t get too in-depth on each of these as Johnson has already done a great job of this in his blog.

The key takeaway here is that polymorphism allows you to program an interface, not just an implementation. What I mean is by creating an interface or superclass it doesn’t matter what type the object being called is you can just call the method on it. For example, you could have a list of Shape objects that can hold a circle or a square or whatever shape you want, and you can call draw() without caring which specific subclass you’re dealing with. Because of this code duplication can be severely cut down due to multiple objects using the same method all stored in the superclass.

This is similar to what we saw in class with the Duck superclass and all the subclasses with different duck types. As long as you were calling a method stored within the superclass it didn’t matter which subclass you were calling it on. Even if the subclass had overridden the method, you would just be running into ad hoc polymorphism as the program would be switching the version of the method used to that of the one stored in that particular subclass.

Even though I’ve been using polymorphism for years through my career here at Worcester State it’s good to finally learn what this practice is actually called. It’s also good to learn that there are forms of it I wasn’t always using when I could of and instead took the less efficient route to solve my problem. The concept is integral to time efficiency and when programming time is incredibly important in a lot of ways.

I plan on taking this newfound knowledge with me through the rest of my career here as well as whatever the future holds for me.

From the blog CS@Worcester – DPCS Blog by Daniel Parker and used with permission of the author. All other rights reserved by the author.

Object Oriented Principles

This blog is based on “OOP Principles: What is Object Oriented Programming?” from Full Stack Foundations. The article has a clear understanding of the four core pillars of object-oriented programming. That being encapsulation, abstraction, inheritance, and polymorphism. It also explores how these principles tie into more advanced design ideas such as composition over inheritance and more.

The article begins by explaining why OOP is valuable, emphasizing that it organizes code into modular blocks that bundle together data. OOP helps developers manage complexity in large systems. It then talks about encapsulation as the practice of hiding code and exposing only interfaces, which helps reduce unintended interactions. Abstraction is explained as representing concepts with simplified models. Inheritance is presented as a practice that allows new classes to build upon existing ones, enabling reuse of behavior. Finally, polymorphism is described as the ability to treat different classes as instances of a common base type, making systems more flexible and adaptable. Later in the article, the author connects these principles to design patterns, noting that good object design avoids fragile hierarchies.

I chose this article because it’s connection to our class, discussing design concepts. OOP is a key topic in this course, from abstraction and encapsulation to design principles and patterns, and I thought this blog was a good representation of OOP. It struck a good balance between the basics of OOP and the many ideas that are needed to think about design in a professional way.

Reading this article reminded me that OOP is more than just syntax like classes and methods. The discussion on abstraction and encapsulation stood out the most to me because in my past projects and classes I often never thought about the exposure of too many details of a class, either through public fields or otherwise. The article emphasized that clean abstraction is essential for maintainability. I also appreciated the warning about inheritance. The article shared the idea that using composition over inheritance can prevent problems and lead to more flexible ideas.

The main takeaway for me is that OOP is an idea that allows code to be built clean and modular rather than something that has to be perfected up front. In future assignments and projects, I want to be more aware about the principles of clean OOP coding. I also plan to make better use of interfaces and encapsulation so that classes depend less on concrete implementations. This resource gave me a refresher on these ideas and hopefully I can build systems that are easier to maintain and improve upon.

https://www.fullstackfoundations.com/blog/oop-principles?

From the blog CS@Worcester – Coding with Tai by Tai Nguyen and used with permission of the author. All other rights reserved by the author.

Understanding UML (Unified Modeling Language)

When I first came across UML in our class activity projects, I often felt lost trying to understand it. There were so many different diagram types, rules, and notations that I struggled to keep track of them all. At first, the symbols looked like a foreign language, and I wasn’t sure how they connected to … Read more

From the blog CS@Worcester – BforBuild by Johnson K and used with permission of the author. All other rights reserved by the author.

UML in A Sequence of Learning Events

Lately, I’ve been having trouble with UML Sequence Diagrams. So, I decided to do further research to better understand the subject.

Due to learning about it in class, I have some prior knowledge about the subject. First, there’s the actor which is usually represented by a stick figure. The actor essentially acts as a user stand in. The rest of the classes are participants. Think of them as a path the actor has to walk across. The diagram shows the path that the code takes when the user executes the code.

I used this article for reference: Sequence Diagrams – Unified Modeling Language (UML) – GeeksforGeeks

It’s a beginner’s guide to UML sequence diagrams. It defines an UML sequence diagram and all vocabulary associated with it. It then informs how to one and the pros and cons of using one.

The first thing I started to better grasp was lifelines. I used to think lifelines were the solid lines but they depict an individual participant. Lifelines represent each instance in a sequence diagram. They are displayed in rectangles and go by their name and type. They are similar to actors but portrays objects internal to the system.

I also learned more about the messages. I knew that solid lines output messages and dashed lines returned them. I didn’t know that a solid line and a dotted represent synchronous messages and a single dotted line represent asynchronous ones. Synchronous messages wait for a reply before the interaction can move forward. Imagine if to people were moving boxes to a truck. Person A hands a box to Person B who puts it the truck. Person A must wait until Person B signals that they are done with their task. On the other hand, asynchronous messages don’t need to wait for a reply so Person A would just hand Person B the box without waiting for a signal.

So, to summarize what I learned. the diagrams are just a different way to demonstrate the code. It’s a communication tool between developers, managers, stakeholders, project managers and clients. It’s like a blueprint that anyone can look over. Clients can look over the plans without getting confused and make edits if necessary. Developers can take the blueprint and convert it into actual code. UML diagrams contain an actor that takes the role of a user engaging with the code. The participants represent the rest of the classes. The vertical rectangles represent the duration of a class’s execution. The arrows, not participants as previously mentioned, represent the path the code takes. Think about everything as components of a map.

Overall, this further research deepened my understanding of UML sequence diagrams. I feel like this would help me with the homework assignment but unfortunately it didn’t answer all my questions.

From the blog CS@Worcester – My Journey through Comp Sci by Joanna Presume and used with permission of the author. All other rights reserved by the author.

DESIGN PATTERNS

Software Design Patterns 101: A Beginner’s Guide, a Medium essay, introduces readers to software design patterns and discusses how they help create systems that are effective, scalable, and manageable. According to the article, design patterns are reusable templates that help programmers produce cleaner, more structured code by resolving common programming problems. The three primary types of design patterns, structural, behavioral, and creational are explained. Object generation is the main emphasis of creational patterns like Factory Method and Singleton. Adapter and Composite are two examples of structural patterns that explain how classes and objects can be merged to create more expansive, adaptable systems. Observer and Strategy are two behavioral patterns that emphasize direct communication and responsibility delegation. Teams can create a common language by employing these patterns, which enhances cooperation and lowers misunderstandings.

I chose this article because it clearly relates to the concepts of object-oriented design and code organization that we have been studying in class. In a recent exercise, for instance, we examined a Duck class hierarchy dilemma in which some subclasses, such as RubberDuck and DecoyDuck, were compelled to inherit unnecessary methods, such quack() and fly(). Because of this design, we had to override methods with “do nothing” implementations because these ducks either didn’t fly or quack. My understanding of why this is a typical example of a design issue that can be fixed using patterns like the Strategy Pattern, Which is under the behavioral category covered in the reading. 

I came to understand how inheritance, although helpful, may become problematic when it compels subclasses to adopt behavior that isn’t appropriate for them through the article and our class discussion. Depending on the type of duck, the quack() and fly() methods in the Duck superclass in our example have different actions. We may dynamically assign these behaviors to various ducks at runtime by classifying them into distinct classes, such as FlyBehavior and QuackBehavior. This method reduced superfluous overrides and increased the design’s adaptability. Here, the Strategy Pattern was essential since it let us alter a duck’s behavior without explicitly changing its class.The way that design patterns like Strategy prioritize composition over inheritance struck resonated with me. By mixing smaller, reusable components instead of depending only on strict class hierarchies, this idea promotes the development of systems. In the Duck example, we can simply construct new behavior classes and mix them in as needed, rather than adding extra subclasses each time a new type of duck is created. I intend to incorporate these ideas into my upcoming work. For instance, I could use behavior classes for activities like jumping, running, and attacking if I were creating a game with many character kinds. This would eliminate the need to rewrite significant portions of code in order to add new characters or change current ones.

From the blog CS@Worcester – A Bostonians Blogs by Abdulhafeedh Sotunbo and used with permission of the author. All other rights reserved by the author.

Understanding Git Collaboration: Communities, Upstreaming, and Merge Conflicts

Hello everyone! Welcome back to my blog posts. Today I would be delivering my first Quarter blog post.

For this week’s blog, I decided to read “Git Forks and Upstreams: How-to and a cool tip” from Atlassian Git Tutorials. I picked this article because it connects directly with what we’ve been practicing in class—working locally, pushing changes upstream, staying synchronized, and handling merge conflicts. I also wanted a guide that explained the actual Git commands rather than just high-level concepts, since I’ve been moving away from relying only on graphical interfaces.

Summary of the Resource

The article explains the difference between origin (your fork) and upstream (the original repository you forked from). It walks through how to set up your fork so you can keep it synchronized with the upstream repo, which is especially important when multiple people are contributing. Commands like git remote add upstream <url>, git fetch upstream, and git merge upstream/main are introduced step by step. The tutorial also shares a useful tip for checking how many commits your branch is ahead or behind the upstream, which makes it easier to stay in sync.

Why I Chose This Resource

I chose this article because it fills a gap in my own Git knowledge. Until recently, I mainly used the graphical interface on the side to commit, push, and sync my changes. That worked for basic assignments, but I often felt like I didn’t really understand what was happening behind the scenes. This tutorial helped me connect the dots by showing me the exact commands and explaining why they matter, especially in collaborative projects.

Reflection and Takeaways

This resource helped me see Git as more than just a tool for saving code. it’s really about teamwork. Understanding how to add and pull from upstream makes me feel much more prepared to collaborate on group projects or open-source contributions. I no longer see merge conflicts as something to fear, but as a natural part of multiple people working on the same code.

One big realization for me was how important it is to stay synchronized with upstream. In one project I did before, I once ignored updates for too long, and the merge that followed was messy and stressful. Now I understand that frequent git fetch upstream and git merge calls prevent bigger problems down the road.

Another personal shift was moving away from the GUI. While the interface made Git feel easier at first, I see now that the terminal gives me more power and clarity. Running git status, git log, or checking how far ahead/behind my branch is compared to upstream makes me feel more in control. It’s like going from driving an automatic car to learning manual, I finally understand how things actually work under the hood.

Looking ahead, I know these lessons will help me not only in this class but also in internships and my future career. Whether I’m working on an open-source project or contributing to a company’s codebase, being comfortable with upstream workflows and conflict resolution will make me a stronger and more reliable teammate.


Citation / Link

From the blog CS@Worcester – Rick’s Software Journal by RickDjouwe1 and used with permission of the author. All other rights reserved by the author.

What are Coding Smells

Currently, in class we are going over code smells. These code smells are how we perceive the code and try to make a change with them that could cause a problem. First let me explain what code smells; Rigidity, Fragility, Immobility, Viscosity, Needless Complexity, Needless Repetition, Opacity. These code smells are what we should try to avoid making a program so that we do not have a future problem when we try to solve it. 

Coding standards and quality will change over time regardless of that programmers need to be aware of the risks of having a program with these issues. When code becomes rigid, it is referring to how a section of the program is needed throughout the program too much and when we try to make changes with that section it would require a lot more code to fix. Fragility is when a change we did makes other parts of the code to not work as intended. Immobility is when a program can not be transferred from one system to another. For example, in certain engines, ides might manipulate certain values in a program so it will be different within the two engines or ides. 

While Viscosity is when a program has a lot of improper coding methods that will slow down the efficiency. Needless Complexity occurs when a program is very complex for the demand it is used for. Needless Repetition, is when code repeats throughout the program that makes multiple unneeded repetitions. Lastly Opacity is how other programmers could see the use of a feature and how clear it is defined. 

From the blog CS@Worcester – Site Title by Ben Santos and used with permission of the author. All other rights reserved by the author.