Use a Single Version Control System for Everything

Every single artifact related to the creation of your software should be under version control. Developers should use it for source code, of course, but also for tests, database scripts, build and deployment scripts, documentation, libraries and configuration files for your application, your compiler and collection of tools, and so on—so that a new member of your team can start working from scratch.

–Continuous Delivery, Jez Humble, David Farley

I agree, but I’d add to this statement. We don’t keep everything under version control simply to ease the ramp up time for new team members (this is just one of many reasons). An even more important reason to keep everything under version control is because it is imperative that we be able to see all the items related to our project at a given point in time. We need traceability and re-creatability! (I think I just invented a new word.)

In nearly every position I’ve ever been in this question has come up: Should we keep project documentation in the same system as source code? Even in my citation above there seems to be some desire to separate development from documentation (developers do much more than simply write source code). I say to even consider placing project documentation in a separate system is a mistake.

Our project is composed of many items, from code to test to documentation, and all of these items need to reference each other. If our documentation resides in some other system (or in the same system but in a separate repository), it becomes impossible to use a ticketing system to link issues to either documentation or code (or both). Instead, our ticketing system may still be used to write up document needs, but now we have lost the ability to link from a ticket to a changeset that includes non-source code files (think of Redmine or Trac and linking to changesets) .

So what’s the point of keeping documentation in a separate version control or ECM system? I have yet to think of any good reason. I suppose there is a natural tendency to want to separate source code from documentation, but as to why, I have no idea.

I’m not suggesting we should mix documentation throughout source code paths. Naturally, we want to have some reasonable repository/project layout. Here’s what I would do (or something similar):

(Note: In a software medical device environment, there would be DHF and DMR paths in the trunk.) There are many other fine ways to lay out a repository. The point here is simply that it is important to keep everything together in the same version control system. This way we can trace, tag, branch and link issues for a project together.

As you can see in my above example, I’ve used a single repository with all sub-projects below. Others prefer a per-project repository setup. That’s fine, and probably appropriate in many situations, but it doesn’t allow relating issues across projects. I like using a single repository because it becomes much easier to reference related items regardless of project (and, in most issue tracking systems, we will have no problem referencing our project repository using its sub-path).

Big cable-backed broadband bill soars through NC House, one step closer to stifling ISP competition — Engadget

Big cable-backed broadband bill soars through NC House, one step closer to stifling ISP competition — Engadget.

.NET on a Resume a Libability?

The CEO of Expensify wrote a post on the company’s blog about why he considers .NET experience on a resume to be a general liability. Wow. I can’t say that I agree, but there are some interesting points. I have been known to think of Windows developers as somehow having less experience, but this is probably more of a personal bias than anything. Many great developers work in .NET because they have no choice.

[Expensify Blog: Why We Don’t Hire .NET Developers] (ouch!)

Good Recruiting

Last night I finally made it to a Ruby Hack Night in Raleigh… And it was good. Being a “techie” the single MOST important thing we can do for our career is to stay relevant (and any techie who does this because he/she likes it should never have a problem in this department). The folks who attend a “hack night” on a Thursday evening are the types that do this stuff because they enjoy it.

Last night a lady showed up who was not a programmer or a Ruby enthusiast. She was there because she wanted to know more about how to hire a good programmer for her company. Having spoken to countless recruiters over the years who had no idea what they were talking about, I immediately had a great deal of respect for the approach this lady was taking. The approach she is taking is not the easy one: Find a programmer and get a butt in a chair; Rather, she is looking for someone who is good at what he/she does and will be a real asset. (And, frankly, if I wasn’t committed to my new role, I may have thrown my resume her way!)

So this got me thinking… I know what I dislike when I am approached by recruiters, but what is it that I like? At this point in my career it is about much more than having a job and programming. I asked this lady if she was looking for a “code monkey” or a leader, and her response was something that was indeed very honest: “I’m not sure yet.”

I think the fact that she wasn’t sure points to the answer: They need a geek with solid programming skills, organizational and management skills, current knowledge and business sense. This is VERY DIFFICULT to come by (and I’ve alluded to the reason why in pasts posts).

Anyway, when I have more time, I’m going to put my thoughts about what I think high level techies want to see in a position.

Running Redmine with an Oracle Backend

Well, it took some figuring out, but I have succeeded in getting Redmine to run with an Oracle database. I did have a little help from this post, but there have been a few changes since then to deal with. Once I got all figured out, it really isn’t all that difficult to repeat (it just took a while to get there). (I’m not going to discuss setting up the Oracle adapter here, only Redmine.)

Here goes.
1. Oracle sees ” and “null” as the same thing.
The biggest issue is the fact that Oracle see ” and ‘null’ as the same thing. That said, there are a few setup scripts that will need modified. I went through db/migrate/001_setup.rb and looked for everything that sets a default value of ” and told it to allow nulls for any such column.

For example, the users table is created like this:

create_table “users”, :force => true do |t|
t.column “login”, :string, :limit => 30, :default => “”, :null => true
t.column “hashed_password”, :string, :limit => 40, :default => “”, :null => true
t.column “firstname”, :string, :limit => 30, :default => “”, :null => true
t.column “lastname”, :string, :limit => 30, :default => “”, :null => true
t.column “mail”, :string, :limit => 60, :default => “”, :null => true
t.column “mail_notification”, :boolean, :default => true, :null => false
t.column “admin”, :boolean, :default => false, :null => false
t.column “status”, :integer, :default => 1, :null => false
t.column “last_login_on”, :datetime
t.column “language”, :string, :limit => 2, :default => “”, :null => true
t.column “auth_source_id”, :integer
t.column “created_on”, :timestamp
t.column “updated_on”, :timestamp
end

…and versions:

create_table “versions”, :force => true do |t|
t.column “project_id”, :integer, :default => 0, :null => true
t.column “name”, :string, :limit => 30, :default => “”, :null => true
t.column “description”, :string, :default => “”
t.column “effective_date”, :date, :null => true
t.column “created_on”, :timestamp
t.column “updated_on”, :timestamp
end

I’m simply allowing nulls where before null was no longer accepted. This shouldn’t be a problem, its just a lacking database constraint. I’ll definitely follow up if it does become a problem.

There are a few other places where you’ll have to make similar changes:

  • 074_add_auth_sources_tls.rb
  • 091_change_changesets_revision_to_string.rb
  • 108_add_identity_url_to_users.rb
  • 20091017214336_add_missing_indexes_to_users.rb

2. Version Effective Date:
Oracle won’t like the syntax of 048_allow_null_version_effective_date.rb. I simply removed this file (it appears that this was a later change in Redmine) and made the version effective data column nullable in 001_setup.rb like this:

create_table “versions”, :force => true do |t|
t.column “project_id”, :integer, :default => 0, :null => true
t.column “name”, :string, :limit => 30, :default => “”, :null => true
t.column “description”, :string, :default => “”
t.column “effective_date”, :date, :null => true
t.column “created_on”, :timestamp
t.column “updated_on”, :timestamp
end

3. The UTF-8 Problem
Assuming your Oracle database uses AL32UTF8, you’ll want to do something like this in environment.rb:

ENV[‘NLS_LANG’]=’american_america.AL32UTF8′

4. Oracle 30-character limitation on table names
Oracle limits table names to 30 characters in length. This is a problem in one particular Redmine db migration script: 107_add_open_id_authentication_tables.rb
I changed this file to use smaller table names:

class AddOpenIdAuthenticationTables < ActiveRecord::Migration
def self.up
create_table :open_id_auth_associations, :force => true do |t|
t.integer :issued, :lifetime
t.string :handle, :assoc_type
t.binary :server_url, :secret
end

create_table :open_id_auth_nonces, :force => true do |t|
t.integer :timestamp, :null => false
t.string :server_url, :null => true
t.string :salt, :null => false
end
end

def self.down
drop_table :open_id_authentication_associations
drop_table :open_id_authentication_nonces
end
end

5. A problem with the Activity Tab
There a problem with Oracle CLOB String comparison (as in, you can’t compare a CLOB to a String). This is documented here: http://www.redmine.org/issues/3699
Unfortunately, the Redmine response is always “Oracle is not supported.” Hey, I don’t care for being stuck with Oracle either, but some of us are. Anyway, you can take care of this problem with a simple change to the comparison. Change redmine/app/models/journal.rb:

acts_as_activity_provider :type => ‘issues’,
:permission => :view_issues,
:author_key => :user_id,
:find_options => {:include => [{:issue => :project}, :details, :user],
:conditions => “#{Journal.table_name}.journalized_type = ‘Issue’ AND” +
” (#{JournalDetail.table_name}.prop_key = ‘status_id’ OR length(#{Journal.table_name}.notes) > 0)”}

8. Change the sequences
Before you get moving, you’re probably going to want to fix the table sequences, setting them to start at 1. This is just a matter of preference, but at least for the ISSUES_SEQ, since the unique ID is used to identify the ticket, it makes sense to start with lower numbers. For some reason that I don’t understand (yet), Oracle 11 starts sequences at 10,000. I recommend doing this:

DROP SEQUENCE REDMINEUSER.ISSUES_SEQ;
CREATE SEQUENCE ISSUES_SEQ
START WITH 1
MAXVALUE 9999999999999999999999999999
MINVALUE 1
NOCYCLE
CACHE 20
NOORDER;
Now your tickets will start with lower numbers. As far as other sequences go, it doesn’t matter too much, since we generally don’t view the id columns.

9. Annoyingly Short VARCHAR2 Defaults
The default VARCHAR2 setting is going to be VARCHAR2(255). When it comes to certain fields, such as the project description, this is a little on the short side. I went ahead and modified the column width myself:

alter table PROJECTS modify description VARCHAR2(4000);
commit;

10. Database Trigger Needed to Copy Workflows
When creating a Tracker, Redmine allows a user to “Copy from existing workflow.” (I.e., You can copy the Tracker workflow from an existing Tracker, making the process of adding a new Tracker much more quick.) This creates a possible error when inserting the new workflow into the Workflows table because for some reason (and I’m not yet sure why), no trigger was created on the Oracle database. Without this trigger you will see a “Cannot insert null” error in your production log file if you attempt to copy a workflow. To get around this problem it is easy enough to create a trigger on the Workflows table:


CREATE OR REPLACE TRIGGER workflows_before_insert
BEFORE INSERT
ON WORKFLOWS
FOR EACH ROW
BEGIN
if :new.id is null then
SELECT workflows_seq.nextval INTO :new.ID FROM dual;
end if;
END;
/

11. Database connection
Finally, database.yml will end up looking something like this:

production:
adapter: oracle_enhanced
database:
host:
port: username: redmine_db_user
password: redmine_db_pass

These changes are very important to note should you ever have to upgrade Redmine.

Redmine on Oracle

I posted this issue to the Redmine group. It seems that Redmine doesn’t play nice with Oracle without some enhancements. This one relates to the nasty 30-character limit on Oracle table names. I’m anxious to see if they pick it up. I also added #7826.

[Redmine – Issue #7825]
[Redmine – Issue #7826]

Riding Rails: DoS Vulnerability in Ruby

Riding Rails: DoS Vulnerability in Ruby.