TypeScript
Our codebase follows the Vercel Engineering Style Guide conventions.ESLint Configuration
We maintain three primary ESLint configurations for different project types:- Library Configuration (for packages):
- React Configuration (for React applications):
- Next.js Configuration (for Next.js applications):
Key Conventions
-
TypeScript Usage
- Strict TypeScript checking enabled
- Explicit type annotations when necessary
- Proper interface and type naming (prefix with T for types, I for interfaces when helpful)
- No use of
any
type unless absolutely necessary
-
Imports/Exports
- Follow strict import ordering:
- Mocks (for testing)
- Server-only imports
- Third-party modules
- Internal
@formbricks/*
modules - Local aliases (
~/*
) - Relative imports
- Follow strict import ordering:
-
Error Handling
- Use typed error responses
- Proper error propagation
- Consistent error message formatting
- Implement error boundaries in React components
-
Async/Await
- Prefer async/await over raw promises
- Proper error handling in async functions
- Use Promise.all for parallel operations
-
React Specific
- Functional components with TypeScript
- Proper use of hooks
- Consistent prop typing
- Server Components by default in Next.js App Router
Code Formatting
We use Prettier with specific configurations:Swift (iOS SDK)
Our iOS SDK follows Swift best practices.Swift Configuration
The iOS SDK requires the following:- Swift Version: 5.7+
- Platform: iOS 16.6+
- Package Manager: Swift Package Manager and CocoaPods support
- ARC: Automatic Reference Counting enabled
Key Conventions
-
Access Control Strategy
public
: SDK public API surface onlyinternal
: Internal SDK communication and shared componentsprivate
: Implementation details within specific classes- Strategic use of
private(set)
for read-only public properties
-
Architecture Patterns
- Singleton Pattern: Main SDK class (
Formbricks
) with static interface - Manager Pattern: Specialized managers (
UserManager
,SurveyManager
,PresentSurveyManager
) - Builder Pattern: Configuration objects (
FormbricksConfig.Builder
) - Protocol-Oriented Programming: Service protocols for dependency injection and testing
- Singleton Pattern: Main SDK class (
-
Error Handling
- Custom error enums with descriptive cases (
FormbricksSDKErrorType
) - Error types conform to
LocalizedError
protocol - Structured error propagation with completion handlers
- Defensive programming with guard statements and early returns
- Custom error enums with descriptive cases (
-
Naming Conventions
- Classes: PascalCase (
FormbricksConfig
,UserManager
) - Properties/Methods: camelCase (
environmentId
,setUserId
) - Constants: camelCase with descriptive names
- Protocol names: Descriptive with “Protocol” suffix (
FormbricksServiceProtocol
)
- Classes: PascalCase (
-
Code Organization
// MARK:
comments for logical section separation- Extensions for related functionality grouping
- Consistent file structure with models, managers, networking, and views
-
Model Design
- Prefer
struct
for data models and value types - Use
class
for reference types and managers - Implement
Codable
for JSON serialization/deserialization - Immutable properties where possible (
let
overvar
)
- Prefer
-
Security & Validation
- HTTPS enforcement for all network requests
- URL validation before network operations
- Input validation with descriptive error messages
- Secure data handling practices
-
Asynchronous Operations
OperationQueue
for network operations- Completion handlers for async operations
- Network connectivity checking with
NWPathMonitor
- Thread-safe operations with proper queue management
Code Formatting
We follow standard Swift formatting conventions: Key Formatting Rules:Kotlin (Android SDK)
Our Android SDK codebase with Kotlin follows modern Android development practices and Kotlin conventions.Key Conventions
-
Package Structure
- Logical grouping by functionality (api, model, network, manager, webview)
- Clear separation of concerns across packages
-
Kotlin Language Features
- Object singletons for stateless utilities and managers (
Formbricks
,Logger
,SDKError
) - Data classes for models with automatic equals/hashCode/toString (
Survey
,User
) - Sealed classes for representing restricted hierarchies
- Extension functions for utility methods (
Guard.kt
,DateExtensions.kt
) - Coroutines for asynchronous operations with proper context switching
- Object singletons for stateless utilities and managers (
-
Error Handling
- Centralized error definitions in
SDKError
object - Use of
Result<T>
type for API responses - Proper exception propagation with meaningful error messages
- Consistent error logging through centralized
Logger
- Centralized error definitions in
-
Android-Specific Patterns
@Keep
annotations for ProGuard/R8 compatibility on public APIs- Proper lifecycle management in fragments and view models
- Use of
FragmentManager
for UI components - Network security configuration for HTTPS enforcement
-
Async/Await Pattern
- Prefer coroutines with
suspend
functions over callbacks - Use
withContext(Dispatchers.IO)
for network operations - Implement retry logic with
delay()
for robust API calls - Proper error handling in async functions
- Prefer coroutines with
-
API and Network Layer
- Retrofit for HTTP client with Gson converter
- OkHttp interceptors for logging and security
- Proper timeout configurations
- Result-based API responses with retry mechanisms
Code Formatting
We use Android Studio’s default Kotlin formattingData Modeling
-
Serialization
- Kotlinx Serialization for modern JSON handling
- Gson annotations for backward compatibility:
@SerializedName
- Consistent nullable and non-nullable field declarations
-
Data Classes
- Immutable data structures where possible
- Proper use of nullable types (
String?
) - Clear property naming and documentation