There's a growing movement of functional programming, and part of that is removing conditions (see Michael Feathers post). In an example a secondary function is used to eliminate the need to have conditions on the length of an array.
Other techniques are to replace conditions with data structures - consider this problem:
http://greoup1/old/<number_without_leading_zeros>
http://greoup2/new/<number_without_leading_zeros>
http://greoup3/tkt_<number_without_leading_zeros>
If one wanted to create a PRCustomLink for this, then they could have conditions like:
| numberPart | PRCustomLink addConversion: [ :aString | (('Ticket ####' match: aString) and: [ (numberPart := aString copyFrom: 9 to: 13) isAllDigits ]) ifTrue: [ numberPart asInteger < 1001 ifTrue: [ 'http://group1/old/' , numberPart asInteger asString] ifFalse: [ numberPart asInteger < 2001 ifTrue: [ 'http://group2/new/' , numberPart] ifFalse: [ 'http://group3/tkt_' , numberPart ] ] ] ]
Another implementation would be:
| ticketRunArray numberPart | ticketRunArray := RunArray new: 1000 withAll: 'http://group1/old/'. ticketRunArray add: (2000 - 1000) withOccurances: 'http://group2/new/'. ticketRunArray add: (1000000 - 10000) withOccurances: 'http://group3/tkt_'. PRCustomLink addConversion: [ :aString | (('Ticket ####' match: aString) and: [ (numberPart := aString copyFrom: 9 to: 13) isAllDigits ]) ifTrue: [ (ticketRunArray at: numberPart asInteger ifAbsent: [^nil]), numberPart asInteger asString]].
Adding another group of tickets requires changing both implementation (adding more tests in the first, and more entries to the run array in the second), however the first ends up with many close braces while the second just gets another line added. Tests show that the RunArray is 10 times faster for 16 conditions.