You are on page 1of 96

The

Even-Darker Art
of

Rails Engines
@lazyatom
github.com/lazyatom/engines
Rails 2.3
history
November 2005
it’s distracting!
reuse is overrated!
Evil! Evil!
Evil!

Evil!

Evil! Evil!
Evil!

Evil! Shit!
eek!
appable_plugins
desert
merb slices?
engines
!"#$%&!"#$'#(%&$#)&!"#$%&*$+,#-.!)
!"#$%&'()
$$*%&'()$++,$-'%!.%&'()./0#'12%)/'0
"0!

3$405/0"6$%1"$7-(5/06$8/)9$%0$%77:$!/1";)'1<=
!"#$"05/0">
$$9%6.%77.!/1";)'1<>
"0!

3$?")(106$)1("$/#$)9"$"05/0"$69/76$8/)9$%$1'()/05$#/-"
!"#$1'()"!>
$$@/-"="A/6)>B1'()/05.#/-"C
"0!

!"#$D/"8.7%)9
$$@/-"=E'/0B!/1";)'1<F$G%77GF$GD/"86GC
"0!
app/controllers/
models/
helpers/
views/
metal/
*$+,#-&"**&23-'!3$$(!&*$+,#-523-'!3$$(!.!)

;-%66$H-(5/0I'0)1'--"1/0/1**$#2"'#3-43-'!3$$(!
$$!"#$/0!"A
$$$$1"0!"1$J)"A)$,K$LM"--'F$H-(5/0NL
$$"0!
"0!
9"-7"1$J%--
won’t load from your plugin
Ticket #1905
config/routes.rb
*$+,#-&23-6#,&!3+'(%.!)

O;)/'0I'0)1'--"1JJ?'()/05JJ?'()"6=!1%8$!'$+2%7+

$$2%7=;'00";)$G:7%)9GF$J;'0)1'--"1$,K$L7-(5/0LF$
$$$$$$$$$$$$$$$$$$$$$$$J%;)/'0$,K$L/0!"AL

"0!
top precedence
in your plugin:
O;)/'0I'0)1'--"1JJ?'()/05JJ?'()"6=!1%8$!'$+2%7+
$$2%7=;'00";)$G:7%)9GF$J;'0)1'--"1$,K$L7-(5/0LF$
$$$$$$$$$$$$$$$$$$$$$$$J%;)/'0$,K$L/0!"AL
"0!

in your app:
O;)/'0I'0)1'--"1JJ?'()/05JJ?'()"6=!1%8$!'$+2%7+
$$3$===$')9"1$1'()"6$===
$$2%7=;'00";)$G:7%)9GF$J;'0)1'--"1$,K$L%77LF$
$$$$$$$$$$$$$$$$$$$$$$$J%;)/'0$,K$L/0!"AL
$$3$===$')9"1$1'()"6$===
"0!
in your plugin:
O;)/'0I'0)1'--"1JJ?'()/05JJ?'()"6=!1%8$!'$+2%7+
$$2%7=;'00";)$G:7%)9GF$J;'0)1'--"1$,K$L7-(5/0LF$
$$$$$$$$$$$$$$$$$$$$$$$J%;)/'0$,K$L/0!"AL
"0!

in your app:
O;)/'0I'0)1'--"1JJ?'()/05JJ?'()"6=!1%8$!'$+2%7+
$$3$===$')9"1$1'()"6$===
$$2%7=;'00";)$G:7%)9GF$J;'0)1'--"1$,K$L%77LF$
$$$$$$$$$$$$$$$$$$$$$$$J%;)/'0$,K$L/0!"AL
$$3$===$')9"1$1'()"6$===
"0!
Ticket #2592
(also Ticket #329)
785*$+,#-&$#)&785*$+,#-.!)
2'!(-"$P<H-(5/0
$$!"#$6"-#=%!!.1'()"6B7"*C
$$$$2%7=;'00";)$L:6)(##LF$J;'0)1'--"1$,K$L)9/056L
$$"0!
"0!

O;)/'0I'0)1'--"1JJ?'()/05JJ?'()"6=!1%8$!'$+2%7+
$$3$<'(1$%77$1'()"6===

$$P<H-(5/0=%!!.1'()"6B2%7C

$$3$");===
"0!
what’s missing?
public assets
copy
file clash
83+!5*$+,#-&#-%'"$$.!)

2<./2%5"6$,$H%)90%2"=0"8B@/-"=!/10%2"B..@QR4..CC$S$
$$$$$$$$$$$$$$L%66")6:/2%5"6L
)%15")$,$?%/-6=1'')$S$L7(&-/;:/2%5"6:2<.7-(5/0L

@/-"T)/-6=2U!/1.7B)%15")C

2<./2%5"6=;9/-!1"0="%;9$!'$+"+$
$$$$@/-"T)/-6=;7.1B"F$)%15")$S$"=&%6"0%2"C$
"0!
83+!5*$+,#-&#-%'"$$.!)

2<./2%5"6$,$H%)90%2"=0"8B@/-"=!/10%2"B..@QR4..CC$S$
$$$$$$$$$$$$$$L%66")6:/2%5"6L
)%15")$,$?%/-6=1'')$S$L7(&-/;:/2%5"6:2<.7-(5/0L

)%15")=2%U".6<2-/0UB2<./2%5"6C$(0-"66$)%15")="A/6)>
migrations
simple DSL
rollback
version !&:2/51%)":
$$VWWXWYWYYVYVZ[.%-79%=1&
20090101121234 VWWXWYWVY[VZ[\.&")%=1&

20090102142345
7-(5/0:!&:2/51%)":
2008123123456 $$VWW]YVZYZ[\^.5%22%=1&
version 1%U"$!&J1'--&%;U
P/51%)'1=1'--&%;U
20090101121234
P/51%)'13;(11"0).D"16/'0
20090102142345
P/51%)'132/51%)"!=-%6)
2008123123456 P/51%)'1=5").%--.D"16/'06

BL_4R4I`$D"16/'0$@?aP$$
$$6;9"2%.2/51%)/'06LC
=2%7BbJ)'./C=6'1)
it gets worse
version !&:2/51%)":
$$WWY.%-79%=1&
001 WWV.&")%=1&

002
7-(5/0:!&:2/51%)":
$$WWY.5%22%=1&
http://www.flickr.com/photos/bk2204/475332962/
single timeline
You 1
ti o n 1
i g ra a tio n
p m ig r
ap n m 2
lu g i t i o n
p i g r a 3
Me p m t i o n
ap i gr a
t a l l p m r a
in s a p m ig
g i n
plu
d e
p g ra
u
n 1
You r atio n 1
m ig tio
pp g r a
a
in mi n 2
plug atio
ig r n 3
p m tio
ap i gr a n 2
ap p m
r atio
mig
g i n
plu
!&:2/51%)":
$$WWY.%-79%=1&
WWV.&")%=1&
WWZ.7-(5/0.)'.WWY=1&
WW[.!"-)%=1&

7-(5/0:!&:2/51%)":
$$WWY.5%22%=1&
Symlink?
!&:2/51%)":
$$WWY.%-79%=1&
WWV.&")%=1&
Reference?
WWZ.7-(5/0.)'.WWY=1&
WW[.!"-)%=1&

7-(5/0:!&:2/51%)":
Copy &
Retimestamp?
$$WWY.5%22%=1&
Ticket #2058
interblah.net/plugin-migrations
my recommendation?
(for the moment, at least)
write a generator
(within your plugin)

c$6;1/7):5"0"1%)"$%;)6.%6.#(.2/51%)/'06
$$$$
$$$"A/6)6$$!&:2/51%)"
$$$;1"%)"$$!&:2/51%)":VWWXW\W\YYYZZd.&-%9=1&

c$===
techniques
overriding functionality
views just work
controllers
straight override
module
namespaced
playing nice with the
class cache
1/23*8/36/1**$#2"'#3-43-'!3$$(!/

<<
'!((/)+'/#%/%'#$$/"2'#:(<<<<<<!
9"%/)((-/!(73:(;/6!37/'9(/73;+$(/
O;)/D"_(77'1)JJe"7"0!"0;/"6=-'%!.'0;".7%)96
ApplicationController

AppController PluginController
ApplicationController

PluginController
23-6#,&(-:#!3-7(-'.!)

?%/-6JJQ0/)/%-/f"1=1(0$!'$+;'0#/5+
$$3$");===

$$;'0#/5=1"-'%!.7-(5/06$,$)1("
$$
"0!
83+!5*$+,#-&"**&23-'!3$$(!%&,33;523-'!3$$(!.!)

;-%66$g''!I'0)1'--"1$h$===
$$(0-'%!%&-"
$$
$$3$");$===

"0!
init.rb woes
785*$+,#-&#-#'.!)

;'0#/5=)'.71"7%1"$!'

$$_'2"O77I-%66="A)"0!BP<i"9%D/'(1C
$$
"0!
testing
ApplicationController

AppController PluginController
ApplicationController

o de
Their C

C o de
Your

PluginController
"
$
!
#
unit test?
test in your own rails
environment?
plugin_test_helper
I care about testing
my chunk
You care about testing
your whole app
empower the
developer
avoiding fail
;%6"$;'!"=;'06(2"1

$$89"0$;'!"=%()9'1
$$$$1"(6"=2'6)-<$,j$:"##";)/D":

$$89"0$1%0!B!"D"-'7"1C
$$$$1"(6"=)1/;U/"1.&().7'66/&-"B)1("C

$$"-6"
$$$$1"(6"='D"11%)"!N

"0!
consume wisely
Nutrition Facts
Serving Size 14 kloc
Amount Per Serving 1 bad engine
Calories 10,666
% Daily Value*
Total Fat 2674g 98%
Long Methods 1578g 34%
God Objects 326g 7%
Stress 320mg 119%
Hairloss 45g 45.8%
Technical Debt 13g 87%
Untested Code 1578mg 34%
Hidden Bugs 326mg 7%
Benefit 1mg 0.1%
you will not be able to
write some engines.
you will not be able to
use some engines.
extract
specific functionality
establish some
clear integration points
you are customer #1
READ the CODE
james@lazyatom.com

FIN
lets@gofreerange.com

You might also like