Category Archives: Week 5

Docker and Automated Testing

Last week, in my post about CI/CD, I brought up Docker. Docker can be used to create an “image”, which is a series of layers that are built upon each other. For example, you can create an image of the Ubuntu operating system. From there, you can define your own image with Python pre-installed as a second layer. When you run this image, you create a “container”. This is isolated and has everything installed already so that you, or anyone else on your development team, can use the image and know reliably that it has all necessary dependencies and is consistent.

Of course, Docker will get much more complicated and images will tend to have many more layers. In projects that run on various platforms, you will also have images that are built differently for different versions.

So how does this apply to CI/CD? Docker images can be used to run your pipeline, build your software, and run your tests.

The company released a Webinar discussing how CI/CD can be integrated with Docker. They discuss the three-step process of developing with Docker and GitLab: Build, Ship, Run. These are the stages they use in the .gitlab-ci.yml file, but remember you can define other intermediate stages if needed. The power of CI/CD and Docker is apparent, because “from a developer’s perspective, all you have to do is a ‘git push’ — and that’s it”. The developer needs to write the code and upload to version control and the rest is automated, with the exception being human testers who give feedback on the deployed product. However, good test coverage should prevent most issues and these tests are more about overall experience.

Docker CI and Delivery Workflow
From Docker Demo Webinar, 4:49

Only five lines of added code in .gitlab-ci.yml are necessary to automate the entire process, although the Docker file contains much more detail about which containers to make. The Docker file defines the created images and the code that needs to be run. In the demo, their latest Ubuntu image is pulled from a server to create a container, on which the code will be run. Then variables are defined and Git is automated to pull source code from the GitLab repository within this container.

Then, a second container is created from an image with Python pre-installed. This container is automated to copy the code from a directory in the first container, explained above. Next, dependencies are automatically installed for Flask, and Flask is run to host the actual code that was copied from the first image.

This defines the blueprint for what to be done when changes are uploaded to GitLab. When the code is pushed, each stage in the pipeline from the .gitlab-ci.yml file is run, each stage passes, and the result is a simple web application already hosted from the Docker image. Everything is done.

In the demo, as should usually be done in practice, this was done on a development branch. Once the features are complete, they can be merged with the master branch and deployed to actual users. And again, from the developer’s perspective, this is done with a simple ‘git push’.

From the blog CS@Worcester – Inquiries and Queries by ausausdauer and used with permission of the author. All other rights reserved by the author.

Exploring the Singleton Design Pattern

As we start to learn about more design patterns and their implementations in class, I wonder more and more about their application in the real world, as well as how they are perceived by modern developers. So far, for each design pattern we have learned, a relatively good job has been done in showing the advantages and pitfalls associated with them.

I became particularly interested in the Singleton pattern after finding the blog post: “Understanding What Singleton Pattern Costs You.” found here: https://blog.ndepend.com/singleton-pattern-costs/. There are also other sources I found that seemed to really dislike the Singleton design pattern, and I wanted to delve deeper into why that is.

In our in-class example with ducks, the Singleton solution seemed to make some sense for what we were trying to do. Rather than creating a new object every time we wanted our ducks to fly, we could have a single object and change its instance when needed. Because of the limited scope of what we were doing with the singleton pattern, we didn’t get a clear example of this practice potentially going south.

One way this can cause problems is that it can obfuscate code. Because a singleton is now essentially “global” and can be called everywhere, certain methods can do things that are part of this singleton that the method itself might not even indicate that it does. An example that the author of the blog provides is this:

In this example, the method is named BuildSimpleOrder, however, this method also logs the order. This makes it so you can make no assumptions about what your methods do, as many of them may have hidden behaviors. This has lead to a phrase that I have seen around tech blogs saying “Singletons are liars.”

This also causes problems in unit testing for similar reasons. Because you can use these singletons essentially globally, it can make it a lot harder to track problems in individual classes. This leads to high coupling. This also breaks the single responsibility principle – something that has been repeated in class a few times.

Learning about the different design approaches that we can take, with implementations evolving as the requirements change has been a good learning experience. It is becoming pretty clear that there is no “one size fits all” design and there can be advantages and pitfalls of each. However, I did want to do this deep dive on singleton, because I had seen it garner almost nothing but flak.

From the blog CS@Worcester – Alan Birdgulch's Blog by cjsteinbrecher and used with permission of the author. All other rights reserved by the author.

Edge Testing

This past week in my Software Testing course I learned about edge Testing. I think when I was first learning about this subject I was more apt to lean towards boundary testing because my thought process was that everything that is supposed to work in a program should work and that’s what is important to test. Anything outside of that can just be blocked and is time consuming and tedious to check because those values will fail. However, I was intrigued by edge testing because it made importance in all values across the domain as well as out of bounds. I saw that it wasn’t enough to just assume the failures, you had to also know why they are causing a failure in order to combat them. Some problems are not easy to find but it is just as important to test the failures as it is to test the correct values and functions. Edge testing is a much more thorough and logical approach. This article was a nice pep-talk and helped persuade my thinking, check it out!

From the blog cs@worcester – Zac's Blog by zloureiro and used with permission of the author. All other rights reserved by the author.

Refactoring or Adapting or … Both!

Refactoring is an inevitable location that all programmers reach eventually. Working on any project there is bound to be changes and new ideas or concepts on how to structure the code. With constant updates and inventions coming about everyday for the software world it simply is something we will all have to deal with. We create a program and find that we need to pass different parameter types to achieve a different outcome well now we have thirty plus methods to go back and change one by one. Now while that may be a necessary actions there is another concept to consider, that is adaptation! A good analogy of the Adapter Design Pattern is to consider a program is a cable you use to plug in an electronic device. Imagine that you travel to another country with your device and cable and now you run into the issue of a different wall socket. Your plug won’t fit even though it works just fine back home. Do you go out and buy a whole new wire to make it work with the new power source. No! Simply buy a wall adapter and your cable will work just fine(Of course you should check the voltage in real life, but the idea is the same). Perhaps there is nothing wrong with the structure of you code, you just need it to execute with different data types. By writing an adaptation class you could save a lot of frustration and time refactoring your original code. The adapter and adaptee could function by both implementing an interface and therefore the adaptee would only need to have an “implements … ” statement. In doing this you now have the ability to create any number of adapter methods instead of changing your original code. 

A nice simplistic example I found from an online article is that of the Rectangle class. Suppose you write a display() method to display the parameters of the rectangle to the user and the method expects the parameters x, y, w, h. However, the user wants to pass x1, y1, x2, y2 but this will cause an error in the display() method. If an interface is created that hold the display() method then if can be adapted in many ways and fix this issue.

My question to you is; do you think that adaptation is in fact refactoring. According to google the meaning of refactoring is “Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure”. Think about this, although I’m sure there is a clearcut textbook answer.

Design Patterns and Refactoring. (n.d.). Retrieved from https://sourcemaking.com/design_patterns/adapter.

From the blog cs@worcester – Zac's Blog by zloureiro and used with permission of the author. All other rights reserved by the author.

Inversion of Control and Dependency Injections

When I started programming, one subject I felt I never fully understood was the Inversion of Control design principle, in the context of using dependency injection when testing. These were commonly mentioned in tutorials, blogs, and documentation. My main takeaway was “make it another class’s problem”, so I think it’s time for a refresher on this topic to see if that holds true. Inversion of Control extends the Dependency Inversion principle, the D in SOLID.

Once again Martin Fowler has a great article on the subject, this time with code examples. Before I summarize his description, what is the problem that IoC solves? A picture says approximately 2¹⁰ words, so:

A MovieLister depends on both the Abstraction and Concrete Class
From https://martinfowler.com/articles/injection.html

Fowler describes a MovieLister class that can act on the MovieFinder interface. This is great for the methods in MovieLister and makes it easy to modify, but MovieLister is also creating the implementation. It would be nice to change the implementation without modifying MovieLister, especially if we want to package MovieLister for use by others, who might need a different implementation of MovieFinder.

“We would prefer it if it were only dependent on the interface, but then how do we make an instance to work with?”

Martin Fowler, Inversion of Control Containers and the Dependency Injection pattern

The basic idea is simple: create the implementation of MovieFinder in another class and “inject” it into the MovieLister. This can be done in a separate Container class, or an Assembler class.

A class acts to assemble the MovieLister by creating the concrete implementation and injecting it to MovieLister
From https://martinfowler.com/articles/injection.html

Dependency Containers allow you to keep track of the classes that you must create and their dependencies. This container will construct the dependencies, create the object you need, and return said object. This isolates all changes to dependencies into a single class. Note that this is encapsulating what varies. The user only needs to decide on concrete implementations in their own custom Container. They can implement MovieFinder in a custom class and use in in their Container.

There are three types of dependency injections: constructor, setter, and interface. The difference is straightforward: either inject the dependency with a constructor at instantiation, a public setter method, or an interface method. Fowler prefers constructors and I’m inclined to agree. If possible, it is better to have a completely constructed object immediately.

I do think this really boils down to “make it another class’s problem”, but this phrase was misleading to me a few years ago. The problem I had with it was figuring out where to end the abstraction and create a concrete class, thinking it should be yet another class’s problem. It was tempting to misuse the design pattern, which left me feeling confused when I didn’t have a good answer. At some point, you need a concrete class to actually do the work. With this design pattern that concrete class is the Dependency Container.

From the blog CS@Worcester – Inquiries and Queries by ausausdauer and used with permission of the author. All other rights reserved by the author.

UML Diagrams

During the first week of my CS 343 class we were learning about reading and writing uml diagrams. I found a article on lucid chart called UML Class Diagram Tutorial which was a big help. Its URL can be found below for anyone who is interested. It talked about hiw “Class diagrams are one of the most useful types of diagrams in UML as they clearly map out the structure of a particular system by modeling its classes, attributes, operations, and relationships between objects”. It also said how a class is made up of three block the top being for the name of the class. It also says how the middle is for attributes such as class variables. It also says how the bottom is for all the methods of the class. It also talks about the member access modifiers like how public is a “+” and private is a “-” and and static is underlined . It also talked about some I did not know about from class like how protected is “#” and package is “~” and derived is a “/” . It also talked about how to do Interfaces and Enumerations. It also had some good examples of them. Most of this though I already understood. What really helped me was the explanation of the different connections between classes and interfaces and such. It said how Inheritance is “the process of a child or sub-class taking on the functionality of a parent or super class, also known as generalization. It’s symbolized with a straight connected line with a closed arrowhead pointing towards the super class” and had an example. This connection I was not to bad with already though. What really helped me was the explanation of association and why only one side had a arrow on it sometimes which I had trouble with in class. The first type that was talked about was a Bidirectional association. They said this was “ The default relationship between two classes. Both classes are aware of each other and their relationship with the other. This association is represented by a straight line between two classes.” The second one they talked about was a Unidirectional association they said this was “a slightly less common relationship between two classes. One class is aware of the other and interacts with it. Unidirectional association is modeled with a straight connecting line that points an open arrowhead from the knowing class to the known class.”. I really learned a lot from this article and will continue to refer to it in the future if I need to be reminded about how to write a UML or how to read one.

https://www.lucidchart.com/pages/uml-class-diagram

From the blog CS@Worcester – Tim’s Blog by therbsty and used with permission of the author. All other rights reserved by the author.

Observe!

In many programs there will be an action taken only when something else has changed. For example, if there was a security app, you would not want it to continuously send you alerts that everything is fine, only when there is an actual emergency. This is where observers come in handy and in specific observer design patterns. Imagine you were creating an alarm system for inclement weather. Whenever there was inclement weather, an alarm would sound, a alarm message would appear on a phone, etc. Without observers, a person would need to run a clock that constantly checks for updates in the weather. By doing so in this process, there is a big strain on hardware. Observers send a signal when there is an update and does not require the constant checking for updates. When using observers, the design pattern should be set up such that there exists an interface called subject. This subject interface will be used to register and unregister observers, notify observers and get an update from the subject. The next interface will be the Observer interface which will contain an update method for the observer and a setSubject method, which is used to attach the subject to the observer. From here you will be able to implement these two interfaces. While implementing the Subject interface you will be able to create a class that overrides register, unregister and update the observer. When implementing the Observer interface, you will be able to override the update which allows for you to implement what the observer needs to be checking for. This allows for the user to have control over what the system is checking for. When that observer notices a change, it will be able to send a signal down to whatever class has extended subject and send out whatever notice must be sent when this event is triggered. By using this type of design pattern, the user is allowed to be very flexible while saving strain on the hardware that would normally be placed there by clocks. Many API’s use this type of design because as mentioned before, if an API had to have a clock running that was checking if someone had pressed a button every so-often, it would be chaos. The API is able to implement an observer for the buttons and when that button is pressed it updates the subject and executes whatever that button was programmed to do. This website gives a great breakdown of the design pattern and how to implement it.

Observer Design Pattern in Java

From the blog CS@Worcester – Journey Through Technology by krothermich and used with permission of the author. All other rights reserved by the author.

You’re Under Arrest

While looking at the course topics for my CS-343 class, the topic Law of Demeter caught my attention and I decided to dig deeper into the topic. I found a post by Arun Sasidharan called “Object Oriented Tricks: #2 Law of Demeter” which talks about what the law of Demeter is and how you should implement it into your code/design patterns. The Law of Demeter is basically that you shouldn’t give a single function the ability to know/navigate the entire system. Codes like ” obj.getX().getY().getZ().doSomething() ” has more knowledge of the structure system than it should. I think that it’s important to follow the Law of Demeter because not only does it look simpler to call only one method to solve a problem but it also avoids a possible security risk. If methods are able to be used and connected to figure out the layout of the system, then it makes the job of a hacker that much easier since they can figure out how they want to get to the information they want or to break the system.
The Law of Demeter seems to be a useful rule that helps to protect data and the overall structure of a system. I want to apply this to my own coding since it will simplify code and keep information secure. It seems that this is a difficult rule to apply and has some disadvantages to applying it as well like writing many wrapper methods and creating narrow interfaces. The Law of Demeter certainly fascinated me with how it can be used and why you should use it in your coding. I think that the Law of Demeter can and will be used as I learn more about it because for the most part I choose to take the easier approach in using multiple methods. Now that I know more about the Law of Demeter, I will look to apply it more in my code and find ways to avoid giving objects too much knowledge of the system structure. one thing that helped my understanding into what the Law of Demeter was was the use of the example of cells which was ” Cells don’t ask each other questions, they tell each other what to do”. this helped me to see how the Law of Demeter was applied and what it truly meant since the objects are the cells in this analogy, meaning that you shouldn’t have your objects asking around the system, the objects should be told what to do.

Link to Article Mentioned: https://hackernoon.com/object-oriented-tricks-2-law-of-demeter-4ecc9becad85

From the blog CS@Worcester – Tyler Quist’s CS Blog by Tyler Quist and used with permission of the author. All other rights reserved by the author.

Continuing Workflow Testing with GitLab Gold

Last week started again with another research meeting with Dr. Wurst. One of the things we talked about was the diagram I had previously created for the proposed workflow. Dr. Wurst wanted to see if it was possible to import and export the diagram using this tool so that it could be added to the LibreFoodPantry repository on GitHub and be in a file format that works with version control for future modifications. One question I had was how should I setup the different local GitLab and GitHub accounts during testing for the workflow for the local repository stuff that’s supposed to happen on certain users’ computers. We ultimately decided that it would be best to create a virtual machine for each account that way it keeps the browser accounts and GitLab / GitHub accounts separate from each other. We also talked about trying to fork Dr. Jackson’s BEAR-Necessities-Market repository from GitHub and try to get GitLab’s CI to run on it. Finally we talked about different roles in the whole workflow such as shop managers and who is the product owner and what guests should be able to do as far as creating issues for a project. 

I started off Wednesday by creating the virtual machines for the test accounts so I could get started with testing out the workflows. I used VirtualBox since it’s free and used Ubuntu 18 LTS as the operating system. After installing the OS, I put Java on each VM, along with Git and a basic text editor. I then signed into each account and soon started working on the workflow. I also tried importing and exporting the diagram in Draw.io and found it can do this as an XML filetype which will work with version control software. While testing the GitLab Gold workflow I hit a snag when it came to creating the feature branch. I didn’t know if the shop manager or the shop developer was supposed to create it so I emailed Dr. Wurst and paused work on this for the day. In the meantime I created GitHub test accounts so I could start working on testing the workflow in GitHub. I also forked Stoney’s BEAR-Necessities-Market into the test GitHub account and imported it into my GitLab account so that I could ultimately enable GitLab CI on it.

Thursday I learned how to move a GitLab project from my account into a group. I did this with the import of BEAR-Necessities-Market from GitHub. I then created a config file to enable GitLab CI and eventually got this to work for the repository. I did this by looking at the config file that was created for Travis CI as it was similar and translated the instructions over to GitLab. I found that GitLab does do its CI config differently than Travis but by reading GitLab’s documentation I figured out how to do what I needed to. I also tested out what permissions guest users have in GitLab with issues and issue boards. I didn’t find anything surprising here, guests can create and comment on issues and that’s about it. 

Friday Dr. Wurst got back to me and I finished testing the workflow in GitLab Gold. I found that everything worked exactly as planned and that it was a smooth process. Dr. Wurst suggested we should have a story mapping session next week for the workflow roles which I thought was great as I am beginning to have questions about who does what during this proposed workflow and the initial diagram doesn’t answer all of these questions. I briefly played around with the security dashboards for the GitLab import of BEAR-Necessities-Market and got it to report dependencies and any security vulnerabilities. This was easy to do with GitLab’s template for this. I also began to test the candidate workflow on GitHub. This is where I began to run into problems as GitHub doesn’t have the same levels of permissions as GitLab does (more on this issue next week). This altered the workflow as the shop manager had to create the feature branch instead of the shop developers. I stopped for the week after this and will continue testing on GitHub before the story mapping meeting on Wednesday.

From the blog CS@Worcester – Chris' Computer Science Blog by cradkowski and used with permission of the author. All other rights reserved by the author.

Unleash Your Enthusiasm

Hello dear readers. Welcome back to my next blog post. This time will be talking about enthusiasm in your new/current work place.

This chapter of the book  talks about how to feel and what to do about your enthusiasm at your work place, being that a new or current environment. I believe these advises would mostly apply to a new work environment as in an old environment you already know your coworkers and your boss. The author gives credits to people with enthusiasm and strongly supports them to unleash and keep the spirit up.

Getting into a new work environment it is indeed a bit hard, especially when that is your first job. When it comes to choosing a job, unfortunately you can’t really know what kind of team and people you are going to work on unless you have been recommended for that job. So being nervous is FINE. And I was crazy nervous in my interview and first week of my job.

I have heard a lot of stories about teams with employees who don’t accept suggestions or new ideas and especially when those are coming from a new employee and a recent graduated student. If you were to read their face, it would say only one thing: YOU DON’T KNOW. At that point it is time to move up and get to your manager and if you are still not heard I truly think is time to move on. But always keep your spirit and enthusiasm up because just because those people don’t accept new ideas doesn’t mean you are wrong.

Never hold back on ideas and always express them. A good team will listen to your idea and will take it in consideration and will explain why that might or not be a good idea. Nobody was experienced on their first jobs! Its true that these new team you are in might know more than you but you might know something they don’t and that’s a plus to the team productivity.

Keep in mind that nobody knows everything. Try to find the person who you think would listen and welcome your ideas. Also accept critics, its very important for your development.

 

From the blog CS@Worcester – Danja's Blog by danja9 and used with permission of the author. All other rights reserved by the author.