Skip to content
Edward Bramanti edited this page Mar 18, 2015 · 6 revisions

This page of the Wiki contains homework assignments from CMSI 402. This project was implemented in tandem with these assignments, which enhanced my knowledge of software engineering overall.

Homework 1

Problem 1.9

When implementing a control program for a dishwasher that has fewer than 10 different washing cycles, what paradigm would you use? Why?

I would use iterative techniques to create the control program. My reasoning for this is to account for a few things. While the diswasher may have fewer than ten cycles now, if the client who hired you to create this program changes their mind then you must return to the software design and requirements anyways. While a waterfall approach would work, the iterative paradigm was designed to address volatility of requirements. While they do seem clear here, they may not be as clear a few months into a project.

In addition, an iterative paradigm is a smart approach because of the volatility of technologies being used to implement the control program. If certain APIs become deprecated mid-development that are essential for the control program, then it could lead to a return to software design from implementation steps midway into the project. The advantage of the iterative paradigm is its ability to manage change well and still produce a great software product in the end.

Problem 1.10

When implementing a website with 10 different pages for a medium-size business, what paradigm would you use? Why?

While similar to my previous answer, I would continue with using the iterative approach. In this specific case, one of the advantages to using an iterative approach is if the client is happy with the work, and wants more pages and more functionality added to the site. You also address the volatility of working with web frameworks and web server technologies. If you begin implementation with Angular 1.0 and realize that Angular 2.0 will be coming out soon with many breaking API changes, it may be smarter to return to design and come back to implementation with a less volatile web framework. This is where the advantage of the iterative paradigm shows: it provides software developers with a model that allows them to react to change and produce an excellent product for the client.

Problem 2.8

####Why is the term life cycle misleading? Which term is more commonly used: life span model or life cycle?

The term "life cycle" for software is misleading because the word cycle assumes it will return to the initial step, which is initial development. If one product or program comes to an end in its software development and use, this does not necessarily mean that one will take its place. However, life cycle is still the more commonly used term today, which is why the author emphasizes the importance of this in his chapter so we are not misled. All software, in reality, has a life span model, and this does not mean anything will necessarily replace that which has ended.

Problem 2.9

####In what situation can the V-model of the software life span be used? Since the V-model is very similar to the waterfall paradigm, one thing that needs to be certain is the client's confidence in the requirements from the beginning. If the requirements are clearly defined and fixed, the V-model works well because testing is a consideration in the design and problems with the product can be found much quicker.

Problem 2.10

####What are the advantages and disadvantages of the prototyping model? The advantage of the prototyping model is that the client can see a first version of the software they want in requirements, but if they say they want something different it is more easily correctable. The requirements volatility is lessened because the prototyping model reacts to change. However, the prototyping model does not address volatility that comes in design and implementation later, and the amount of time and effort required to build a prototype may make it take longer to bring a software product to market.

Problem 3.13

What is inheritance in object-oriented technology? Give an example.

Inheritance stems out of the IS-A relationship, but it is the object-oriented representation of this relationship. The superclass, or base class, of an object is inherited and a subclass is created. Therefore, the subclass inherits the properties of the superclass. An example of inheritance would be in a software application for a school district: a person object being the superclass, and students and teachers being subclasses of this person superclass.

Problem 3.14

####What is the difference between an object and a class in OO technology?

Classes are modules that allow for the definition of properties of several objects. Objects are a subset of classes: they qre individual representation of the properties of data in the real world. For example, a book has pages, which would be an example of a possible property of a Book object. Classes allow for the main definition of the object, and there could be multiple objects using a class to define their attributes.

Problem 3.15

Describe the role of polymorphism in object-oriented technology. Give an example.

Polymorphism is used to derive something from a base type. The book provides a few different methods of doing this, but commonly this is done with variable declaration or a function parameter. One example of polymorphism would be the base class of a book deriving its Title from taking in a parameter into its constructor function.

Problem 3.16

Describe the role of "information hiding" in program comprehension.

Information hiding is where objects present themselves to the outside world as being simpler than they truly are. This is helpful in program comprehension in a few ways. Information hiding allows for complicated functions and attributes to be hidden away inside the object. It makes interactions simpler without having to manage multiple functions for multiple objects, and it makes it easier to understand the software functionality.

Problem 4.1

Draw a class diagram of a small banking system showing the associations between three classes: the bank, the customer, and the account.

Problem 4.1 UML

Problem 4.9

Explain the meaning of the activity diagram in Figure 4.15 in the textbook.

Figure 4.15 is demonstrating the activity of using version control. You first checkout your code from some source, and then you begin adding your changes to the codebase. If there are no other people working with you on this Git project, then you can go ahead and commit your changes without worry of conflicts. However, if there are other members of the Git repository, then you must first update your code and check for conflicts in the codebase. If there are none, commit; if there are, resolve the conflict and then commit.

This activity diagram allows for the application checking functionality to be seen, and how to prototype the workflow of an application.

Homework 2

Problem 5.8

Consider a class DateToDay() that contains a method char* convert(int,int,int). It converts the date into day, and the precondition is that all three integers of the date are two-digit integers, representing the month, day of the month, and a year (see the code below). Change the preconditions of convert in such a way that the year is a four-digit integer like 2010. Take into account the corresponding quirks of the Gregorian calendar.

class DateToDay {
 public:
    char* convert( int dd, int mm, int yyyy ) {
       if( !(dd > 0 && dd <= lengthOfMonth(mm,yyyy) && mm > 0 && mm < 13) )
          throw;
    
    int dayNumber = dd % 7;
    for( int y = 0; y < yy; y++ )
       dayNumber = (dayNumber + 365 + isLeapYear(y)) % 7;
    for( int m = 1; m < mm; m++ )
       dayNumber = (dayNumber + lengthOfMonth(m,yy)) % 7;
    switch( dayNumber ) {
       case 0:
          return( "Sunday" );
          break;
       case 1:
          return( "Monday" );
          break;
       case 2:
          return( "Tuesday" );
          break;
       case 3:
          return( "Wednesday" );
          break;
       case 4:
          return( "Thursday" );
          break;
       case 5:
          return( "Friday" );
          break;
       case 6:
          return( "Saturday" );
          break;
       default: throw;
    }
 }
 private:
    int lengthOfMonth( int mm, int yyyy ) {
       switch( mm ) {
          case 4: case 6: case 9: case 11:
             return( 30 );
          case 2:
             if( isLeapYear( yyyy ) )
                return( 29 );
             else
                return( 28 );
          default:
             return( 31 );
       }
    }
    isLeapYear( int yyyy ) {
       return( (yyyy != 0) && ((yyyy % 4 == 0) && ((yyyy % 100 != 0) || (yyyy % 400 == 0))) );
    }
};

Problem 5.9

You are the manager of a business software; you distribue 3-in x 5-in cards to your users and encourage them to write requests for new functionality to your software. A user of your software calls one day and says, "I can't fit my user story on these small cards. I'm going to submit a 10-page user story." What should you tell this user? Why?

You should tell the user that the card requirement must be honored. If their current user story can not be described on the card, it needs to be divided up. Instead of one ten-page user story, it will be divided up into many components so that user stories are clear and achievable. This makes things easier in making the softwware plan, and it provdes a deck of goals that the software development team is trying to achieve.

Problem 6.6

Describe a situation when a grep search fails. What would you do if this happened to you?

A grep search may fail if you are looking for a certain variable in the code, but you named it differently than one would expect due to a scoping conflict of variables. If this happens, it is important to be in the file where you expect the concept you are looking for, and then to narrow the search through other means. One example would be to simplify the grep search, so that it looks for part of a identifier so that you may be able to grab part of what you are looking for.

Problem 7.5

What is a propagating class? Give an example.

Propagating classes are classes that do not change themselves, but propagate a change to their neigboring class. One example would be a bank using a mail carrier to send a default letter, and the person having to loan the money from a friend in order to prevent default. The change originates from the bank, propagates through the mail carrier to the person who has the loan from the bank. However, the mail carrier does not have to change anything; it is performing its function, but it is propagating change to the person who has the loan with the bank.

Problem 14.3

What is the purpose of the software plan?

The purpose of the software plan is to identify the important issues of a project. This is done through a document that allows for a codification of what is to be accomplished in the project. From there, a team can make informed decisions on how to proceed.

Problem 14.8

Create a product backlog for a small software program that controls a washing machine.

Since a product backlog is created after users can get hands-on experience with some form of prototype, this backlog represents improvements and new features on top of the basic functionality of a normal washing machine.

  • Add smartwatch functionality so users can check remaining time for the wash cycle.
  • Add customization for dirt setting: mild, medium, or heavy
  • Add more customization for delicates: dress shirts and finer cloth material
  • Add custom sounds for when the wash cycle is completed or halfway done.

Problem 8.1

If you have a choice to incorporate your changes through polymorphism or through a component class, which one are you going to choose? Why?

Polymorphism is an easier change than adding a component class. Polymorphism allows for a straightfoward incorporation for the new functionality. However, this can sometimes not work for big changes, which requires using a component class. Component classes can cause change propagation though, which could break code in other parts of the app, breaking the interactions between the object-oriented modules.

Problem 10.1

After completing 100% statement coverage, is software without a bug? Give a simple example to validate your answer.

While every statement in the code has been tested, this does not necessarily mean that the software does not have a bug. Testing can only demonstrate the presence of bugs, not its absence. This is unfortunately a product of the halting problem, a problem extensively studied in the theory of computer science. Since the halting problem makes it impossible to analyze a program and determine whether the program contains an infinite loop, it makes it impossible to create a perfect tool that shows a piece of software has no bugs.

Problem 10.2

What is unit testing and why is it used?

Unit testing is verification testing of specific modules of a software package. It tests whether the many parts of a piece of software do what they are supposed to do and act according to the guidelines and constraints of each module design. It is used in verification, to make sure that a software package performs as it should. It also provides evidence to a client that the software provided does in fact work and perform according to specifications.

Problem 10.4

What is regression testing? What does regression testing prevent?

Regression testing attempts to discern whether a change introduced any bugs into currently working parts of software. Regression tests helps to verify that new functionality being introduced into code are not causing any of the previous tests to fail. Therefore, regression tests are mostly past tests for older versions of the software, to assure the development team that the introduced code into the software package did not change older functionality.

Problem 10.7

Explain the difference between unit and functional testing.

Unit testing focuses more on testing the modules that make up the codebase of the software package. It focuses on inputting values into these many modules, and verifying that the returned values are expected values. Functional testing goes beyond the scope of unit testing. Functional testing verifies the functionality of the whole software package available to users. This involvs testing the interface the user sees itself. Therefore, functional testing focuses more on what users should expect to happen ewhen they use software, while unit testing verifies for software developers that modules they have built for the software package are returning expected values.

Problem 10.12

Inspect the following code and identify bugs in it.

 public double calculatePercentage( int x, int y ) {
    if( x == 0 )
       return 0;
    else
       return x/y;
 }

One immediately apparent bug is the lack of checking if the denominator is 0. If 0 is passed in for the denominator, there is no check and it will cause an execution error. Another bug is return x/y. Since that expression is integer division, it will return as 0 instead of the expected double value. Therefore, the values must be casted to doubles before the division is performed. One optimization for the program could be returning the numerator if the numerator is 0, and returning the numerator if the denominator is equal to 1.

Homework 3

##Problem 9.1 ####During the software change process, the programmer has already done refactoring during the prefactoring phase. Why is postfactoring needed? Postfactoring is needed to prevent code decay, make future software evolution seamless, and aim for good code structure. This is performed after prefactoring because this type of cleanup needs to happen after actualization. This allows for those maintaining the software project to encounter clean, logical code structure in future development.

##Problem 9.3 ####Associate the following types of refactoring with prefactoring and postfactoring. Justify each decision.

  1. Move function from one class to another. -> Postfactoring

Functions have to have been implemented, which means methods have been actualized. This means that moving a function is postfactoring, because it happens after this actualization.

2. Extract superclass -> **Prefactoring**

This occurs because methods need to be actualized, but the superclass needs to be modified in order to represent these subclasses. That means that the superclass is prefactored, because it happens before this actualization.

3. Extract component class -> **Prefactoring**

This happens before method implementation so that the code is organized well before methods are implemented. This falls squarely within prefactoring.

4. Merge classes -> **Postfactoring**

Merging classes means that the methods have been actualized, which suggests that merging classes that now exist is a postfactoring task.

##Problem 9.4 ####From the following function printPosition(), extract a new function that returns the position of the beginning of a given string in a given text. void printPosition() { int i, j; char text[1024] = "1234567890"; int text_length = 10; char array_to_search1[4] = "23"; int array_to_search1_length = 2; int position1 = -1; for( i = 0; i < text_length - array_to_search1_length + 1; i++ ) { bool found = true; for( j = 0; j < array_to_search1_length; j++ ) if( text[i+j] != array_to_search1[j] ) found = false; if( found ) { position1 = i; break; } } cout << position1; }

I have pulled out a function named positionOfString, which takes in the necessary parameters to return the position of the beginning of a given string in a given text.

int positionOfString(char[] text, int text_length, char[] array_to_search1, int array_to_search1_length) {
    int i, j;
    int result = -1;
    for( i = 0; i < text_length - array_to_search1_length + 1; i++ ) {
        bool found = true;
        for( j = 0; j < array_to_search1_length; j++ ) {
           if( text[i+j] != array_to_search1[j] ) {
              found = false;
           }
        }
        if( found ) {
           result = i;
           break;
        }
    }
    return result;
}

##Problem 9.5 ####The following program calulates the square root of the absolute value of a given number. The program contains duplicate code, dead code, and variables without a meaning. Apply refactoring, and justify your decisions.

 public class A {
    public static void main( String args[] ) {
       double c = Double.parseDouble( args[0] );
       if( c > 0 ) {
          double t = c;
          double EPSILON = ie-15;
          while( Math.abs( t - c/t ) > t * EPSILON ) {
             t = (c/t + t) / 2.0;
          }
          System.out.println( t );
       } else {
          double t = c;
          c = -c;
          double EPSILON = 1e-15;
          while( Math.abs( t - c/t ) > t * EPSILON ) {
             t = (c/t + t) / 2.0;
          }
          System.out.println( t );
    }
       if( c < 0 ) {
          System.out.println( «Error: the number is
                                smaller than 0» );
       }
    }
 }

Since the absolute value is always taken, there is no need to check if the parsed double is greater than 0. In addition, I refactored the logic into a separate function so that it actually returns the square root of an absolute value. Finally, I used Math.sqrt. Since Math.abs is already being used, it is much simpler to just call Math.sqrt as well.

public class AbsoluteRoot {
    public double absoluteRoot(double number) {
        return Math.sqrt(Math.abs(number));
    }

    public static void main(String[] args) {
        try {
            double c = Double.parseDouble(args[0]);
            System.out.println(absoluteRoot(c));
        } catch (Exception e) {
            e.toString();
        }
    }
}

##Problem 15.2 ####Name two causes of code decay.

One cause of code decay is concept location. If there is a decayed structure of the code, it complicates unit testing and code inspection. It makes the software package increasingly unpredictable. Insufficient knowledge is another one of the reasons for code decay. If the domain of the software is not known to the programmer, the new code the programmer produces may not mesh well with the old code. This can result in code decay.

##Problem 15.4 ####Suppose that you have a method in the code that calculates a day for a given date within year 2011, and it has a day and a month as parameters. How would you wrap this method so that it calculates a correct date for the year 2012?

If you wrap the method, there are two conditions you need to check for in 2012. If it is before February 29th, you increment the day by 1. If it is after February 29th, then you need to increment by 2 days since you must take leap year into account. This will allow days in 2012 to be printed correctly using a 2011 date method.

##Problem 15.7 ####What is the difference between homogeneous and heterogeneous software? Homogeneous software means that all modules of the software package are in the same stage of the software life span. Heterogenous software means that the software package is broken into components where some modules are evolvable and some modules are decayed and can not be evolved any further. There are also stabilized modules in heterogeneous software that do not need to be change. The obvious difference is the component nature of heterogeneous software, where each part is in a different life stage.

##Problem 15.11 ####What is the difference between reverse engineering and reengineering? Reverse engineering is where programmers analyze old code, and extract relevant information from it. It is the first task of reengineering. Reengineering reverses code decay, while requiring an arduous process to do so. Reverse engineering is the first step in this process, with forward engineering occurring after this is complete.

##Problem 12.3 ####In Awesome Software Company (ASC) developers are rewarded based on their productivity as measured by LOC/day.

  1. What are the advantages and disadvantages of such a criterion?

The advantage is that more code will be written since rewards are based on the lines of code. The disadvantage of this methodology is that it will not necessarily produce good code. In most cases, it will probably cause damage to the code base.

2. _One developer, Bob, decides to increase his productivity by repeating the same lines of code. What are the effects of such a practice during software evolution?_

One problem is that the code is not DRY because the same function is being repeated over and over. An even greater side effect is if the repeated code needs to be updated, it has to be updated in every place where that code was copied. If the repeated code was a function and called in each of these instances, the logic would only need to be changed once.

3. _After a while, the manager detects a higher defect density in the code written by Bob. What type of verification should the manager use to detect the problems introduced by Bob?_

Using SIP can help detect problems that Bob may be introducing into the code earlier. Since it is a verification process, it will allow for iterative fixes and catching this duplicated code earlier so that he will not continue making the same mistake.

##Problem 12.8 ####What is a defect log? Why is it important to keep it? A defect log monitors the known defects in the code. It can be used to determine which tasks are most likely to introduce a defect, the average time to fix a bug, and how many unfixed defects there are in a codebase at any given time.

##Problem 13.4 ####What is the advantage of separating programmers into developers and testers? The advantage of separating out programmers in this way is that it prevents conflict of interest. Developers may be tempted to overlook cases in their code, but independent testers do not have this temptation. Their decisions in the creation of a test suite is inherently less biased than the developers who have worked on the software product.

##Problem 13.10 ####Is "extreme programming" a variation on AIP or DIP? [Instructor note: Justify your choice.] Extreme programming is a variation on AIP. The reason it is a variation on AIP is because it focuses on small releases so that feedback from customers is received quickly. This is an iterative process. Another example of how extreme programming is like AIP is it involves planning of these iterations, which prioritizes change requests. These quick iterations closely model the agile iterative process.

Clone this wiki locally