| A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | As CTO at TraBase, I received a codebase of 1.2M lines of legacy PHP code (5 years old; PHP+JS; 1.2M lines; 400+ MySQL tables, 80% in use) Over 13 months, my team of 4 developers and I transformed the live system into a structured, OO, unit-tested Laravel back end and a modern front while also serving customers with new features. Our changes over time: | |||||||||||||||
2 | Months of the project | Aspect | Before | After | ||||||||||||
3 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | |||
4 | x | Development tool (IDE) | A variety of Eclipse, Sublime Text and Notepad++. | Uniformized to JetBrains' PhpStorm. | ||||||||||||
5 | x | Common code style | No common style whatsoever. | Wrote coding style guide based on PSR-1 and PSR-2, with additions such as “no abbreviations are allowed”, “no code warnings allowed” etc. | ||||||||||||
6 | x | Database documentation | None. | Gathered all the information I could, on a DB-level, on a table-level, and for the most central tables, on a column-level. | ||||||||||||
7 | x | Server documentation | Our remote administrator team knew everything, but there was no written information in-house. | I sat down with the administrators and documented the system architecture. Now, everybody at the company uses it as a reference. | ||||||||||||
8 | x | Debugging | var_dump() | XDebug (breakpoints etc.) | ||||||||||||
9 | x | Documentation | A DocuWiki with very scarce information, also mostly deprecated. | An up-to-date DocuWiki, with sufficient information for a new developer to read it and start working on the system, using the wiki as a reference. | ||||||||||||
10 | x | x | x | x | x | x | x | x | x | x | Code errors and warnings | Tens of thousands of errors and warnings identified by PhpStorm. | Gradually eliminated the problems. Enabling PhpStorm's "Analyze code before committing" feature became possible. | |||
11 | x | x | x | x | x | x | x | x | x | x | x | x | x | PHP error log | Everyday unknown errors and warnings are "normal". | Only real errors in the log. |
12 | x | x | Legal matters | Mostly illegal software: MS Windows, MS Office, Sublime Text. | Legalized Windows, switched to LibreOffice, bought PhpStorm, everything else is free software. | |||||||||||
13 | x | x | x | x | x | Third-party libraries | Third-party libraries were scattered around in the codebase, some of the customized (modified in library core code), some deprecated. | Step 1: Started using Composer. Step 2: Removed all third-party libraries from the codebase. | ||||||||
14 | x | x | x | Code encapsulation | About 50% is spaghetti code, the rest is in classes, but without much information hiding. | Step 1: Created a PSR-0 namespace with a simple custom autoloader. Step 2: New classes go to a PSR-4 namespace and are loaded with Composer’s autoloader. | ||||||||||
15 | x | x | x | Partner API information | Scattered around in a network share and a Dropbox share. Most of it deprecated. | Found and listed online sources of info: API docs etc. | ||||||||||
16 | x | x | x | Subdomains | Had about 40 subdomains, they were not tracked, some contained sensitive information (such as development sites). | Got rid of half of the subdomains, protected all sensitive ones with Apache HTTP authentication. | ||||||||||
17 | x | x | x | x | x | x | Configuration | In various unversioned config files, most of them different across environments, not checked in to SVN. There were 100+ distinct files like this. | Step 1: Created a common Config class Step 2: All settings are in environment-specific config files, checked in to Git. | |||||||
18 | x | x | x | x | x | x | Language | English and Hungarian is about 60-40% in the code. | English–Hungarian ratio is about 80-20%. | |||||||
19 | x | x | x | x | x | x | PhpStorm | PhpStorm had no chance to understand the project, finding class/method usages etc. | PhpStorm understands most of the calls and references. | |||||||
20 | x | x | x | x | x | x | x | x | Critical issues | Every third day, we had some serious problem. Once in the beginning, a poorly written SQL UPDATE (without a WHERE clause in an obscure, rarely run module) deleted all the passenger contact details. | Some bigger issue once in 2 weeks, but they are usually not critical. | |||||
21 | x | Background processes (cron scripts) | About 25 undocumented processes, distinct entry points, randomly running/not running across environments. | Tightly tracked, documented, uniformized across environments. There is 1 common entry point for all cron scripts. | ||||||||||||
22 | x | x | x | x | x | x | x | x | Dead code | About 20% of the code was dead. | Identified dead code by logging doubted code block execution. Then removed dead code blocks. | |||||
23 | x | x | x | x | x | x | x | x | Constants | Global constants all around the place. | Moved configuration values to config files, others to model and service classes. | |||||
24 | x | Entry points | About 250 back-end entry points separate (php files) with no common bootstrapping | Made a list of all the entry points. We couldn't switch to a front controller, but a common bootstrap file is now included at all entry points. | ||||||||||||
25 | x | Cron scripts logging | Some of them logged to files, in various formats. Most of them didn't log anywhere. | Uniformized, to a DB table. | ||||||||||||
26 | x | Remote access | Remote desktop | VPN | ||||||||||||
27 | x | x | x | x | x | x | x | x | x | MVC | No MVC structure whatsoever. Most files contain SQL, PHP and HTML. | Models created step by step. Controller layer identified much later. Views even later. | ||||
28 | x | x | x | x | x | x | x | x | Processes | Common processes, such as static data updates were not documented, nor scheduled. | Described and scheduled these common processes. | |||||
29 | x | Versioning system | 8 different SVN repositories, with their history lost for shady reasons. | One Git repository, on GitHub. | ||||||||||||
30 | x | Mailing lists | Non-personal company e-mail addresses and mailing lists were a mystery for everyone. | We have a diagram of the mailing lists and common e-mail addresses as nodes, and the subscriptions and forwards as relations, so e-mail flow is very clear. | ||||||||||||
31 | x | Benchmarking | Slow MySQL queries reported by the server daily. No code benchmarking whatsoever. | Global script run benchmarking feature implemented. | ||||||||||||
32 | x | x | x | x | x | x | x | x | DB access | 5 different ways of accessing the DB, all of them using the deprecated mysql_* function set. Logging MySQL queries or errors was not possible. | One global DB facade that uses Laravel's Query Builder, with PDO at its core. Logging MySQL errors and queries is implemented, slow queries are logged too. | |||||
33 | x | x | x | x | x | x | x | Tempate engine | A very simple, custom template engine built in-house. | Twig | ||||||
34 | x | x | x | x | x | x | x | Duplicate code | A big chunk of the codebase was copy-pasted to 4 instances, to form new applications. Then of course, changes were made to each of the instances here and there. | Identified common parts and moved to a common space. | ||||||
35 | x | x | PHP version | PHP 5.3, already pretty old at the time. Upgrading was not viable for the lack of documentation and testability | Upgraded to PHP 5.6.10, the latest at the time. | |||||||||||
36 | x | x | x | Automated tests | Spaghetti code. No tests. | Codebase is written with unit testing in mind (short methods, well-defined, minimal dependencies). New code and refactored core parts of the old code are unit tested. | ||||||||||
37 | x | x | E-mails | E-mails sent from the system at random places, untracked, failures not logged. | E-mails are sent by a central Mailer class. Mailer calls are short and clean. Mail sending actions are logged with failures logged separately. | |||||||||||
38 | x | Internationalization | Global constants, loaded from DB+memcached, and sometimes from redundant .ini files. Constants were not recognizable by the IDE and difficult to comprehend when debugging. | One global __('TEXT_RESOURCE_NAME') function. | ||||||||||||