Instruction file imported from bradcstevens/github-copilot-agent-mode-starter-kit (
.github/instructions/technologies/spring.instructions.md). Copyright stays with the author.
-
Code Organization and Structure
- Directory Structure Best Practices
- Layered Architecture: Organize code into layers:
controller,service,repository,model,configuration, andexception. This provides clear separation of concerns. Example:src/ └── main/ └── java/ └── com/example/app/ ├── controller/ │ └── OrderController.java ├── service/ │ └── OrderService.java ├── repository/ │ └── OrderRepository.java ├── model/ │ └── Order.java ├── configuration/ │ └── AppConfig.java └── exception/ └── OrderNotFoundException.java - Feature-Based Organization: Group code by feature rather than layer. This keeps related files together for easier navigation. Use when features are more important than technical separation.
src/ └── main/ └── java/ └── com/example/app/ ├── order/ │ ├── OrderController.java │ ├── OrderService.java │ ├── OrderRepository.java │ └── Order.java └── customer/ ├── CustomerController.java ├── CustomerService.java ├── CustomerRepository.java └── Customer.java
- Layered Architecture: Organize code into layers:
- File Naming Conventions
- Classes: Use
PascalCase. Names should be nouns representing the purpose of the class. Example:OrderService,ProductController. - Interfaces: Use
PascalCase. Often named with an-ablesuffix (e.g.,Runnable,Serializable) or prefixed withI(e.g.,IUserService). Example:OrderRepository,UserService. - Methods: Use
camelCase. Names should be verbs indicating the action performed. Example:createOrder(),calculateTotalPrice(). - Variables: Use
camelCase. Descriptive and concise names providing context. Avoid abbreviations unless widely understood. Example:orderTotal,userList. - Constants: Use
UPPER_SNAKE_CASE. Example:MAX_RETRIES,DEFAULT_TIMEOUT.
- Classes: Use
- Module Organization
- Modular Monolith: Break down the application into logical modules, each with a specific responsibility. This promotes maintainability and testability without the complexity of microservices. Maven or Gradle can be used to manage modules.
- Microservices: When appropriate, consider breaking the application into independent microservices communicating over APIs. This provides scalability and independent deployment. Example:
Order Service,Payment Service,Customer Service.
- Component Architecture
- Controllers: Handle HTTP requests and delegate business logic to services. Keep controllers thin and focused on request mapping and response formatting.
- Services: Contain the core business logic of the application. Services should be stateless and independent of HTTP concerns.
- Repositories: Handle data access and persistence. Use Spring Data JPA repositories to simplify database interactions.
- Data Transfer Objects (DTOs): Use DTOs for request and response payloads to separate API contracts from domain models. This allows for flexibility in evolving the API without affecting internal data structures.
- Code Splitting Strategies
- By Feature: Split code into modules based on features, improving maintainability and scalability.
- By Layer: Split code into distinct layers (presentation, business, data) to separate concerns and improve testability.
- Directory Structure Best Practices
-
Common Patterns and Anti-Patterns
- Design Patterns
- Dependency Injection: Core to Spring. Use constructor injection for required dependencies and setter injection for optional dependencies. Avoid field injection.
- Inversion of Control (IoC): Let the Spring container manage the creation and lifecycle of beans.
- Aspect-Oriented Programming (AOP): Use AOP for cross-cutting concerns like logging, security, and transaction management. Use
@Aspectannotation. - Template Method: Apply when different implementations of an algorithm are needed. Spring's
JdbcTemplateis a classical example. - Factory Pattern: Can be used for abstracting object creation.
- Singleton Pattern: Spring beans are singletons by default, but be mindful when dealing with stateful beans.
- Recommended Approaches
- Configuration Properties: Externalize configuration using
@ConfigurationPropertiesfor type-safe access to properties. - Event Handling: Use Spring's event publishing and listening mechanism for decoupling components. Use
@EventListenerannotation. - Transaction Management: Use
@Transactionalannotation for declarative transaction management. - Validation: Use
@Validatedand JSR-303 annotations for request parameter and body validation.
- Configuration Properties: Externalize configuration using
- Anti-Patterns and Code Smells
- God Classes: Avoid classes with too many responsibilities. Apply the Single Responsibility Principle.
- Long Methods: Break down long methods into smaller, more focused methods.
- Primitive Obsession: Avoid using primitive types excessively. Encapsulate related data into value objects.
- Magic Numbers/Strings: Replace hardcoded values with constants or configuration properties.
- Tight Coupling: Minimize dependencies between components through dependency injection and interfaces.
- State Management
- Stateless Services: Services should be stateless to improve scalability and concurrency.
- Session Management: Use Spring Session for managing user sessions in a distributed environment. Consider using Redis or other external storage for session data.
- Caching: Implement caching strategically to reduce database load and improve response times. Use Spring Cache abstraction with appropriate cache providers.
- Error Handling Patterns
- Global Exception Handling: Use
@ControllerAdviceand@ExceptionHandlerto handle exceptions globally and provide consistent error responses. - Custom Exceptions: Create custom exception classes to represent application-specific errors.
- Logging: Log exceptions with appropriate levels (e.g.,
error,warn,info). - Return Meaningful Error Responses: Return well-structured error responses with clear error codes and messages. Use a consistent format for error responses.
- Global Exception Handling: Use
- Design Patterns
-
Performance Considerations
- Optimization Techniques
- Database Connection Pooling: Use a connection pool (e.g., HikariCP) to reuse database connections and reduce overhead.
- Caching: Implement caching using Spring Cache abstraction to store frequently accessed data.
- Asynchronous Processing: Use
@Asyncfor long-running tasks that don't need to be executed synchronously. - Lazy Loading: Use lazy loading for entities and relationships in JPA to avoid loading unnecessary data.
- Profiling: Use profiling tools (e.g., VisualVM, JProfiler) to identify performance bottlenecks.
- Memory Management
- Garbage Collection Tuning: Tune JVM garbage collection settings for optimal performance. Monitor GC performance and adjust parameters as needed.
- Object Pooling: Consider using object pooling for frequently created and destroyed objects.
- Avoid Memory Leaks: Be careful to release resources properly to prevent memory leaks. Use try-with-resources for closing streams and other resources.
- Rendering Optimization
- (Not Directly Applicable to Spring Backend - Focus on API Response times and efficiency)
- Minimize Data Transfer: Only return the data needed by the client.
- Use Efficient Data Structures: Use appropriate data structures for API responses (e.g., lists, maps).
- Compression: Enable GZIP compression for API responses to reduce the size of the data transferred over the network.
- Bundle Size Optimization
- (Not Directly Applicable to Spring Backend - Although Dependency Management is crucial)
- Minimize Dependencies: Only include necessary dependencies.
- Use Code Analysis Tools: Use tools like SonarQube to identify unused code and dependencies.
- Lazy Loading
- JPA Lazy Loading: Use lazy loading for JPA relationships to avoid loading unnecessary data. Use the
@OneToMany(fetch = FetchType.LAZY)annotation.
- JPA Lazy Loading: Use lazy loading for JPA relationships to avoid loading unnecessary data. Use the
- Optimization Techniques
-
Security Best Practices
- Common Vulnerabilities and Prevention
- SQL Injection: Use parameterized queries or ORM frameworks (e.g., Spring Data JPA) to prevent SQL injection.
- Cross-Site Scripting (XSS): Sanitize user input to prevent XSS attacks.
- Cross-Site Request Forgery (CSRF): Use CSRF protection mechanisms (e.g., Spring Security's CSRF support).
- Authentication/Authorization Flaws: Implement robust authentication and authorization mechanisms using Spring Security.
- Dependency Vulnerabilities: Regularly scan dependencies for known vulnerabilities and update them.
- Input Validation
- Server-Side Validation: Always perform input validation on the server-side.
- JSR-303 Validation: Use JSR-303 annotations for validating request parameters and body.
- Custom Validation: Implement custom validation logic for complex validation instructions.
- Authentication and Authorization
- Spring Security: Use Spring Security for authentication and authorization.
- OAuth 2.0/OpenID Connect: Use OAuth 2.0/OpenID Connect for delegating authentication and authorization to external providers.
- Role-Based Access Control (RBAC): Implement RBAC to control access to resources based on user roles.
- Data Protection
- Encryption: Encrypt sensitive data at rest and in transit.
- Hashing: Hash passwords using strong hashing algorithms (e.g., bcrypt, Argon2).
- Data Masking: Mask sensitive data when displaying or logging it.
- Secure API Communication
- HTTPS: Use HTTPS for all API communication.
- API Keys: Use API keys for authenticating clients.
- Rate Limiting: Implement rate limiting to prevent abuse.
- Common Vulnerabilities and Prevention
-
Testing Approaches
- Unit Testing
- JUnit: Use JUnit for writing unit tests.
- Mockito: Use Mockito for mocking dependencies.
- Test-Driven Development (TDD): Write tests before writing code.
- Focus on Business Logic: Focus unit tests on the business logic of the application.
- Integration Testing
- Spring Boot Test: Use
@SpringBootTestannotation for integration tests. - TestRestTemplate: Use
TestRestTemplatefor testing REST endpoints. - Database Testing: Use an in-memory database (e.g., H2, embedded database) or a test database for integration tests.
- Verify Component Interactions: Verify that different components of the application work together correctly.
- Spring Boot Test: Use
- End-to-End Testing
- Selenium: Use Selenium for end-to-end testing of web applications.
- Cypress: Use Cypress as another alternative for end-to-end testing.
- Test the Entire System: Test the entire system from the user interface to the database.
- Test Organization
- Separate Test Directory: Keep tests in a separate directory from the source code.
- Test Naming Conventions: Use clear and consistent naming conventions for tests (e.g.,
ClassNameTest). - Organize Tests by Component: Organize tests by component or feature.
- Mocking and Stubbing
- Mockito Annotations: Use Mockito annotations (e.g.,
@Mock,@InjectMocks) to simplify mocking. - When/Then: Use the
when()andthenReturn()methods to define mock behavior. - Verify Interactions: Use the
verify()method to verify that mock interactions occurred.
- Mockito Annotations: Use Mockito annotations (e.g.,
- Unit Testing
-
Common Pitfalls and Gotchas
- Frequent Mistakes
- Over-Engineering: Avoid over-engineering solutions. Keep it simple and only add complexity when needed.
- Ignoring Exceptions: Don't catch exceptions and ignore them. Always log exceptions and handle them appropriately.
- Hardcoding Values: Avoid hardcoding values. Use configuration properties instead.
- Not Using Dependency Injection Properly: Use dependency injection to decouple components and improve testability.
- Edge Cases
- Null Values: Handle null values gracefully.
- Concurrency Issues: Be aware of concurrency issues when dealing with shared resources.
- Resource Exhaustion: Handle resource exhaustion gracefully (e.g., database connections, memory).
- Version-Specific Issues
- Check Release Notes: Review release notes for each version of Spring Boot and its dependencies to identify potential issues.
- Test Upgrades: Thoroughly test upgrades to ensure compatibility.
- Compatibility Concerns
- Dependency Conflicts: Manage dependency conflicts using Maven or Gradle.
- Java Version Compatibility: Ensure compatibility between Spring Boot and the Java version.
- Debugging Strategies
- Logging: Use logging liberally to track the flow of execution and identify issues.
- Debuggers: Use debuggers to step through code and inspect variables.
- Remote Debugging: Use remote debugging to debug applications running in remote environments.
- Frequent Mistakes
-
Tooling and Environment
- Recommended Development Tools
- IntelliJ IDEA: Popular IDE with excellent Spring Boot support.
- Eclipse: Another popular IDE with Spring Tool Suite plugin.
- Spring Initializr: Web-based tool for generating Spring Boot projects.
- Build Configuration
- Maven: Use Maven for dependency management and building projects.
- Gradle: Use Gradle as another alternative to Maven.
- Spring Boot Plugin: Use the Spring Boot Maven or Gradle plugin for building executable JARs.
- Linting and Formatting
- Checkstyle: Use Checkstyle for enforcing coding standards.
- PMD: Use PMD for finding potential bugs and code smells.
- SpotBugs: Use SpotBugs to find potential bug patterns in the code.
- Prettier: Use Prettier for formatting code consistently.
- Deployment Best Practices
- Containerization: Use Docker for containerizing applications.
- Cloud Platforms: Deploy applications to cloud platforms (e.g., AWS, Azure, GCP).
- Immutable Infrastructure: Use immutable infrastructure for deploying applications.
- CI/CD Integration
- Jenkins: Use Jenkins for continuous integration and continuous deployment.
- GitLab CI: Use GitLab CI as another CI/CD alternative.
- GitHub Actions: Use GitHub Actions for automating build, test, and deployment workflows.
- Recommended Development Tools
-
Additional Tips
- Use Spring Boot DevTools: These tools provide automatic application restarts, live reloading, and other useful features during development.
- Monitor Application Health: Use Spring Boot Actuator to monitor application health and performance metrics.
- Stay Up-to-Date: Keep up-to-date with the latest Spring Boot releases and best practices.