Category Archives: Week 8

Web Apps vs. Native Apps

With our discussions in class about typescript and java script for use with Web-apps, I believe it is important to discuss the difference between web-apps and native apps and how our knowledge of them can help us decide which one is more preferable. I choose this article by Lifewire because it provides a great compare and contrast of web-apps and native apps.

There has been an ongoing debate over what type of app is better – Web Apps or Native apps. Firstly, I think it is important to distinguish the two. Typically, a native app is an app that is used local on a device. These apps are usually downloaded and installed on the device. For example, the camera app on an android phone or Microsoft word on a desktop computer. While native apps are usually local on a device, Web Apps are apps that are not installed locally on a device.

Let’s take for instance a locally installed app. That app can access almost all of the devices features (if permissions are granted). Snapchat, for example, is an instant messaging app using a smart-device’s internal camera. That is a native app using another native app. A web app only has access to a limited number of the device’s native features. This may seem like a bad thing, however, there are greater benefits to web-apps than you may think

The great thing about native apps is that since they operate specifically on software designed for a particular device, it can be greatly optimized and catered towards that device, thus enhancing the users experience. At the same time, this means whenever a native app needs to be updated, the device needs to keep downloading updates and bug fixes. With a web app, all updates are handled on the back-end, therefore no native changes or downloads need to be made.

Both web-apps and native apps are used everyday, and arguably, they can both be used hand in hand. Web apps can be developed for native apps and native apps can be developed for web apps. Paypal has a web-app in browser, however they also have a native app that can be downloaded and updated. I think as technology progresses, we will see more web-apps as cloud computing seems to be the future. Knowing this, I personally think that web-apps will continue to evolve because they require no user action to update and they do not need to be designed for a specific system, therefore making

 

Source: (https://www.lifewire.com/native-apps-vs-web-apps-2373133)

From the blog CS@Worcester – Amir Adelinia's Computer Science Blog by aadelinia1 and used with permission of the author. All other rights reserved by the author.

Alpha vs Beta Testing

For this week’s blog I chose the article titled “Alpha Testing vs Beta Testing.” I chose this article because it covers two types of testing I haven’t read too much about. I also like the comparison type so I can see different situations why I might choose one over the other.

To start, alpha testing is a type of acceptance testing. It’s used to identify all the possible issues in a product before it gets released to users. The idea of this type of testing is to simulate real users by using blackbox and whitebox methods. The article mentions this type of testing is usually done by internal employees in a lab type environment. The overall goal is perform tasks that the typical user will be doing frequently. This testing is done near the end of the software development cycle but before beta testing if beta testing is being done.

Beta Testing is another form of acceptance testing done by real users in a real environment. It’s mainly used to gather feedback and limit product risks before the product gets released to anyone and not just a small testing group. This would be the last type of testing before a final product gets shipped to customers.

While beta testing and alpha testing share some similarities there are some key differences. The first being that in beta testing reliability, security, and robustness are checked which is not true for alpha testing. Another difference is how issues are addressed. For alpha testing it’s not uncommon to make code changes before an official release. With beta testing code changes will usually be planned for future versions after the product is released.  Lastly, with beta testing you are getting feedback from real users and this will usually be a more accurate analysis of how a product will perform over alpha testing.

For larger product firms, a product release will usually incorporate both alpha and beta testing. Below is a typical flow chart of the process.

alpha.png

To clarify, the pre alpha phase would be a prototype where not all features have been completed and the software has not been officially published. The release candidate phase is when any bug fixes are small feedback based changes have been made.

In conclusion, this article was really great comparing alpha and beta testing. It goes into more details with some advantages and disadvantages of the two as well as some entry and exit criteria however this goes beyond the scope of this blog. After reading about these two types of testing I would definitely want to include both in a product release strategy however I would choose beta testing if I could only choose one. I think real user feedback in a real time and natural environment is most valuable before releasing. At the same time it would be easy to argue that terrible feedback in a beta testing cycle could be prevented with prior alpha testing.

From the blog CS@Worcester – Software Development Blog by dcafferky and used with permission of the author. All other rights reserved by the author.

Pipe and Filter Architecture

For this week’s blog I chose an article on the pipe and filter architecture appropriately titled “Pipe-And-Filter.” I chose this article after googling what some of the most common software architectures are and learning that pipe and filter was commonly implemented. This article seemed like a good length with straightforward information and diagrams to help with understanding the material so that is what I chose it.

To begin, this architecture consists of any number of components referred to as filters due to the fact that they filter data before passing it through connectors called pipes to other components. All of the filters work at the same time and this is usually implemented in simpler sequences although is not limited to that.

pipe1

Above is a simple diagram to show how the architecture flows. It’s important to know that filters can transform the input data from any number of pipes. The pipes pass data between filters however it is unidirectional implemented by a buffer until the downstream filter can process it. The pump is where the data originates such as a text file or I/O device. Lastly the sink is the end target of the transformed data such as a file, database, or output to a screen.

One good example of this architecture would be a Unix program. One program’s output can piped into another program’s input.

pipe2

Above is a more complex diagram to show how pipe and filter can start to become complex. Different sources or pumps can interconnect data into their respective streams. An application that uses this architecture will typically link all the components together and then spawn a thread for each filter to run in.

One interesting functionality of this pattern is a recursive filter technique. This is implemented by having a filter inside of another filter.

One common issue with this type of architecture concerns what kind of data types are allowed in a certain pipe. If only one type is allowed, filters need to parse for this which can slow an application down. You may also limit yourself to what pipes can connect to which filters.

After reading this article I have a good idea of pipe and filters main concepts. One thing I wished the article had discussed more in detail would be specific implementations of this architecture. I can’t directly see how I would need to use these concepts in any of the coding I’ve done so far. I can see a general use for this model for an application that takes in a lot of raw data and needs to output it in a useful format for making business decisions. In summary this was a well written article but I need to do some further reading on implementation examples.

From the blog CS@Worcester – Software Development Blog by dcafferky and used with permission of the author. All other rights reserved by the author.

Common Code Smells

https://8thlight.com/blog/georgina-mcfadyen/2017/01/19/common-code-smells.html

This blog describes some of the most common code smells. A code smell is “a surface indication that usually corresponds to a deeper problem in the system.” Being able to catch code smells early will make it easier to refactor into code that is more extendable, readable, and supportable.

Long Methods

Having long methods makes your code harder to maintain and debug. It will also be more difficult to read as you have to keep a lot of complex logic in mind while reading a long method. Ideally, a method should not have more than one responsibility.

Refuse Bequest

Inheritance is not always the best model to use. If inherited methods go unused or are overridden to do nothing, it could be a sign of this code smell. Inheritance should only be used when a class needs to reuse code from its superclass.

Data Clumps

If multiple methods take the same type of parameters, it’s a sign that those parameters are probably related. The parameters can be combined together in a class to keep them together, which will help keep the code organized.

For example, instead of having a method with three parameters:

connect(String host, int port, String username);

They can be combined in a class so that a reference to the class object is all that has to be passed into the parameter list:

class DatabaseCredentials{
 ...
   public String getHost(){
     return host;
   }
   public int getPort(){
     return port;
   }
   public String getUsername(){
     return username;
   }
}
...
connect(DatabaseCredentials databaseCredentials);

Duplicate Code

This is the same idea as the Don’t Repeat Yourself design principle. Duplicate code is unnecessary and will create similar bugs in different parts of code.

Middle Man

If a class exists just to delegate to another class, you should ask yourself if it is really necessary. If a class doesn’t justify its existence, it should be removed.

Primitive Obsession

Primitive types give little domain context and are not always clear. Where primitives have a domain meaning, it is a good idea to wrap them in a small class to represent the idea.

Comments

Comments provide little value when they reiterate what can be read by a developer, especially if they have not been updated and no longer reflect the current code. Before adding a comment to clarify a piece of code, try to refactor the code so that the comment is no longer needed.

I chose this blog post because code smells are another topic on the concept map. They are similar to design principles and anti-patterns because being aware of them will make sure that good coding practices are being followed. Like the design principles and anti-patterns, I will be applying what I’ve learned to my future code. The more of these blogs I read the better understanding I have of how object-oriented code should be structured, which is one of the important learning outcomes of this class.

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

How to Effectively Discuss Software Testing

It is not easy to come up with a definition that truly encompasses all that the discipline of software testing entails. From writing test cases to performing automated testing, what a particular software tester does can vary greatly. It is not surprising then, that there often misconceptions surrounding discussions of software testing. Reading a post titled “Six Things That Go Wrong With Discussions About Testing” by James Bach on his blog gave me insight into some of the things that I should avoid when talking about testing.

The first point that Bach brings up is that the number of test cases that you have written does not matter. To anyone who has ever written a test case, this is a pretty obvious one. You could write a million test cases that all do the same thing, but if you’re not exercising the code in unique and possibly unexpected way, then you are wasting your time. Any tester who brags about the number of test cases that he or she has written is clearly missing some critical understanding of the purpose of testing software.

Secondly, Bach states that each test should be thought of as an event rather than as an object. Whether it is done automatically or manually, tests must be performed, they do not simply exist. This is why software testers will never be replaced by computers or algorithms. Each time a tester performs a test, it produces a unique and meaningful result. This ties in with Bach’s fourth point, which is that even in the case of automated testing, humans are responsible for the successes or failures of the tests being run. Computers are unable to think critically about problems like humans can, and they can only go so far as to check simple facts, not effectively test software.

Backtracking to Bach’s third point, testers should always be able to describe their testing strategy, even as it evolves over the course of testing. Understanding how and why a given test is being performed allows testers to think about things such as how to improve the test, what tests need to be developed next, and how to develop better tests more quickly in the future.

The fifth topic that Bach discusses is how people “talk as if there is only one kind of test coverage”. As a student currently learning about the types of testing coverage, this one came as a bit of a surprise to me. I imagine that testers who fall victim to this fallacy of testing never received formal education in software testing or have become so set in a single way of testing that they are failing to see the bigger picture.

Lastly, Bach discusses testing as an exploratory learning task rather than as some scripted, monotonous procedure. Again, I think that my current enrollment in a software testing course leaves me a bit biased on this point. Nearly every test that I write is a learning experience for me, and I certainly do not feel that testing is a static task.

While I can certainly see where Bach is coming from with all six of his “Things That Go Wrong With Discussions About Testing,” I am pleased to know that the my understanding of software testing does not fall into any of his categories for the most part. I feel that many of these things apply to testers who may have been self-taught or had minimal theoretical training. I think that my education certainly helps me to see the big picture of why software testing is so essential, rather than just going through the motions of writing test cases for the sake of it.

From the blog CS@Worcester – ~/GeorgeMatthew/etc by gmatthew and used with permission of the author. All other rights reserved by the author.

Practical Uses for Design Patterns

Sometimes completing assignments can become monotonous. I think that I find this mainly happens when I cannot seem to think of a practical use for what I am currently working on. While I understand that many of the example implementations of design patterns are intentionally left abstract so as to highlight the importance of the pattern rather than the complexities of the underlying system, this bores me. My approach to programming is often utilitarian in the sense that I want to know how what I am currently working on is going to make someone’s life easier.

(Image source: https://drquicklook.com/products/usb-to-sd-card-adapter)

This week I listened to Episode 30 of the Coding Blocks podcast, from July 26, 2015. In the episode, Allen, Joe, and Michael discuss the Adapter, Facade, and Memento design patterns. The first pattern that was discussed was the Adapter pattern. I paid particularly close attention to this pattern, as I will be researching and compiling an informative piece on the Adapter pattern in the coming weeks. The podcast provided a link to an excellent tutorial on TutorialsPoint, which I will most definitely be using as a reference for my project research. The real-life example used to describe the Adapter design pattern was that of the SD-card adapter, which takes the SD card and adapts, through the use of an interface, to a USB cable that the computer can recognize and use. The Adapter design pattern implemented in software provides a very similar function by taking two otherwise incompatible interfaces and acting as a bridge between them so that they may seamlessly interact with one another.

In the discussion of the Facade design pattern, I saw some parallels to the Adapter pattern but there were certainly also observable differences. The Facade patterns aims to hide the complexities of some underlying system by providing a simplified interface through which the user can gain access and use the resources provided by the system. The example that the three discuss that I found very interesting was transactional payment processing systems such as PayPal. The goal of applying Facade in this case would be to hide multiple repeated calls to APIs that must be completed each time a user would like to perform a task such as setting up a secure connection, passing a token, storing a token, etc. before actually accomplishing the desired task.

The final pattern that is discussed is the Memento design pattern. While the three seem to have mixed feelings about the usefulness of the Memento pattern, I thought that the discussions regarding Megaman and System Restore’s implementation of this pattern were extremely useful and interesting examples. The pattern, in a basic sense, aims to save a complete copy of the state of the object at any given time. This state object is accessed and maintained by two classes – a caretaker and an originator.

What I like most about the examples and explanations that the three give for their respective design patterns is how practical they seem. While the ultimate goal of applying a design pattern to a particular problem is to simplify the overall implementation, it is certainly not always a simple task to apply a pattern. Understanding some of the motivation behind why applying the design patterns makes an implementation cleaner and more effective satisfies my utilitarian inclinations. I am looking forward to exploring the complexities of the Adapter pattern more thoroughly in the near future.

From the blog CS@Worcester – ~/GeorgeMatthew/etc by gmatthew and used with permission of the author. All other rights reserved by the author.

Best Practices for Naming Your JUnit Test Cases

Over the past couple of weeks in our Software Quality Assurance and Testing course, we’ve been working on writing code using Test-Driven-Development as well as coming up with JUnit test cases based on code that was already written. Over this time, I’ve come to notice that naming conventions for test cases can prove to be a little challenging in some situations. This is especially the case when writing tests in a Behavior-Driven-Development (BDD) manor. BDD, I feel, has kind of become the norm when it comes to naming conventions for JUnit tests and what this means is that tests are written specifically to test certain expected behaviors of methods/classes and are named as such. To clarify this, let me give an example using the code we were working on in class; imagine you write a test case that is going to test our readToGraduate() method in our Student class. While you will most likely have multiple test cases for this method, since there are multiple factors to consider when determining if a student is ready to graduate, one of your JUnit tests might test to make sure the method returns false when the student’s LASC and major requirements are complete, and they have obtained enough credits but their GPA is less than 2.0. A possible name for this test, following the BDD practice of naming, might be:

 

As you can see this is kind of a mouth-full. Even though this describes the behavior we should expect with the given input, the readability of this code is pretty lousy. That’s why I decided to do some research on different naming conventions for naming JUnit test cases for this week’s blog post.

I found a blog post titled, Getting JUnit Test Names Right, written by Frank Appel, a software engineering professional, in which he addresses the same problem I have just described. Essentially what Frank suggests in his blog post is that we keep naming simple, which may mean making our test names less descriptive, and use good naming conventions for methods and variables inside the test case to enhance readability. He explains that test names can be made simple through our test’s name only describing state information. Hence the test case I described earlier may look something like this:

 

Although the name of this test may apply to multiple tests with different inputs we could address this by simply adding a number at the end of the name for different input values being tested.  Frank, addresses this issue as well in his explanation. He says that although this naming convention may lead to names that could apply to a variety of tests, using good naming conventions inside your test method will clear up some of the vagueness. Also, as Frank points out, since the JUnit reporting view provides pretty descriptive messages when a test fails, this will also help clear up some of the ambiguity.

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

B8: Flyweight Design Pattern

Flyweight

The blog I chose to talk about this week goes into detail about the flyweight design pattern using its applications and implementations. When the blog starts talking about the applications of the design pattern, it begins with the situations of when you should use this design pattern. It explains that flyweight is centered around memory and sharing which may not be an issue for today’s computers, but it still is prevalent within mobile phones. When there is a need to create many objects, that needs memory power to execute but this design pattern focuses on efficiently optimizing that memory sharing which helps boost performance. The application of this design is shown in the blog when it talks about the large number of objects being used by the system and how flyweight will group certain objects together to reuse code to make the entire problem less repetitive. The blog then goes on to talk about the intrinsic and extrinsic states which is explained through the types of data values the objects can hold. It explains how a concrete object may hold an intrinsic state as a value which allows that value to have certain properties. These properties can be extrinsic and be modified as needed.

I chose this article because as I read more about this flyweight design pattern, I realized it also had the possibility for factory implementation as well due to the efficiency with mass object creation. This really interested me since we just went over factories and I wanted some more experience in understanding how factories can be used in other patterns. Though it would just be used to test this design pattern, I thought it was good exposure to how they worked, and it worked well with explaining how flyweight worked. The content was easy to explain with the examples used that had written out code and UML diagrams. The blog used these resources together with JDK to produce an output based off a test class that emphasized the main points of the applications and implementations. They helped cement the idea of factories and code sharing between different objects very well and used similar concepts to those discussed in class. This would affect my future practice by allowing a new view on code reuse which is an important concept. This pattern taught me more about code efficiency using factories and different pattern concepts as well as the idea of objects having different modifiable properties.

From the blog CS@Worcester – Student To Scholar by kumarcomputerscience and used with permission of the author. All other rights reserved by the author.

Unit Testing Tips and Tricks

First of all, what are unit tests and why are they important? The meaning behind them is kind of given away in the name. They are designed to test individual features/components (a.k.a. units) of code to makes sure it is working the way it is supposed to. This helps eliminate external factors like other features affecting the one you want to test. Unit tests are used anywhere and everywhere whether you are aware that you are using them or not. I can say that we use them on a regular basis at work and I use them when writing any sort of software, even if I might not specifically think “Lets unit test this piece”. With unit testing being so important, I thought why not see if there are ways to improve them, and luckily Stormpath has a blog with tips on it that I found quite useful and intend to use in the future.

The first thing they suggest is to use a framework for testing such as Junit. To put it simply, these frameworks just make life easier. They help setup, organize, and run your tests and I cannot agree more that frameworks both make tests easier and help improve testing. Next on their list is to use test driven development. This basically means that your write the tests before you write the code. Assuming the tests are written based off requirement, this forces you to make sure you hit those requirements and it provides a more complete, modular product in the end. I generally agree with these, but I do believe there are times where this can be difficult. Sometimes the customer may not know what they want to end product to be. What happens if the design shifts in the middle of development? Then you might have to rewrite all of the tests. If possible however, test driven development is a good approach to use. They then suggest to check how much code you are covering. In other words, are you testing every line of the unit you are testing? If not, you are leaving yourself open to bugs. Stormpath discussed a couple of other suggestions as well, but they have one that I feel is particularly important, so I am going to devote my time to that one, which is to tests negative situations and edge cases.  Sure, you’ve tested all of your code and it works as long valid data has been entered. However, your program doesn’t live under a rock, so it is going to be exposed all sorts of situations. This can include users putting in invalid data. You have no control over what they are going to do with it, so your program needs to be able to handle those situations. I would argue that testing edge and invalid tests cases might be more important than normal test cases, simply because you can probably predict how it will be have when the user stays in bounds, but who knows what could happen if they don’t.

Link:

https://stormpath.com/blog/7-tips-writing-unit-tests-java

 

From the blog CS@Worcester – README by Matthew Foley and used with permission of the author. All other rights reserved by the author.

DRY, KISS, and YAGNI Design Principals

This week I have decided to continue with the discussion about design principals from last week. I like design principals because they generally provide important things to keep in mind while coding and are written in a fashion that is easy to remember (typically an acronym of some sort), which is why I’ve continued to discuss them. This week there are three I want to discuss: KISS, YANGI, and DRY. Now, you might be asking, why three? Well, these principals all focus on keeping things as simple as possible, so they kind of go together. Jonathan San Miguel has nice blog that discusses the basics of these principals.

First in the queue is DRY. Don’t Repeat Yourself. Another way of putting this would be to say, “don’t reinvent the wheel”. Have you ever been looking through your code or someone else’s code and realizes that there are similar or identical pieces of code in different parts of the program? Well, following this design principal will help eliminate that. You shouldn’t have to repeat code, and if you do, the original piece should be redesigned so you don’t have to waist your time writing the same thing over and over again. I always find it frustrating when I find similar code because I have to spend time trying to determine if they are exactly the same, why there is a need to have it twice, what is the little variation in it that made them write it twice, etc. So to summarize, unless you have a clear, distinct reason for repeating code, don’t do it.

Next up is KISS. Keep It Simple Stupid. This one is kind of self-explanatory, but basically it means don’t make your code more complicated than it needs to be. Keeping code simpler makes it easier for others to read, easier to modify, and easier to look back to later on. I especially agree with being able to go back and modify later on. At the time, the complicated code you wrote probably made perfect sense to you, but if you go back to it a year later to make some adjusts you may end up asking yourself what the heck you were trying to do with that piece of code for the next two hours. I know I’ve done it. Miguel also suggest avoiding using language specific features. By avoiding this, it can allow other people that aren’t familiar with the language to still understand what is going on.

Last on the list YAGNI. You Aren’t Gonna Need It. If you don’t need a feature at the point in time of writing it, don’t include it. You don’t need it now and you probably won’t need it in the future. You are simple wasting your time and other people’s time as well as probably causing some confusion.

I hope you found these principals insightful and useful. I know I did and will keep them in mind when writing code.

Link:

http://www.itexico.com/blog/bid/99765/software-development-kiss-yagni-dry-3-principles-to-simplify-your-life

 

From the blog CS@Worcester – README by Matthew Foley and used with permission of the author. All other rights reserved by the author.