sada_shopping
TRANSCRIPT
BSc Computing
Final Year Project Report
SADA shopping E-commerce application
Author: Rodrigo Magalhaes de Castro Supervisor: Dr. Igor Razgon Word count: 10.546 Date: 03/05/2016
BSc Computing Project Report, Birkbeck College, University of London, 2016. This report is the result of my own work except where explicitly stated in the text. The report may be freely copied and distributed provided the source is explicitly acknowledged.
Abstract
Nowadays, an increasing number of people are using the Internet to buy products and services, and
a huge number of web applications are available to users. In order to beat the competition, an e-
commerce application must be able to offer a wide range of functionalities. Creating an e-commerce
application that meets, or exceeds, the users’ expectations and needs is not an easy task and requires
a huge amount of time and effort.
This report describes the components of an e-commerce application called SADA shopping, and the
different phases of its development process, such as planning, requirements gathering, interface and
architecture design. The report also shows how the project adopted an Agile and TDD approaches.
Finally, the report gives details of how the application was hosted on the Cloud.
The final result is a complete insight into the final application structure and the difficulties and
challenges faced during its construction.
2
Table of Contents
1- Introduction.....................................................................................................................................41.1 – Project aim..............................................................................................................................41.2 – Online shopping......................................................................................................................51.3 - SADA shopping.......................................................................................................................5
2 – Project planning.............................................................................................................................62.1 – Agile methodology..................................................................................................................62.2 - Adapting SCRUM to sole development..................................................................................6
2.2.1 - User stories......................................................................................................................62.2.2 - Iterations..........................................................................................................................82.2.3 – Backlog...........................................................................................................................8
2.3 – Milestones...............................................................................................................................9 3- System Analysis............................................................................................................................10
3.1 – Target users...........................................................................................................................103.2 – User stories...........................................................................................................................103.3 – Non-functional requirements................................................................................................103.4 – Domain and database model.................................................................................................12
4 – Design..........................................................................................................................................144.1 – Application layout.................................................................................................................144.2 – Navigation.............................................................................................................................16
5 – Application architecture...............................................................................................................185.1 – Initial application..................................................................................................................185.2 – Conventions..........................................................................................................................185.3 – MVC.....................................................................................................................................19
5.3.1 – Model layer...................................................................................................................195.3.2 – Database implementation..............................................................................................225.3.3 – Controller layer.............................................................................................................245.3.4 – View layer.....................................................................................................................27
5.4 – Mailers..................................................................................................................................30 6 – Security........................................................................................................................................31
6.1 – Passwords..............................................................................................................................316.2 – Mass assignments.................................................................................................................326.3 – Cross-site Scripting (XSS)....................................................................................................356.4 – Session hijacking..................................................................................................................366.5 – Cross-Site Request Forgery..................................................................................................37
7- Testing...........................................................................................................................................387.1 – TDD......................................................................................................................................387.2 – Testing the application..........................................................................................................387.3 – User-testing...........................................................................................................................40
8- Deployment...................................................................................................................................418.1 – Heroku..................................................................................................................................418.2 – Environments........................................................................................................................41
9 – Conclusion...................................................................................................................................42 10 - Reflections..................................................................................................................................43 11 – References..................................................................................................................................44 12 – Bibliography..............................................................................................................................46 13 – Appendices................................................................................................................................49
Appendix A – User stories.............................................................................................................49 Appendix B – Test files.................................................................................................................51
Appendix C – User questionnaires................................................................................................53
3
1- Introduction
1.1 – Project aim
The aim of this project was to develop an e-commerce web application, describe its components,
explore common issues and problems a web developer faces when building such a complex web
app and how these problems can be overcome by applying well-known design patterns, following
best practises and using Rails framework’s features. The sections bellow briefly describe some of
these problems and how Rails helps to solve them:
Managing files and folders is one of the issues faced during the development of web applications.
Some developers try to solve this problem by creating a file structure from scratch and configuring
the files as necessary [1], however, this process can be error prone and time consuming. Rails solves
this problem by creating a default file structure with the minimum configuration necessary for a
simple web application, the developer can then focus on the implementation of the desired features
leaving the framework responsible for all the background configuration.
In order to build applications that are easier to maintain, good developers always try to find the best
way to reuse code. Some languages allow developers to reuse code by importing files into another
file or using external libraries. Rails has many features that make coding reusing easier, such as
partials and gems (libraries) that are very easy to implement.
The majority of current web applications have some kind of security vulnerability [2]. I order to
avoid security threats developers have to take care of things like filtering content entered in forms,
performing encryption, etc. In order to prevent security threats, Rails offers some features, such as
escaping strings by default and many security related gems (libraries), e.g. Bcrypt, which is used to
perform encryption.
4
1.2 – Online shopping
Online shopping has increased sharply in recent years. It is predicted that just in Europe it will reach
£185.44 bn in sales by 2016 [3], and some predict that in a near future it could overtake the sales
made by high street outlets.
The fact that more powerful mobile devices connected to fast and reliable networks, such as 4G, are
accessible to an increasing number of users, and potential customers, increases, even more, the
potential for the online retail market.
However, there are many barriers and constraints faced by online retailers, such as effective brand
marketing, having an application that is easy to use and offers a high level of security [4][5].
1.3 - SADA shopping
The word Sada (사다), is a Korean verb that means 'to buy'.
The SADA shopping application was built using the Ruby on Rails framework and it is intended to
be used by both customers or system administrators.
The application offers many functionalities commonly used in other online shopping applications,
which include creating and editing profiles, adding and removing products, posting product
reviews, among many others.
The application is also hosted on the cloud, and its URL is:
https://salty-lowlands-27483.herokuapp.com/
5
2 – Project planning
2.1 – Agile methodology
The Agile software development methodology, also known as just Agile, is an alternative to other
methodologies, such as waterfall and Rapid application development (RAD), and is widely used by
teams involved in big and complex software development projects.
Better user involvement, better response to changes in the project requirements and better final
product are among the reasons why Agile is so popular [6].
The most popular example of the Agile methodology is the SCRUM framework, which is
characterized by “empirical feedback, team self-management, and striving to build properly tested
product increments within short iterations“ [7].
2.2 - Adapting SCRUM to sole development
Although SCRUM is best suited to projects undertaken by teams, it is possible to borrow some of
the SCRUM's best principles to guide the development of projects undertaken by sole developers.
Development through sprint iterations, user stories, using backlogs to separate tasks that need to be
worked and tasks that are already done are all SCRUM principles that can be very helpful for sole
developers. The sections bellow try to explain how some of these principles were adapted to the
SADA application development.
2.2.1 - User stories
User stories are one of the first pieces of documentation produced in any project that follows the
SCRUM framework, they describe the system requirements from the users’ point of view, and
should be short and concise, describing 'what' are the tasks that a user wants to accomplish instead
of 'how' the user should perform these tasks [8].
6
The user stories used in the SADA development have the following format:
As a (role) I want to (some action) so that (benefit/result)
As a customer I want to add a product to the cart so that I can order the product
The MoSCoW prioritization technique was used to determine the order in which the user stories had
to be implemented [9]. Every user story has a field called ‘Priority’ with a character, M(must),
S(should), C(could) or W(won't), indicating the degree of priority for the user story. For example,
user stories with an ‘M’ would have higher priority than the rest, so it would have to be
implemented first.
Additionally, each user story has a field called ‘Acceptance criteria’, which was used to establish
when a user story could be marked as 'done', in other words, when a feature was properly
implemented [10][11].
Finally, each user story was accompanied by a test, or a test suit, which was used to test the
acceptance criteria feature(s). As a result, each user story has the following format:
<User story description> <Priority> <Acceptance criteria> <Test cases>
The picture bellow shows an example of an actual user story with the format described above:
Figure 1 – User story
7
ID USER STORY PRIORITY ACCEPTANCE CRITERIA TESTS
1 M 1- The products are displayed in the front page along with
information about the product an image if any. show_products_page_specproduct. 2- The user can clicks in a link for the product's
own page3- user can see if product is available or not
As a customer I want to see the products displayed in the catalogue so that I can select my desired
2.2.2 - Iterations
One of the core concepts of the SCRUM framework is the development through time boxing, which
in SCRUM is called a 'Sprint'. A project development using SCRUM is normally broken into many
Sprints, each lasting a predefined fixed period, for example, 1 week, in which developers have to
work on a user story, performing tasks that will result in the implementation of a system’s
functionality.
During the SADA application development, Sprints were used to focus on implementing one user
story at the time, and each Sprint lasted one week. If at the end of one week the result was not
satisfactory, an evaluation was made to decide whether the user story would be assigned another
Sprint, 1 week, or it had to be broken down into smaller user stories, for example, at the end of the
Sprint for the ‘Create product’ user story it was noticed that the assignment of categories to products
was more complex than expected, therefore, the ‘Create category’ user story was created and both
‘Create product’ and ‘Create category’ were assigned a 1 week Sprint each.
2.2.3 – Backlog
A product backlog is an ordered list of features (user stories) that need to be implemented. The
backlog used in the SADA development had a decremental order, which meant that the most
important features (Must) were placed at the top of the list.
In order divide the workload and keep the development process simple, the backlog contained only
four columns. The first column was called 'To Do' and showed the user stories that needed to be
worked, 'In Progress' indicated the user stories that were being worked on the current Sprint, 'Verify'
showed the user stories that needed to be tested and 'Done' showed the user stories that were
completed.
8
The table bellow gives an example of how the user stories were arranged at one point of the
development process:
To Do In Progress Verify Done
As a user I want to be
able to see the products
in my Wish list so that I
can manage the products
in it.
As a user I want to be
able to add or delete
products on my wish list
so that other users can
see the products I want.
As a user I want to be
able to filter the display
of products so that I can
find a specific product.
As a customer I want to see
the products displayed in the
catalogue so that I can
select my desired product.
As a user I want to be
able to see other user's
wishlist so that I can find
out what users want to
buy.
Figure 2 – Backlog
2.3 – Milestones
This section lists the project’s milestones, which had to be met by the end of the specified month.
Most of the milestones were successfully met on time, with an exception of 4, because the
application’s beta version and report were finished by mid-April, therefore, leaving less time to
revise both.
1 - October-2015 – Decide project type and name, find a supervisor, first draft of the proposal.
2 - November-2015 – Develop initial design, gather requirements, application pre-alpha version.
3 - January-2016 – Application alpha version, first draft of project report, show the report draft
to the supervisor, implement user testing.
4 - March-2016 – Application Beta version, final version of project report, show final
version of the application and report to supervisor.
5 - April-2016 – Revise report and application.
6 - May-2015 – Submit project.
9
3- System Analysis
3.1 – Target users
The target users for the SADA application are divided into two categories, administrators and
customers. Administrators are responsible for the administrative tasks, such as adding and editing
products, managing orders, among others, and customers can buy products, post reviews, manage
their profile and orders, etc.
3.2 – User stories
The user stories in this project try to describe the actions that either a customer or an admin user
should be able to perform, such as add products to shopping carts, post reviews about products,
add/edit products, etc.
For a list of all user stories please see appendix A.
3.3 – Non-functional requirements
While the user stories specified the functional requirements for the application, it was also
important to analyse the non-functional requirements, which are not related to the actions the
application must perform, but to other aspects that also affect the application, such as portability,
integrity, usability, security, among others [12].
There were four non-functional requirements for the SADA application:
The system should display different types of information to customers and administrators.
This requirement is related to the flexibility of the application, and it was fulfilled by separating the
layout displayed to different types of users, for example, if a user is and admin they will be able to
see buttons related to admin tasks, such as adding products to the application, on the other hand, if
the user is a customer they will see a different set of buttons.
10
The system should offer an authentication mechanism.
This requirement is related to security and was satisfied by implementing a ‘Sign in/Sign up’
mechanism that checks for users names and passwords.
The system should allow users to add products to the cart even if they are not logged in.
This usability related requirement was satisfied by allowing the users to add products to a cart by
pressing the “Add to cart” button even if they are not Signed in, however, they are required to Sign
in if they want to proceed to the checkout.
The system should be hosted on the cloud.
This is a portability requirement and was fulfilled by hosting the application on the Heroku cloud
platform, which is a highly scalable and free PaaS.
11
3.4 – Domain and database model
Figure 3 – Application’s classes
Figure 3.1 shows the application’s classes and their respective attributes and data types. Inside each
square, right bellow the class’ name, there are two types of declarations, ‘has_many’ and
‘belongs_to’, these declarations indicate the associations of a class with other classes, for example,
the ‘Order’ class has two declarations, ‘has_many :product_items’ and ‘belongs_to :user’, these
declarations mean that each instance of the ‘Order’ class is associated with many instances of the
‘ProductItem’ class (has_many: product_items), and to one and only one instance of the ‘User’ class
(belongs_to :user).
All the classes are directly linked to database tables with similar names, for example, the ‘User’
class is linked to a table called ‘Users’. The link between the classes and tables is done through a
technique called Object-Relational Mapping (ORM), which will be better explained in chapter 5.
12
The diagram bellow shows the database tables and the relationship among them.
Figure 4 – Entity-Relationship
As it was pointed before, each class is linked to a database table, consequently, the classes’
attributes and tables’ columns will have the same name. The associations among classes also reflect
on the relationship among the tables, for example, the association between the ‘Order’,
‘ProductItem’ and ‘User’ classes can be seen reflected on the relationship among the ‘Orders’,
‘ProductItems’ and ‘Users’ tables, since one row in the ‘Orders’ table can be related to one or many
rows in the ‘ProductItems’ table (has_many :product_items/one-to-many), and it is related to one
and only one row in the ‘Users’ table (belongs_to :user/one-to-one).
Another example of the link between classes and tables is the association between the ‘Product’ and
‘Category’ classes, both classes use the declaration ‘has_many:categorizations’ which associates
each one to an intermediate class called ‘Categorizations’ that has a ‘product_id’ and ‘category_id’
attributes. Similarly, the ‘Categorizations’ table is used to intermediate the many-to-many
relationship between the ‘Products’ and ‘Categories’ tables.
13
4 – Design
4.1 – Application layout
The image bellow shows a wireframe of the application's index page.
Figure 5 - Wireframe
1- Application logo.
2- Header.
3- If the user is signed in, a link to the user's account is displayed alongside a ‘Sign out’ button,
otherwise, a ‘Sign in’ and ‘Sign up’ buttons are displayed.
4- Search box to refine the display of the products.
5- Sidebar links.
6- Product image.
7- Product name.
8- Product details.
9- Shopping cart (only displayed if user adds a product to the shopping cart).
10- Footer.
14
2
10
68
1
7
68
7
4
9
3
5
The application has a simple 3 columns layout with two columns, sidebar and main content, visible
all the time and a third column visible only if the user adds a product to the shopping cart.
The links displayed on the sidebar are different for administrators and customers. When a customer
is signed in, the sidebar displays links, such as 'My account' and 'My orders, that are commonly
used by all customers. On the other hand, if the user signed in is an admin, the sidebar displays the
links to the pages that perform administrative tasks, such as add products, manage orders, among
others. Similarly, if an administrator accesses the page for a product, he/she can see links to edit and
delete the product being displayed on the page as well as a list of users that added that product to
their wish lists.
15
4.2 – Navigation
The diagrams bellow illustrate the navigation structure for the SADA application. The navigation
can be different depending on whether the user is signed in or not, and if the user signed in is a
customer or an administrator.
Figure 6 – Not signed in navigation
Diagram 4.2 shows the application navigation when the user is not signed in. The ‘Products’ page is
the index page and shows a catalogue with all the products, the ‘Product’ page is the page for
specific products, where only one product is shown.
Even if the user is not signed in he/she can add products to the shopping cart, which is then
displayed only on the 'Products' and 'Product' pages. The user is able to access the 'Edit cart' page
through a link on the shopping cart.
16
Figure 7 – Signed in customer
The diagram shown in figure 4.3, shows the navigation when a customer is signed in. In addition to
the pages shown in diagram 4.2, customers can access the 'My account', 'My wish lists' and 'My
orders' pages. Customers can also access the 'Review' page for a specific product.
Figure 8 – Signed in administrator
The diagram in figure 4.4 shows the navigation structure when an admin user is signed in. When the
admin accesses the 'Product' page he/she can see a link to the 'Edit product' page, where the
product details can be changed. On the same ‘Product’ page, the admin can also see a list of users’
name that added that product to their wish list, each name is a link that redirects to the user's profile.
If the 'Orders' page is accessed by an admin user, it displays a list of all orders from all users
alongside a link to the 'Edit order' page where he/she can change the dispatched status of the order,
for example from 'No' to 'Yes'.
17
5 – Application architecture
5.1 – Initial application
The first step when creating the SADA application was to run the command “rails new
sada_shopping” in the Rails’ command line. This command created a simple web application with
an initial set of folders and files.
The sections bellow explain the final structure of the application, and how some conventions and
best practises were used during its development process.
5.2 – Conventions
The development of web applications can be a very complex process and this complexity might
lead to many problems such as bugs and applications that are difficult to maintain.
In order to simplify the development process, Rails encourages developers to follow some common
software development principles. Two of the most important principles used in this project were:
Don't Repeat Yourself (DRY): This principle states that code should not be repeated, hence
avoiding duplication that can make the program faulty and difficult to maintain [13]. Rails
encourages extensive use of partials and helpers so that the same code can be reused in different
parts of the application, resulting in less repetition and consequently fewer lines of code. For
example, the “admin_user?” method inside the ApplicationController is defined as a
‘helper_method’, and as a result, it can also be used in the View files (view layer).
18
Convention Over Configuration: This principle states that “Systems, libraries, and frameworks
should assume reasonable defaults. Without requiring unnecessary configuration, systems should
“just work” [14]. Rails follows this principle by creating default names, locations and configuration
for files. For instance, Rails Controllers automatically renders data to View files that have the same
name as controller actions, therefore, if the “new” action in the UsersController creates a variable
“@users” the “new.html.erb” in the users view folder will be the only file able to access the
“@users” variable.
5.3 – MVC
MVC is a software architecture pattern used to separate a system into three different layers, each
one “being capable of being engineered and tested in isolation“ [15]. The M stands for Model,
which is the layer responsible for persisting the application's data, the V stands for View, which is
the presentation layer, and the C is the Controller, which is responsible for connecting the Model
and the View layers.
The Sada application follows the traditional MVC pattern. The following sections describe in more
detail all the application's layers and also the best practises that were applied when building each
one of them.
5.3.1 – Model layer
The application's model layer is responsible for the business/domain logic, validation, data
persistence and class association/database table relationships.
Logic encapsulation
It is always a good practice to keep the domain logic isolated in the model layer (classes), and that
was always a concern during the SADA application development, for example, the code bellow
shows a function that determines if a product was recently added to the database:
1 class Product < ActiveRecord::Base 2 //code 3 def new? 4 Time.now < created_at.to_time + (60 * 60 * 24) 5 end 6 end
19
The responsibility to determine whether a product is new is encapsulated in the Product class, then
if any other part of the application needs to know whether a Product instance is new, it just needs to
call the '.new?' method on that instance of the Product class. If the rules for a product being
considered ‘new’ changes, for example, a product is ‘new’ if it was created in less than one week,
instead of one day, as it currently is, the changes need to be done in only one place, the Product
class (model layer).
Validation
Validation is essential for any web application since validation restricts the access of invalid or
malicious data to the application. Examples of validation are checking if a field is present and
checking if the data entered respects a specific pattern. Some validation can be done on the client
side, in order to make the application more responsive and interactive, for example, to show the
validation errors as the user fills the forms, however, the main responsible for the validation should
be the server side, more specifically the model layer of the application. The code bellow shows an
example of validation of the SADA application's User class:
1 class User < ActiveRecord::Base 2 //code 3 validates :name, presence: true 4 validates :email, presence: true, format: /\A\S+@\S+\z/, 5 uniqueness: { case_sensitive: false } 6 validates :password, length: { minimum: 8, maximum: 15, 7 allow_blank: true }
Each 'validates' method takes as its first parameter the name of the field that needs to be validated.
The first validation, line 3, validates the “name” field. It uses another method called 'presence' that
in this case has a value 'true', and indicates that the field must be present when the object is saved in
the database.
In the line 4, the second validation, in addition to checking if the field is present, checks if the value
in the ‘email’ field follows a specific regular expression. It also uses the 'uniqueness' helper method
to check if the field has a unique value when compared to other fields of different instances of the
same class.
On line 6, the ' length ' helper is used to restrict the minimum and maximum length of a field.
20
Other helper methods were also used to validate the classes throughout the SADA application, such
as in the Product class:
validates :quantity, numericality: { greater_than_or_equal_to: 0}
The 'numericality' checks if a field value is numeric and in this particular case it takes another
helper 'greater_than_or_equal_to' that checks if the value is grater than 0.
Associations
The SADA application's model layer is also responsible for defining the associations between
different classes, which also reflects on the relationship among tables in the database.
1 class User < ActiveRecord::Base 2 //code 3 has_many :orders, dependent: :destroy 4 //code 5 end 6 7 class Order < ActiveRecord::Base 8 //code 9 belongs_to :user 10 //code 11 end
The code above shows two different classes (models), ‘User’ and ‘Order’. In line 3, the User class
uses the 'has_many' declaration, this declaration indicates that each ‘User’ instance is related to
many ‘Order’ instances, which generates a one-to-many relationship between the ‘Users’ and
‘Orders’ tables in the database. On the other side of the association, line 9, the ‘Order’ class declares
that it 'belongs_to' a user, that means that each instance of the ‘Order’ class is associated to one and
only one instance of the ‘User’ class, as a result, each row in the ‘Orders’ table have a 'user_id'
column, which is a foreign key linked to a row in the ‘Users’ table.
The associations create methods in the classes that can be used to query the tables in the database,
for example, the ‘has_many’ association on the ‘User’ class creates the ‘.orders’ method, when this
method is called it creates a SQL statement that will query the ‘Orders’ table to find the row that
have in its ‘user_id’ column the id of the ‘User’ instance calling the function.
21
Another example of associations among the SADA application classes is shown bellow:
1 class User < ActiveRecord::Base 2 //code 3 has_many :wishlists, dependent: :destroy 4 has_many :wished_products, through: :wishlists, source: :product 5 //code 6 end 7 8 class Wishlist < ActiveRecord::Base 9 belongs_to :product 10 belongs_to :user 11 end 12 13 class Product < ActiveRecord::Base 14 //code 15 has_many :wishlists, dependent: :destroy 16 //code 17 end
The code above shows the classes User, Wishlist and Product.
Both ‘User’ and ‘Product’ classes are associated to the ‘Wishlist’ class, through the 'has_many
:wishlists' declarations, lines 3 and 15, which creates a ‘.wishlists’ method inside each class, this
method creates SQL statements that query the ‘Wishlists’ table to find the row(s) that have the id of
the class, either ‘User’ or ‘Product’, instance calling the function.
On the other side, the 'belongs_to :product' and a 'belongs_to :user' declarations in the ‘Wishlist’
class create a ‘user_id’ and a ‘product_id’ attributes in the Wishlist class, and consequently columns
with the same name in the ‘Wishlists’ table.
5.3.2 – Database implementation
In chapter 3, the figure 3.1 shows the representation of the application's classes. Each class is
directly mapped to their corresponding database tables through a technique called Object-Relational
Mapping (ORM). The ORM technique basically maps each class instance to a row on the database
table, and each class attribute to a column on the table. [16].
22
Class/Table mapping
Each class corresponds to a database table named with the plural version of the class name, for
example, the ‘User’ class is connected to the ‘Users’ table in the database, which means that each
‘User’ class instance is related to a row in the ‘Users’ table, similarly, every attribute in the ‘User’
class corresponds to a column in the ‘Users’ table, for example, the ‘name’ and ‘email’ attributes in
the ‘User’ class corresponds to the ‘name’ and ‘email’ columns in the ‘Users’ table.
Migrations
The database tables were created and modified by using 'Migration files'. A migration file can be
created as a stand-alone file, however, it is more convenient to automatically create migrations
whenever a new class is created, for instance, when the ‘Product’ class was created, by running the
command 'rails generate model Product', the migration file 'create_products.rb' was automatically
created in the '../db/migrate' folder.
1 class CreateProducts < ActiveRecord::Migration 2 def change 3 create_table :products do |t| 4 t.string :name 5 t.text :description 6 t.decimal :price 7 t.string :image_url 8 9 t.timestamps 10 end 11 end 12 end
The file above contains a Ruby class, CreateProducts, that has only one method called 'change', line
2, which has a Ruby block called ‘create_table’, line 3, with the name of the table to be created,
'products' in this example. The lines 4-7 generate the table's columns that are named the same as the
attributes in the ‘Product’ class. Therefore, the process of creation of tables can be resumed as:
class creation → migration file creation → database table creation
23
When a change had to be made to the database schema, such as adding or deleting a column, a
separated migration file was created, for example, after creating the ‘User’ class and subsequently
the 'Users’ table, it was necessary to add the 'admin' column to the latter showing whether a user
was admin or not, this was achieved by creating the migration file below:
1 class AddAdminFieldToUsers < ActiveRecord::Migration 2 def change 3 add_column :users, :admin, :boolean, default: false 4 end 5 end
This piece of code shows another of the Rails naming conventions (convention over configuration
principle), when naming the migration with the format AddSomethingToSometable Rails assumes
that we need to add something, perhaps a column, to a database table. Therefore the
'AddAdminFieldToUsers' migration has a change method, line 2, that calls a method add_column,
line 3, that generates the SQL statement in order to change the database schema.
5.3.3 – Controller layer
Controllers are known as the big orchestrator in Rails applications. Controllers are responsible for
routing all the application's request-response actions.
Because the controller layer is one of the most important parts of any application, many developers
tend to define most, or in some cases all, of the methods in the controllers, however, this can result
in very complex controllers that are difficult to understand and maintain.
One of the concerns during the SADA application development was to make Controllers as simple
as possible by distributing responsibilities to other parts of the application. Bellow are some
alternatives used to accomplish that:
Inheritance
All the controllers in the application are subclasses of the super class ApplicationController, which
means that every function defined in the super class will also be accessible by the subclasses, for
example, the ApplicationController class has a method called 'logged_user' that assigns the user to a
session or returns the user associated with the current session. The same code inside the
'logged_user' function is used by three other controllers, ProductItems, WishLists and Reviews
through inheritance.
24
Callbacks
Callback functions are very useful for avoiding duplicated code in controllers. Their arguments can
be any function defined either in the ApplicationController or in its subclasses. The example bellow
shows how they were implemented in the SADA application:
1 class UsersController < ApplicationController 2 //code 3 before_action :request_signin_first, except: [:new, :create] 4 //code 5 end 6 7 class ReviewsController < ApplicationController 8 //code 9 before_action :request_signin_first, except: [:index, :show] 10 //code 11 end
The code above shows two different classes (Models) and it is an example of callbacks being used
to avoid duplicating code.
A function called “request_signin_first” is defined in the ApplicationController class, both the
UsersController and ReviewsController use the “before_action” callback followed by the
“request_signin_first” function, lines 3 and 9 respectively, to run the method before specific
actions. If the callbacks were not used, the whole code for the “request_signin_first” function would
have to be placed in each one of the controllers' actions that need to use it, which would generate a
lot of duplication. The “except” keyword, lines 3 and 9, filters the number of controller actions that
need the callback functions.
'Fat model, skinny controller'
'Fat model, skinny controller' is a design pattern commonly used on applications that follow the
MVC pattern. According to this pattern controllers should be only responsible for managing the
application's request-response logic [17], therefore, it is always a good practice to push any domain
logic from the controllers into the application's model layer, for example, the product index page
displays whether a product is “IN STOCK” or “OUT OF STOCK”, but which part of the
application is responsible for ‘deciding’ whether a product is available(in stock) or not?
25
The first solution found for this problem was to define a function called 'product_is_available'
inside the ProductsController, however, this solution proved to be a 'bad' solution, as explained
bellow:
1 class ProductsController < ApplicationController 2 //code 3 def product_is_available(product) 4 if product.quantity > 0 5 "YES" 6 else 7 "NO" 8 end 9 end 10 11 helper_method :product_is_available 12 //code 13 end
The code above shows the 'product_is_available' method, lines 3-9, which is assigned to a helper
method, line 11, as a result, the product page can call this function in order to show if the product is
available or not.
<p> Availability: <%= product_is_available(product) %> </p>
Although this solution would work, it would violate the controller’s purpose definition since now
the controller is not only responsible for routing requests but also for ‘deciding’ if a product is
available or not.
The solution adopted was to push the responsibility of 'deciding' if a product is available from the
controller to the model layer, therefore the ‘Product’ class received the method bellow:
1 class Product < ActiveRecord::Base 2 //code 3 def available? 4 quantity != nil && quantity > 0 5 end 6 end
26
Then the '../app/views/products/index' and '../app/helpers/products_helper.rb' received the code
bellow:
1 ../app/views/products/index.html.erb 2 Quantity available: <%= product_availability(product) %> 3 4 ../app/helpers/products_helper.rb 5 def product_availability(product) 6 if product.available? 7 product.quantity 8 else 9 "Not currently available" 10 end 11 end
The product_availability, line 5, is a method inside the view's helper that is solely responsible to
formatting the HTML section depending on the result of the '.available?' function on the Product
instance object, line 6. This shows a separation of concerns since the decision of whether a product
is available is made by the Product class instance itself, in line 6, and not inside the controller.
5.3.4 – View layer
The view layer is responsible for the application’s interface. The sections bellow describe how some
of the components of the view layer were built.
Instance variables
The controller and view layers work together by sharing data, more precisely the controller has to
provide data that is rendered by the view, this was done through Ruby instance variables, preceded
by the '@' character. For example:
1 class UsersController < ApplicationController 2 //code 3 def index 4 @users = User.all 5 end 6 //code 7 end 8 9 //user index page 10 <% @users.each do |user| %>
In the code above, the lines 1-7 show part of the UsersController, the 'index' action, lines 3-5,
assigns all the users instances to an instance variable ‘@users’, line 4, that instance variable can
then be accessed by the 'index.html.erb', in line 10. In that case the instance variable @users was an
array and allowed the index page to manipulate the variable using arrays methods, such as '.each'.
27
Partials
Partials were very important for the SADA application development since they can be accessed by
any view file inside the same folder, which greatly helps on code reusing, for example, the
‘_form.html.erb’ partial file was created inside the ‘../views/users’ folder, then the ‘new.html.erb’
and ‘edit.html.erb’ files, inside the same folder, can both use the ‘_form.html.erb’ partial file by
using the code bellow:
<%= render 'form' %>
The code above shows the 'render' method followed by the name of the partial to be displayed,
without the underscore( _ ), this allows one form file to be shared among all the views inside the
folder and as a result avoiding repetition.
Helper methods
The SADA application also used 'helper_method' declarations, that allow the view layer to use
methods from inside controllers, for example, the super class ApplicationController has the
following piece of code:
1 def logged_user?(user) 2 user == logged_user 3 end 4 5 helper_method :logged_user?
The code above shows a method called 'logged_user?', lines 1-3, that is used mostly in the
controller layer, but because the method has the 'helper_method' declaration, line 5, it can also be
used by the '../views/show.html.erb' file, as shown bellow:
<% if logged_user?(@user) || admin_user? %>
28
Displaying cart with AJAX
Normally, Rails applications follow the 'request-response' cycle, which means that whenever a page
is requested the browser parses the request to the server, then the server fetches the pages and assets
returning them to the browser. Most of the time the SADA application followed this 'request-
response' cycle, with an exception of the shopping cart display, which had to be updated without a
whole page refresh.
In order to add a product to the shopping cart, a user has to click the 'Add to cart' button on the
product page. The 'Add to cart' button is created by the following piece of code:
1
<%= button_to "Add to cart", product_items_path(product: @product), remote: true, class: "button"%>
The code above generates the following HTML:
2 3
<div id="btn"><form action="/product_items?product=9" class="button_to" data-remote="true"
method="post"><div><input class="button" type="submit" value="Add to cart" />
The most important parts in the code fragments are the 'remote: true’(1) and the 'data-
remote="true"'(3), which indicate that the browser will send an AJAX request instead of the
normal request-response.
The 'form action', in the HTML code, redirects to the 'create' action in the ProductItemsController.
In a normal flow the controller would then redirect to the '../views/product_items/create.html.erb'
which would then perform a whole page refresh, nevertheless, this was not the desired result, since
the only part to be modified should be the cart section. In order to achieve that a Ruby 'respond_to'
block, was inserted into the ProductItemsController's create action.
1 <% if logged_user?(@user) || admin_user? %> 2 respond_to do |format| 3 if @product_item.save 4 format.html { redirect_to products_path } 5 format.js 6 end
29
The respond_to block, lines 2-6, takes two types of request, HTML, line 4, and javascript, line 5,
since the 'remote:true' in the form makes the request a Javascript/AJAX request, the HTML part in
the code above is ignored and the request will be answered by the 'format.js', consequently, the
response will be sent to the file '../views/product_items/create.js.erb' which contains the following
line of code:
$('div#cart').html("<%= escape_javascript render 'layouts/sider_user' %>")
This line of code fetches an element that has a div with a 'cart' id, which is the cart section, and
changes only the internal HTML of that section, leaving the rest of the page unchanged.
5.4 – Mailers
Another very important class used in the SADA application was the Mailer class, which is usually
used by applications that need to format and send emails. Mailer classes, or just Mailers, are very
similar to Controllers in that they have actions that are linked to views with similar names, the
difference between Controllers and Mailers is that Controllers format data to be used in HTML
pages, whereas Mailers format emails that will be sent by the application.
1 class OrderMailer < ActionMailer::Base 2 //code 3 def received(order) 4 @order = order 5 @product_items = @order.product_items 6 mail to: @order.user.email, subject: "Order confirmation" 7 end 8 //code 9 def dispatched(order) 10 @order = order 11 @product_items = @order.product_items 12 mail to: @order.user.email, subject: "Order dispatched" 13 end 14 end
The code above shows the OrderMailer class, which has two actions, 'received' and 'dispatched',
these actions are called when a specific condition is met, for example, when a new order is placed,
the OrdersController 'create' action runs the following code:
OrderMailer.received(@order).deliver
This line of code passes the '@order' object to the 'received' action in the OrderMailer, the 'received'
action then uses the data from the ‘@order’ object to format the email. which is then sent by calling
the '.deliver' method.
30
6 – Security
This section tries to briefly describe some of the most common attacks on the internet and show
how the security features in the Rails framework were used to avoid them. This section by no means
aims at describing in details all the possible attacks that might affect web applications.
6.1 – Passwords
One of the most sensitive issues with web applications is the safety of users passwords. If an
attacker is able to access the database containing users details, including passwords, in a plain text
format, they can use that information for their own benefit by logging in the application as the user,
or even worse, if the user uses the same password other applications attackers can access user
accounts on these applications [18][19].
It is always recommended that passwords should NOT be stored as plain text, but instead, they
should go through an encryption/hashing process and only the encrypted version should be stored in
the database, so that in case the database is compromised, and an attacker gets access to the
passwords, they would not be able to decrypt them back to the plain text format.
The SADA application uses the Bcrypt gem (library), which uses the bcrypt hash algorithm, to
perform a one-way encryption of strings. In the SADA application, the Bcrypt gem was used to
encrypt the passwords, resulting in a hashed value that was then stored in the database.
In order to use this gem a password_digest field had to be created, by declaring the password type
as 'digest', as seen in the command line bellow:
1
“rails generate resource user name email password:digest”
The command above generated the following class:
1 class User < ActiveRecord::Base 2 has_secure_password 3 end
31
The 'has_secure_password' method, line 2, was automatically generated by the 'password:digest',
number 1 in the command line, and it created two fields in the ‘User’ class, namely 'password' and
'password_confirmation'.
The command also generated a migration file that was used to create the ‘Users’ table in the
database.
1 class CreateUsers < ActiveRecord::Migration 2 def change 3 create_table :users do |t| 4 t.string :name 5 t.string :email 6 t.string :password_digest 7 8 t.timestamps 9 end 10 end 11 end
Line 6, in the migration file above, creates a 'password_digest' column in the ‘Users’ table that
holds the encrypted version of the password, so whenever a new ‘User’ instance is saved in the
database, the Bcrypt gem performs an encryption on the password field and only the resulting hash
value is saved in the database, for example, when the first User instance was created he was given
the password 'supersecret' and when the same User instance was saved in the database, the hashed
value of his password was created:
'$2a$10$wZgF2XjUqXCR/Aqcxu8z0O1toBSC6yaMs.NTuRQEmHu4cBzbmelem'
This completely random string was then saved in the database as the user password.
6.2 – Mass assignments
Mass assignment of attributes is a very common and useful feature in the Rails framework, but it
can also cause some security problems. This section gives a brief explanation of how this feature
works, an example of a security threat it poses and how this security threat was prevented in the
SADA application.
32
Rails allows the mass assignment of attributes when a new class instance is created by passing a
hash with attributes and its values, so instead of assigning all the attributes separately, like this:
user = User.new()
user.name: “oneuser”
user. email: “[email protected]”
user. password: “onesecret”
user. password_confirmation: “onsesecret”
They can be assigned at one fell swoop, like this:
user = User.new(name: “oneuser”, email: “[email protected]”, password: “onesecret”,
password_confirmation: “onsesecret”)
An example of how this feature was used in the SADA application can be seen in the
UsersController class:
1 class UsersController < ApplicationController 2 //code 3 def create 4 @user = User.new(user_params) 5 //code 6 end 7 //code 8 def user_params 9 params.require(:user).permit! 10 end 11 //code 12 end
Line 4 shows a new User instance being created, and it was given a hash of values from the
'user_params' method, lines 8-10, which contains the values from the form fields.
Every User class instance has a field called 'admin' that grants full access to the application if it has
the boolean value ‘true’. A possible attacker can then use the 'Sign up' form to assign a 'true' value
for their own ‘admin’ field. As shown bellow:
33
Figure 9 – Form field modification
The picture above, shows that the attacker used the browser's inspect tool to change the name of one
of the form's fields, from user[password_confirmation] to user[admin], and set its value to 'true',
then when the form is submitted the following nested hash is passed to the UsersController.
"user"=>{"name"=>"attacker", "email"=>"[email protected]",
"password"=>"[FILTERED]", "admin"=>"true"}
Notice that the value of 'admin' was set to 'true', which thanks to the mass assignment featured will
set the admin value of the user to 'true' and grant him/her full access to the application.
The solution for this problem was to 'white list' the parameters that were allowed to be mass
assigned by adding the '.permit' method to the hash followed by the attributes that should be
allowed to be assigned from the form, like bellow:
34
1 class UsersController < ApplicationController 2 //code 3 def create 4 @user = User.new(user_params) 5 //code 6 end 7 //code 8 def user_params 9 params.require(:user).permit(:name, :email, :password, :password_confirmation) 10 end 11 //code 12 end
Line 9, shows the list of attributes that can be mass assigned, so if the malicious user tries to modify
the form as shown in the picture 6.1, their account will be created, however, their admin field will
be unchanged and receive the default value 'false'.
6.3 – Cross-site Scripting (XSS)
One of the most common attacks on the internet is the Cross-site Scripting (XSS) attack, that
happens when attackers are able to insert malicious scripting tags in form fields [20]. The Rails
framework escapes all the strings by default, which prevents any scripting tag being processed, and
instead displays the raw HTML. However, sometimes this default behaviour affected the SADA
application and had, whenever safe, to be turned off. One example can be seen in the code bellow:
1 //index.html.erb 2 <p> 3 Availability: <%= product_availability(product).html_safe %> 4 </p> 5 6 //products_helper.rb 7 def product_availability(product) 8 if product.available? 9 "<div id='instock'>IN STOCK</div>" 10 else 11 "<div id='outstock'>'OUT OF STOCK'</div>" 12 end 13 end
The code above shows an extract from two different files, 'index.html.erb', lines 1-4, from the
products views folder, and 'products_helper.rb', lines 7-13, from the helpers folder. The product
index page calls the 'product_availability' method, line 3, which is found in the 'products_helper'
file, 7-13, and returns a string containing div tags with different ids, depending on whether the
product is available or not. The problem was that the string returned by the 'product_availability'
method was being escaped by default and the raw string was being displayed, instead of the desired
35
HTML div tags, therefore, the '.html_safe', line 3, was used to turn off the default behaviour and
allow the div tags to be rendered.
6.4 – Session hijacking
Session hijacking happens when an attacker inserts malicious code in the application to try getting
access to the user's session and log into the application as if they were the user [21].
The first measure used to prevent this kind of attack, and also the simplest one, was to display a
highly visible 'Sign out' button on the application's header as soon as the user signs in, then by
signing out of the application, the user's current session expires and can no longer be used by the
attacker.
The second measure was to use HTTP Secure(https:\\) to encrypt and protect the contents in the
requests, including session details, against sniffing.
The SADA application is hosted on Heroku, which is a PaaS, and offers the HTTP Secure as default
to any application that it hosts, however, to use the default HTTP Secure feature the application has
to use a Heroku app sub-domain, such as the SADA application's 'https://salty-lowlands-
27483.herokuapp.com/'. As the SADA application is currently just a demonstration application it
uses the Heroku's default sub-domain, and consequently the default HTTP Secure, however, if in
the future the application uses a custom sub-domain, such as 'sadashopping.com', the Heroku's
default HTTP Secure can no longer be used, and in order to keep the application safe it would be
necessary to purchase an SSL certificate, add it to the HEROKU server and set the following code
in the configuration file:
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true
This piece of code assures that all the pages on the application use the 'https' instead of just 'http',
therefore securing and encrypting all the traffic between user and server, including the session key.
36
6.5 – Cross-Site Request Forgery
Another well-known form of attack is called Cross-Site Request Forgery (CSRF), which “involves
forcing a victim to send a HTTP request to a target destination without their knowledge or intent in
order to perform an action as the victim“ [22].
The CSRF attack basically takes advantage of the fact that the user is authenticated in the target
application, and the browser has a valid cookie/session, to send form actions. Differently of the
'Session hijacking' attack, the attacker does not need to know the exact value of the user session, but
instead they hide instructions, usually Javascript code, on another site the user is accessing, those
instructions will force the user's browser to send the form actions to the target application.
In order to prevent this kind of attack, the SADA application uses a method called
'protect_from_forgery', which is provided by the framework:
1 class ApplicationController < ActionController::Base 2 //code 3 protect_from_forgery with: :exception 4 // 5 code
The code above shows the super class ApplicationController, which is inherited by all the
controllers in the application. The 'protect_from_forgery', line 3, creates a hidden field called
‘autenticity_token’ on every form produced by the application and adds a token, which is in fact a
random string, to it.
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post"><div
style="display:none"><input name="utf8" type="hidden" value="✓" /><input
name="authenticity_token" type="hidden"
value="5ZoMSuOk0vJhq1Se6M+Gaf4SkSBtj84TxkouPIFV8Ws=" />
The code above shows part of the source code for the SADA application's ‘sign up’ form, the
method for the form is POST, the next two highlighted parts show the name of the field,
'authenticity_token', and the value for that field, the long random string. Whenever the form is
submitted, the application server checks the token and can verify that the request was made by a
form generated by the application itself and not from another source, possible attacker, if the token
is not present or it is invalid the request is denied. This process works as long as the attacker does
not get access to the user's token value.
37
7- Testing
7.1 – TDD
Test-driven development (TDD) is an approach to software development in which tests are written
before any code is produced. It is argued that TDD helps “to think through your requirements or
design before your write your functional” [23].
The working flow in TDD is simple, the first step is to write a test that fails, then some code is
written so that the test succeeds, if the test passes the code is refactored. This cycle is repeated for
every feature that is added to the application.
7.2 – Testing the application
Rspec
Whenever a resource, such as a class or a controller, is added to a Rails application, the framework
automatically creates test stubs related to that resource. Rails uses the Test::Unit framework as the
default testing tool, however, the SADA application used the Rspec framework, which generates
tests that are much more readable than the default tests generated by the framework.
There are a few different formats for generating a Rspec test, but the format chosen for the SADA
application is shown bellow:
describe “the behaviour being tested” do it “the test” do //code end end
38
The file 'add_product_spec”, shown bellow, gives an example of the format previously described:
1 describe "Adding a new product" do 2 it "saves the product and shows the product's details" do 3 //code 4 end 5 6 it "does not save the product if it field are invalid" do 7 //code 8 end 9 end
This test file has a block named 'describe' which tests the 'Adding new product' behaviour, inside
the block there are two test examples that test if the desired result was achieved.
Test files
The 'sada_shopping/spec' folder have sub-folders containing test files for different parts of the
application. The main sub-folders are:
Controllers: contains files for testing the application's controllers;
Features: contains files that test the application's functionality through its interface (views);
Models: contains files that test the application's classes;
Mailers: contains files that test the creation and delivery of the application's emails.
For a complete list of tests. Please see Appendix B.
Creating the tests
The tests created were based on the user stories’ acceptance criteria fields, as described bellow:
“As a customer I want to see the products displayed in the catalogue so that I can select one or more products to buy”
This user story would have the following acceptance criteria:
1- The products are displayed on the front page along with information about the
product and an image.
2- The user can click a link for the product's page.
3- User can see if a product is available or not.
39
The “show_products_page_spec.rb” file contains tests that check whether the acceptance criteria
described above was successfully implemented.
7.3 – User-testing
In order to evaluate the application from the users' perspective, the development process included a
simple, small scale user-testing process, with a total of 3 users.
The user-testing process required users to answer a user questionnaire, however, because the
application has two different types of users, the questionnaire was divided into two sections, one
based on customers and other on administrators. Each person taking part on the testing process had
to answer both sections of the questionnaires.
Firstly, users were asked to freely use the application, without any instruction or directions, for
about 5 minutes.
Secondly, users were asked to perform pre-defined tasks, which just indicated 'what' the users had to
achieve and not 'how' they had to perform the tasks, for example, one task was:
“Search for a specific product by its name.”
The intention of the questionnaire was to test how intuitive the application was, and if users could
perform the tasks with minimum or no direction. Every task was followed by questions that asked
users their opinion on the degree of difficulty in performing the task and how they would improve
the application's features related to the task.
Finally, users were asked to answer a series of questions based on the System Usability Scale
(SUS), that measures the overall usability of the system.
Appendix C shows a user questionnaire completed by one of the users.
40
8- Deployment
8.1 – Heroku
One of the non-functional requirements for the SADA application was that “The system should be
hosted on the cloud”, and in order to fulfil this requirement three cloud service provides were
considered, Amazon AWS, Heroku and Engine Yard. All three options had their advantages and
disadvantages, however, Heroku was the chosen provider because it is widely used by most of
Rails developers, it is very easy to deploy/modify the application and it is free.
Heroku allows developers to use the GIT version control to deploy the application's initial version,
and the subsequent modified versions, to its servers.
When the application was first deployed, Heroku created a default URL:
https://salty-lowlands-27483.herokuapp.com/
It is very easy to change the application's default URL to any other custom URL, however, in order
to avoid spending time and resources in acquiring a domain name, which is necessary if one wants
to use a custom URL, the SADA application uses the default URL built by Heroku.
8.2 – Environments
Every Rails application have three different environments, namely development, test and
production, and each environment is configured with one or more Ruby gems (libraries). The code
bellow shows an extract from the file where the different environments were configured.
1 group :test, :development do 2 gem 'sqlite3' 3 //code 4 end 5 6 group :production do 7 gem 'pg' 8 end
Line 2 shows the default database system, SQLite3, used in the development and test environments,
however, the SQLite3 is not supported by Heroku, so the production environment had to be
reconfigured by changing the database to PostgreSQL, as shown in line 7.
41
9 – Conclusion
Overall, the project has met its main goals which were to implement a cloud based e-commerce
application and provide an insight into the solutions adopted for common problems faced during the
development process of web applications. All the tests, including user questionnaires, proved that
the application satisfactorily met its requirements.
Although the final version of the application was satisfactory, considering that it is just a
demonstration app, in order to be used in a real world scenario some features might have to be
added, for example, a card payment system could be implemented by adding a Ruby gem (library),
e.g. Active Merchant, which would abstract different Payment Service Providers’ APIs. In addition,
some gems, such as ActiveShipping or Stripe, could be used to access many delivery companies'
APIs and calculate the shipping costs according to the product’s delivery destination. Other future
extensions that could be useful for the application are the Rails Internationalization API, that helps
translating the applications pages to different languages, and the addition of analytic tools such as
Google Analytics.
The future plans for the application include improving the layout, adding more AJAX capabilities
and producing a mobile version.
42
10 - Reflections
The project was a great learning exercise and allowed me to better understand the challenges and
complexity of developing a web application. I was also able to learn more about the programming
languages and frameworks commonly used in web development.
Before starting the project, it was necessary to decide which programming language/framework
should be used. Three option were considered, PHP/laravel, JAVA/Play and Ruby/Rails, but at the
end Rails was chosen for two main reasons, firstly, because I had previously worked with Ruby and
found it a very flexible and powerful language, secondly, there are plentiful documentation and
resources available, including from the Rails community.
One of the most challenging aspects during the project was to follow the TDD principle. Writing
tests before any code was produced felt rather unusual at the beginning, however, towards the
middle of the project I was already comfortable with that technique.
All in all, I am happy with the results of my project and all the knowledge that I gained during its
development.
43
11 – References
[1]D. Reynolds (2009, Jul. 20), "Organize Your Next PHP Project the Right Way". Tutsplus [Online]. Available: http://code.tutsplus.com/tutorials/organize-your-next-php-project-the-right-way--net-5873.
[2]J. Stangarone (2015, May 27), "7 web development challenges you can’t ignore - mrc's Cup of Joe Blog", mrc's Cup of Joe Blog. [Online]. Available: http://www.mrc-productivity.com/blog/2015/05/7-web-development-challenges-you-cant-ignore/.
[3]Centre for Retail Research (2014), "Online Retailing: Britain, Europe, US and Canada 2016." [Online]. Available: http://www.retailresearch.org/onlineretailing.php.
[4]Z. Cutler (2014, Nov 6), "The 4 Biggest Challenges Facing E-Commerce Businesses | Cutler PR",Cutlerpr.co. [Online]. Available: http://www.cutlerpr.co/4-biggest-challenges-facing-e-commerce-businesses/.
[5]C. Floren, "The Top 10 e-Commerce Challenges for Business Owners",Myecommerce.biz, 2016.[Online]. Available: http://myecommerce.biz/blog/2012/03/the-top-10-e-commerce-challenges-for-business-owners/. [Accessed: 28- Apr- 2016].
[6]K. Waters (2007, Jun. 11), "10 Good Reasons To Do Agile Development", All About Agile. [Online]. Available: http://www.allaboutagile.com/10-good-reasons-to-do-agile-development/.
[7]Agile Methodology (2008, Oct. 23)"The Agile Movement", Agile Methodology. [Online]. Available: http://agilemethodology.org/.
[8]S. Ambler (2014), "User Stories: An Agile Introduction", Agile Modeling. [Online]. Available: http://www.agilemodeling.com/artifacts/userStory.htm.
[9]K. Waters (2009, Jan. 12), "Prioritization using MoSCoW", All About Agile. [Online]. Available: http://www.allaboutagile.com/prioritization-using-moscow/.
[10]J. Hill (2014, Jun. 9), “Why Acceptance Criteria Are Needed Before User Stories Can Be Relatively Sized“, Scrum Alliance. [Online], Available: https://www.scrumalliance.org/community/articles/2014/june/why-acceptance-criteria%E2%80%9D-is-needed-before-user-sto
[11]W. Jackson (2015, Sep. 3), “What Characteristics Make Good Agile Acceptance Criteria?“, Segue Technologies.[Online]. Available: http://www.seguetech.com/blog/2013/03/25/characteristics-good-agile-acceptance-criteria
[12]A. Stellman (2010, Feb. 17), "Understanding nonfunctional requirements", Oreilly. [Online]. Available: http://broadcast.oreilly.com/2010/02/nonfunctional-requirements-how.html.
[13]R. C. Martin, Clean Code A Handbook of Agile Software Craftsmanship. Boston: Pearson, 2009, p. 48.
44
[14]T. O'Brien et al. (2011), "Convention Over Configuration",The Nexus. [Online]. Available: https://books.sonatype.com/mvnex-book/reference/installation-sect-conventionConfiguration.html.
[15]A. Gamble et al. Beginning Rails 4. Sacramento, CA: Apress, 2013, p. 7.
[16]A. Gamble et al. Beginning Rails 4. Sacramento, CA: Apress, 2013, p. 61.
[17]D. Laycock (2011, Mar. 18), "10 Ruby on Rails Best Practices", Site Point. [Online]. Available: http://www.sitepoint.com/10-ruby-on-rails-best-practices/.
[18]Microsoft (2016), "Basic Security Practices for Web Applications", Msdn.microsoft.com. [Online]. Available: https://msdn.microsoft.com/en-us/library/zdh19h94.aspx#cpconbestsecuritypracticesforwebapplicationsanchor7.
[19]I. Gray (2012), "Your Password is not safe. The dangers of storing passwords.",Seriously Socialwith Ian Anderson Gray. [Online]. Available: http://iag.me/web/your-password-is-not-safe/
[20]Cgi Security (2002), "The Cross-Site Scripting (XSS)", Cgi Security. [Online]. Available: http://www.cgisecurity.com/xss-faq.html.
[21]L. Millanta (2013, Aug. 23), "How to: Understanding session hijacking", PC Authority. [Online]. Available: http://www.pcauthority.com.au/Feature/354468,how-to-understanding-session-hijacking.aspx.
[22]R. Auger (2010), "Cross Site Request Forgery", The Web Application Security Consortium. [Online]. Available: http://projects.webappsec.org/w/page/13246919/Cross%20Site%20Request%20Forgery.
[23]S. Ambler (2013), "Introduction to Test Driven Development (TDD)",Agile Data. [Online]. Available: http://agiledata.org/essays/tdd.html.
45
12 – Bibliography
Hunt, A. and Thomas, D. (1999), Pragmatic Programmer, The: From Journeyman to Master. US:Addison-Wesley
David Moth. (2015). UK online retail sales to reach £52.25bn in 2015: report. Available: https://econsultancy.com/blog/66007-uk-online-retail-sales-to-reach-52-25bn-in-2015-report/.
Patrick Dixon. (2013). Future of Retail Industry, shopping malls, e-commerce, online and offline consumers, impact of mobile and Big Data. Available: http://www.globalchange.com/future-of-retail-industry-shopping-malls-online-and-offline-consumers-and-impact-of-mobile-keynote-speaker.html.
Demir Selmanovic . (). The 10 Most Common Mistakes Web Developers Make: A Tutorial for Developers. Available: https://www.toptal.com/web/top-10-mistakes-that-web-developers-make.
Simon St. Laurent . (2014). Web application development is different (and better). Available: http://radar.oreilly.com/2014/01/web-application-development-is-different-and-better.html.
Snook, J. (2004). Building a Web Application: Requirements Gathering. Available: http://snook.ca/archives/building_a_web_application/building_a_web_5.
Wunderlich, T. (). Requirements Gathering for Application Design. Available: http://www.eveandersson.com/arsdigita/asj/requirements/.
Putnam, D.. (). Team Size Can Be the Key to a Successful Software Project Available: http://www.qsm.com/process_improvement_01.html.
Ambler, S.. (2002). Introduction to Test Driven Development (TDD). Available: http://agiledata.org/essays/tdd.html.
Garcia, A. (2013). UX Research | Standardized Usability Questionnaires. Available: http://chaione.com/ux-research-standardizing-usability-questionnaires/.
Usability.gov. (). System Usability Scale (SUS). Available: http://www.usability.gov/how-to-and-tools/methods/system-usability-scale.html.
Rails guides. (). Rails Internationalization (I18n) API. Available: http://guides.rubyonrails.org/i18n.html. Fowler, M.. (2006). GUI Architectures. Available: http://martinfowler.com/eaaDev/uiArchs.html.
Bergin, J. (2007). Building Graphical User Interfaces with the MVC Pattern. Available: https://csis.pace.edu/~bergin/mvc/mvcgui.html.
Tutorials Point. (). Basic MVC Architecture. Available: http://www.tutorialspoint.com/struts_2/basic_mvc_architecture.htm.
46
Mittal, A . (2015). Learning MVC - Part 1: Introduction to MVC Architecture and Separation of Concerns. Available: http://www.codeproject.com/Articles/620195/Learning-MVC-Part-Introduction-to-MVC-Architectu.
Mozilla. (2016). MVC architecture. Available: https://developer.mozilla.org/en-US/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture.
Barry, D. K. (). Object-Relational Mapping Articles. Available: http://www.service-architecture.com/articles/object-relational-mapping/.
Ambler, S. (2013). Mapping Objects to Relational Databases: O/R Mapping In Detail . Available: http://agiledata.org/essays/mappingObjects.html.
API Ruby on Rails. (2016). Active Record – Object-relational mapping in Rails. Available: http://api.rubyonrails.org/files/activerecord/README_rdoc.html.
Yii framework. (). Model-View-Controller (MVC). Available: http://www.yiiframework.com/doc/guide/1.1/en/basics.mvc.
Buck, J. (2006). Skinny Controller, Fat Model. Available: http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model
Claudio. (2010). Rails Best Practices 1: Fat Model – Skinny Controller. Available: http://www.devinterface.com/en/blog/rails-best-practices-1-fat-model-skinny-controller.
Olinescu, M. (2009). jQuery Validation in Ruby on Rails. Available: http://sleekd.com/tutorials/jquery-validation-in-ruby-on-rails/.
Hale, C. (2016). bcrypt-ruby. Available: https://github.com/codahale/bcrypt-ruby.
Acunetix. (2016). Cross-site Scripting (XSS) Attack. Available: http://www.acunetix.com/websitesecurity/cross-site-scripting/
Imperva. (2009). XSS Cross Site Scripting Demonstration. Available: https://www.youtube.com/watch?v=r79ozjCL7DA
Imperva. (2009). Session Hijacking . Available: https://www.youtube.com/watch?v=P_u3g95bzIE
Rails Guides. (). Ruby on Rails Security Guide. Available: http://guides.rubyonrails.org/security.html
Helme, S.. (2013). Advanced Session Hijacking - Is coffee shop WiFi such a good idea?. Available: https://scotthelme.co.uk/advanced-session-hijacking/.
Shiflett, C. (2004). Session Hijacking. Available: http://shiflett.org/articles/session-hijacking.
Acunetix. (). CSRF Attacks, XSRF or Sea-Surf – What They Are and How to Defend Against Them. Available: http://www.acunetix.com/websitesecurity/csrf-attacks/.
47
DuPaul, N. (). Cross-Site Request Forgery Guide: learn all about CSRF attacks and CSRF protection. Available: http://www.veracode.co.uk/security/csrf.
https://www.youtube.com/watch?v=vrjgD0azkCw
Irizarry, A. (2014). Cross-Site Request Forgery (CSRF) in Plain English . Available: https://www.tinfoilsecurity.com/blog/what-is-cross-site-request-forgery-csrf.
eeeDeveloper. (2012). CSRF Attacks . Available: https://www.youtube.com/watch?v=QJmYhIJraOo.
Rails Guides. (). Working with JavaScript in Rails. Available: http://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html.
Vanloo, B. (). Buggy Rails Code: The 10 Most Common Mistakes That Rails Developers Make. Available: https://www.toptal.com/ruby-on-rails/top-10-mistakes-that-rails-programmers-make.
Rorot. (2015). Session Hijacking Cheat Sheet. Available: http://resources.infosecinstitute.com/session-hijacking-cheat-sheet/.
48
13 – Appendices Appendix A – User stories
49
ID USER STORY PRIORITY ACCEPTANCE CRITERIA TESTS
1 As a customer I want to see the products displayed M 1- The products are displayed in the front page along within the catalogue so that I can select my desired information about the product an image if any. show_products_page_specproduct. 2- The user can clicks in a link for the product's
own page3- user can see if product is available or not
2 As a user I want to be able to filter the display of M 1- A searchbox is displayed in the product's listingproducts so that I can find a specific product. page. show_products_page_spec
2- When a user enters part or entire products nameonly the products related to the search are displayed
3 As a user I want to be able to add or delete products on my 1- In each product page a button to 'add to wishlist add_products_to_wishlists_specwish list so that other users can see the products I is displayed.want 2- If the user clicks in the link the product is added
to the wishlist database. 3- A button to delete the product is displayed if the product isalready on the wishlist.
4 As a user I want to be able to see the products in my M 1- A link to the user's wishlist is displayed show_wishlist_specWish list so that I can manage the products in it 2 – A list with all the products in the user's wishlist is
displayed
5 As a user I want to be able to see other user's wishlist S 1-The user can access a page with a list of user's wishlistso that I can find out what users want to buy. 2-A search box for the wishlist is shown list_wishlists_spec(not working)
3-When a user enters a name and press search only the listsrelated to the name are shown.
6 As a user I want to be able to access the an individual M 1- The front page has a link to the product's pageproduct page so that I can see the product's details 2- When the user clicks on the product name link show_product_spec. he/she is redirected to the product's page
7 As an admin I want to be able to add or delete products M 1- A form to add products is shown is the user is admin add_product_specso that I can manage the inventory. delete_product_spec
2- A link to delete product is displayed
8 As an admin I want to be able to see all the orders M 1- A list with all the orders with the customer's details list_orders_specmade by every customer so that I can fulfil the orders. and items purchased is shown
9 As an admin I want to be able to delete any order M 1- A link to delete the each single order isplaced by customers so that I can remove orders placed in the orders list page. delete_order_specif customer wants to cancel the purchase.
10 As an admin I want to be able to edit the order so that M 1- A link to edit order is placed for each individual orderI can change the order dispatched status. 2- When the user clicks the edit link he/she is edit_order_spec
redirected to a form where they can change the dispatched status of the order from 'no' to 'yes'.3- If the order status is changed an email is sent to the user
50
ID USER STORY PRIORITY ACCEPTANCE CRITERIA TESTS
11 As an admin I want to be able to see a list of users S 1- A link to the users page is displayed.so that I can see all the application's users. 2 When the admin clicks on the users link he/her list_users_spec
is redirected to the users page.3- A list of all users is displayed.
12 As a admin I want to be able to see which customers C 1- In each product page there should be a section visible only show_product_specadded a product to their wishlist so that I can send for admin, showing a list of users who added the product to promotional materials to him/her their wishlist.
13 As a user I want to be able to edit the quantity of each S 1- A link to edit order is displayed edit_cart_spec(not working)product in the shopping cart so that I can increase or 2- The user can see the list of all products in the cart and andecrease their quantity in my order. option to change their quantity individually.
14 As a user I want to be able to delete the product in my S 1- A link to delete order is displayed delete_product_cart_spec(not working)shopping cart so that I can remove products I do not want.
15 As a admin I want to be able to create promotional coupons C 1- A link create coupon is displayed if the user logged in is an so that I can give discount to customers on their orders admin. TO BE IMPLEMENTED
2- by clicking the 'create coupon' link a page showing a form for creating the coupon is shown.
16 As a user I want to be able to enter a discount code so C 1- A field to enter the code is displayed TO BE IMPLEMENTEDthat I can have a discount on my order. 2- A redeem coupon button is displayed
3- When user click 'redeem coupon' the amount in their orderis reduced by the amount in the coupon
17 As an admin I want to be able to create new categories M 1 – A link to create a new category page is displayed create_category_specso that I can assign categories to products. 2 – The create category page displays a form to enter the
category's details.
18 As an admin I want to be able to delete a user account M 1- A 'delete account' link is displayed. delete_user_specso that I can delete someone's account if necessary 2- If the 'delete account' link is clicked the user account
is deleted.
19 As a user I want to be able to see products reviews so that S 1- A link to 'reviews' is shown. display_reviews_specI can see other users' opinion about the product. 2- When a user clicks the 'reviews' link they are shown a list of
reviews posted by other users.
20 As a user I want to be able to post reviews so that I can 1- A link to 'write review' is displayedpost my opinion about specific products 2- When a user clicks on 'write review' they are shown a form to post_review_spec
post their review.
21 As a user I want to be able to create an account so that I 1- A link to create an account(sign in) is displayed.have my own account. 2- When a user clicks on the 'sign in' link they are shown a create_user_spec
form to enter the account details.
22 As a user I want to be able to edit my account so that I 1- A link to edit the account is displayed.can change my account details 2- When a user clicks the link to edit account they are shown edit_user_spec
the same form to create an account.
23 As a user I want to be able to see a list of orders made by 1- A link to my orders is displayed list_orders_specme so that I can see all the products I bought. 2- When a user click 'My orders' link they can see a list of
orders made only by them and not by other users.
Appendix B – Test files.
51
Test name File Purpose Result
Add products to catalogue add_product_spec.rb Test if a product is correctly added to PASSthe application.
Add a products to shopping carts. add_product_to_cart_spec.rb Test if a product is correctly added to a PASSshopping cart
Add a product to wish lists. add_products_to_wishlists_spec.rb Test if a product is correctly added to PASSthe logged in user's wish lists.
Create new categories create_category_spec.rb Test if a new category is correctly PASScreated and associated to other categories.
Create new discount coupons create_coupon_spec.rb Test if a new discount coupon is created PASSand gives the right discount to the correct user.
Create users create_user_spec.rb Test if a new user account is correctly PASScreated.
Delete orders delete_order_spec.rb Test if an existing order is deleted. PASS
Delete products from shopping cart delete_product_cart_spec.rb Test if a single product are correctly PASSdeleted from an existing shopping cart
Delete products from catalogue delete_product_spec.rb Test if the selected product is deleted PASSfrom the application and no longer displayed.
Delete user accounts delete_user_spec.rb Test if a selected user is delete from PASSthe application database.
Display products reviews display_reviews_spec.rb Test if the reviews for a product is properly displayed. PASS
Edit products in the shopping carts edit_cart_spec.rb Test if a shopping cart is correctly PASSedit by modifying the items on it.
Edit orders edit_order_spec.rb Test if a order is correctly edited by PASSchanging its dispatched field from 'no' toyes'.
Edit products details edit_product_spec.rb Test if the details of a product are PASScorrectly modified and saved in the database.
52
Test name File Purpose Result
Edit users details edit_user_spec.rb Test if the user details are correctly PASSchanged and saved.
Delete products from cart empty_cart_spec.br Test if all the products in the shopping PASScart are correctly deleted in one fell swoop.
Display orders list list_orders_spec.rb Test if a list with all the orders is PASSCorrectly displayed.
Display list of users list_users_spec.rb Test if a list with all users is correctly PASSdisplayed.
Display list of wish lists list_wishlists_spec.rb Test if a list of wish lists is correctly PASSdisplayed and the user is able to findspecific wish lists.
Access product page navigate_products_spec.rb Test if a product page can be accessed PASSand it is correctly displayed.
Add products new_product_spec.rb Test if a product is correctly added to PASSthe database.
Post reviews post_review_spec.rb Test if a review posted by a user is PASSdisplayed.
Place orders save_order_spec.rb Test if a order is correctly saved and its PASSdetails displayed.
Display products details show_product_spec.rb Test if the details of a specific product PASSare properly displayed.
Display products catalogue show_products_page_spec.rb Test if the index page shows a list of PASSproducts.
Display users accounts show_user_spec.rb Test if user details are shown on their PASSprofile page.
Display users wish list items show_wishlist_spec.rb Test is the items in a user wish list are PASSproperly displayed and are a link.
Sign in signin_spec.rb Test if a user is correctly signed in. PASS
Sign out signout_spec.rb Test if a user is properly signed out. PASS
Orders controller test orders_controller_spec.rb Test if the restrictions for the orders PASScontroller actions are correct.
Products controller test products_controller_spec.rb Test the actions on the products PASScontroller.
Users controller test users_controller_spec.rb Test the actions on the users controller PASS
Orders mailer test order_mailer_spec.rb Test if an email is correctly formatted. PASS
Appendix C – User questionnaires
User Testing
Name: Jieun K Lee
Please complete the tasks described in this sheet, fill the square brackets [ ] with a number between 1 (strongly agree) and 4 (strongly disagree), and answer the questions.
1 – Strongly disagree 2 – Disagree 3 – Agree 4 – Strongly agree
Customer
1) Search for a specific product by its name. It was easy to perform this task. [ 3 ] Was there any problem in completing this task? I took me some time to realize that the search box could be used to search for a specific product. How did you perform this task? I put the name of the product inside the search box. How would you make this task easier? I would put some text inside the search box indicating that I could enter the product name as I saw in other websites. 2) Search for products by category. It was easy to perform this task. [ 3 ] Was there any problem in completing this task? No. How did you perform this task? I clicked on the categories button and on the category that I wanted in the list. How would you make this task easier? Don't know.
3) Write a review for a product. It was easy to perform this task. [ 4 ] Was there any problem in completing this task? No. How did you perform this task? I selected the product page and clicked on the write review button. How would you make this task easier? Don't know.
53
4) Create an account. It was easy to perform this task. [ 3 ] Was there any problem in completing this task? No. How did you perform this task? I clicked on the Sign up button and created the account. How would you make this task easier? I would put a link saying specifically 'create account' to make it very clear.5) Sign in to the application. It was easy to perform this task. [ 4 ] Was there any problem in completing this task? No. How did you perform this task? I click on the Sign in button and filled up the form. How would you make this task easier? Don't know.
6) Edit your account by changing the password. It was easy to perform this task. [ 4 ] Was there any problem in completing this task? No. How did you perform this task? I clicked on the My account button, on the edit button and changed the password. How would you make this task easier? Don't know.
7) Add a product to your wish list. It was easy to perform this task. [ 4 ] Was there any problem in completing this task? No. How did you perform this task? I clicked on the product link and on the Add to wish list button. How would you make this task easier? Maybe giving the Add to wish list button a different color.
8) Remove a product from your wish list. It was easy to perform this task. [ 3 ] Was there any problem in completing this task? I did't realize that I had to visit the product page again to remove it from my wish list. How did you perform this task? I firstly clicked on My wishlists button but because I didn't see any link to remove the product I visited the product page where I saw the link to remove it from my wish list. How would you make this task easier? I would put a link to remove the product on the wish list page.
54
9) Find a wish list from a user named Rodrigo. It was easy to perform this task. [ 4 ] Was there any problem in completing this task? No. How did you perform this task? I clicked on wishlists button and entered the name on the search box. How would you make this task easier? Maybe changing the name of the button to make it more clear the it is used to search all the wish lists.
10) Add a product to the shopping cart. It was easy to perform this task. [ 4 ] Was there any problem in completing this task? No. How did you perform this task? I visited the product page and clicked the Add to cart button. How would you make this task easier? Don't know.
11) Change the quantity of the product in the shopping cart. It was easy to perform this task. [ 3 ] Was there any problem in completing this task? The only small problem was that it wasn't very clear that the drop menu with the number in it could be used to change the quantity for the product. How did you perform this task? After adding the cart tot eh product I clicked on the Edit cart button, selected another number inside the drop box and clicked Update item. How would you make this task easier? Change somehow the button names to make it clearer what they could be used for.
12) Delete all the products from the shopping cart. It was easy to perform this task. [ 4 ] Was there any problem in completing this task? No. How did you perform this task? After adding the product to the cart I clicked the Empty cart button. How would you make this task easier? Don't know.
13) Add another product to the shopping cart and complete the order. It was easy to perform this task. [ 4 ] Was there any problem in completing this task? No. How did you perform this task? After adding the product to the cart I clicked the Checkout button and filled the form for the order. How would you make this task easier? Don't know.
55
Administrator
1) Sign in to the application using the email: '[email protected]' and password: 'supersecret' Try to add a new product to the catalogue. It was easy to perform this task. [ 2 ] Was there any problem in completing this task? Adding the categories to the products was a bit tricky. How did you perform this task? I filled the form with the product information and clicked the Create product button. How would you make this task easier? I would put a page explaining how the categories work.
2) Edit the details for an existing product. It was easy to perform this task. [ 4 ] Was there any problem in completing this task? No. How did you perform this task? I visited the product page, clicked on the Edit product button, and changed the name of the product. How would you make this task easier? Don't know.
3) Delete an existing product. It was easy to perform this task. [ 4 ] Was there any problem in completing this task? No How did you perform this task? I visited the product page and clicked on the Delete product link How would you make this task easier? Don't know.
4) Access the account of a user named 'Kate' It was easy to perform this task. [ 4 ] Was there any problem in completing this task? No. How did you perform this task? I clicked on the Users button and on the name 'Kate' on the list. How would you make this task easier? Don't know.
5) Add three new categories named 'Games', 'PC' and 'New game' so that the final hierarchy is Games > PC > New game. It was easy to perform this task. [ 2 ] Was there any problem in completing this task? As with adding categories to products, creating new categories was rather tricky. How did you perform this task? I couldn't complete this task. How would you make this task easier? I would put information about how the process of creating categories work.
56
6) Create an discount coupon for Kate giving her a 10% discount valid for 10 days. It was easy to perform this task. [ 4 ] Was there any problem in completing this task? No. How did you perform this task? I clicked on the Create coupon button and filled the form. How would you make this task easier? Don't know.
Based on your experience using the system, answer the following questions by giving a score based on the scale bellow:
Strongly Strongly disagree agree
1. I think that I would like to use this system frequently |_______|_______|_______|___X___|_______| 1 2 3 4 5
2. I found the system unnecessarily complex |_______|___X___|_______|_______|_______| 1 2 3 4 5
3. I thought the system was easy to use |_______|_______|_______|___X___|_______| 1 2 3 4 5
4. I think that I would need the support of a technical person to be able to use this system |_______|_______|_______|___X___|_______| 1 2 3 4 5
5. I found the various functions in this system were well integrated |_______|_______|___X___|_______|_______| 1 2 3 4 5
57
6. I thought there was too much inconsistency in this system |_______|___X___|_______|_______|_______| 1 2 3 4 5
7. I would imagine that most people would learn to use this system very quickly |_______|_______|___X___|_______|_______| 1 2 3 4 5
8. I found the system very cumbersome to use |___X___|_______|_______|_______|_______| 1 2 3 4 5
9. I felt very confident using the system |_______|_______|_______|___X___|_______| 1 2 3 4 5
10. I needed to learn a lot of things before I could get going with this system |_______|___X___|_______|_______|_______| 1 2 3 4 5
58
59
60