Dec 10, 2025
php
Laravel remains one of the most popular PHP frameworks. Here are modern development practices for building scalable Laravel applications.
1. Project Structure Recommended Structure app/ ├── Http/ │ ├── Controllers/ │ ├── Middleware/ │ ├── Requests/ │ └── Resources/ ├── Models/ ├── Services/ ├── Repositories/ ├── Events/ ├── Listeners/ └── Jobs/ 2. Eloquent Best Practices Model Relationships // User Model class User extends Model { public function posts() { return $this->hasMany(Post::class); } public function profile() { return $this->hasOne(Profile::class); } public function roles() { return $this->belongsToMany(Role::class); } } Eager Loading // Bad: N+1 problem $users = User::all(); foreach ($users as $user) { echo $user->posts->count(); // Query for each user } // Good: Eager loading $users = User::with('posts')->get(); foreach ($users as $user) { echo $user->posts->count(); // No additional queries } Query Scopes class Post extends Model { public function scopePublished($query) { return $query->where('status', 'published'); } public function scopeRecent($query) { return $query->orderBy('created_at', 'desc'); } } // Usage $posts = Post::published()->recent()->get(); 3. Service Layer Pattern Service Class class UserService { protected $userRepository; protected $emailService; public function __construct( UserRepository $userRepository, EmailService $emailService ) { $this->userRepository = $userRepository; $this->emailService = $emailService; } public function createUser(array $data): User { DB::beginTransaction(); try { $user = $this->userRepository->create($data); $this->emailService->sendWelcomeEmail($user); DB::commit(); return $user; } catch (\Exception $e) { DB::rollBack(); throw $e; } } } 4. Form Requests Validation class CreateUserRequest extends FormRequest { public function rules(): array { return [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'email', 'unique:users,email'], 'password' => ['required', 'string', 'min:8', 'confirmed'], ]; } public function messages(): array { return [ 'email.unique' => 'This email is already registered.', 'password.min' => 'Password must be at least 8 characters.', ]; } } // Controller public function store(CreateUserRequest $request) { $user = $this->userService->createUser($request->validated()); return new UserResource($user); } 5. API Resources Resource Transformation class UserResource extends JsonResource { public function toArray($request): array { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'created_at' => $this->created_at->toIso8601String(), 'posts' => PostResource::collection($this->whenLoaded('posts')), ]; } } 6. Queues and Jobs Job Implementation class SendWelcomeEmail implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public function __construct( public User $user ) {} public function handle(EmailService $emailService): void { $emailService->sendWelcomeEmail($this->user); } public function failed(\Throwable $exception): void { // Handle failure } } // Dispatch SendWelcomeEmail::dispatch($user); 7. Events and Listeners Event System // Event class UserRegistered { public function __construct( public User $user ) {} } // Listener class SendWelcomeEmail { public function handle(UserRegistered $event): void { Mail::to($event->user->email)->send(new WelcomeMail($event->user)); } } // Dispatch event(new UserRegistered($user)); 8. Caching Cache Implementation // Cache user $user = Cache::remember("user.{$id}", 3600, function () use ($id) { return User::find($id); }); // Cache tags Cache::tags(['users', 'posts'])->put("user.{$id}", $user, 3600); // Clear cache Cache::tags(['users'])->flush(); 9. Database Migrations Migration Best Practices Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('email')->unique(); $table->string('name'); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->timestamps(); $table->softDeletes(); $table->index('email'); }); 10. Testing Feature Tests class UserTest extends TestCase { use RefreshDatabase; public function test_can_create_user(): void { $response = $this->postJson('/api/users', [ 'name' => 'John Doe', 'email' => '[email protected]', 'password' => 'password123', 'password_confirmation' => 'password123', ]); $response->assertStatus(201) ->assertJsonStructure([ 'data' => [ 'id', 'name', 'email', ] ]); $this->assertDatabaseHas('users', [ 'email' => '[email protected]', ]); } } Best Practices Use Service Layer for business logic Form Requests for validation API Resources for data transformation Queues for long-running tasks Events for decoupled actions Eager Loading to avoid N+1 queries Caching for performance Write Tests for critical paths Conclusion Laravel provides powerful tools for building modern applications. Follow these practices to create maintainable, scalable Laravel applications! 🚀
ReadDec 10, 2025
go
Go’s concurrency model is one of its strongest features. Here’s how to effectively use goroutines, channels, and concurrency patterns.
Goroutines Basic Usage // Simple goroutine go func() { fmt.Println("Running in goroutine") }() // With function go processData(data) WaitGroup import "sync" var wg sync.WaitGroup func main() { for i := 0; i < 10; i++ { wg.Add(1) go func(id int) { defer wg.Done() processItem(id) }(i) } wg.Wait() // Wait for all goroutines } Channels Basic Channel Operations // Unbuffered channel ch := make(chan int) // Send ch <- 42 // Receive value := <-ch // Close close(ch) Buffered Channels // Buffered channel (capacity 10) ch := make(chan int, 10) // Non-blocking send if buffer not full ch <- 1 ch <- 2 Channel Directions // Send-only channel func sendOnly(ch chan<- int) { ch <- 42 } // Receive-only channel func receiveOnly(ch <-chan int) { value := <-ch } // Bidirectional (default) func bidirectional(ch chan int) { ch <- 42 value := <-ch } Common Patterns Worker Pool func workerPool(jobs <-chan int, results chan<- int, numWorkers int) { var wg sync.WaitGroup for i := 0; i < numWorkers; i++ { wg.Add(1) go func() { defer wg.Done() for job := range jobs { result := processJob(job) results <- result } }() } wg.Wait() close(results) } Fan-Out, Fan-In // Fan-out: Distribute work func fanOut(input <-chan int, outputs []chan int) { for value := range input { for _, output := range outputs { output <- value } } for _, output := range outputs { close(output) } } // Fan-in: Combine results func fanIn(inputs []<-chan int) <-chan int { output := make(chan int) var wg sync.WaitGroup for _, input := range inputs { wg.Add(1) go func(ch <-chan int) { defer wg.Done() for value := range ch { output <- value } }(input) } go func() { wg.Wait() close(output) }() return output } Pipeline Pattern func pipeline(input <-chan int) <-chan int { stage1 := make(chan int) stage2 := make(chan int) // Stage 1 go func() { defer close(stage1) for value := range input { stage1 <- value * 2 } }() // Stage 2 go func() { defer close(stage2) for value := range stage1 { stage2 <- value + 1 } }() return stage2 } Context for Cancellation Using Context import "context" func processWithContext(ctx context.Context, data []int) error { for _, item := range data { select { case <-ctx.Done(): return ctx.Err() default: processItem(item) } } return nil } // Usage ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() err := processWithContext(ctx, data) Context with Timeout ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result, err := fetchData(ctx) Select Statement Non-Blocking Operations select { case value := <-ch1: // Handle value from ch1 case value := <-ch2: // Handle value from ch2 case ch3 <- 42: // Successfully sent to ch3 default: // No channel ready } Timeout Pattern select { case result := <-ch: return result case <-time.After(5 * time.Second): return errors.New("timeout") } Mutex and RWMutex Protecting Shared State type SafeCounter struct { mu sync.Mutex value int } func (c *SafeCounter) Increment() { c.mu.Lock() defer c.mu.Unlock() c.value++ } func (c *SafeCounter) Value() int { c.mu.Lock() defer c.mu.Unlock() return c.value } Read-Write Mutex type SafeMap struct { mu sync.RWMutex data map[string]int } func (m *SafeMap) Get(key string) int { m.mu.RLock() defer m.mu.RUnlock() return m.data[key] } func (m *SafeMap) Set(key string, value int) { m.mu.Lock() defer m.mu.Unlock() m.data[key] = value } Best Practices 1. Always Use defer for Cleanup // Good func process() { mu.Lock() defer mu.Unlock() // Process } // Bad func process() { mu.Lock() // Process mu.Unlock() // Might not execute if panic } 2. Avoid Goroutine Leaks // Good: Use context for cancellation func worker(ctx context.Context) { for { select { case <-ctx.Done(): return default: // Work } } } // Bad: Goroutine runs forever func worker() { for { // Work forever } } 3. Close Channels Properly // Good: Close channel when done func producer(ch chan int) { defer close(ch) for i := 0; i < 10; i++ { ch <- i } } Common Pitfalls 1. Race Conditions // Bad: Race condition var counter int func increment() { counter++ // Not thread-safe } // Good: Use mutex var ( counter int mu sync.Mutex ) func increment() { mu.Lock() defer mu.Unlock() counter++ } 2. Closing Closed Channel // Bad: Panic if channel already closed close(ch) close(ch) // Panic! // Good: Check or use sync.Once var once sync.Once once.Do(func() { close(ch) }) Performance Tips 1. Use Buffered Channels // For known capacity ch := make(chan int, 100) 2. Limit Goroutine Count // Use worker pool instead of unlimited goroutines const maxWorkers = 10 semaphore := make(chan struct{}, maxWorkers) 3. Profile Your Code import _ "net/http/pprof" // Add to main go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }() Conclusion Go’s concurrency model provides:
...
ReadDec 10, 2025
java
Spring Boot is the most popular Java framework for building enterprise applications. Here are best practices for building production-ready Spring Boot applications.
1. Project Structure Recommended Structure src/ ├── main/ │ ├── java/ │ │ └── com/example/ │ │ ├── Application.java │ │ ├── config/ │ │ ├── controller/ │ │ ├── service/ │ │ ├── repository/ │ │ ├── model/ │ │ └── dto/ │ └── resources/ │ ├── application.yml │ └── application-prod.yml └── test/ 2. Configuration Management Use YAML for Configuration # application.yml spring: datasource: url: jdbc:postgresql://localhost:5432/mydb username: ${DB_USERNAME} password: ${DB_PASSWORD} jpa: hibernate: ddl-auto: validate show-sql: false properties: hibernate: format_sql: true server: port: 8080 error: include-message: always include-stacktrace: on_param Profile-Based Configuration # application-dev.yml spring: datasource: url: jdbc:h2:mem:testdb jpa: show-sql: true # application-prod.yml spring: datasource: url: ${DATABASE_URL} jpa: show-sql: false 3. Dependency Injection Constructor Injection // Good: Constructor injection @Service public class UserService { private final UserRepository userRepository; private final EmailService emailService; public UserService(UserRepository userRepository, EmailService emailService) { this.userRepository = userRepository; this.emailService = emailService; } } // Bad: Field injection @Service public class UserService { @Autowired private UserRepository userRepository; } 4. Exception Handling Global Exception Handler @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<ErrorResponse> handleNotFound( ResourceNotFoundException ex) { ErrorResponse error = new ErrorResponse( HttpStatus.NOT_FOUND.value(), ex.getMessage() ); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> handleValidation( MethodArgumentNotValidException ex) { Map<String, String> errors = new HashMap<>(); ex.getBindingResult().getFieldErrors().forEach(error -> errors.put(error.getField(), error.getDefaultMessage()) ); ErrorResponse error = new ErrorResponse( HttpStatus.BAD_REQUEST.value(), "Validation failed", errors ); return ResponseEntity.badRequest().body(error); } } 5. REST API Design Controller Best Practices @RestController @RequestMapping("/api/v1/users") @Validated public class UserController { private final UserService userService; @GetMapping public ResponseEntity<List<UserDTO>> getAllUsers( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size) { List<UserDTO> users = userService.getAllUsers(page, size); return ResponseEntity.ok(users); } @GetMapping("/{id}") public ResponseEntity<UserDTO> getUser(@PathVariable Long id) { UserDTO user = userService.getUserById(id); return ResponseEntity.ok(user); } @PostMapping public ResponseEntity<UserDTO> createUser( @Valid @RequestBody CreateUserRequest request) { UserDTO user = userService.createUser(request); return ResponseEntity.status(HttpStatus.CREATED).body(user); } @PutMapping("/{id}") public ResponseEntity<UserDTO> updateUser( @PathVariable Long id, @Valid @RequestBody UpdateUserRequest request) { UserDTO user = userService.updateUser(id, request); return ResponseEntity.ok(user); } @DeleteMapping("/{id}") public ResponseEntity<Void> deleteUser(@PathVariable Long id) { userService.deleteUser(id); return ResponseEntity.noContent().build(); } } 6. Service Layer Service Implementation @Service @Transactional public class UserService { private final UserRepository userRepository; private final UserMapper userMapper; public UserDTO getUserById(Long id) { User user = userRepository.findById(id) .orElseThrow(() -> new ResourceNotFoundException( "User not found with id: " + id)); return userMapper.toDTO(user); } public UserDTO createUser(CreateUserRequest request) { if (userRepository.existsByEmail(request.getEmail())) { throw new DuplicateResourceException( "Email already exists"); } User user = userMapper.toEntity(request); user = userRepository.save(user); return userMapper.toDTO(user); } } 7. Repository Layer JPA Repository @Repository public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByEmail(String email); boolean existsByEmail(String email); @Query("SELECT u FROM User u WHERE u.status = :status") List<User> findByStatus(@Param("status") UserStatus status); @Modifying @Query("UPDATE User u SET u.status = :status WHERE u.id = :id") int updateStatus(@Param("id") Long id, @Param("status") UserStatus status); } 8. Entity Design JPA Entity @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, unique = true) private String email; @Column(nullable = false) private String name; @Enumerated(EnumType.STRING) private UserStatus status; @CreatedDate private LocalDateTime createdAt; @LastModifiedDate private LocalDateTime updatedAt; @Version private Long version; // Getters and setters } 9. Validation DTO Validation public class CreateUserRequest { @NotBlank(message = "Email is required") @Email(message = "Invalid email format") private String email; @NotBlank(message = "Name is required") @Size(min = 2, max = 100, message = "Name must be between 2 and 100 characters") private String name; @Min(value = 18, message = "Age must be at least 18") @Max(value = 120, message = "Age must be at most 120") private Integer age; // Getters and setters } 10. Security Spring Security Configuration @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeHttpRequests(auth -> auth .requestMatchers("/api/public/**").permitAll() .requestMatchers("/api/admin/**").hasRole("ADMIN") .anyRequest().authenticated() ) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.STATELESS) ) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt.decoder(jwtDecoder())) ); return http.build(); } } 11. Testing Unit Tests @ExtendWith(MockitoExtension.class) class UserServiceTest { @Mock private UserRepository userRepository; @InjectMocks private UserService userService; @Test void shouldCreateUser() { // Given CreateUserRequest request = new CreateUserRequest(); request.setEmail("[email protected]"); request.setName("Test User"); User savedUser = new User(); savedUser.setId(1L); savedUser.setEmail(request.getEmail()); when(userRepository.existsByEmail(request.getEmail())).thenReturn(false); when(userRepository.save(any(User.class))).thenReturn(savedUser); // When UserDTO result = userService.createUser(request); // Then assertThat(result.getId()).isEqualTo(1L); assertThat(result.getEmail()).isEqualTo("[email protected]"); } } Integration Tests @SpringBootTest @AutoConfigureMockMvc class UserControllerIntegrationTest { @Autowired private MockMvc mockMvc; @Autowired private UserRepository userRepository; @Test void shouldCreateUser() throws Exception { CreateUserRequest request = new CreateUserRequest(); request.setEmail("[email protected]"); request.setName("Test User"); mockMvc.perform(post("/api/v1/users") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(status().isCreated()) .andExpect(jsonPath("$.email").value("[email protected]")); } } 12. Performance Optimization Connection Pooling spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000 Caching @Configuration @EnableCaching public class CacheConfig { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager("users", "posts"); } } // Usage @Service public class UserService { @Cacheable(value = "users", key = "#id") public UserDTO getUserById(Long id) { return userRepository.findById(id) .map(userMapper::toDTO) .orElseThrow(); } @CacheEvict(value = "users", key = "#id") public void deleteUser(Long id) { userRepository.deleteById(id); } } 13. Monitoring and Logging Actuator Endpoints management: endpoints: web: exposure: include: health,info,metrics,prometheus endpoint: health: show-details: when-authorized Logging Configuration logging: level: root: INFO com.example: DEBUG pattern: console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" file: name: logs/application.log max-size: 10MB max-history: 30 Best Practices Summary Use constructor injection for dependencies Implement global exception handling Validate all inputs with Bean Validation Use DTOs to separate API from domain models Implement proper logging and monitoring Use profiles for environment-specific config Write comprehensive tests Optimize database queries Implement caching where appropriate Follow RESTful conventions Conclusion Spring Boot best practices help you build:
...
ReadDec 10, 2025
nodejs
Asynchronous programming is at the heart of Node.js. Here are practical strategies to master async operations.
Understanding Async Patterns Callbacks // Traditional callback pattern function readFile(callback) { fs.readFile('file.txt', 'utf8', (err, data) => { if (err) return callback(err); callback(null, data); }); } Promises // Promise-based function readFile() { return new Promise((resolve, reject) => { fs.readFile('file.txt', 'utf8', (err, data) => { if (err) reject(err); else resolve(data); }); }); } Async/Await // Modern async/await async function readFile() { try { const data = await fs.promises.readFile('file.txt', 'utf8'); return data; } catch (err) { throw err; } } Common Patterns Sequential Execution // Execute operations one after another async function sequential() { const user = await getUser(userId); const profile = await getProfile(user.id); const posts = await getPosts(user.id); return { user, profile, posts }; } Parallel Execution // Execute operations in parallel async function parallel() { const [user, profile, posts] = await Promise.all([ getUser(userId), getProfile(userId), getPosts(userId) ]); return { user, profile, posts }; } Race Conditions // Get first resolved promise async function race() { const result = await Promise.race([ fetchFromAPI1(), fetchFromAPI2(), timeout(5000) // Fallback ]); return result; } Error Handling Try-Catch with Async/Await async function handleErrors() { try { const data = await fetchData(); return data; } catch (error) { if (error.code === 'ENOENT') { // Handle file not found } else if (error.code === 'ECONNREFUSED') { // Handle connection refused } else { // Handle other errors } throw error; } } Promise Error Handling // Chain error handling fetchData() .then(data => processData(data)) .catch(error => { console.error('Error:', error); return fallbackData(); }) .finally(() => { cleanup(); }); Advanced Patterns Retry Logic async function retry(fn, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fn(); } catch (error) { if (i === maxRetries - 1) throw error; await sleep(1000 * (i + 1)); // Exponential backoff } } } Timeout Pattern function withTimeout(promise, ms) { return Promise.race([ promise, new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), ms) ) ]); } // Usage const data = await withTimeout(fetchData(), 5000); Batch Processing async function processBatch(items, batchSize = 10) { for (let i = 0; i < items.length; i += batchSize) { const batch = items.slice(i, i + batchSize); await Promise.all(batch.map(item => processItem(item))); } } Best Practices 1. Always Await Promises // Bad: Fire and forget asyncFunction(); // Unhandled promise // Good: Always await await asyncFunction(); 2. Use Promise.all for Independent Operations // Good: Parallel execution const [users, posts, comments] = await Promise.all([ getUsers(), getPosts(), getComments() ]); 3. Handle Rejections // Always handle promise rejections process.on('unhandledRejection', (reason, promise) => { console.error('Unhandled Rejection:', reason); }); Conclusion Mastering async operations requires:
...
ReadDec 10, 2025
nodejs
Understanding Node.js architecture is crucial for building scalable applications. Let’s dive into the event loop, async operations, and how Node.js handles concurrency.
The Event Loop Node.js uses a single-threaded event loop to handle asynchronous operations efficiently.
Event Loop Phases // Simplified event loop phases ┌───────────────────────────┐ │ ┌─────────────────────┐ │ │ │ Timers │ │ // setTimeout, setInterval │ └─────────────────────┘ │ │ ┌─────────────────────┐ │ │ │ Pending Callbacks │ │ // I/O callbacks │ └─────────────────────┘ │ │ ┌─────────────────────┐ │ │ │ Idle, Prepare │ │ // Internal use │ └─────────────────────┘ │ │ ┌─────────────────────┐ │ │ │ Poll │ │ // Fetch new I/O events │ └─────────────────────┘ │ │ ┌─────────────────────┐ │ │ │ Check │ │ // setImmediate callbacks │ └─────────────────────┘ │ │ ┌─────────────────────┐ │ │ │ Close Callbacks │ │ // socket.on('close') │ └─────────────────────┘ │ └───────────────────────────┘ How It Works // Example: Understanding execution order console.log('1'); setTimeout(() => console.log('2'), 0); Promise.resolve().then(() => console.log('3')); console.log('4'); // Output: 1, 4, 3, 2 // Why: // - Synchronous code runs first (1, 4) // - Microtasks (Promises) run before macrotasks (setTimeout) // - Event loop processes callbacks Asynchronous Operations Callbacks // Traditional callback fs.readFile('file.txt', (err, data) => { if (err) { console.error(err); return; } console.log(data); }); Promises // Promise-based fs.promises.readFile('file.txt') .then(data => console.log(data)) .catch(err => console.error(err)); // Async/await async function readFile() { try { const data = await fs.promises.readFile('file.txt'); console.log(data); } catch (err) { console.error(err); } } Event Emitters const EventEmitter = require('events'); class MyEmitter extends EventEmitter {} const myEmitter = new MyEmitter(); myEmitter.on('event', (data) => { console.log('Event received:', data); }); myEmitter.emit('event', 'Hello World'); Concurrency Model Single-Threaded but Non-Blocking // Node.js handles I/O asynchronously const http = require('http'); // This doesn't block http.get('http://example.com', (res) => { res.on('data', (chunk) => { console.log(chunk); }); }); // This continues immediately console.log('Request sent, continuing...'); Worker Threads for CPU-Intensive Tasks // For CPU-intensive operations const { Worker, isMainThread, parentPort } = require('worker_threads'); if (isMainThread) { const worker = new Worker(__filename); worker.postMessage('Start calculation'); worker.on('message', (result) => { console.log('Result:', result); }); } else { parentPort.on('message', (msg) => { // Heavy computation const result = performHeavyCalculation(); parentPort.postMessage(result); }); } Scaling Strategies Cluster Module const cluster = require('cluster'); const os = require('os'); if (cluster.isMaster) { const numWorkers = os.cpus().length; for (let i = 0; i < numWorkers; i++) { cluster.fork(); } cluster.on('exit', (worker) => { console.log(`Worker ${worker.id} died`); cluster.fork(); // Restart worker }); } else { // Worker process require('./server.js'); } Load Balancing // PM2 for process management // pm2 start app.js -i max // Or use nginx/HAProxy for load balancing Best Practices 1. Avoid Blocking the Event Loop // Bad: Blocks event loop function heavyComputation() { let result = 0; for (let i = 0; i < 10000000000; i++) { result += i; } return result; } // Good: Use worker threads or break into chunks function asyncHeavyComputation() { return new Promise((resolve) => { setImmediate(() => { // Process in chunks resolve(computeChunk()); }); }); } 2. Use Streams for Large Data // Bad: Loads entire file into memory const data = fs.readFileSync('large-file.txt'); // Good: Stream processing const stream = fs.createReadStream('large-file.txt'); stream.on('data', (chunk) => { processChunk(chunk); }); 3. Handle Errors Properly // Always handle errors in async operations async function fetchData() { try { const data = await fetch('http://api.example.com'); return data; } catch (error) { // Log and handle error console.error('Fetch failed:', error); throw error; } } Performance Tips 1. Connection Pooling // Database connection pooling const pool = mysql.createPool({ connectionLimit: 10, host: 'localhost', user: 'user', password: 'password', database: 'mydb' }); 2. Caching // Use Redis for caching const redis = require('redis'); const client = redis.createClient(); async function getCachedData(key) { const cached = await client.get(key); if (cached) return JSON.parse(cached); const data = await fetchData(); await client.setex(key, 3600, JSON.stringify(data)); return data; } 3. Compression // Enable gzip compression const compression = require('compression'); app.use(compression()); Common Pitfalls 1. Callback Hell // Bad: Nested callbacks fs.readFile('file1.txt', (err, data1) => { fs.readFile('file2.txt', (err, data2) => { fs.readFile('file3.txt', (err, data3) => { // Deep nesting }); }); }); // Good: Use async/await async function readFiles() { const [data1, data2, data3] = await Promise.all([ fs.promises.readFile('file1.txt'), fs.promises.readFile('file2.txt'), fs.promises.readFile('file3.txt') ]); } 2. Unhandled Promise Rejections // Always handle promise rejections process.on('unhandledRejection', (reason, promise) => { console.error('Unhandled Rejection:', reason); // Log and handle }); Conclusion Node.js architecture is powerful because:
...
ReadDec 10, 2025
graphql
GraphQL and REST are both popular API design approaches. Here’s when to use each.
REST API Overview REST (Representational State Transfer) uses HTTP methods to interact with resources.
Characteristics Resource-based: URLs represent resources HTTP methods: GET, POST, PUT, DELETE Stateless: Each request is independent Multiple endpoints: Different URLs for different resources Example GET /api/users GET /api/users/123 POST /api/users PUT /api/users/123 DELETE /api/users/123 GraphQL Overview GraphQL is a query language and runtime for APIs.
...
ReadDec 10, 2025
api
Good API design is crucial for developer experience and system success. Here are best practices for designing RESTful APIs.
1. Use RESTful Conventions Resource-Based URLs # Good: Resource-based GET /api/users GET /api/users/123 POST /api/users PUT /api/users/123 DELETE /api/users/123 # Bad: Action-based GET /api/getUsers POST /api/createUser POST /api/deleteUser HTTP Methods GET: Retrieve resources POST: Create resources PUT: Update entire resource PATCH: Partial update DELETE: Remove resource 2. Consistent Naming Use Plural Nouns # Good GET /api/users GET /api/orders GET /api/products # Bad GET /api/user GET /api/order GET /api/product Use kebab-case or camelCase # Good: Consistent GET /api/user-profiles GET /api/orderItems # Bad: Mixed GET /api/user_profiles GET /api/order-items 3. Version Your API URL Versioning GET /api/v1/users GET /api/v2/users Header Versioning GET /api/users Accept: application/vnd.api+json;version=2 4. Use Proper HTTP Status Codes Success Codes 200 OK # Successful GET, PUT, PATCH 201 Created # Successful POST 204 No Content # Successful DELETE Client Error Codes 400 Bad Request # Invalid request 401 Unauthorized # Authentication required 403 Forbidden # Not authorized 404 Not Found # Resource doesn't exist 409 Conflict # Resource conflict 422 Unprocessable # Validation errors Server Error Codes 500 Internal Server Error 502 Bad Gateway 503 Service Unavailable 5. Consistent Response Format Standard Response Structure { "data": { "id": "123", "type": "user", "attributes": { "name": "John Doe", "email": "[email protected]" } }, "meta": { "timestamp": "2025-12-10T10:00:00Z" } } Error Response Format { "error": { "code": "VALIDATION_ERROR", "message": "Invalid input", "details": [ { "field": "email", "message": "Invalid email format" } ] } } 6. Pagination Cursor-Based Pagination GET /api/users?cursor=eyJpZCI6IjEyMyJ9&limit=20 Response: { "data": [...], "pagination": { "cursor": "eyJpZCI6IjE0MyJ9", "has_more": true } } Offset-Based Pagination GET /api/users?page=1&limit=20 Response: { "data": [...], "pagination": { "page": 1, "limit": 20, "total": 100, "total_pages": 5 } } 7. Filtering and Sorting Filtering GET /api/users?status=active&role=admin GET /api/orders?created_after=2024-01-01&created_before=2024-12-31 Sorting GET /api/users?sort=name,email&order=asc,desc GET /api/users?sort=-created_at # Descending 8. Field Selection Sparse Fieldsets GET /api/users?fields=id,name,email GET /api/users/123?fields=id,name Include Related Resources GET /api/users/123?include=orders,profile 9. Rate Limiting Headers X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 999 X-RateLimit-Reset: 1609459200 Response HTTP/1.1 429 Too Many Requests Retry-After: 60 10. Authentication and Authorization Use Standard Methods # Bearer token Authorization: Bearer <token> # API key X-API-Key: <key> Return Clear Errors { "error": { "code": "UNAUTHORIZED", "message": "Invalid or expired token" } } 11. Documentation OpenAPI/Swagger openapi: 3.0.0 info: title: User API version: 1.0.0 paths: /users: get: summary: List users responses: '200': description: Success Interactive Documentation Swagger UI: Visual API documentation Postman: API testing and docs Redoc: Beautiful API docs 12. Error Handling Consistent Error Format { "error": { "code": "RESOURCE_NOT_FOUND", "message": "User with ID 123 not found", "request_id": "req_abc123" } } Validation Errors { "error": { "code": "VALIDATION_ERROR", "message": "Validation failed", "errors": [ { "field": "email", "message": "Invalid email format", "code": "INVALID_FORMAT" } ] } } 13. Caching Cache Headers Cache-Control: public, max-age=3600 ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4" Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT Conditional Requests GET /api/users/123 If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4" # 304 Not Modified if unchanged 14. Security Best Practices Use HTTPS Always use HTTPS in production.
...
ReadDec 10, 2025
testing
This write-up condenses the published DEV tutorial “Browser-based performance testing with K6” into an actionable walkthrough for frontend teams.
Why k6 browser Simulates real browser interactions (Chromium) vs. protocol-only tests. Captures Web Vitals (LCP/INP/CLS) and UX signals (spinners, interactivity). Reuses familiar k6 scripting with async/await + locators. Setup Install k6 (latest) and ensure Node/npm are available. Project skeleton: k6-tests/ libs/ # flows (login, add to cart, checkout) pages/ # Page Object Model classes tests/ # test entry scripts utils/ # shared options (browser config, VUs, iterations) Configure browser scenario (utils/k6-options.js): export const browserOptions = { scenarios: { ui: { executor: "shared-iterations", vus: 1, iterations: 15, options: { browser: { type: "chromium" } }, }, }, }; Example flow (simplified) import { browser } from "k6/browser"; import { check } from "k6"; export const options = browserOptions; export default async function () { const page = await browser.newPage(); await page.goto("https://www.saucedemo.com/"); await page.locator("#user-name").type("standard_user"); await page.locator("#password").type("secret_sauce"); await page.locator("#login-button").click(); check(page, { "login ok": () => page.locator(".title").textContent() === "Products" }); await page.close(); } Running & reporting CLI run: k6 run ./tests/buyItemsUserA.js Live dashboard: K6_WEB_DASHBOARD=true K6_WEB_DASHBOARD_OPEN=true k6 run ... Export HTML report: K6_WEB_DASHBOARD=true K6_WEB_DASHBOARD_EXPORT=results/report.html Metrics to watch (aligns to Core Web Vitals) browser_web_vital_lcp — largest content paint; target < 2.5s p75. browser_web_vital_inp — interaction to next paint; target < 200ms p75. browser_web_vital_cls — layout shift; target < 0.1. Add custom checks for “spinner disappears”, “cart count”, “success message”. Tips Keep tests short and focused; one scenario per file. Reuse Page Objects for maintainability. Run with realistic VUs/iterations that mirror expected traffic. Use screenshots on failure for debuggability (page.screenshot()). Takeaway: k6 browser mode gives frontend teams reproducible, scriptable UX performance checks—ideal for catching regressions before they reach real users.
ReadDec 10, 2025
frontend
This post distills the key ideas from the published DEV article “Frontend Performance Optimization: A Comprehensive Guide 🚀” into a concise, production-focused playbook.
What matters Fast first paint and interaction: prioritize above-the-fold content, cut JS weight, avoid layout shifts. Ship less: smaller bundles, fewer blocking requests, cache aggressively. Ship smarter: load what’s needed when it’s needed (on demand and in priority order). Core techniques 1) Selective rendering Render only what is visible (e.g., IntersectionObserver + skeletons). Defer heavy components until scrolled into view. 2) Code splitting & dynamic imports Split by route/feature; lazy-load non-critical views. Example (React): const Page = lazy(() => import("./Page")); <Suspense fallback={<div>Loading…</div>}> <Page /> </Suspense>; 3) Prefetching & caching Prefetch likely-next routes/assets (<link rel="prefetch"> or router prefetch). Pre-warm API data with React Query/Next.js loader functions. 4) Priority-based loading Preload critical CSS/hero imagery: <link rel="preload" as="style" href="styles.css">. Use defer/async for non-critical scripts. 5) Compression & transfer Enable Brotli/Gzip at the edge; pre-compress static assets in CI/CD. Serve modern formats (AVIF/WebP) and keep caching headers long-lived. 6) Loading sequence hygiene Order: HTML → critical CSS → critical JS → images/fonts → analytics. Avoid long main-thread tasks; prefer requestIdleCallback for non-urgent work. 7) Tree shaking & dead-code elimination Use ESM named imports; avoid import *. Keep build in production mode with minification + module side-effects flags. Measurement & guardrails Track Core Web Vitals (LCP, INP, CLS) plus TTFB and bundle size per release. Run Lighthouse/WebPageTest in CI; fail builds on regressions above agreed budgets. Monitor real-user metrics (RUM) to validate improvements after deploys. Quick starter checklist Lazy-load routes and heavy widgets. Preload hero font/hero image; inline critical CSS if needed. Turn on Brotli at CDN; cache static assets with versioned filenames. Set performance budgets (JS < 200KB gz, LCP < 2.5s p75, INP < 200ms). Automate audits in CI and watch RUM dashboards after each release. Bottom line: Combine “ship less” (smaller, shaken, compressed bundles) with “ship smarter” (prioritized, on-demand loading) and enforce budgets with automated checks to keep your app fast over time.
Read