Author Archives: Sarah T

My Thoughts on Apprenticeship Patterns Intros

This week, I read chapter 1 and the introductions of chapters 2-6 of “Apprenticeship Patterns” by Dave Hoover and Adewale Oshineye. I appreciate the values that the book covers. They basically say that we should work to better ourselves and failure doesn’t mean that we ourselves are failures, but that we should take different approaches next time. I like the way that we should work to get things done and do not need to aim for complete perfection since it may not be realistic for what we’re working with.

I also like the little story they gave with the teacup ceremony and the young philosopher. The story was a great way to introduce the notion that we should be freeing ourselves from being stuck in a certain mindset and should be more open to learning new things from others, and I think that’s a great thing to think about moving forward.

I found it useful that the chapters also mention getting out of your comfort zone. I think that’s something important to do, and I believe we need to do so to improve, and I agree that we should be thinking about not just being average or a little above average, but we should be aiming for more than that since there is much ahead of us.

I thought the introduction to Chapter 6 was a little interesting with how it mentions that we need books for studying. I see that it can be like a “don’t forget the roots” belief as it feels like a “please don’t underestimate the old books, it mentions things the internet does not”. Thinking more about this intro, I think it’s important that we expand our learning outside of the classroom and it’s our responsibility to study related concepts and to assign different material and sources to ourselves.

I don’t really disagree with anything in the reading. I’m mostly just taking in all the information and they’re all fairly applicable for working towards self-improvement. The chapters that seem most relevant to me are 1, 2, 3, and 4. They all get me thinking about not settling where I am and to strive to increase my knowledge. We should be more open to opportunities and not get tied up with what we already know or past experiences, and should try our best to learn more from others and use different sources. I’m looking forward to reading and discussing the design patterns from this book.

From the blog CS@Worcester – CS With Sarah by Sarah T and used with permission of the author. All other rights reserved by the author.

A Peek Into LibreFoodPantry & Theas Pantry

Before working on anything for LibreFoodPantry, I needed to read up on the project. LibreFoodPantry values FOSSisms: https://opensource.com/education/14/6/16-foss-principles-for-educators. I thought this was an interesting read, especially because I am new to open source culture. It discusses some values and beliefs, one of them being that if something didn’t happen publicly, then it didn’t happen. This would make it easier for people to be able to see what’s being done and join, and documenting things helps keep people up-to-date on such a large project. Some FOSSisms also mention that students’ changes aren’t likely to completely mess up a project because of versioning and branches exist. This is reassuring that something I do for the project, even something small, is still helpful, and changes I make would not be entirely damaging.

I read up on Theas Pantry at https://gitlab.com/LibreFoodPantry/client-solutions/theas-pantry/documentation/-/blob/main/README.md. An interesting component of information from those files is the User Stories. I wanted to highlight this because it is helpful in helping us understand the flow of how signing in would work for different people, and any restrictions there may be. This gives us a better idea of the coding. For example, we know to code for a blank registration form appearing if the visiting guest’s WSU ID has not been swiped at the pantry before. We would also know to code for the guest’s current information to be displayed if they’ve visited before. On the topic of restrictions, the user story tells us that only one guest is allowed in the pantry at a time, so we know to maybe only code for up to one person to be signed in at a time, and they’d need to sign/check out before another guest could.

From the blog CS@Worcester – CS With Sarah by Sarah T and used with permission of the author. All other rights reserved by the author.

GRASP

In this final week of blogging for CS-343, I wanted to look over the General Responsibility Assignment Software Principles, or GRASP.

I took to learning about GRASP from Code Specialist at https://code-specialist.com/code-principles/grasp/, which discussed all nine GRASP principles and provided diagrams and code examples.

I’ve learned that the nine principles are: controller, creator, indirection, information expert, low coupling, high cohesion, polymorphism, protected variations, and pure fabrication.

Controller: helps “control” (not implement) events indirectly related to the user interface. It acts as a mediator between signals from the user interface and the backend.

Creator: a class responsible for the creation of certain objects, such as object A. This principle has a few rules for the creator, which are: creator B aggregates instances of A, B contains A objects, B records instances of A objects, B closely uses A objects, and B has the inputs for when A is created.

Indirection: is an idea that works with other concepts, like low coupling. It serves to avoid direct coupling. For example, the controller is an indirection between the UI and backend.

Information expert: a class containing the information needed to decide where an operation should occur. The operation should occur where most of the input needed for it is stored.

Low coupling: the idea of little interdependency between modules. By having few dependencies between modules, it would be less complicated to make changes to the code.

High Cohesion: describes the flow inside modules, not between them. High cohesion mainly helps to reduce complexity. Classes should be made to only fit their purposes and not go beyond that scope. We should not have large classes that do not really relate and are hard to work with.

Polymorphism: there are many variations of the same method and they work differently in different classes.

Protected variations: wrap unstable code with a stable environment. The unstable code can be wrapped with an interface that creates multiple implementations of that code.

Pure fabrication: creating a class that does not represent a real-world problem, but serves to support low coupling and high cohesion.

I thought this was a nice source to learn from because the page has neat orientation and provides diagrams and some sample code. Many of these principles seem interconnected with other principles to help reduce the complexity of code. High cohesion reminded me of the SOLID design principle single-responsibility principle in which classes have one responsibility and should not cover more than that responsibility. It would make the classes easier to understand, and less changes would need to be made to the class if it covers less functions. All of these principles I have learned will help me write neater code in the future as I keep in mind the need to reduce interdependence and complexity.

From the blog CS@Worcester – CS With Sarah by Sarah T and used with permission of the author. All other rights reserved by the author.

Anti-Patterns

In addition to learning about design patterns that should be referenced when programming, I wanted to learn about bad software design, which led me to anti-patterns.

A wonderful source covering anti-patterns that I learned from can be found at: https://www.freecodecamp.org/news/antipatterns-to-avoid-in-code/.

Anti-patterns are bad software designs that show how not to solve problems in programming. The source covers 6 different anti-patterns: Spaghetti Code, Golden Hammer, Boat Anchor, Dead Code, Proliferation of Code, and the God Object.

Spaghetti Code is when there is barely any structure to the code. Files are thrown in random directories and it is difficult to follow the flow of the program. This would produce many issues when needing to modify the code, because the program can break and it would be difficult to tell what caused it. It would also be difficult to estimate what may break after you make a change.

Golden Hammer is when you repeatedly use an architectural approach in your code that does not exactly fit the program you are making. Despite the fact that it doesn’t exactly fit the program, it is still utilized because it gets the job done eventually. Problems arise from the fact that it does not fit the program, and can cause longer runtimes.

Boat Anchor is when programmers leave code in the codebase that has no purpose at the moment, and is kept incase it is needed in the future. This code acts as an anchor because it holds the program back– it increases build time, and can make code reading difficult when programmers have to discern between code used and the code saved for later.

Dead Code is when programmers cannot tell which parts of code are currently necessary for the program and which parts of code are no longer needed.

Proliferation of Code is when objects in your codebase only serve to create a more important object. This makes the code more difficult to follow.

God Objects are objects that have too many responsibilities. The code should be broken down more so that objects do not have to undergo functions that other, smaller bits of code can cover.

The Boat Anchor anti-pattern reminded me of YAGNI (“You aren’t gonna need it”). YAGNI is the principle that you should not add functionality to the program until it is actually needed. Adding the functionality in advance may end up messing with schedules and requirements may be changed in the future where that functionality is not even needed. The God Object anti-pattern reminded me of the single-responsibility principle (which the article briefly mentions). These anti-patterns will be very useful to apply to my code to prevent the program from being too complex and hard to follow.

From the blog CS@Worcester – CS With Sarah by Sarah T and used with permission of the author. All other rights reserved by the author.

REST API Design

For the past few weeks, I have been working on class activities relating to REST API Design. I wanted to research more about it before continuing to homework assignments utilizing it.

This led me to the website: https://www.mulesoft.com/resources/api/what-is-rest-api-design.

REST API is an application programming interface that uses the constraints of REST, or Representational State Transfer. REST API takes advantafge of HTTP which means that developers do not need to install additional software to utilize it. There are six main constraints of REST API design: client-server, stateless, cache, uniform interface, layered system, and Code on Demand.

Client-server constraint: the client and the server should be separate from each other and be able to change separately. This would allow changes to be made to a mobile application without impacting the server, and also for changes to be made to the database or server without affecting the mobile application.

Stateless constraint: REST APIs are stateless, meaning that each call can be made independently and have enough data to complete itself. REST APIs should only rely on the data that is given in the call itself. Servers do not store identifying information; instead the call has that information, be it an access token or user ID. This helps make the API more reliable because it does not need to rely on multiple calls to the server to create an object.

Cache constraint: REST API should encourage cacheable data to be stored.

Uniform interface constraint: the uniform interface should provide a standard way to communicate between the client and server. The uniform interface should also allow the evolution of the application without the application intertwined too much with the API layer.

Layered system constraint: having a layered system helps shield differently accessed components from one another. It allows for systems to be moved in and out of the architecture which can help as technology evolves. It can also help with security, as it can help with attacks at a proxy layer or other layers before it reaches actual server architecture.

Code on Demand constraint: this constraint is optional, but it allows for code or applet to be sent out through the API, meaning the server can add information to the code.

I chose this source because I wanted to read about how REST APIs are broken down, and how these constraints are helpful. This source helped me understand how the individual evolution of the servers and the clients are important, and I will consider this information for when I need to decide if REST API is the type of API I should utilize for a future project.

From the blog CS@Worcester – CS With Sarah by Sarah T and used with permission of the author. All other rights reserved by the author.

SOLID Principles of Object-Oriented Programming

Thinking about design patterns, I decided to research the SOLID principles that reinforce the need for design patterns.

A wonderful source explaining the SOLID principles is from https://www.freecodecamp.org/news/solid-principles-explained-in-plain-english/.

The SOLID acronym was formed from:

  • Single Responsibility Principle
  • Open-Closed Principle
  • Liskov Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle

The Single Responsibility Principle states that a class has only one responsibility and therefore should only have one reason that it changes.

The Open-Closed Principle states that extensions to classes can be added for new functionality, but the code of the class should not be changed.

The Liskov Substitution Principle states that objects of a subclass should be able to work with methods that expect the object of the superclass and the method should not give irregular output.

The Interface Segregation Principle relates to separating interfaces. There should be multiple specific interfaces versus creating one general interface in which there are many overridden methods that have no use.

The Dependency Inversion Principle states that classes should depend on interfaces or abstract classes rather than concrete classes and functions. This would help classes be open to extensions.

I researched SOLID from this source because it had in-depth examples of code violating the examples, and how it could be fixed. For the Single Responsibility Principle example, it showed how class Invoice had too many responsibilities and separated its methods and created class InvoicePrinter and InvoicePersistence so that each class has one responsibility for the application.

The Liskov Substitution Principle example involves a Rectangle superclass and Square subclass (because a Square is a Rectangle). The setters for the Square class are overridden because of the property of squares to have the same height and width. However, this violates the principle because of what happens when the getArea function from the Rectangle class is tested. The test class puts in a value of 10 for the height and expects the area to be width * 10, but because of the override for the Square class dimensions, the width is also changed to 10. So if the width was originally 4, the getArea test expects 40, but the Square class override makes it 100. I thought this was a great example because I would expect the function to pass the test but did not remember how assigning the height in the test would also change the width.

The examples provided were very helpful in understanding how it can be seen in code, and the diagrams were a bonus for visual representation of the code. Going forward, I will know that I have this information to reference, if need be, when dealing with class designs. It has shown me principles to help make coherent classes with detailed explanations.

From the blog CS@Worcester – CS With Sarah by Sarah T and used with permission of the author. All other rights reserved by the author.

Code Smells

This week, I wanted to read up on code smells. Code smells are conditions of code that indicate problems with code quality.

A great resource I stumbled upon is “Everything you need to know about Code Smells” from Codegrip at https://www.codegrip.tech/productivity/everything-you-need-to-know-about-code-smells/.

Code smells may slow down processing and can make it easier for bugs to develop in the program. There are three levels of smells: application level, class level, and method level smells.

Codegrip lists duplicate code, shotgun surgery, and contrived complexity as application level smells. Duplicate code, of course, is similar code that appears in more than one location. Shotgun surgery is a change that results in the need to change other classes. Contrived complexity is using complex design patterns where a simpler design could be used.

Class level smells are: large class, freeloader, feature envy, divergent code, data clump, inappropriate intimacy, middle man, downcasting, parallel inheritance hierarchy, refused bequest, and cyclomatic complexity.

Large class smells are when a class has too many functions and it has too many instance variables, whereas freeloader is when a class does too little. Feature envy is when a class with a method wants to use features of other classes more than its own. Divergent code smell arises from a class that has to undergo many changes in order to make a change in a system. Inappropriate intimacy is when a class depends too much on the implementation information of other classes. Downcasting is when there’s a typecast that breaks the abstraction model. Parallel inheritance hierarchy smells are present when you make a subclass for a single class, and then a subclass must be made for other classes. Refused bequest is when a subclass does not use the methods and data of the superclass. Cyclomatic complexity smells occur when a class has an excessive amount of branches and loops.

Method level smells are: long method, speculative generality, message chains, too many parameters, oddball solutions, god line, excessive returner, and identifier size.

Speculative generality smells are present when only test cases are users of methods. Message chains are when methods call on other methods and those methods call on additional methods. Oddball solutions occur when multiple methods are used to solve the same problem. God line is when a line of code is unreasonably long. Excessive returner is when a method returns more data than what is actually needed. Identifier size occurs when the identifier is too short or too long.

I selected this source because I liked how it neatly categorized the different levels of code smells and offered an audio version of the post. In addition, I thought it was interesting to see how Codegrip explained code smells as it provides tools to recognize code smells and provides suggestions for how to resolve them. This source helped me learn the code smell types and how to recognize them. I’ll be able to apply this to my code in the future to prevent opportunities for big errors to develop down the line.

From the blog CS@Worcester – CS With Sarah by Sarah T and used with permission of the author. All other rights reserved by the author.

Technical Debt

This weekend, I decided to research technical debt. I wanted to look further into this topic because one of my classes had activity introducing the term. I came across a wonderful blog discussing the different types of technical debt and how to manage them.

The blog: https://www.bmc.com/blogs/technical-debt-explained-the-complete-guide-to-understanding-and-dealing-with-technical-debt/#ref4

The blog lists four types of technical debt: planned technical debt, unintentional technical debt, unavoidable technical debt, and software entropy.

Planned technical debt: when a team has to compromise on the code but knows the risks and damages collecting the debt will have. An example is a team not spending time coding smaller aspects of a project in order to meet a deadline. The blog advises to keep a detailed record of the compromises to help the team keep track of what to address in the future.

Unintentional technical debt: arises from struggles with new coding techniques and problems from rollouts. An example of unintentional technical debt occurring is a design having many errors due to miscommunication between different teams working on a project.

Unavoidable technical debt: arises from changes in technology and business. A business may suddenly change its views on what features a project should have, and new technology may come out that can perform the functions more smoothly. This would make old code defunct.

Software entropy: occurs as software quality degrades. This can be caused by the changes developers (who do not fully understand the purpose of some code) make that yield more complex code. Overtime, the software will be riddled with errors and will be difficult to use.

The blog discusses three ways to manage technical debt, which are: assessing debt, communicating debt, and paying off debt.

Assessing debt: technical debt can be measured by how many days it would take developers to refactor or make changes to the target project, and the monetary value of that time can be calculated. This data could then be compared to upcoming significant events to help with cost analysis.

Communicating debt: it is important to properly convey the existence and impacts of technical debt to stakeholders so that fixes can be accounted for later.

Paying off debt: there are three ways to pay off technical debt: waive the requirement, refactor the application, or replace the application. Waiving the requirement would not set the team back in creating new features. Refactoring would help improve the structure of the code without changing program behavior. Replacing the application would result in new technical debt, but it should be limited and dealt with quickly.

This blog post taught me about technical debt in more depth, with the different types and different management aspects. I was curious on how technical debt could be calculated, but I’ve learned it can be measured by time spent to make the changes. Going forward, this information can help me understand what technical debt a project has and how to help deal with it. The graphics and the video the blog attached discussing debt was pleasant to view.

From the blog CS@Worcester – CS With Sarah by Sarah T and used with permission of the author. All other rights reserved by the author.

UML Class Diagram Arrows

Seeing how one of my CS classes just recently introduced me to UML class diagrams, I wanted to conduct some research on the formation and comprehension of the diagrams. I looked for blog posts that showed examples of the diagrams and how they would be written, since I like reading written explanations and visual representations.

I stumbled across a blog covering the different arrows used in the diagrams, as well as when and how they can be used. That blog can be accessed at https://www.gleek.io/blog/class-diagram-arrows.html.

The blog presents to us six different types of class diagram arrows: directed association, inheritance, composition, realization/implementation, aggregation, and dependency. I had already seen directed association, inheritance, and implementation arrows, but I had not yet familiarized myself with the others. I learned the following from the blog:

A composition arrow in a UML diagram does not have an actual arrowhead, but instead looks like a solid diamond at the end of a solid line. The solid diamond is at the sub-object end of the solid line, and indicates that the sub-object cannot exist without the container class. It can be shown using -<*>.

The aggregation arrow looks just like the composition arrow, except that the diamond is hollow/white. The aggregation arrow is used to show association between two classes, but the subclass can still exist without the super class. It is shown with -<>.

Dependency arrows have a thin arrowhead and a dashed line. They show that two elements depend on each other but the dependency is weaker than standard association. Making changes to the parent class will have an impact on the child class. It is shown with -.->.

This blog was a great source to understand the usage of different arrows for UML diagrams. It provided great examples of when to use aggregation and composition, and I now know to take those into account for when I will need to make my own UML class diagrams in the future. It was easy to understand how the relationship between a library class and a book class can use the aggregation arrow because books can still exist after they are borrowed from the library. It was also easy to see how the relationship between a shirt class and pocket class can be composition association because a shirt pocket would not exist without the shirt. I also think it was a nice touch for the blog to include a video on the page where it explains the arrows and shows how the examples would be typed up on gleek.io.

From the blog CS@Worcester – CS With Sarah by Sarah T and used with permission of the author. All other rights reserved by the author.

Blog Introductory

Hello world!

My name is Sarah and I’m just getting started with blogging.

I’m going to be exploring different forms of media to learn about different models, techniques, and technologies related to computer science.

I hope to share the interesting information I learn with you through this blog!

From the blog CS@Worcester – CS With Sarah by Sarah T and used with permission of the author. All other rights reserved by the author.