How to move fast while keeping the codebase clean?
See an article on Moving Fast With High Code Quality and clearPHP rules
- First an foremost keeping the codebase clean to avoid rewrites in long term
- Make profit!
- Other's interest in integration with your project (API)
- Move fast with development, don't use a tool if it slows down development
- Keep developer morale high
- Have a fixed time frame for paying back technical debt
- Think about the far future when making decisions today
- Software architecture ☀️ ☀️ ☀️
- Documented code design ☀️ ☀️
- Implementation (source code writing) ☀️
- Automatic and manual testing
- Periodic code review, security audit
Bits and bytes.
- Execute bit off
- Consistent indentation
- LF lineends
- UTF-8 encoding without BOM
- Trim trailing whitespaces
- Insert final newlines
- Non-ASCII characters (emoji, accented letter, signs)
LC_ALL=C grep -P '[\x80-\xFF]'
- Declare class, method and variable naming, consider PSRs
- Frameworks/CMS-s
- Packages/Libraries
- SaaS (Loco, Paperplane)
- Unified email, calendar, contacts API (Nylas)
- Development tools (Vagrant, Laragon)
- Testing tools (CI)
- Build and deployment tools (CD)
- Changelog (Headway)
- Application performance and error monitoring (Checkly)
- New feature or fix is ready and "works for me" → PR (new branch)
- → CI all green → dev branch
- → Previous feature approved → staging branch + deploy to staging server 🚢
- → Testing folks approve it → master branch
- → Wait for release → tag and deploy to production server 🚢
Commit checklist:
code, tests, changelog, commit message
with emojis 🐛,
issue link, watch CI (PULL_REQUEST_TEMPLATE.md)
Release checklist: tag, build, deploy, announce (blog, email, Wiki)
- Catastrophe → hotfix branch + deploy to production server 🚢
- Alert (email, chat, SMS)
- Watch logs
- Merge changes to dev branch
What to include in continuous integration with 0% code coverage? (no unit tests, no functional test)
Use Docker containers for testing.
- Modern task runner (composer:scripts, consolidation/robo, npm:scripts, grunt, gulp)
- Parallel package installation (hirak/prestissimo)
- Git hook integration (phpro/grumphp)
- Parallel syntax check (php-parallel-lint)
- PSR-12-based coding style (phpcs)
- Warn on
TODOandFIXME: "Move it into issues!" (phpcs) - PHP Compatibility check (phpcompatibility/php-compatibility)
- PHPDoc checker
- Static analysis (phpstan, larastan, psalm, phan)
- Mess Detector (phpmd) rules: clean code, code size, controversial, design, naming, unused code
- Critical vulnerabilities in dependencies (sensiolabs/security-checker, roave/security-advisories, dependencies.io)
- Build assets (webpack)
- Metrics (phpmetrics, phploc, laravel-stats)
- PHPUnit
- Measure code coverage
- Codeception, Behat, KantuX
- Packaging
- Test deploy
Try Scrutinizer or Exakat on Debian
- Performance (Tideways, Blackfire)
- Security scanner (Netsparker, Ripstech, StackHawk, awesome-php-security)
- Laravel Analyzer
A file SHOULD declare new symbols (classes, functions, constants, etc.) and cause no other side effects,
or it SHOULD execute logic with side effects,
but SHOULD NOT do both.
- Separate frontend, backend, API, CLI, cron/queue
- Make your frontend a UI for your API ⭐
- Comment your source code like a travel guide!
- The less indentation the better code
- Leave environment settings to the server, and check environment (php-env-check.php)
- Move resource-intensive tasks to cron jobs/queues
- Store and calculate dates, times in UTC and display it in the user's timezone
- Develop simple maintenance tools (e.g. deploy, import, export) for the command line
- Autoloading (composer)
- DI containers
- Exception handling
- Logging
- ORM
- Database migration
- Application caching aka. object cache (PSR-6)
- HTTP communication (request, response, routes) and security (URL structure, WAF)
- Session handling (very long sessions, CSRF, session expiration UX: timer, warning, redirect, password input)
- Form handling, input validation, sanitization (UserFrontValidate->Request->BackendValidate->BusinessLogic->Response)
- Escaping (SQL, HTML, URL, JavaScript)
- Internationalization and localization (PHP, JavaScript, language, time zone, calendar, number formats and units, string collation), string translation (gettext, pseudo English)
- Content management: large pieces of markup, reusable content blocks
- Templating
- Authentication (Web Authentication API, client certificate, 2FA, password security, lock session to IP address, stronger authentication for admins)
- Ability of matching an event (uncaught exception) to a user ID or session
- User roles and capabilities
- Email addresses, composing and sending (maximum length, obfuscate email addresses, hidden field in form, mailcheck.js, plain text version, NeverBounce)
- Document generation (CSV, PDF, Excel, image)
- Image management (Cloudinary, https://blurha.sh/ )
- Maintenance mode switch and placeholder page (HTTP/503)
- Static asset management (building, versioning) and loading
- Search experience
- Keep A Changelog
- Analytics, visitor tracking (HEAP, Hotjar, Smartlook, Clicktale)
- Performance (application monitoring, New Relic)
- Error tracking: JavaScript, PHP, queue, cron (no overlapping)
- Document everything in
hosting.yml - Declare PHP version, extensions, directives, functions and test them in php-env-check, run in composer.json:pre-install-cmd, PHP version and extensions also in composer.json:require
- Have an update policy for PHP, framework, packages
- Set environment variables (PHP-FPM pool,
.env) - Publish Dockerfile of CI (GitLab Container Registry, Docker Hub)
- Build and deploy script (file permissions)
- Cron jobs and queues (check periodically, email sending and time consuming tasks,
catch SIGTERM on system shutdown
pcntl_signal(SIGTERM, 'signal_handler');) - Generate sitemaps
- File change notification:
siteprotection.sh - Manage and monitor application/config/route/view cache and sessions
- Run
git statushourly - Report application log extract hourly (recipients)
- Rotate application log
- Move per-directory webserver configuration to vhost configuration
- Redirect removed routes, substitute missing images (URL-s)
- Use queuing MTA for fast email delivery (external SMTP is slow), bounce handling
- Include firewall/Fail2ban triggers at least for: 404-s, failed login attempts, hidden form fields (WAF)
- Host a honey pot
- Register to webmaster tools (Google, Bing, Yandex)
- Match production/staging/development/local environments (Docker, php-env-check)
- Environment examples: development, staging, beta, demo
- Different domain name (SLD)
- Disallowing robots.txt
- Different Apache configuration
- Different PHP extensions and directives (
opcache.validate_timestamps) - Alternative email delivery
- Modified application configuration (environment name, debug logging)
- Change crypto salts, regenerate password hashes
- Disable/use another CDN
- Disable/switch to sandbox mode in 3rd party integrations (analytics, chat, performance monitoring, payment gateway)
- Disable automatic updates
- Stop cron jobs
- Visually distinguish non-production sites
- Change favicon to an animated GIF image
- Tag page title
<title>[STAGING] $page_title</title> - Add a flashy line
#MainMavigation { border-top: 3px dashed magenta; } - Surround/invert the company logo
#BrandLogo { outline: 3px dotted magenta; } - Change background color of WordPress admin bar
- Logo and title
- Language selector
- News or marketing message
- "Remember me" checkbox
- "Forgot password" link
- Login and Sign up page linking each other
- Direct registration on login page: email field and signup button
- SSO
- Privacy Policy and Terms of Service links
- Support email and chat/open ticket
- Marketing message on "logged out" pages
- Analyze HTTP headers
- Browser check with JavaScript (proof-of-work)
- Client-side email address check
- Suspicious email address:
- company domain
- blocked domain (e.g. example.com, *.test)
- disposable address
- non-existent domain
- missing MX
- unresolvable MX
- Blocked usernames
- Force strong passwords:
- previously used
- on most common passwords list
- similarity to name, username or other user details
- length
- complexity
- xkcd password strength
- pwned password
- Provide 2FA (TOTP, SMS, email), encourage users to use KeePass
- Use Argon2 hashing
password_hash($pwd, PASSWORD_ARGON2I) - Wipe the plaintext password from memory
- Login security: lock sessions to, and allow login from
- 1 IP address (IPv4, IPv6)
- In an IP range (e.g. a /24 network)
- Within 1 AS (autonomous system) thus inside an ISP
- Within multiple AS-es (mobile roaming)
- Within a country
- Within a region/timezone (multiple countries)
- Within a continent
- Same user agent strings
- Same device (user agent strings) with upgrades (device, OS, browser)
- Allow/deny multiple (how many?) sessions
- Session timeout
- Authorize IP address procedure
- Login notification
- New device notification
- Login logging or last successful login logging
- Inactive accounts
- Authentication as a Service
- Authentication system
- If you choose an identity provider search the web for its name plus "breach" "exploit" "security"
formanalyze HTTP requestformhidden field in forminputmaximum lengthinputmailcheck.jsinputSuspicious email addressinputNeverBounceoutputobfuscate email addressesdeliveryprevent automatic responsesdeliverydetect bounce -> take action (stop sending, notify user or user's team)
List: https://www.g2.com/categories/help-desk
Multilingual support.
- Password reminder
- Ask for a new password
- Get help (see Logged in section)
- Suggest a password manager (avoid saving passwords to browser)
- Short video about password and cybersecurity
- Signing in on an old login page (reopened by the browser) with expired cookies
- Login to a specific page (inside the application) through the login page
- Custom messages on each failed login attempt, automatic redirect to password reminder page
- Open ticket
- Start online chat
- Search knowledge base (help articles)
- Take a screenshot
- Send attachments
- General feedback, bug reporting
- Record sessions
Have me on board: viktor@szepe.net
These lists are theory-free! All of them were real-life problems.