Performance is an integral part of the Application design and plays a vital role in the success of your product/application. This is Part-2 of my performance optimization articles series. Performance optimization considerations as part of various stages are discussed in Part-1.
Before delving into performance optimization techniques, let us discuss the factors that impact the performance of an application. below are the most critical factors that impact the performance from my view.
Factors that impact the performance of the application
- Stuffing home/start page with lots of functionality
- Making a huge number of API calls/ Loading large JS bundles as part of the initial load of the applications
- Using large size images without any image optimization/compression
- Preloading all the data in the browser instead of considering user preferences/user actions
- Not adopting CDN to deliver the content to the global audience (at least static content/files)
- Invalid network/tool configurations
- Using the same website/ APIs for Mobile and Desktop
Performance Optimization techniques
This section gives you an overview of the various techniques that can be employed at various levels of your application. At a global level, below are few areas
- User Interface
Below are the few of core best practices to consider as part of the user interface design and development
User Interface design best practices
- Consider server-side rendering for your home/landing page if it stuffed with too much functionality
- Load data on demand always
- Enabling paging when dealing with large datasets
- Always keep your JS files bottom of your page
- Use bundling and minification tools as part of your build process
- Tools: Webpack, Gulp, grunt, browserify etc.
- Avoid using inefficient looping logic on client-side
- Using async and defer while loading the JS files into the browse
- use preload and prefetch
- use DNS-Prefetch
- Ensure you have enabled caching on your JS files (Every application comes with hashing the JS files.Ensure you are enabling them)
- Remove unused packages or be attentive towards the size of the installed package
- Tools: Amazon CloudFront, KeyCDN, Akamai, etc.
- Use compression tools to optimize the file sizes over the network
- Tools: gzip
CSS best practices
- Use preloading of CSS
- Use CSS sprites
- Avoid @import to include external stylesheets
Images best practices
- define images based on the device
- Avoid using large size images as part of the application (define max size and apply across the app)
- Optimize your images without losing the quality (At Least a stage human eye can’t catch the difference)
Caching can drastically improve the performance of the application if configured optimally. By employing caching, you can reduce the GET queries on the databases and reduce the network calls.
- Object Caching
Object caching is used to store the processed data into a cache-store. The cached data will get served for the incoming requests.
Providers: Memcached, Redis cache, Ignite, EhCache, etc. These cache providers are available as part of the cloud provider as well.
Below diagram depicts the high level flow involved in Object caching
- HTTP Caching
By using Http cache headers we can cache the data in the browser. When the HTTP cache is enabled for a specific endpoint for 30 minutes, the browser will not make the request to the endpoint by storing the data in the cache itself.
By defining the below-mentioned HTTP directives, you can enable the HTTP caching.
- Cache Control: contains one or more comma-separated directives. These directives determine whether a response is cacheable and if so, by whom, and for how long e.g. max-age or s-max-age directives.
- Expires: specifies an absolute expiry time for a cached representation
- ETag: an opaque string token that a server associates with a resource to uniquely identify the state of the resource over its lifetime. When the resource changes, the ETag changes accordingly.
- Last-Modified: indicates when the response was generated, the Last-Modified header indicates when the associated resource last changed.
ORM has become an integral part of application development. ORMs allow you to encapsulate all your logic in your business layer instead of burying in a database.
- Avoid N+1 problem by adopting projection queries
- Load child tables only when required (consider lazy loading while writing the queries)
- Avoid writing complex queries using ORM framework ( I personally choose named queries or native queries to avoid performance bottlenecks of ORM queries)
API CDN Providers
You can use the CDNs to provide optimal performance for your APIs across various geographical regions.
Providers: Fastly (https://docs.fastly.com/en/guides/enabling-api-caching), Amazon Cloudfront, Key CDN, etc.
Relational databases are difficult to scale when compared to NO-SQL. Consider exploring on NO-SQL databases when evaluating databases for your application.
Below are the few of the techniques helpful while tuning the relational database
- Created Optimized indexes
- Determine the expected growth and design your database
- Select fields instead of using ‘SELECT *’
- Foreign keys can impact performance negatively. Please move your foreign key validation to the business layer if possible
- Explore possibilities to use
- Run your scheduled jobs in non-business hours
- Explore on the possibility of using read-only databases for GET queries and master database for data modifications (Majority of Cloud providers support instant replication of data)
- Tools: ProxySQL (https://proxysql.com/)
- Indexes can negatively impact data modification operations. Ensure indexes are disabled when loading the huge amounts of data
- Avoid distinct clause if possible
- Always select limited data
- One schema may not be suitable for all the requirements. If you have a reporting system, consider having a reporting database
- Configure notifications when a query is executing on the server beyond defined threshold times.
Network configuration is one other key area where performance of an application depends on. We have mentioned a few of the practices as part of the Network considerations. These are just starting points and can be extended further.
- DevOps / DevSecOps team should work collaboratively work with development team instead of working in their own terms
- Configure network monitoring tools to identify when there is a sudden surge of requests
- Enable notifications for your network failures and warnings
- Ensure Autoscaling groups are configured and battle-tested before enabling them in production
- Configure HTTP2 protocol for faster retrievals
- Ensure your applications are tested from various geographical regions
- Tools: https://geopeeker.com/