Monday, March 31, 2014

Git pull tips

My project team is using Git (Open Source software) as a version control system to handle all the changes we made in the code. This software, combined with Bitbucket, a free code-hosting service, makes a really powerful tool which makes life easier (at least the programmer's life).

When we want to pull all the changes from the remote repository, we use the general pattern for the "pull" command:

> git pull [options] [<repository> [<refspec>...]]

The "standard" way to pull the remote repository is by typing:
> git pull

This fetches and integrates the remote repository with your local repository or local branch. However, a stashing operation before pulling is strongly recommended in order to avoid merge conflicts with not-done work (code tasks in progress). Git documentation defines the stashing operation as the one that "takes the dirty state of your working directory — that is, your modified tracked files and staged changes — and saves it on a stack of unfinished changes that you can reapply at any time." Then, we should type:

> git stash
> git pull

After these two consecutive operations, we can easily check if there exists something to be merged by using the "status" command:

> git status
If the pulling operation was successful, the console will show a message "no things need to be merged", otherwise, it will display an "unmerged" message, and you will have to decide what changes you want to keep by editing each one of the files listed. When all the files are merged (check it by typing again "git status" command), we would have our local repository already updated. Although it is also recommended to run two more commands:

> bundle install

Bundle install all the dependencies you need (gems from your specified sources). This is interesting to avoid issues if somebody changed any code in the Gemfile from the remote repository.
Finally, other useful way to keep the consistence of our application is related to possible migrations, so do not forget to run:

> rake db:migrate

This will run any migration stored in the /db/migrate/ folder. 

In my next post, I am going to talk about how to pull an specific folder when using Git.

Saturday, March 29, 2014

Fifth client meeting reactions

Yesterday, we met with professor Ackley in our fifth client meeting. We kept in mind the last time we tried to show a demo to Ackley (third client meeting), when we were not able to show the model properly because of a clear lack of preparation. Fortunately, we learnt from our mistakes and the past week we showed a decent demo to Nikan. As Ackley had not seen any proper demo, it was our chance to demonstrate that we had already most of functionality working.

As usual, we started the meeting with the last week task report. No problems in this sense, because all the members of the team were able to complete their tasks due to before the client meeting. Then, we spent almost all the rest of the meeting showing the demo. Last time, we used my laptop to present our demo. It actually worked fine, but since I am running Rails on an Ubuntu installation inside a Virtual Machine (VirtualBox), the screen resolution features are not as good as in a regular installation. This caused some minor visualization issues when we ran the demo using Firefox browser. Therefore, this time we decided to use Natalie's Macbook laptop in order to avoid this kind of problems that could worsen the user's experience.

Again, the Demigod's demo was really good because we were able to show all the functionality that were working properly so far. As we were working most of the time focused on the functionality rather than on the design, the demo looked not as pretty as we liked, but the main goal right now is that the application works fine, and then, we will address the style and design stuff.

Even though we did a great job showing the demo, Ackley made some comments about our application, such as:

- The Index page may include a kind of animated carousel.
- Profile page: show the user’s name instead of the email. Include the username and a logout button on the right side of the navigation bar, as usual on this kind of websites.
- A small picture of each challenge may be added. Also applied for the different categories of challenges.
- He suggested using always the same name to define a "Check-in", instead of things like “Success”.
- Fail button should include a confirmation dialog (“Are you sure?”)
- What the points really mean? Points distribution: Can you distribute the points in different dimensions?
- Statistics and challenges page need better design...
- On the way encouragement when you log in (motivation quotes or something similar)
- Decide the final list of challenges.
- Was the maximum number of check-ins per week (7) our choice?
- He also suggest starting to think about the final demo of our project.

However, it seems Ackley liked our demo, and he said that his less concern about our project so far is about the functionality. This sounded like "Ok guys, let's focus on the design", but we still have to deal with some functionality features. Anyway, we are going to start working on the design the next week.

Wednesday, March 26, 2014

Guest speaker in class

Last Monday,  the founder of Vandyke Software visited our class and talked to us about how software is developing in the real world. He explained that every day, they follow the same pattern when we work on a software project:

- Feature requests, bug reports
  • Test track (database)
    • Acceptance tests (light-weight process. No database needed. It includes conversations between developers and project managers)
      • Iteration planning (Poker estimates, 1 hour/day in average)
        • Story, stories (Theme)
          • Task estimates (developers & project managers)
            • Buffer (Were the estimates good enough?)
            • Fudge factor (Measure how good were the estimates)
- Iteration
  • Bootlog Friday (Relieve value)
- Commit (Smaller code chunks are usually better)
- QA (If the code does not pass the tests, send back to developers as soon as possible)

He spoke about the iteration planning, focusing on the Poker estimates. They are basically a way to estimate the effort needed to achieve a goal when working on a software project (how long this task/problem will take?). If there is not a clear idea about the the task duration estimate, it is a good idea to divide the problem is smaller problems, because they will definitely be easier to measure. In terms on task estimates, he said that developers can only make rough estimates, but project managers are able to do more accurate estimates because they have the project's budget. Anyway, it is always better for all the members of the team to divide tasks in smaller chunks in order to estimate times, although the average task duration should be between 4 and 8 hours.

Moreover, from the point of view of Vandyke, the stories based on a theme (basically a request that has been already received previously) should be splitted (again the same approach) into two or three weeks in order to get something more valuable at the end. He also talked to us about code committing and the difference between his expectation and the reality, because, ideally, developers should commit code ready to be submitted, however, about the 50% of the committed code comes back to developers after being tested by QA. Regarding how to commit the code. Vandyke explained that sometimes is very difficult for developers to commit small code portions, but they should try to do it, because if a bug comes up, it will be easier and faster for the rest of the team to find out where the issue is.

He also referred several times to a book named "Extreme programming explained: embrace change", which he recommended for all the developers interested in software engineering.

Monday, March 24, 2014

Generating a new scaffold in Rails

Recently, Natalie and I had other programming session in which we decided to create a new structure in order to get an easier way to deal with the check-ins interval. This had to be done by splitting the challenge's duration in weeks (instead of considering the whole duration) to keep track of the check-ins made by the user.

We essentially required to create a new Rails model that actually could be directly generated through the Rails console. But instead of using that method, we decided to setup up a scaffold, a tool provided by Rails which helps programmers create structures such as views, models and controllers for a new resource, but only in a single operation. In this case, we had to create a new model, so thanks to the scaffolding method, we were able to do it easily by using the following pattern :

rails g model <model_name> <field_1:type> <field_2:type> … <field_n:type>

The previous command generates a new table in the database with the specified fields and data types. In our case, the model was called "week", and it contained three fields:

rails g model week start_week:datetime end_week:datetime checkins_completed:boolean

Rails console creates the migration file in /db/migrate/ folder, by labeling it with the common patter: <current_date>_create_<model_name>.rb. Rails also executes this migration in our repository, thus, Rails creates the model itself (weeks.rb) in the ./project_name/app/models/ folder, as well as the rspec file (spec/models/week_spec.rb) and the factory file (spec/factories/weeks.rb)

Once we had the new table, we added the current data from other tables (relations) into the new table by following this convention (creating a new migration file):

rails g migration Add<source_field_name1>And<source_field_name2>And<source_field_name_n>To<destination_table> <destination_field_name1>:<type> <destination_field_name2>:<type> ...<destination_field_name_n>:<type>

Note that you need to apply the previous code separately for each one of the tables you want to get any field.

For example, we created two migration files, one per each table of the database we dealt with:

rails g migration AddUserIdAndUserChallengeIdAndCheckinsToWeek user_id:integer user_challenge_id:integer checkins:integer

rails g migration AddWeekIdToHistory week_id:integer

We edited the generated migration files adding the proper information to the new table. For example, this was the code for the Week table:

create_table "weeks", force: true do |t|
t.datetime "start_week"
t.datetime "end_week"
t.boolean "checkins_completed"
t.datetime "created_at"
t.datetime "updated_at"
t.string "user_id"
t.integer "user_challenge_id"
end

Finally, Natalie and I added the active record associations (in our particular case, "belongs_to" and "has_many" associations) into the model files (history.rb and week.rb), and we executed a rake db:migrate command in order to apply all the changes in our local repositories.

Sunday, March 23, 2014

Migrations in Ruby on Rails

Last week, Natalie and I continued working on the progress bar. In order to keep track of the challenges that the user have succeed, we decided that we need to add a new field to the database. This new boolean field had to be added to the user challenges table, and was called "finished". We looked for some documentation, and we figured out that there was a kind of migration "convention", which is used each time you want to make changes in a database.

The first step was to create the new column in the database by typing in the RoR console (Rails c) a command that follows this pattern:

rails g migration add_<new_field_name>_to_<table_name> <new_field_name>:<type>

If we need to delete a column, we should use the same format, but switching "add" by "remove":

rails g migration remove_<field_name>_from_<table_name>

Returning to our particular case, the command used was:

rails g migration add_finished_to_user_challenges finished:boolean

This command creates a new .rb file in the migrations folder, located at your_project_folder/db/migrate/. It is labeled with the current date following by the same name as we wrote the previous command. For this reason, it is very important to use the convention that I commented on the first paragraph.

Thus, we edited the new migration file, by creating a new class that generates the new field:

class AddFinishedToUserChallenge < ActiveRecord::Migration
  def change
    add_column :user_challenges, :finished, :boolean, default: false
  end
end

Moreover, we also decided to edit an existing field in the same table (user_challenges) and the histories table. This time, we needed to change the data type of the "duration" field, because it was created as an integer. As it was calculated by multiplying the number of times per week that the user have to check in and the number of weeks of the challenge, and we divided that value by 100 to get a progress bar percentage, the value was eventually rounded causing accuracy issues. Therefore, Natalie and I changed the "duration" field type from integer to decimal, following this format:

rails g migration change_data_type_for_<field_name>_in_<table_name>

Applying the previous pattern to our case:

rails g migration change_data_type_for_progress_in_user_challenges

rails g migration change_data_type_for_progress_in_histories

After creating the migration files, the next step was to define the class in both files to define the migrations:

class ChangeDataTypeForProgressInUserChallenge < ActiveRecord::Migration
  def change
    change_table :user_challenges do |t|
      t.change :progress, :decimal
    end
  end
end

Finally, Natalie and I executed a rake db:migrate command to apply the changes specified in the migration files. Thanks to this approach, we committed all the new files and the rest of the members of the team were able to pull this files, getting the same changes immediately.

- More information about migrations on RoR

Thursday, March 20, 2014

Fourth client meeting reactions

We had our fourth client meeting last Friday with Nikan, as we are switching our client (Nikan <-> Ackley) every week. This time, there was a new way for us to face a meeting, because we had to plan the agenda of the meeting. All the points to discuss were up to us.

At the beginning, it may seemed as a benefit for the team, because you can actually divide the time (25 minutes) as you want, focusing on the parts you prefer to discuss or showing a demo to your client. You actually take the control over the meeting, and you are able to choose the points that you want to deal with. This way may be seen as an advantage, but sometimes it could be tricky especially if you do not distribute your time correctly, because you have to be able to control the meeting's flow by distributing the time. Hence, if you want to success, keep in mind that you need to plan the meeting in advance, and then, fit your meeting's agenda as you planned.

For this reason, we decided discussing about the schedule before Friday's meeting. As we had certain parts of the functionality already running, we decided focus the meeting on showing Nikan a model with the progress since we start working: user registration and sign in process, avatar upload, challenge selection page, current challenge progress bar (I have been working on it with Natalie for several weeks), new challenges creation, etc.

Although we wanted to spend most of the time available showing the demo, we began the meeting with a brief review over the tasks done the previous week. In the meantime, we have fulfilled the timeline and all the weekly tasks have completed by each team member. After that, we went through the Demigod demo. Note that in the last meeting we made a mistake when we tried to show a demo to Ackley, but fortunately we learned from our mistakes, and this time we brought a laptop with a Rails server running and the website ready to be displayed.

The demo was introduced by Matt, who clearly explained each functionality which was already working properly as well as showed several suggestions and tests suggested by Nikan. We felt that she was really satisfied with our work, and she actually congratulated us for our progress. Moreover, I think we made a great control of the time, because once we ended the demo we still had five minutes left to identified the tasks we need to accomplish due next meeting (after the Spring Break).

From my point of view, this was the most successful client meeting so far. We hope the next one be even better since we are working hard to have all the Demigod's functionality ready as soon as possible.

Monday, March 17, 2014

Demigod: How to avoid cheating when check-in using jQuery and Ruby

Natalie and I have worked on the challenges progress bar. The number of check-ins needed to success the challenge depends on two variables whose combination gives its duration (or number of total check-ins needed): the number of check-ins per week, and the number of weeks. So, if we select a challenge requires 2 check-ins per week during 4 weeks, the duration is going to be 8 check-ins. Taken into account the previous statement, the main problem is how to control user's cheating when check-in, because if we do not control it, a user could check-in continuously, succeeding the challenge in few seconds.

The idea was to simplify the problem and then, trying to apply to a real situation. To do this in a simple approach, we thought that the easiest way was to prevent check-ins in the first minute since the user picks a challenge. We needed to disable the "Success" and "Fail" buttons during one minute, and then, enable both of them. We focused on the user's challenge partial file, one of the files we have in the views/users/ folder (Ruby on Rails).

The first variable we need is the current progress for the selected challenge, which we retrieved from the instance variable in the users controller (*.rb). Note that we added Ruby code inside the jQuery function using the proper syntax: #{ruby_code}:

var progress = #{@current_progress};

We created a new function called isValidCheckin which receives the current progress and basically checks the time that has passed since the first time stamp in the database associated to that pair challenge-user (we use an history table to store this information). Therefore, the function either enables or disables the "Success"/"Fail buttons depending on the time time between the first time stamp and the current time. Because of testing reasons, we set this time to 1 minute delay:

    function isValidCheckin(progress){
          
        var startTimestamp = "#{@start_timestamp}";
        var difference = "#{(Time.now - @start_timestamp.to_time)/1.minute}";
        console.log("Difference: " + difference);
        
        if(difference > 1 && progress < 100){
          $('#successBtn').removeAttr("disabled");
          $('#failBtn').removeAttr("disabled");
        }
        else {
          $('#successBtn').attr("disabled","disabled");
          $('#failBtn').attr("disabled","disabled");
        } 

    } 

To get the number of minutes that have passed since the first time stamp, Ruby has a very useful function: number.minute/day/hour/year... In this case, we used 1.minute, that gets the number of minutes. Having this value stored in the "difference" variable, we checked if it is greater than 1 minute, and if the challenge is not completed yet, we enabled both buttons, otherwise, we disabled them.

Natalie and I started by initializing the buttons, because the user could refresh the page or even log out and log in again. Anyway, if the current challenge is not started yet (progress = 0) or it is done (progress = 100), we had to avoid check-in by disabling both buttons with the "attr" jQuery property. Else, if the challenge is in progress, the buttons must be enabled (jQuery property "removeAttr"):

if ((progress >= 100) || (progress == 0)){
        $('#successBtn').attr("disabled","disabled");
        $('#failBtn').attr("disabled","disabled");
      }
      else if (progress > 0 && progress < 100){
        //enable buttons
        $('#successBtn').removeAttr("disabled");
        $('#failBtn').removeAttr("disabled");
      }

After this piece of code, we called the function to check the time:

isValidCheckin(Progress);

We also added some "breakpoints" to check the variable values on the browser's console. This can be easily done by writing the console.log(variable_name), for example:

console.log("Challenge progress: " + progress);
console.log("Difference (min): " + difference);

In order to test the code, we picked a random challenge and then, we checked the Firefox's console, that showed these messages:

As the challenge was not started, the progress is 0, and the difference en minutes since the challenge started was just a few seconds., the outcome showed on our browser was a disabled "Success" button:


1 minute after we picked the challenge, we refreshed the browser, and again, we checked the console:


Now, the difference is more than 1 minute, so we were able to check in:


The next step is to convert this code to do the same function when the minimum time needed to wait between check-ins depends on the challenge's duration, as I told in the first paragraph.