edition of an enterprise software in php, feedback
TRANSCRIPT
Edition of an Enterprise Software in PHP
N I C O L A S D U P O N T @ d u p o n i c o # f o r u m p h p j o i n d . i n / 1 5 7 1 4
NICOLAS DUPONT
Co-founder & Lead Developer
@duponico
nidup
agile software dev, continuous
improvement, open source, beers.
ENTERPRISE SOFTWARE
Solves an enterprise-wide problem
Improves the productivity
Is robust and reliable
For instance, Enterprise Resource Planning (ERP), Business Intelligence (BI), Customer
Relationship Management (CRM), Business Process Management (BPM), Master Data
Management (MDM), etc
PRODUCT INFORMATION MANAGEMENT (PIM)
COMMUNITY & ENTERPRISE EDITIONS
Symfony 2.7 Full Stack
+ Community Bundles
Open Source license, free of charge
Symfony 2.7 Full Stack
+ Community Bundles
+ Enterprise Bundles
+ SLA-backed support
Commercial license, annual subscription fee
25k+ installations
134k LoC (PHP)
60+ customers
134k LoC + 49k LoC (PHP)
FEW ENTERPRISE CUSTOMERS
Clothing &Accessories
Retailers Service SpecialistRetailers
Others
... ... ... ... ...
ECOSYSTEM
Akeneo 40+people
Edition
SolutionPartners
25+companies
Integration
Community 2500+people
Contribution ... 160+ countries
KICK OFF
Timeline [01/13] ... 06/13 ...
Akeneo Team 4
Product Team 2
Community Edition starting (0 LoC)
Enterprise Edition not started
WHY PHP?
Strong community
Open source friendly
Good libraries (ex: thephpleague)
More and more mature (ex: composer)
Easy to hire for our partners
WHY SYMFONY (FULL STACK)?
Proven Framework
Strong community
Good documentation
Guidelines/practises
Speed up the development
BUSINESS APPLICATION NEEDS
UI (navigation, grid, etc)
User
Security
Workflow
Reporting
...
Common requirements
Same needs than OroCRM
Let's contribute to
FIRST DIFFICULTIES
Few months later...
Lot of technical pieces started...
Nothing 100% finished,
Nothing 100% useable
NEW ORGANIZATION!
Product owner joins the team
Scrum team (2 weeks / sprint)
Focus on business value
Focus on finished increments
Focus on technical practises
RESPONSIBILITIES
Product Owner
Build the right thing
Developer
Build the thing right
Agile coach
Build the thing fast
ALPHA RELEASE!
Timeline 01/13 ... [06/13] ... 01/14 ...
Akeneo Team 7 (+3)
Product Team 5 (+3)
Community Edition v1.0.0-alpha (39k LoC)
Enterprise Edition not started
FIRST PROJECTS
We integrate a first project on v1.0.0-alpha
Solution partners integrate few others
Integration? standard distrib, write custom import and export, addextra models, write specific business rules, create new screens, etc
Problems! extensibility, unclear naming, lake of interfaces, toomuch responsibilities per class, etc
CUSTOMIZABLE+MAINTAINABLE
SOLID OOP principles
+ Dependency Injection Container
+ Unit Tests
+ Functional Tests
= Easy to change any small part of the appPhpMetric, size = Complexity,
color = Maintainability
pim_catalog.updater.product_property_setter: class: %pim_catalog.updater.product_property_setter.class% arguments: '@pim_catalog.repository.cached_attribute' '@pim_catalog.updater.setter.registry'
UNIT TESTS
1) Describe a class behavior
2) Implement the behavior
3) Refactor the code
>> Helps to specify and design classes
Today, ~1000 specs
class ProductBuilderSpec extends ObjectBehavior //[...] function it_creates_product_without_family($repository, AttributeInterface $sku) $repository>getIdentifier()>willReturn($sku); $this>createProduct()>shouldReturnAnInstanceOf(self::PRODUCT_CLASS); //[...]
FUNCTIONAL TESTS
1) Describe a feature
2) Implement it
>> Helps to specify featurestoday, ~1400 scenarios
Feature: Edit a product [...] Scenario: Successfully edit and save a product Given I am logged in as "Mary" And I am on the "sandal" product page And I fill in the following information: | Name | My Sandal | When I press the "Save" button Then I should be on the product "sandal" page And the product Name should be "My Sandal"
CONTINUOUS INTEGRATION
Jenkins CI
Static analysis (phpmd, phpcs, phpcpd, jshint, etc)
Unit Tests (phpspec, jasmine)
Functional + API Tests (behat) Jenkins CI
Travis CI
Static analysis + Unit Tests
Github Integration Travis CI
CODE WORKFLOW (GIT)
For each story / bug,
Create a new branch
Write code + tests
Do a pull request
Check the Definition Of Done (DOD)
MergeDefinition Of Done (Story)
| Q | A| | | Specs || Behats || Blue CI || Changelog updated || Code review and 2 GTM || Micro Demo (PO) || Migration script || Tech Doc |
STABLE RELEASE!
Timeline ... 06/13 ... [01/14] ... 04/14 ...
Akeneo Team 9 (+2)
Product Team 5 (=)
Community Edition v1.0.0 (62k LoC)
Enterprise Edition not started
COMMUNITY EDITION V1.0.0
Hard to release the first stable version
Why? very last change, postpone, another one, etc
So? ~2 months to "finish"
Lot of new projects (and problems)!
"If you are not embarrassed by the first version of your product, you’ve launched too late."
Reid Hoffman
PERFORMANCE PROBLEM
Customer with 100k products, 100 attributes
Application is slow (grids, forms)...
Why? Doctrine ORM hydration + greedy algo
So? ~1 month to optimize the code
SCALABILITY PROBLEM
Customer with 1M+ products
Application will not work...
Why? RDBMS + Entity Attribute Value (EAV)
So? ~1 month to add a MongoDB storage + minor release
LET'S START THE ENTERPRISE EDITION!
Timeline ... 01/14 ... [04/14] ... 11/14 ...
Akeneo Team 12 (+3)
Product Team 5 (=)
Community Edition v1.1.0 (67k LoC)
Enterprise Edition starting
NOT STARTED, ALREADY LATE!
Scope (~fixed): too big!
Team (fixed): 4 (+1) developers
Schedule (fixed): July, 3 months
Iron Triangle
ENTERPRISE EDITION V1.0.0
Extends the Community Edition
Brings workflow, advanced permissions, advanced versioning
Released 1 month late
By reducing scope (simplify and remove features)
By reducing internal quality (technical shortcuts)
NEW ACTIVITY
Support + Maintainance
3 minor versions (1.5 year)
Dedicated person / sprint
Qualify issues
Fix bugs (with new tests)
Release patches
TECHNICAL DEBT
Monetary debt metaphor
Not necessarily a bad thing
Must be managed
Must be paid back
Technical Debt Quadrant, Martin Fowler
TAKE CARE OF THE CODEBASE
Broken windows theory
Criminological theory (1982)
Prevent small crimes to avoidmore serious crimes
Boy scout rule
"Always leave the campgroundcode cleaner than you found it."
SCALE THE TEAM!
Timeline ... 04/14 ... [11/14] ... today
Akeneo Team 18 (+6)
Product Team 5 (=)
Community Edition v1.2.0 (78k LoC)
Enterprise Edition v1.0.0 (20k LoC)
PRODUCT TEAM SIZE X 3
Akeneo raises $2.4 Million and hiring time!
November + 2, December + 2, January + 2, February +2 ... Stop!
From 5 to 14 people in few months
Impacts on organization and architecture
SCALE THE ORGANIZATION
Squad: pluridisciplinary, autonomous, temporary, has a clear goal
Feature Squad x 3: Delivers finished product increments
Support/Maintainance Squad x 1: Takes care of our ecosystem
Tooling Squad x 1: Takes care of our tools (CI first)
SCALE THE ARCHITECTURE
Quite "monolithic software" is ok for a small team
Team size x 3 ~= features x 3 + side effects x 3 + dependencies x 3
Improve the internal API: querying, data update, validation, etc
Build new features by using this internal API
COUPLING, BUSINESS CODE - ORM
Business code directly uses Doctrine ORM classes
For performance reason, we need to write a direct to DB import
So? Introduce and use new interfaces!
namespace Akeneo\Component\StorageUtils\Saver;
interface SaverInterface public function save($object, array $options = []);
// RemoverInterface, ProductRepositoryInterface, AttributeRepositoryInterface, etc
COUPLING, BUSINESS CODE - FRAMEWORK
Business code directly uses Symfony Framework classes
In v1.0, product draft edition is coupled to Symfony Form
In v1.4, we need to import product drafts from csv files...
No way to re-use our business code... re-write a decoupled API
BACKWARD COMPATIBILITY
Semantic Versioning (semver.org)
Given a version vMAJOR.MINOR.PATCH
MAJOR+1 when you make incompatible API changes
MINOR+1 when you add functionality in a BC manner
PATCH+1 when you make BC bug fixes
Public API?
Software using Semantic Versioning MUST declare a public API
API could be declared in the code itself or exist strictly in doc
PUBLIC API
Symfony (since v2.3)
Declared in the code (interfaces and @api tag)
Explained in the doc with "Backwards Compatibility Promise"
Akeneo PIM (in v1.4)
Not declared... so, public API = 1500 classes and 6749 methods
We're working on a first declaration: CSV file formats forimports/exports, connector interfaces and services, internal API,etc
BC BREAK
Minor version (v1.4.0)
Add new features
Use of @deprecated tag for "API" changes
BC Break on "internal" code only
Upgrade doc and scripts
Patch version (v1.4.1)
Bugs fixes only
No BC Break (at all) on "API" and "internal"
DEPRECATED
Ex: import system has been revamped in v1.4
New system is introduced
Old system is deprecated (code and tests are kept)
Old system is maintained (tests are runned, bugs are fixed)
TODAY
Timeline ... 11/14 ... [today] ...
Akeneo Team 42 (+22)
Product Team 15 (+10)
Community Edition v1.4.0 (134k LoC)
Enterprise Edition v1.4.0 (50k LoC)
WHAT'S NEXT?
Improve User eXperience (productivity, perfs, etc)
Improve Developer eXperience (api, doc, support, etc)
Conquer the (PIM) world!
QUESTIONS?
Nicolas Dupont
@duponico
Join us! We're hiring!
https://joind.in/15714