Archive for the ‘Developer Essentials’ Category
Debugging in Rails
Learning how to debug in Ruby on Rails is arguably one of the most important things to learn when getting started with rails development, yet isn’t always easy to pick up with the documentation available. What follows is an introductory guide to rails debugging, with the goal of getting new developers up and running with the command-line debugger as quickly as possible.
Logging
One of the simplest ways to debug in rails is to simply output information to the screen. This is especially convenient when it is necessary to continuously output the value of a variable over time.
The easiest way to do this depends on where you are debugging – whether it is within a view, controller or model.
Views: DebugHelper
The Rails ActionView comes with a debug helper that makes debugging in a view easy.
Within a view, simply enter debug followed by the name of the variable of interest to print out the variable in a human-readable format. For example:
<%= debug @current_user %>
The above code will display a detailed YAML output of the given variable, in this case @current_user, at that particular point in the execution:
--- !ruby/object:Admin
attributes:
first_name: admin
section_id:
notes_count: 0
last_name: admin
updated_at: 2013-01-19 01:05:27 Z
created_at: 2013-01-19 00:56:14 Z
grace_credits: 0
hidden: 0
api_key: MjBjZDk1Y2Q5MjdhZTU1MjE2NjBlYTNmYmQzODY4Zjc=
id: 1
user_name: a
type: Admin
attributes_cache: {}
changed_attributes: {}
destroyed: false
marked_for_destruction: false
new_record: false
previously_changed: {}
readonly: false
Controllers and Models: Logger
Within a controller, it’s still possible to pass debugging information to the screen by passing it to a view object, although it is typically simpler to log it to the console. This can be done using the default rails logger, which takes a string as input. Duplicating the above example using the logger:
logger.debug "Current user: #{@current_user.inspect}"
In this example, the inspect method is used to convert the contents of the @current_user object into a human-readable format, which is then output to the console by the logger. Note that the console output is also logged to a text file for later viewing. In the Markus development environment, this is saved in logs/development.log.
Debugging
For more complex problems, it is often necessary to step through the code to get to the root of the problem. This can be done using the built-in ruby-debug gem.
The ruby-debug gem must be first installed in the Markus environment, which can be done with the following command:
sudo gem install ruby-debug
The debugger can then be invoked by entering debugger anywhere in the ruby code, which has the effect of creating a breakpoint. When the debugger statement is reached, the application is paused and creates a debugger shell in the terminal.
Some of the most important commands include:
- backtrace – Display a stack trace of the application execution.
- break – Set new breakpoints, at a particular line or method in a file/class.
- catch – Tells the debugger to catch all exceptions of a particular type, or (with no arguments) catch all exceptions.
- continue - Resume execution.
- delete/disable – Delete/disable a breakpoint.
- display – Used to set the debugger to display the value of a certain variable each time you move the debugger to a new point.
- down/up - Move up/down n levels in the execution stack.
- finish – Continue execution until the current (or specified) stack frame returns.
- frame – Used to move to any point in the execution stack. Call frame n, where n is the number listed in the backtrace.
- irb – Start an interactive ruby interpreter. Interactively execute code within the current application context.
- list (or l) – Display the lines of code surrounding the current line being executed. Can be used in succession to display following lines of code. Use list- to display previous lines of code.
- method – Display methods available to an object or class.
- next/step – Steps through the code, one line at a time. Next is more like “step over” and step more like “step in”. Use next/step- to move backwards.
- p or pp – Print (or pretty print) the value of a ruby expression.
- quit – Exit the debugger shell. Also will terminate the server.
- reload – Reload the ruby source. Required to reload the code if you change it while the debugger session is running.
- thread – Show running threads, switch between them, and stop/resume.
- var – Display all variables of a certain type (gloabl, instance, local, constant) and their values.
For the specific parameters of these commands, enter help <command> in the debugger shell. Simply entering help will provide a list of all commands.
Remarking Process Overview
This term, I worked on the re-marking feature in MarkUs together with Alysha. Besides the major change to database schema, a number of other changes and additions were made to improve the usability of the feature.
For a general overview of how the remarking process works in its current state, I have added a section in the Wiki on this topic: https://github.com/m-wu/Wiki/blob/issue-18/HowGradingWorks.rst#the-life-cycle-of-a-remark-request
Personal gains from contributing to UCOSP
My involvement in the UCOSP program was quite rewarding and satisfying. I gained valuable real-world experience as well as knowledge pertinent to my school studies and long-term career goals. Prior to working on Markus, I did not have any experience contributing to open source projects. For this reason, I found it difficult to understand why certain people spend a lot of their spare time producing stuff without being paid and then give it away for free. What are some of the personal benefits you can gain as a developer from participating in open source projects?
Self-education
This is your chance to work on projects and problems that you are most enthusiastic about, which is a strong motivator for doing your best and reaching creative heights.
Having your work reviewed and critiqued publicly may seem out of the norm. However, criticism can be viewed as a tool for improving your skills, attitudes and habits towards quality. You will develop a tendency to avoid sloppy coding knowing that your work is accessible by anyone.
The larger projects that have survived for years and continue to evolve often have great leadership, organization and development guidelines. Chances are you will become part of a team and learn from people that are many levels better than yourself.
Contribution
Some people actually develop feelings of wanting to give something back. Maybe not trying to make a difference but simply showing a token of gratitude to a community providing such a strong foundation for learning and education to anyone in society.
Control
Most people wish for freedom to control their lives. It can be incredibly frustrating to work on a project with budget constraints where software is rushed into a unmanageable mess. Reorganization and outsourcing can also seed feelings of disappointment and helplessness.
With open source you are no longer are a victim of such circumstances. You are free to implement and improve the features you think matter the most, while users help with finding relevance and setting priorities.
Reuse
Most programmers develop an urge to not repeat themselves throughout their careers. Producing open source software is the freedom to truly reuse efforts when changing jobs (or starting your own company) and share them with anyone.
These intentions stimulate thinking using broader perspectives and designs that are cooperative, flexible and adaptable to different environments in order to maximize opportunities for reuse. Keeping users loyal often means maintaining version compatibility and upgradability. Having to deal with all this complexity will make you a better programmer.
Open source is a lot about a community of freedom and sharing and it is not hard to see why open source developers often are highly respected. Participation will introduce you to a community of incredible talented, like-minded and caring people that may help improve your skills beyond imagination.
How to Succeed in UCOSP Projects
Success in a UCOSP project, or any open source project can be achieved using some of the following methods I have used myself, and methods I have observed other people using.
- Time Tracking
It is crucial to keep a log of whatever it is that you have been working on and in which direction you want to head in next.
- Constant Communication
Keep up to date with meetings and mailing list emails so you can understand what the rest of your team is doing. This helps in many ways. Also, ask your mentors or any other projects members involved if you ever have any questions regarding your project. They have most likely been involved in the project for quite a while, and can provide you with valuable advice.
- Don’t give up easily
There are times when you may run into problems such as not being able to understand what is going on in the application or not knowing how to write a specific code in a new language. Don’t give up! Ask others in your communication channels for help, and try to understand what is going on.
Life and Career Lessons Learned from UCOSP
I have learned a couple career lessons that I will keep in mind in my future jobs.
- Time Estimates
This was definitely the biggest lesson. Before I started on my term goal, I had done a lot of research into my topic. I had originally estimated that I could complete the goal before the end of the semester, but as I approached the last few weeks I knew that this could not be done. Essentially, make sure the goal you are attempting to achieve is realistic given your time frame, and in case you cannot achieve your goal have some sort of way to integrate the work you have done into the main project so that others in the future can continue on your work.
- Communication is Key
In the case where you are working with a partner on any sort of project, it is very important to have a central place where you can keep track of changes and look at the work that the other person has done. You can use a project management tool, version control, or even just a simple spreadsheet for this.
I also have a bit more written on my personal blog as well.
Punchlines – ECN PAPPL 2013 OptimMarkus – 2013-03-20
Claire:
- submitted pull request for issue #1007
- reproduced and worked on issue #127
Gaëtan:
- submitted pull request to add unit tests for issue #559
- worked on issue #230: suggested UI design, dove into code
Punchlines – UCOSP Winter 2013 – Week 9
Mike Wu
Status:
-
Working on issue #1028:
-
Implemented colour-coding for the rubrics: green for selected marks and yellow for old marks.
-
Set unedited criteria to old marks upon changing marking_state to complete.
Roadblocks:
-
Need to decide on some UI details:
-
For example, when starting on a remark request, does the total shown on the page start with the original total mark and them adjust to remarks or start with 0 and reflect the actual remark result in the database (which is not populated with the original result at the beginning)?
-
Populate extra marks (i.e. bonus/deduction)? could and probably should be done in a separated task I think.
Next week:
- Sort out all the UI details and submit a pull request for #1028
Marc
Status:
- Reached a point where my level of progress can now be integrated into the master MarkUs branch. I have begun to work on making jQuery compatible with Prototype by using jQuery in a noConflict mode. I have also been making sure none of my changes have broken anything throughout the MarkUs application.
Roadblocks:
- Have a problem with some of the features of the new data tables for displaying students, but should be resolved once Prototype is renabled.
Next week:
- Keep working on getting jQuery to work with Prototype with jQuery being in a noConflict mode.
Alysha
Status:
- Worked on fix for issue 1027 (going over code base and updated it to use appropriate result related methods)
Roadblocks:
- takes some time to understand what certain areas of code are doing to know which is the appropriate fix for it
Next week:
- finish up fix for issue 1027
- work on some remark related bugs
Ian
Status:
- Added code to allow for unlimited tokens for test scripts. Tokens are currently not used anywhere so it’s just a boolean somewhere waiting to be used when we implement student run tests. Added code to choose between using the latest or best mark for all test scripts.
Roadblocks:
- None.
Next week:
- Possibly make a full test script or work on getting students to be able to run test scripts.
Mike Stewart
Status:
- Initial UI for the grader tab for grade entry is complete, with all of the kinks worked out.
Roadblocks:
- None.
Next week:
- Modify the functionality to assign graders on a many-to-one basis to users, instead of to groups.
Oussama
Status:
- Submitted pull request for issue 1035
Roadblocks:
- Waiting for pull request to be merged
Next week:
- Keep working on grades sheets’ viewing functionality for TAs
Nick
Status:
- Worked on displaying test run position with Redis and Resque
Roadblocks:
- Redis-status requires the perform method to be a class instance method, but right now it’s just a module method. It might take a lot of code refactoring to change it.
Next week:
- Keep working on displaying test run position and test run progress
Daryn
Status:
- Began making changes to make jQuery code noConflict() to be compatible with Prototype
- Working on update_collected_submissions function used in the Assignments dashboard.
Roadblocks:
- None
Next week:
- Meeting with Marc this Friday to regroup on progress and goals for the end of the semester
Daniel
Status:
- Worked on submissions, and integrating the existing API. Also started documentation.
Roadblocks:
- Thinking of including small examples for working with the API. What language would be preferred out of Java, Python and Ruby?
Next week:
- Finish up the assignments routes.
Punchlines – ECN PAPPL 2013 OptimMarkus – 2013-03-11
Claire
- fixed issue #1007
- reproduced issue #230
- was assigned to issue #126 and issue #127
Gaëtan
- fixed issue #559 – posted pull request #1046
- was assigned to issue #230
Database Schema Change: Submissions and Results
For the past while, I’ve been working on updating the database schema for the relationship between Submissions and Results. Originally, Submissions was created so it had a one to one relationship with Results. However, a feature was later added so that students could submit remark requests, requiring more than one result to be related to a single submission. The schema was then changed so that submissions had the following relation:
has_one :result, :dependent => :destroy
belongs_to :remark_result, :class_name => “Result”
Where ideally, we would want a has_many relationship. With the previous implementation, an error appeared about old results sometimes not showing up (documented in this blog post). A quick fix was implemented but it was dependent on database ordering and time stamps. I took the following steps to improve this implementation and schema:
1. The schema
- I updated removed the belongs_to remark_result relation, and changed the has_one result to has_many
- This change means that submission.results will return an array of results and that we can no longer call submission.result and submission.remark_result to get the results
2. Helper methods
- I implemented two helper methods: get_original_result and get_remark_result that would return the appropriate result for the submission
- These helper methods utilized the already existing field: remark_result_id in the Submissions table in order to differentiate between the two results (this removed our dependency on ordering/timestamps)
3. Updating the code base
- I updated the way results were created so that they would add to the array of results, and I had to manually fill in the remark_result_id column of the Submissions table when a remark result is created (since the belongs_to dependency no longer exists)
- All areas of the code that were using either the result or remark_result had to be updated with the helper methods and then tested to ensure functionality did not change
Next Steps
Originally, the suggestion on issue-941 (the schema update issue) was for the two methods to be get_result and get_old_result. The idea behind the methods was that get_result would return the remark result, if it exists, otherwise return the original result. Then, get_old_result, if a remark result exists, would return the original. When I implemented this approach, I realized several errors and differing functionality. Comparing it to the original code, I realized that the remark result was actually not being used in many places in the code base and that the original was result was generally used most of the time (without checking if a remark exists). Another problem is that in some cases you only want the latest completed result to be displayed rather than just the latest existing result.
So, the approach we took was to update the schema without changing any functionality (by using helper methods that would return the same type of result – original or remark – each time), and then follow up by going over sections of the code and updating them so that they will be using the appropriate result in that case. This issue has been opened and can be found here.
My suggestion for implementation is to create another helper method, get_latest_result, that would utilize the current helper methods get_original_result, get_remark_result, has_remark?, and remark_submitted? to return the latest result (note: only use remark result if remark request has been submitted). We would have to determine areas where this method would be appropriate to use instead of always using the original result.
Update
As per the “Next Steps” section, I have added in helper methods and then gone over the code base that uses results, updating method calls where appropriate. I implemented two helper methods: get_latest_result and get_latest_completed_result for the update. The former will return a remark result only if the remark request has been submitted, and the latter will only return a result whose marking state is “completed”. These changes can be found in pull-request 1058.
Punchlines – ECN PAPPL 2013 OptimMarkus – 2013-02-18
Claire
- was assigned to issue #1007
- worked on issue #1007: examined existing code in order to find the methods needed for this feature
Gaëtan
- reproduced issue #559 and added a more detailed description – as a comment
- got started developing to implement the required feature
- learned how to use the debugger
Punchlines – ECN PAPPL 2013 OptimMarkus – 2013-02-11
Claire
- finished Ruby on Rails tutorial
- created issue #1007 for the issue I’m working on
- reproduced issue #1007
Gaëtan
- finished Ruby on Rails tutorial
- unsuccessfully tried to reproduce issue #270 thus asked for it to be closed
- created issues #1005 and #1006
- was assigned to issue #559
