Tag: CS-343

  • Design Patterns

    A design pattern is a general solution that can be used to solve commonly occurring problems in software design. A design pattern cannot be put directly into code, rather it is a template of how to solve a problem that can be used various situations.

    Design patterns are helpful as they speed up the development process by providing proven examples to be used as a reference for common problems. When designing software, small subtle issues can build up leading to major problems that can only be seen during implementation. Using design patterns can help prevent these subtle issues from occurring which reduces the likelihood of major issues occurring.

    Because design patterns are tested, proven, and commonly used, patterns also allows for better communication among developers by using well known and understood names for software interactions.

    Types of Design Patterns

    Creational

    Creational design patterns cover class instantiation. These patterns can be further divided into two classifications, class-creation and object-creational patterns. Class creation uses inheritance in the instantiation process, while object creation uses delegation to create objects. Some creational design patterns are:

    • Singleton
      • A class where only a single instance can exist
    • Factory Method
      • Creates an instance of several derived classes
    • Object Pool
      • Avoids expensive acquisition and release of resources by recycling objects that are no longer in use

    Structural

    Structural design patterns are about class and object composition. Like creational patterns, structural patterns can also be broken down into class creation and structural object patterns. Class creation patterns use inheritance to compose interfaces, while object patterns define ways to compose objects to obtain new functionality. Some structural patterns are:

    • Adapter
      • Matches interfaces of different classes
    • Private Class Data
      • Restricts accessor/mutator method access
    • Decorator
      • Adds responsibility to objects dynamically

    Behavior

    Behavior design patterns are about how objects communicate with each other. Some examples of behavior design patterns are:

    • Null Object
      • Used to act as a default value of an object
    • Chain of Responsibility
      • A way of passing a request between a chain of objects
    • State
      • Alter an object’s behavior when its state changes

    Conclusion

    This article was chosen because it clearly described what design patterns are, what they are used for, and gave examples of the different types of design patterns. As stated before, not only does the usage of design patterns help with preventing major issues, they also allow for better communication among developers which is essential to a team’s success which is why I chose to write about design patterns. As I continue to design software, effectively using design patterns will become more and more prevalent, so learning about them now will only be beneficial.

    Resources:

    https://sourcemaking.com/design_patterns

  • Anti-Patterns

    Anti-Patterns are “imperfect” fixes that may seem like they solve a problem, but over time, can lead to more problems where using anti-patterns are more inconvenient than not. Because anti-patterns cause problems over time, teams are forced to go back and fix them which lead to higher costs and delayed release schedule.

    Types of Anti-Patterns

    Spaghetti Code

    Spaghetti code refers to the logical structure of the code resembling a plate of spaghetti, meaning it is unorganized and confusing. Spaghetti code usually occurs when a developer starts a project without putting much thought into the organization of the code. Although the end product may work, adding functionality may increase fragility. Using the spaghetti analogy, adding more code would be like adding more spaghetti leading to an even larger tangled mess.

    Golden Hammer

    Golden Hammer refers to one tool being the solution to all problems. A developer may have used a well designed piece of code to solve previous problems, but relies too heavily on it by trying to use the code for problems that do not necessarily belong. Forcing code where it may not belong can lead to spaghetti code. The Golden Hammer concept can be thought of as trying to cut a piece of wood with a hammer.

    Boat Anchor

    The Boat Anchor anti-pattern occurs when a piece of code is left in the code base, so it can be saved for later use. Although the code may not make sense for the program, the thought process of saving the code is if the code is needed later it can be turned on and off with comments. Some may think because a piece of code is commented out, there is no harm in leaving it. However leaving unnecessary code can lead other developers confused about what the code is intended for and over time may slow down build times. Turning the code back on may also break the code if changes were made to the point where the saved code may no longer be compatible.

    God Object

    A God Object is an object or a class that has too much responsibility for the program. This violates the single responsibility principle, as every object and class should only be responsible for one single part of the program. For example, there is a customer ID class responsible for the customer’s first and last name, transactions, and more. Rather than the customer ID class manage all those details, better practice would be to have customer ID be responsible for the customer’s name while a separate class is created for transactions.

    Reflection

    This resource was chosen because it explains what anti-patterns are, why they are bad, and listed common types of anti patterns. The article was informative as I realized I am guilty of utilizing many of these anti patterns such as spaghetti code and god object. After reading this article I am now aware of these anti patterns, and will be more mindful to not use them in the future.

    Resources:

    https://www.lucidchart.com/blog/what-are-software-anti-patterns

  • Refactoring Code

    Refactoring is an important process when maintaining code bases. The goal of refactoring is to change the implementation, definition, and/or the structure of the code without changing pre-existing functionality of the application. Refactoring allows for better extensibility, maintainability, and readability. Refactoring usually results in smaller and simpler code bases, allowing new functionality easier to implement.

    When to refactor?

    Because refactoring results in simpler code bases, refactoring should be done before adding new features. Working with clean code after refactoring makes the process of adding new functionality easier. For example, if the code base is not extensible, then adding new functionality might break the code leading to more work to fix the problem. Refactoring should also be done before code reviews or before addressing bugs.

    What code needs refactoring?

    Code smells can be defined as structures in the code that indicate violations of fundamental design principles and negatively impact design quality. Code smells can be used to identify what needs to be refactored. There are over 70 refactoring techniques that help identify problems and provide a known solution. Some techniques are the Extract Method, Replacing Temp with Query, and Encapsulation of a Field.

    Refactoring techniques

    Extract Method

    The Extract Method can be used when code can be grouped together. For example, there is a class called ‘Student’ that has two print statements that prints student details such as name and year. Refactoring would include grouping the two print statements together into its own function. This is helpful because if you wanted to add more details to be printed, you only have to add one line to the function.

    Replace Temp with Query

    Temp refers to a temporary variable that holds a value of an expression to be used later in the code. This technique replaces the temp variable with a query method that returns the result of an expression. For example, there is a variable where ‘basePrice = quantity * costPerItem’. The variable can be represented as a new method called ‘basePrice()’ that returns the expression, ‘quantity * costPerItem’. If the temp variable is used among multiple classes, having a common method would more manageable.

    Encapsulate Field

    Encapsulating a field involves using methods that read and write data rather than accessing data directly. When accessing variables directly, they are often set to public which allows the data to be modified without a way to validate the change. Getter and Setter methods should be used to access class variables instead because the access level for the variables can be set to private, meaning the data itself cannot be accessed unless using the access methods. Using access methods provides a way to validate changes.

    Reflection

    This resource was used because it was clear and concise, making the content easy to understand. The article also included code examples of the techniques which improved comprehension. Before reading, I was unaware of some of the techniques listed which will be helpful when refactoring in the future.

    Resources:

    https://www.geeksforgeeks.org/refactoring-introduction-and-its-techniques/#

  • Software Frameworks

    What is a framework?

    A framework is a platform providing a foundation for creating software development projects. Frameworks can be thought of as a template of a working program where developers can modify the program by adding code. Because frameworks are essentially templates, there are shared resources that are bundled into one package. Some of these resources include libraries, image files, and reference documents. The package can be customized to match the needs of the project.

    Different types of frameworks

    Backend Web Frameworks

    Backend Web, or also known as simply Web Frameworks, are the most commonly used. These frameworks help developers create web applications and dynamic websites. The use of web frameworks has streamlined the process of web development by automating common tasks of web developers such as database access and session management. Rather than using HTML, JavaScript and CSS, backend frameworks use programming languages to access a database, hosted on a server. A common backend framework is Django.

    Frontend

    Unlike backend where frameworks are loaded server-side, frontend frameworks are executed in the user’s browser. Frontend frameworks allow developers to customize and design the way the web application looks to the user. Popular frontend frameworks are Angular JS and React.

    Mobile Development

    Nowadays mobile applications are extremely common resulting in mobile development frameworks. Similarly to desktop frameworks, these give developers a foundation to build their mobile applications while allowing full customizability. There are two types of mobile frameworks, native and cross-platform. Native frameworks are for applications that are built specifically for a particular operating system (iOS or Android). Alternatively cross-platform frameworks are for apps that are built to be compatible with any phone. A commonly used mobile framework is Flutter.

    What makes a good framework?

    A good framework should be simple to understand and easy to implement. It should also follow design principles such as:

    • Being extendable, adding new functionality by adding code rather than modifying
      • Framework cannot be modified at all, but only extended
    • Allows developers to create components that can be reused
    • Should have a default behavior and be useful. No redundant code that is unnecessary

    Why use a framework?

    Frameworks greatly reduces the time spent on developing. When starting a new project, there are steps that need to be done regardless the project. Using frameworks helps streamline that process by already providing those details. This allows developers to focus their time on extending the functionality specific to their application’s needs.

    Reflection

    This article was chosen because it broke down the different parts of a framework such as what it is, the different types, and why one might use a framework. Prior to reading this blog, I had a somewhat unclear understanding of what frameworks are. Now I understand that they are useful tools that speeds up the development process by providing essentially a template of a working program. What was learned will be applied to future, larger projects that could benefit from a framework.

    Resources:

    https://codeinstitute.net/global/blog/what-is-a-framework/

  • SOLID Design Principles

    SOLID is a subcategory of five principles, the first being:

    Single Responsibility Principle (SRP)

    SRP states that a class, module, or function should only have a singular function.

    For example, having a class ‘Animal’ with methods ‘displayAnimalName()’, ‘animalSound()’, ‘feedAnimal()’ would be a violation of SRP because each method has a different function. Creating three separate classes that would each represent a functionality resolves the violation. This entails new classes are created for DisplayName, Sound, and Feeding. Although this may lead to more code overall, having separate classes allows for better maintainability. Without SRP, making changes to one functionality may break another.

    Open-Closed Principle (OCP)

    OCP states that code should be open for extension, but closed for modification. Therefore the code’s behavior should be extended by adding more code rather than modifying the existing code.

    Function ‘getArea()’ calculates the area of a shape using a switch statement where there are cases for a square and circle. To add another shape, the switch statement must be modified to add a case for the new shape, violating OCP. To satisfy OCP, one would create separate classes for each shape that implements the Area interface. Now to add a new shape, one would add a new class and implement the Area interface rather than modify the original switch statement.

    Liskov Substitution Principle (LSP)

    LSP states that child class objects must be substitutable with objects of the parent class without affecting the correctness of the code.

    Imagine a parent class ‘Bird’ with method ‘fly()’, and child classes ‘Penguin’ and ‘Eagle’. Both inherit ‘fly()’ because ‘Penguin’ and ‘Eagle’ are child classes of ‘Bird’. Because penguins cannot fly, the ‘fly()’ method in ‘Penguin’ has been overridden to do nothing. Doing this would violate LSP because objects of ‘Penguin’ would not be substitutable for objects of ‘Bird’.

    Interface Segregation Principle (ISP)

    ISP states that users should not be forced to implement interfaces they will not use.

    Imagine an interface ‘Worker’ that has methods ‘work()’ and ‘eatOfficeLunch()’. Classes ‘FieldWorker’ and ‘OfficeWorker’ both implement the ‘Worker’ interface. Because ‘FieldWorker’ does not eat in office, the method ‘eatOfficeLunch()’ is unnecessary. This violates ISP because ‘FieldWorker’ is forced to implement ‘eatOfficeLunch()’ although the method will not be used.

    Dependency Inversion Principle (DIP)

    DIP states that high-level modules should not depend on low-level modules, keeping that as separate as possible.

    For example, there’s a project with high-level systems (backend logic), that relies on low-level modules (database access). However the project’s team wants to change the database from one type to a different. Because the high-level systems are specifically written and depend on the database type, they would no longer work once the database type changes. Having high-level systems be more abstract and able to be implemented in different ways is ideal.

    Conclusion

    The article used was chosen because it gave examples with code, making understanding easy. As someone who wishes to have a career in software development, knowing the best practices for designing maintainable code is crucial. I expect to apply these principles to all future projects.

    Resources:

    https://www.freecodecamp.org/news/solid-design-principles-in-software-development/

  • Object Oriented Programming Principles

    In object oriented programming there are four basic principles: Encapsulation, Abstraction, Inheritance, and Polymorphism. These principles are fundamental such that they are referred to as the four pillars of object oriented programming.

    Encapsulation

    Encapsulation is hiding or protecting data about a class. This can be achieved by restricting access to public methods. Variables within a class are kept private, while accessor methods are kept public in order to access the private variables.

    Encapsulating data helps prevents unauthorized modifications of data by only allowing access to the data using the defined accessor methods. For example, when adding variables to a class rather than accessing/modifying them directly, one would create “getter” and “setter” methods that would still be able to access the data. These methods would allow users the same functionality, but without the risk of undesired changes.

    Abstraction

    Abstraction is showing only relevant data of classes. Abstraction enables working with high level mechanisms of a class rather than the specific details of implementation, thus reducing complexity.

    Picture a system storing different types of vehicles. Rather than creating different concrete classes for each type of vehicle, abstraction can be applied to create one class, ‘Vehicle’, that has the frameworks of basic behaviors and attributes that all vehicles have. These could include methods and attributes such as ‘start()’ and ‘stop()’, and ‘make’ and ‘model’. Then classes for each type of vehicle can be made to extend the ‘Vehicle’ class. Classes that extend ‘Vehicle’ can add specific implementations to the methods and attributes, depending on the vehicle.

    Inheritance

    Inheritance can be defined as having a “is-a”/”has-a” relationship between a parent class and it’s child classes. The child class derives all methods and attributes from the parent class, enabling reuse of code, but also allowing the addition of unique attributes and methods.

    Imagine a system for a college representing faculty and students. A parent class, ‘Person’, is created for common data among all people at the college such as ‘name’ and ’email’. Child classes of ‘Person’ can be created such as ‘Faculty’ and ‘Student’. Both child classes would inherit ‘name’ and ’email’ from the ‘Person’ class, while unique information can be added to each of the child classes. Unique attributes could include ‘gpa’ for ‘Student’ and ‘salary’ for ‘Faculty’.

    Polymorphism

    Polymorphism can be simply put as reusing code with different types of objects, reducing code redundancy.

    Using an interface called ‘Shape’ with method ‘calculateArea()’, different types of shapes can implement ‘calculateArea()’ and change how the specific shape uses the method. For example a square would calculate the area differently than a circle. However, both can still use ‘calculateArea()’ due to polymorphism.

    Conclusion

    As we learned earlier in the semester, many of us did not have a complete understanding of the four principles above, which is why I chose to learn more about them. After reading the blog, I now better understand the differences and why each of the principles are important. I will be implementing these principles into all future projects.

    Resources:

    View at Medium.com

  • Welcome to my first blog post! My name is Zack Tram and am a senior completing my undergraduate CS degree. In the upcoming weeks, I’ll be posting about topics relating to how software is managed, designed and constructed.

    I look forward to completing my degree this year, and everything that comes with it!

Design a site like this with WordPress.com
Get started