Κυριακή 27 Σεπτεμβρίου 2020

Lighthouse Angular performance improvement hints






Improve the performance of our Angular frontend app, using Lighthouse plugin of Chrome's DevTools:

















SERVE STATIC ASSETS WITH EFFICIENT CACHE POLICY



HTTP Caching
- Edit HTTP response's cache-control / max-age to a bigger number
- Verify in Inspect/Network tab, that images are cached (from memory cache)
See https://web.dev/uses-long-cache-ttl/


Angular-level caching
- Create an ImageService that:
- Stores images' blobs in array of url/blob objects
- Retrieves images from this array, if already stored there


Method-level caching with ngx-cacheable
- Use cacheable decorator to:
- Retrieve objects from cache (@Cacheable)
- Update cache when saving/updating function runs (@CacheBuster)







MINIMIZE MAIN THREAD WORK (SCRIPT EVALUATION)


Optimize third-party JavaScript



     Check all "Show 3rd-party resources" points, and see if they are time-consuming.
     Consider refactoring these 3rd parties' packages



Debounce your input handlers

 - Using input handlers / animations can slow your app's responses
 - In order to diagnose this, 
    - Run Performance test in Performance tab (or click View Trace in Lighthouse tab)
    - Search for "Recalculate Style" or "Forced Reflow" signs, like below:







Use web workers


 - Relief main thread's work, with web workers
 - Using these, some chosen actions/methods will execute on another thread.
 - First, we pass data from DOM/main thread to Worker thread (worker.postMessage(data))
 - Then, worker does the heavy job
 - Finally, worker passes data from worker's thread to DOM/main thread(postMessage(data))













MINIMIZE MAIN BUNDLE SIZE


Remove imports of large CSS files (e.g. styles.scss) in SCSS/CSS files of all components.
Refactor former ones to smaller files, and then import in each component.











IMPROVE IMAGES/MEDIA FETCHING


Avoid multiple calls for media assets for every component or request.
Have a centralized service for this task.










Κυριακή 13 Σεπτεμβρίου 2020

Spring - Validate REST layer (Java Bean Validation API 2.0 - JSR-380)






Validate a list of DTOs when reaching our endpoint

















1. Dependencies - pom.xml


<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>

or

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> <version>2.2.6.RELEASE</version> </dependency>


(By default, Spring uses hibernate-validator, which implements the JSR-380)


2. Controller class - REST level


// Enables validation in method level @Validated @RestController @RequestMapping("/api/project") public class DayActivityResource { // Our list object cannot be null // List elements are validated each, using @Valid @PostMapping("/day-activities") public ResponseEntity<List<DayActivityDTO>> createDayActivities(@NotNull @RequestBody List<@Valid DayActivityDTO> dayActivityDtos) { // ... } }



3. DTO classes with constraint annotations



import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; import javax.validation.constraints.Valid; public class DayActivityDTO implements Serializable { private String id; private String activityId; private String activityTypeId; // We want this String to be numeric @Pattern(message = "amountFactor must be a number", regexp="^[0-9]*$") @Size(min=1, max=7) private String generalFactor; // A log date must always exist @NotNull private LocalDate logDate; // Validate nested object @Valid private DayActivityRecurringInfo recurringInfo; @Email(message = "Please enter a valid email") private String sendUpdateToEmail; } // Nested class public class DayActivityRecurringInfo { @Min(1) private Integer recurEveryDays; @Max(4) private Integer recurForWeeks; }