SlideShare a Scribd company logo
@asgrim
Please clone & composer install:
https://github.com/asgrim/quality-tutorial
WiFi: php2019 / php2019
Best practices for crafting high quality PHP apps
@asgrim
Best practices for crafting high
quality PHP apps
James Titcumb
php[world] 2019
Please clone & composer install:
https://github.com/asgrim/quality-tutorial
WiFi: php2019 / php2019
$ whoami
James Titcumb
www.jamestitcumb.com
www.roave.com
@asgrim
Please clone & composer install:
https://github.com/asgrim/quality-tutorial
WiFi: php2019 / php2019
@asgrim
Please clone & composer install:
https://github.com/asgrim/quality-tutorial
WiFi: php2019 / php2019
@asgrim
What is “quality”?
@asgrim
photo: Rob Allen https://flic.kr/p/qmGpsq
@asgrim
@asgrim
@asgrim
Quality.
@asgrim
"The best code is no code at all”
-- Jeff Atwood
source: https://blog.codinghorror.com/the-best-code-is-no-code-at-all/
@asgrim
Trade-offs.
@asgrim
Prototyping & short-lived apps/sites
@asgrim
Products
Long-lived projects. Open source software.
@asgrim
What is quality in applications?
@asgrim
What about time/cost…?
@asgrim
“A freelancer at $25 an hour for 100 hours still
costs more than a freelancer at $150 an hour that
takes 10 hours to do the same task”
-- Brandon Savage
source: http://www.brandonsavage.net/earning-more-money-as-a-php-freelancer/
@asgrim
Get an expert in.
@asgrim
Complexity
@asgrim
Processes
@asgrim
This talk...
● Planning
● Development
● Testing
● Continuous integration
● Code reviews
● Deployments
@asgrim
Planning
@asgrim
Planning is communication
@asgrim
Use business terminology
@asgrim
Explore and discover
@asgrim
Build a model of the business
@asgrim
@asgrim
Event Storming
Practical Exercise
@asgrim
Event Storming - Practical Exercise
● Booking a hotel room
● Customer must select dates
● Rooms must be paid for when booking
● Stripe is the chosen payment provider
● Payment must only be taken once room is reserved
● Room availability is checked & reserved via 3rd party API
● All rooms & dates cost the same (e.g. $100 per night)
● Notify the customer (e.g. email) on a successful reservation
● Customer can cancel a booking
● On cancellation, full refund if more than 48 hours before the stay
@asgrim
@asgrim
The model must be fluid.
@asgrim
Feature Planning
Practical Exercise
@asgrim
Feature Planning
Feature: Booking a room for a hotel
Scenario: Making a successful booking
Given ...
When ...
Then ...
Scenario: Cancelling an existing booking
Given ...
When ...
Then ...
Scenario: If a room is booked by the time payment is made,
do not charge the card or reserve the room
Given ...
When ...
Then ...
@asgrim
“Estimates”
@asgrim
Development
@asgrim
Care about code
@asgrim
“There are only two hard things in Computer
Science: cache invalidation and naming things.”
-- Phil Karlton
source: https://martinfowler.com/bliki/TwoHardThings.html
@asgrim
SimpleBeanFactoryAwareAspectInstanceFactory
@asgrim
Loader
@asgrim
Describe intent
@asgrim
“Give awkward names to awkward concepts”
-- Eric Evans
source: https://skillsmatter.com/conferences/8231-ddd-exchange-2017
@asgrim
SOLID
@asgrim
SOLID Violation Example
interface Thing {
public function doStuff() : void;
}
final class ImplementationOfThing implements Thing {
public function doStuff() : void { ... }
public function moreStuff() : void;
}
class ConsumerOfThing {
/** @var Thing */
private $thing;
public function woo() {
$this->thing->moreStuff();
}
}
@asgrim
KISS
@asgrim
Object Calisthenics - Practical
● One level of indentation in a method
● Avoid “else” keyword
● Wrap primitive types (e.g. strings, int)
● First class collections (instead of Thing[])
● One object operator (Law of Demeter)
● Avoid abbreviations (naming!)
● Keep classes small
● Avoid more than 2 instance variables
● No getters/setters
@asgrim
Avoid early abstraction
@asgrim
“Code for your use-case,
not for your re-use-case”
-- Marco Pivetta
source: https://ocramius.github.io/extremely-defensive-php/#/39
@asgrim
Care about your API
@asgrim
A public method is like a child:
once you've written it,
you are going to maintain it
for the rest of its life!
-- Stefan Priebsch
@asgrim
Strict type declarations.
Use declare(strict_types=1); by default
@asgrim
Immutable value objects
declare(strict_types=1);
use AssertAssertion; // beberlei/assert library !
final class PostalCode
{
private const VALIDATION_EXPRESSION = '(GIR 0AA)|((([A-Z-[QVX]][0-9][0-...
/** @var string */
private $value;
public function __construct(string $value) {
$this->assertValidPostalCode($value);
$this->value = $value;
}
private function assertValidPostalCode(string $value) : string {
Assertion::regex($value, self::VALIDATION_EXPRESSION);
}
public function __toString() : string {
return $this->value;
}
}
@asgrim
Value objects are valid!
declare(strict_types=1);
final class Thing {
public function assignPostalCode(PostalCode $postalCode) : void
{
// ... we can trust $postalCode is a valid postal code
}
}
// 12345 is not valid - EXCEPTION!
$myThing->assignPostalCode(new PostalCode('12345'));
// assignPostalCode is happy
$myThing->assignPostalCode(new PostalCode('PO1 1AA'));
// With STRICT types, this will also FAIL
$myThing->assignPostalCode(new PostalCode(12345));
@asgrim
Types & Value Objects
Practical
@asgrim
Static Analysis with phpstan / Psalm
Practical
@asgrim
Implement a Domain
Practical
@asgrim
Testing
@asgrim
Testing is NOT a separate line item
@asgrim
Testing should be an assumption
@asgrim
You’re already testing.
@asgrim
Still need convincing?
@asgrim
How?
@asgrim
Reduce complexity
@asgrim
Reduce complexity
public function process(Stuff a, string b, int c) : MoreStuff
{
// lots of complicated code
// lots of complicated code
// lots of complicated code
// lots of complicated code
// lots of complicated code
// lots of complicated code
// lots of complicated code
// lots of complicated code
// lots of complicated code
// lots of complicated code
// lots of complicated code
// lots of complicated code
// lots of complicated code
// lots of complicated code
@asgrim
Reduce complexity
public function meaningfulThing(Stuff a, string b, int c) : More
{
// call nicer, meaningful methods below
}
private function throwStuffIntoFire(Stuff a) : Fire
{
// smaller, meaningful chunk of code
}
private function combineStringWithFire(Fire a, string b) : string
{
// simple, lovely code!
}
private function postFlowersToSpain(int c) : void
@asgrim
More complexity = more tests
@asgrim
Testing Legacy Code
Yes it’s possible… but harder
@asgrim
Test coverage
@asgrim
Line coverage
<?php
function foo(bool $a, bool $b) {
if ($a) {
echo "A";
}
if ($b) {
echo "B";
}
}
// generate coverage using calls:
foo(true, false);
foo(false, true);
@asgrim
Line coverage
<?php
function foo(bool $a, bool $b) {
if ($a) {
echo "A";
}
if ($b) {
echo "B";
}
}
// generate coverage using calls:
foo(true, false);
foo(false, true);
@asgrim
Branch coverage
<?php
function foo(bool $a, bool $b) {
if ($a) {
echo "A";
}
if ($b) {
echo "B";
}
}
// generate coverage using calls:
foo(true, false);
foo(false, true);
@asgrim
Branch coverage
<?php
function foo(bool $a, bool $b) {
if ($a) {
echo "A";
}
if ($b) {
echo "B";
}
}
// generate coverage using calls:
foo(true, false);
foo(false, true);
@asgrim
Branch coverage
<?php
function foo(bool $a, bool $b) {
if ($a) {
echo "A";
}
if ($b) {
echo "B";
}
}
// generate coverage using calls:
foo(true, false);
foo(false, true);
foo(false, false); // NEW TEST!!!
@asgrim
Branch coverage
<?php
function foo(bool $a, bool $b) {
if ($a) {
echo "A";
}
if ($b) {
echo "B";
}
}
// generate coverage using calls:
foo(true, false);
foo(false, true);
foo(false, false); // NEW TEST!!!
foo(true, true); // NEW TEST!!!
@asgrim
Branch vs Line Coverage
@asgrim
Prevent coverage leaking
@asgrim
Prevent coverage leaking
<?php
namespace Foo;
/**
* @covers FooBar
*/
final class BarTest extends TestCase
{
// write some tests!
}
@asgrim
Prevent coverage leaking
@asgrim
Are the tests testing?
@asgrim
Example of a test not testing…
public function testPurchaseTickets()
{
$event = Event::create(uniq('event', true)
$customer = Customer::create(uniq('name', true));
$shop->purchaseTicket(1, $event, [$customer]);
}
@asgrim
@asgrim
Assert you’re asserting
public function testPurchaseTickets()
{
$event = Event::create(uniq('event', true)
$customer = Customer::create(uniq('name', true));
$receipt = $shop->purchaseTicket(1, $event, [$customer]);
self::assertSame($event, $receipt->event());
$customersInReceipt = $receipt->customers();
self::assertCount(1, $customersInReceipt);
self::assertContains($customer, $customersInReceipt);
}
@asgrim
@asgrim
Test the tests are testing!
@asgrim
Infection PHP
@asgrim
Mutation testing
function add(int $a, int $b) : int {
return $a + $b;
}
function testAdd() {
$result = add(2, 3);
// self::assertSame(5, $result);
}
@asgrim
Mutation testing
function add(int $a, int $b) : int {
return $a - $b;
}
function testAdd() {
$result = add(2, 3);
// self::assertSame(5, $result);
}
@asgrim
Mutation testing
function add(int $a, int $b) : int {
return $a - $b;
}
function testAdd() {
$result = add(2, 3);
self::assertSame(5, $result);
// /// test will now fail with mutation
}
@asgrim
What about other tests?
@asgrim
Integration tests
@asgrim
Behaviour tests
@asgrim
BAD! Do not do this.
Feature: Ability to print my boarding pass
Scenario: A checked in passenger can print their boarding pass
Given I have a flight booked
And I have checked in
When I visit the home page
And I click the ".manage-booking" button
And I enter "CJM23L" in the ".bref-ipt-fld" field
And I click the "Find Booking" button
Then I should see the ".booking-ref.print" button
When I click the ".booking-ref.print" button
Then I should see the print dialogue
@asgrim
Better Behaviour test
Feature: Ability to print my boarding pass
Policies:
- Boarding passes are only available when already checked in
- If customer cannot print boarding pass, they can collect at
The airport
- more business rules etc...
Scenario: A checked in passenger can print their boarding pass
Given I have a flight booked for LHR-MIA on 24th May
And I have previously checked in for the flight
When I display my booking reference "CJM23L"
Then I should be able to print my boarding pass
And the boarding pass should display flight details correctly
@asgrim
Why is this important?
@asgrim
Automate these tests
@asgrim
Automated tests
Application (and UI, API, etc.)
Domain / Business Logic
Infrastructure (DBAL, APIs, etc.)
@asgrim
Automated tests
Application (and UI, API, etc.)
Domain / Business Logic
Infrastructure (DBAL, APIs, etc.)
@asgrim
Testing at domain layer
Application (UI, API, etc.)
Domain / Business Logic
Infrastructure (DB, APIs, etc.)
// Testing via the UI
public function iDisplayMyBookingReference(string $reference)
{
$page = $this->getSession()->getPage();
$page->click(".manage-booking");
$page->findField(".bref-ipt-fld")->setValue($reference);
$page->click("Find Booking");
}
// Using the domain layer directly in tests
public function iDisplayMyBookingReference(string $reference)
{
$this->booking = $this->retrieveBooking($reference);
}
@asgrim
Some UI testing is okay!!!
Feature: Ability to print my boarding pass
Policies:
- Boarding passes are only available when already checked in
- If customer cannot print boarding pass, they can collect at
The airport
- more business rules etc...
@ui
Scenario: A checked in passenger can print their boarding pass
Given I have a flight booked for LHR-OTP on 24th May
And I have previously checked in for the flight
When I display my booking reference "CJM23L"
Then I should be able to print my boarding pass
And the boarding pass should display flight details correctly
@asgrim
Automate all the things!
@asgrim
Continuous Integration
@asgrim
Tests cost money to run
(manually)
@asgrim
Travis-CI.com
@asgrim
Jenkins
@asgrim
What to automate?
@asgrim
The goal?
@asgrim
Code reviews
@asgrim
What to look for in code review?
@asgrim
What to look for in code review?
Code style.
@asgrim
What to look for in code review?
Small, atomic changes.
@asgrim
What to look for in code review?
Composer versions.
@asgrim
What to look for in code review?
Structure & good practices.
@asgrim
What to look for in code review?
Tests.
@asgrim
What to look for in code review?
Documentation.
@asgrim
What to look for in code review?
Security.
@asgrim
What to look for in code review?
Insight.
@asgrim
It takes practice.
Some ideas:
https://asgrim.github.io/code-review-checklist/
@asgrim
Deployments
@asgrim
Automate deployments!
@asgrim
One-click deployments
@asgrim
Easy Deployment Example
Using Heroku (not sponsored)
@asgrim
“Move fast and break things”
-- a stupid Facebook mantra
@asgrim
“Move fast and break things with stable infra”
-- Facebook mantra since 2014
@asgrim
Continuous Delivery & Deployment
@asgrim
Better quality
@asgrim
Better quality = Higher confidence
@asgrim
Better quality = Higher confidence = Happy customers
Any questions?
https://joind.in/talk/f74a3
James Titcumb
@asgrim
@asgrim
Resources
● Event Storming - Alberto Brandolini
○ http://ziobrando.blogspot.co.uk/2013/11/introducing-event-storming.html
● “Good Design is Imperfect Design” - Eric Evans
○ https://skillsmatter.com/skillscasts/9171-good-design-is-imperfect-design
● “Writing code that lasts” - Rafael Dohms
○ https://www.youtube.com/watch?v=I0y5jU61pS4
● Object Calisthenics - William Durand
○ https://williamdurand.fr/2013/06/03/object-calisthenics/
● “Driving Design through Examples” - Ciaran McNulty
○ https://www.youtube.com/watch?v=83GbyDpJDI4
● Code Review Checklist
○ https://asgrim.github.io/code-review-checklist/

More Related Content

PDF
Best practices for crafting high quality PHP apps (Bulgaria 2019)
PDF
Best practices for crafting high quality PHP apps (ScotlandPHP 2018)
PDF
Best practices for crafting high quality PHP apps - PHP UK 2019
PDF
Best practices for crafting high quality PHP apps (PHP South Africa 2018)
PDF
Crafting Quality PHP Applications (PHP Benelux 2018)
PDF
Crafting Quality PHP Applications (PHPkonf 2018)
PDF
Best practices for crafting high quality PHP apps (PHP Yorkshire 2018)
PDF
Crafting Quality PHP Applications (PHP Joburg Oct 2019)
Best practices for crafting high quality PHP apps (Bulgaria 2019)
Best practices for crafting high quality PHP apps (ScotlandPHP 2018)
Best practices for crafting high quality PHP apps - PHP UK 2019
Best practices for crafting high quality PHP apps (PHP South Africa 2018)
Crafting Quality PHP Applications (PHP Benelux 2018)
Crafting Quality PHP Applications (PHPkonf 2018)
Best practices for crafting high quality PHP apps (PHP Yorkshire 2018)
Crafting Quality PHP Applications (PHP Joburg Oct 2019)

What's hot (20)

PDF
Crafting Quality PHP Applications (Bucharest Tech Week 2017)
PDF
Crafting Quality PHP Applications (ConFoo YVR 2017)
PDF
Crafting Quality PHP Applications: an overview (PHPSW March 2018)
PDF
Kicking off with Zend Expressive and Doctrine ORM (ConFoo YVR 2017)
PDF
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
PDF
"Managing API Complexity". Matthew Flaming, Temboo
ODP
Step objects
PDF
Testing web APIs
PPTX
Testing ASP.net Web Applications using Ruby
PPT
JavaScript Needn't Hurt!
ODP
Non Conventional Android Programming En
PDF
Beyond MVC: from Model to Domain
ZIP
Solving Problems with YUI3: AutoComplete
PDF
Twig: Friendly Curly Braces Invade Your Templates!
KEY
Aprendendo solid com exemplos
PDF
Unfiltered Unveiled
PDF
TDD with PhpSpec - Lone Star PHP 2016
ODP
Um2010
PDF
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
ODP
Modern Web Development with Perl
Crafting Quality PHP Applications (Bucharest Tech Week 2017)
Crafting Quality PHP Applications (ConFoo YVR 2017)
Crafting Quality PHP Applications: an overview (PHPSW March 2018)
Kicking off with Zend Expressive and Doctrine ORM (ConFoo YVR 2017)
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
"Managing API Complexity". Matthew Flaming, Temboo
Step objects
Testing web APIs
Testing ASP.net Web Applications using Ruby
JavaScript Needn't Hurt!
Non Conventional Android Programming En
Beyond MVC: from Model to Domain
Solving Problems with YUI3: AutoComplete
Twig: Friendly Curly Braces Invade Your Templates!
Aprendendo solid com exemplos
Unfiltered Unveiled
TDD with PhpSpec - Lone Star PHP 2016
Um2010
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
Modern Web Development with Perl
Ad

Similar to Best practices for crafting high quality PHP apps (php[world] 2019) (20)

PDF
Great Developers Steal
PDF
Bringing modern PHP development to IBM i (ZendCon 2016)
PDF
Rack Middleware
PDF
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
PPT
Demystifying Maven
PDF
Diving into HHVM Extensions (php[tek] 2016)
PPT
Effecient javascript
PPT
Swift: Apple's New Programming Language for iOS and OS X
PDF
Apidays Paris 2023 - Forget TypeScript, Choose Rust to build Robust, Fast and...
PDF
How to improve the quality of your TYPO3 extensions
PDF
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
ODP
Non Conventional Android Programming (English)
PDF
InspiringCon15: Bringing TYPO3 Legacy Applications into the Flow
PDF
Static types on javascript?! Type checking approaches to ensure healthy appli...
KEY
PDF
Lightweight Webservices with Sinatra and RestClient
KEY
Socket applications
PDF
Bologna Developer Zone - About Kotlin
PPTX
Do I need tests when I have the compiler - Andrzej Jóźwiak - TomTom Dev Day 2020
PDF
James Thomas - Serverless Machine Learning With TensorFlow - Codemotion Berli...
Great Developers Steal
Bringing modern PHP development to IBM i (ZendCon 2016)
Rack Middleware
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Demystifying Maven
Diving into HHVM Extensions (php[tek] 2016)
Effecient javascript
Swift: Apple's New Programming Language for iOS and OS X
Apidays Paris 2023 - Forget TypeScript, Choose Rust to build Robust, Fast and...
How to improve the quality of your TYPO3 extensions
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
Non Conventional Android Programming (English)
InspiringCon15: Bringing TYPO3 Legacy Applications into the Flow
Static types on javascript?! Type checking approaches to ensure healthy appli...
Lightweight Webservices with Sinatra and RestClient
Socket applications
Bologna Developer Zone - About Kotlin
Do I need tests when I have the compiler - Andrzej Jóźwiak - TomTom Dev Day 2020
James Thomas - Serverless Machine Learning With TensorFlow - Codemotion Berli...
Ad

More from James Titcumb (18)

PDF
Living the Best Life on a Legacy Project (phpday 2022).pdf
PDF
Tips for Tackling a Legacy Codebase (ScotlandPHP 2021)
PDF
Climbing the Abstract Syntax Tree (Midwest PHP 2020)
PDF
Climbing the Abstract Syntax Tree (php[world] 2019)
PDF
Climbing the Abstract Syntax Tree (PHP Russia 2019)
PDF
Climbing the Abstract Syntax Tree (ScotlandPHP 2018)
PDF
Kicking off with Zend Expressive and Doctrine ORM (PHP South Africa 2018)
PDF
Climbing the Abstract Syntax Tree (PHP Developer Days Dresden 2018)
PDF
Climbing the Abstract Syntax Tree (Southeast PHP 2018)
PDF
Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)
PDF
Climbing the Abstract Syntax Tree (PHP UK 2018)
PDF
Climbing the Abstract Syntax Tree (Forum PHP 2017)
PDF
Dip Your Toes in the Sea of Security (IPC Fall 2017)
PDF
Climbing the Abstract Syntax Tree (IPC Fall 2017)
PDF
Dip Your Toes in the Sea of Security (PHP South Africa 2017)
PDF
Climbing the Abstract Syntax Tree (PHP South Africa 2017)
PDF
Get Started with RabbitMQ (CoderCruise 2017)
PDF
Dip Your Toes in the Sea of Security (CoderCruise 2017)
Living the Best Life on a Legacy Project (phpday 2022).pdf
Tips for Tackling a Legacy Codebase (ScotlandPHP 2021)
Climbing the Abstract Syntax Tree (Midwest PHP 2020)
Climbing the Abstract Syntax Tree (php[world] 2019)
Climbing the Abstract Syntax Tree (PHP Russia 2019)
Climbing the Abstract Syntax Tree (ScotlandPHP 2018)
Kicking off with Zend Expressive and Doctrine ORM (PHP South Africa 2018)
Climbing the Abstract Syntax Tree (PHP Developer Days Dresden 2018)
Climbing the Abstract Syntax Tree (Southeast PHP 2018)
Kicking off with Zend Expressive and Doctrine ORM (PHP MiNDS March 2018)
Climbing the Abstract Syntax Tree (PHP UK 2018)
Climbing the Abstract Syntax Tree (Forum PHP 2017)
Dip Your Toes in the Sea of Security (IPC Fall 2017)
Climbing the Abstract Syntax Tree (IPC Fall 2017)
Dip Your Toes in the Sea of Security (PHP South Africa 2017)
Climbing the Abstract Syntax Tree (PHP South Africa 2017)
Get Started with RabbitMQ (CoderCruise 2017)
Dip Your Toes in the Sea of Security (CoderCruise 2017)

Recently uploaded (20)

PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
cuic standard and advanced reporting.pdf
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
Cloud computing and distributed systems.
PPTX
A Presentation on Artificial Intelligence
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Machine learning based COVID-19 study performance prediction
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
Per capita expenditure prediction using model stacking based on satellite ima...
The Rise and Fall of 3GPP – Time for a Sabbatical?
cuic standard and advanced reporting.pdf
Building Integrated photovoltaic BIPV_UPV.pdf
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Mobile App Security Testing_ A Comprehensive Guide.pdf
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
Reach Out and Touch Someone: Haptics and Empathic Computing
MYSQL Presentation for SQL database connectivity
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Cloud computing and distributed systems.
A Presentation on Artificial Intelligence
Understanding_Digital_Forensics_Presentation.pptx
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Machine learning based COVID-19 study performance prediction
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Review of recent advances in non-invasive hemoglobin estimation
Digital-Transformation-Roadmap-for-Companies.pptx

Best practices for crafting high quality PHP apps (php[world] 2019)