PHP and its community has evolved really fast in the last few years to allow for professional architectures and solutions. However, there are thousands of existing PHP applications which have not evolved in the meantime and are now crippled and unmaintainable because of that. These applications represent a real threat to the competitiveness of the business that relies on them.
The best approach in terms of business to solve this problem is progressive rewrite. Symfony2 and its modular architecture make it possible. This talk will cover the main technical difficulties of the progressive approach when rewriting legacy PHP applications using Symfony2
2. The
need
for
progressive
rewrite
The
technical
challenges
and
our
solu0ons
The
future
23/11/2012
2
THEODO
3. Legacy
PHP
applica9ons
are
everywhere
History
of
PHP
applica9ons
• 79%
:
websites
wriBen
in
PHP
among
the
top
1
million,
according
to
W3Techs.com
• 1994:
PHP
was
created.
Start
of
the
SpageBhi
age
• 2004:
PHP5
was
released
• 2007:
ZF
1.0.0
and
SF
1.0
were
released.
Start
of
the
MVC
age
13
years
of
(mostly)
spageBhi-‐coded
web-‐apps
23/11/2012
3
THEODO
4. How
do
these
applica9ons
cope
with
evolu9ons?
The
need
for
rewrite
• Many
businesses
rely
on
web
apps
wriBen
during
the
spageBhi
age
• Making
legacy
applica0ons
evolve
in
a
«
fast
»
way
becomes
impossible.
This
threatens
the
businesses
that
rely
on
them.
Before
the
big
used
to
eat
the
small,
nowadays
it
is
the
fast
who
eat
the
slow
• What
they
lack
is
a
well-‐designed
decoupled
and
tested
architecture
that
would
bring
flexibility
of
evolu0on.
23/11/2012
4
THEODO
5. Star9ng
a
new
version
from
scratch
is
a
danger
to
the
business
The
dangers
of
total
rewrite
• New
developments
are
invisible
un0l
the
new
version
is
finished
• You
need
twice
more
developers:
one
team
to
maintain
the
old
applica0on,
while
the
second
team
is
wri0ng
the
new
version
• The
probability
of
forge]ng
features
during
the
rewrite
is
high
• Transi0on
when
the
new
version
is
ready
becomes
costly
and
very
dangerous:
everything
is
impacted
at
once
23/11/2012
5
THEODO
6. Progressive
rewrite
is
the
solu9on…
but
is
very
challenging
The
challenge
of
progressive
rewrite
• You
have
to
work
with
hard-‐to-‐read
code
• All
the
aspects
of
an
applica0on
in
produc0on
are
concerned:
Ø source
code
of
course
Ø system
Ø data
Ø cache
Ø remote
webservices,
etc.
• The
major
conceptual
challenge
in
all
those
aspects
is
decoupling
of
modules.
Just
like
in
scaling!
23/11/2012
6
THEODO
7. Progressive rewrite is more profitable
Unbeatable
9me-‐to-‐market
Functionalities
Functionalities
Evolu9on
Time Time
• No new features for months • Only 1 app to maintain
• 2 apps to maintain • Lower regression risks
• Unbeatable time-to-market
23/11/2012
7
THEODO
8. The
need
for
progressive
rewrite
The
technical
challenges
and
our
solu0ons
The
future
23/11/2012
8
THEODO
9. Theodo
Evolu9on
Our
solu9on
at
Theodo
• R&D
project
started
at
Theodo
in
2012
• Aims
to
solve
all
these
issues
to
make
app
rewri0ng
agile
again
• And
help
Symfony2
take
over
the
world!
23/11/2012
9
THEODO
10. The
technical
experts
behind
Theodo
Evolu9on
Theodo
Evolu9on
team
23/11/2012
10
THEODO
11. The
big
picture
of
the
different
technical
aspects
to
solve
The
technical
challenges
• Preven0ng
regressions
• Upgrading
the
system
• Rou0ng
• Sharing
the
layout
• Sharing
the
session/authen0ca0on
• Decoupling
the
code
• Migra0ng
the
model
and
data
23/11/2012
11
THEODO
13. Belt
and
straps
are
necessary…
and
won’t
be
enough…
Preven9ng
regressions
23/11/2012
13
THEODO
14. Func9onnaly
test
what
could
harm
your
business
Preven9ng
regressions
• By
defini0on,
spaghe]
code
is
deeply
coupled.
Touching
one
part
breaks
something
at
the
other
end
• Create
func0onal
tests
on
the
most
cri0cal
scenarios
• Mink
+
ZombieJS:
hBps://github.com/Behat/Mink
23/11/2012
14
THEODO
15. Setup
external
monitoring
and
a
fast
deployment
pipeline
Preven9ng
regressions
The
most
thorough
func0onal
tes0ng
is
done...
by
pu]ng
in
produc0on!
• Monitor
produc0on
well
• Deploy
ohen
and
small
updates
• Setup
a
fast
rollback
system
• Setup
a
fast
deployment
system,
because
you
want
to
make
it
faster
to
correct
small
problems
than
to
rollback
23/11/2012
15
THEODO
17. Migrate
to
a
modern
environment
that
supports
Symfony2
…and
improves
performance
as
a
bonus.
Upgrading
the
system
• Symfony2
requires:
• PHP
5.3.3
• Sqlite3,
JSON,
ctype
• date.0mezone
set
in
php.ini
• php
app/check.php
23/11/2012
17
THEODO
18. Check
that
the
legacy
code
will
support
PHP
5.3/5.4
Upgrading
the
system
• Phpcs
CodeSniffs
for
5.3
and
5.4
compa0bility:
hBps://github.com/wimg/PHPCompa0bility
• Setup
a
pre-‐produc0on
environment
in
the
upgraded
environment
and
run
your
func0onal
tests
on
it
• And
this
0me
provision
your
environment
with
Puppet
or
Chef!
Check
Blueprint:
hBps://github.com/devstructure/blueprint
23/11/2012
18
THEODO
20. Rou9ng
between
the
old
and
the
new
Rou9ng
• The
beauty
of
PHP:
some
legacy
apps
have
simply
no
rou0ng
system!
• Host
the
new
app
next
to
the
old
app,
with
clear
URL
differences,
and
proxy
at
the
server
level
• Subdomain:
v2.myapp.com
• Subfolder:
www.myapp.com/v2/
• My
favourite:
create
a
catchall
route
with
Symfony2
23/11/2012
20
THEODO
21. The
CatchAll
Route
Rou9ng
class LegacyController extends Controller!
{!
/**!
* @Route("/{filename}.php", name="_proxy")!
*/!
public function proxyAction($filename)!
{!
ob_start();!
include $filename . '.php';!
!
return new Response(ob_get_clean());!
}!
}!
23/11/2012
21
THEODO
22. Rou9ng
from
the
new
to
the
legacy
Rou9ng
• If
you
have
a
rou0ng
system
in
the
legacy,
you
need
to
boot
it
• For
Symfony1,
create
a
twig
extension
to
use
«
url_for
»
in
your
new
templates
• Don’t
forget:
sfConfig::set('sf_no_script_name', true);
23/11/2012
22
THEODO
24. For
end-‐users
«
progressive
rewrite
»
=
«
same
template
»
Sharing
the
layout
• Copy-‐pas0ng
the
layout
is
not
a
good
solu0on
• Our
solu0on
:
crawl
the
legacy
layout
and
include
it
as
ESIs
!
<esi:include src="{{ path('legacylayout_top') }}" />!
!
{% block body %}{% endblock %}!
!
<esi:include src="{{ path('legacylayout_bottom') }}" />!
!
23/11/2012
24
THEODO
25. The
«
crawling
»
part
of
the
ESI
sub-‐request
Sharing
the
layout
!
$this->client->setHeader('Cookie', $currentCookie);
if ($request->headers->has('authorization')) {
$this->client->setHeader(
'Authorization',
$request->headers->get('authorization')
);
}
if ($this->session->isStarted()) {
$this->session->save();
}
$this->client->request('GET', $url);
$esiContent = $this->client->getResponse()->getContent();
23/11/2012
25
THEODO
27. Make
the
legacy
session
accessible
from
Symfony2
Sharing
the
session/authen9ca9on
• You
want
to
access
what
your
legacy
app
has
put
in
the
session
from
within
Symfony2…
• BUT
Symfony2
expects
session
informa0on
to
be
neatly
stored
in
arrays
in
the
«
_sf2_aBributes
»
namespace
to
make
your
legacy
session
accessible,
you
need
to
:
• register
«
Bags
»
for
each
of
your
legacy
$_SESSION
keys
• create
a
«
ScalarBag
»
type
when
these
values
are
not
arrays
23/11/2012
27
THEODO
28. Example
for
a
Symfony1
Session
Sharing
the
session/authen9ca9on
// onKernelRequest!
foreach ( array('symfony/user/sfUser/credentials',!
!'symfony/user/sfUser/attributes’) as $namespace)
{!
$bag = new NamespacedAttributeBag($namespace, '.');
$bag->setName($namespace);!
$session->registerBag($bag);!
}!
23/11/2012
28
THEODO
29. Integra9ng
9ghtly
sf1
and
Sf2
authen9ca9on
systems
Sharing
the
session/authen9ca9on
We
have
created
a
great
bundle
for
that!
23/11/2012
29
THEODO
40. You
need
to
create
the
dream
API
and
slowly
refactor
around
it
Decoupling
the
code
A
A P
P I
A
I P
I
A
P
I
A
P
I A
A P
P
I
I
23/11/2012
40
THEODO
41. You
need
to
create
the
dream
API
and
slowly
refactor
around
it
Decoupling
the
code
A
A P
P I
A
I P
I
A
P
I
A
P
I A
A P
P
I
I
23/11/2012
41
THEODO
42. You
need
to
create
the
dream
API
and
slowly
refactor
around
it
Decoupling
the
code
A
A P
P I
A
I P
I
A
P
I
A
P
I A
A P
P
I
I
23/11/2012
42
THEODO
43. You
need
to
create
the
dream
API
and
slowly
refactor
around
it
Decoupling
the
code
A
A P
P I
A
I P
I
A
P
I
A
P
I A
A P
P
I
I
23/11/2012
43
THEODO
44. This
is
called
«
Facade
Pa^ern
»
Decoupling
the
code
Wikipedia
A
facade
is
an
object
that
provides
a
simplified
interface
to
a
larger
body
of
code,
such
as
a
class
library.
A
facade
can:
• make
a
sohware
library
easier
to
use,
understand
and
test,
since
the
facade
has
convenient
methods
for
common
tasks;
• make
the
library
more
readable,
for
the
same
reason;
• reduce
dependencies
of
outside
code
on
the
inner
workings
of
a
library,
since
most
code
uses
the
facade,
thus
allowing
more
flexibility
in
developing
the
system;
• wrap
a
poorly
designed
collec0on
of
APIs
with
a
single
well-‐
designed
API
(as
per
task
needs).
23/11/2012
44
THEODO
45. Symfony2
Service
Container
Decoupling
the
code
• With
Symfony2,
the
new
API
of
the
Facade
PaBern
is
a
service
• Create
a
bundle
for
every
«
module
»
you
iden0fied.
• Create
a
service
for
every
bundle
you
now
have,
that
will
serve
as
your
Facade
API
• …
and
start
using
these
services!
23/11/2012
45
THEODO
47. A
typical
MySQL
database
is
highly
coupled
Migra9ng
the
model
and
data
23/11/2012
47
THEODO
48. Decoupling
a
rela9onal
DB
is
like
a^acking
a
giant
monster
Migra9ng
the
model
and
data
23/11/2012
48
THEODO
49. The
classical
solu9on
is
syncing
two
versions
of
the
data
Migra9ng
the
model
and
data
• Syncing
can
be
done
with
ETL
tools
like
KeBle
or
with
custom
code
in
the
new
applica0on
• To
avoid
unbearable
headaches,
it
is
highly
recommended
to
write
in
only
one
DB.
Which
means
to
rewrite
parts
of
the
legacy
code
to
save,
update
and
delete
in
the
new
DB
23/11/2012
49
THEODO
50. A
«
bearable
headache
»
solu9on:
Migra9ng
the
model
and
data
Legacy
Applica0on
New
applica0on
Rou0ng
23/11/2012
50
THEODO
51. A
«
bearable
headache
»
solu9on:
Migra9ng
the
model
and
data
Legacy
Applica0on
New
applica0on
Rou0ng
23/11/2012
51
THEODO
52. MongoDB
and
DoctrineODM
make
it
(a
li^le)
easier
Migra9ng
the
model
and
data
• Remember:
progressive
rewrite
relies
on
decoupling,
just
like
scaling.
Non-‐rela0onal
DBs
make
par0al
evolu0ons
easier
in
the
long-‐term
• In
a
document
DB
like
MongoDB
you
can
have
in
the
same
collec0on
data
which
coexist
in
different
versions.
• To
migrate
them
«
just
in
0me
»
use
/**
@MongoDBPreLoad
*/
from
the
Doctrine
ODM
23/11/2012
52
THEODO
53. The
need
for
progressive
rewrite
The
technical
challenges
and
our
solu0ons
The
future
23/11/2012
53
THEODO
54. The
evolu9on
of
Theodo
Evolu9on
Theodo
Evolu9on
strategy
• The
Theodo
team
is
today
18
and
growing
excellent
web
devs
working
currently
on
6
progressive
rewrites
of
huge
applica0ons
to
Symfony2
• Every
technical
solu0on
for
progressive
rewrite
to
Symfony2
is
bundled
in
our
project
Theodo
Evolu0on
• The
goal:
make
it
an
out-‐of-‐the-‐box
solu0on
to
work
on
legacy
apps
without
touching
legacy
code
• And
that
way
convert
the
whole
PHP
world
to
Symfony2
23/11/2012
54
THEODO
55. How
you
can
profit
from
Theodo
Evolu9on?
Theodo
Evolu9on
strategy
• Some
Theodo
Evolu0on
bundles
will
be
open-‐
sourced!
• Use
our
massive
presence
here
today!
Please
ask
ques0ons
to
the
guys
with
the
black
Theodo
hoodies!
• Contact
us
@theodo
or
fabriceb@theodo.fr
23/11/2012
55
THEODO