First off, thank you for considering contributing to Concurrency! It's people like you that make Concurrency such a great tool.
- Code of Conduct
- Getting Started
- How Can I Contribute?
- Development Workflow
- Coding Standards
- Community
This project and everyone participating in it is governed by our Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to nv3212@gmail.com.
-
Fork the repository
# Click the "Fork" button on GitHub -
Clone your fork
git clone https://github.com/YOUR_USERNAME/concurrency.git cd concurrency -
Set up the development environment
# Bootstrap the project make bootstrap -
Create a feature branch
git checkout -b feature/your-feature-name
-
Open the project in Xcode
open Package.swift
Before creating a bug report, please check the existing issues to avoid duplicates.
When creating a bug report, include:
- Clear title - Describe the issue concisely
- Reproduction steps - Detailed steps to reproduce the bug
- Expected behavior - What you expected to happen
- Actual behavior - What actually happened
- Environment - OS, Xcode version, Swift version
- Code samples - Minimal reproducible example
- Error messages - Complete error output if applicable
Example:
**Title:** TestDispatchQueue does not execute blocks synchronously
**Steps to reproduce:**
1. Create TestDispatchQueue instance
2. Call async with a block that modifies state
3. Check state immediately after async call
**Expected:** Block should execute immediately
**Actual:** Block is queued for later execution
**Environment:**
- macOS 14.0
- Xcode 15.3
- Swift 5.10
**Code:**
\`\`\`swift
let testQueue = TestDispatchQueue()
var value = 0
testQueue.async {
value = 42
}
print(value) // Expected: 42, Actual: 0
\`\`\`We love feature suggestions! When proposing a new feature, include:
- Problem statement - What problem does this solve?
- Proposed solution - How should it work?
- Alternatives - What alternatives did you consider?
- Use cases - Real-world scenarios
- API design - Example code showing usage
- Breaking changes - Will this break existing code?
Example:
**Feature:** Add barrier support for concurrent queues
**Problem:** Users need to synchronize writes in concurrent queue contexts while maintaining read parallelism.
**Solution:** Add barrier methods to IDispatchQueue protocol.
**API:**
\`\`\`swift
protocol IDispatchQueue {
func async(flags: DispatchWorkItemFlags, execute work: @escaping () -> Void)
func asyncBarrier(execute work: @escaping () -> Void)
}
\`\`\`
**Use case:** Thread-safe cache that allows concurrent reads but exclusive writes:
\`\`\`swift
class Cache {
private let queue: IDispatchQueue
func read() {
queue.async { /* read operation */ }
}
func write() {
queue.asyncBarrier { /* write operation */ }
}
}
\`\`\`Documentation improvements are always welcome:
- Code comments - Add/improve inline documentation
- DocC documentation - Enhance documentation articles
- README - Fix typos, add examples
- Guides - Write tutorials or how-to guides
- API documentation - Document public APIs
- Check existing work - Look for related issues or PRs
- Discuss major changes - Open an issue for large features
- Follow coding standards - See Coding Standards
- Write tests - All code changes require tests
- Update documentation - Keep docs in sync with code
- Create a pull request - Use clear description
We use a simplified branching model:
main- Main development branch (all PRs target this)feature/*- New featuresfix/*- Bug fixesdocs/*- Documentation updatesrefactor/*- Code refactoringtest/*- Test improvements
Branch naming examples:
feature/add-barrier-support
fix/test-queue-synchronization
docs/update-testing-guide
refactor/simplify-queue-factory
test/add-concurrent-queue-testsWe use Conventional Commits for clear, structured commit history.
Format:
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat- New featurefix- Bug fixdocs- Documentation changesstyle- Code style (formatting, no logic changes)refactor- Code refactoringtest- Adding or updating testschore- Maintenance tasksperf- Performance improvements
Scopes:
factory- DispatchQueueFactoryprotocol- IDispatchQueue protocoltest- TestConcurrency targetqueue- Queue implementationsdeps- Dependencies
Examples:
feat(factory): add support for dispatch queue with target
Allow users to specify target queue when creating private queues.
This enables hierarchical queue setups for better resource management.
Closes #23
---
fix(test): ensure TestDispatchQueue executes blocks immediately
TestDispatchQueue was queuing blocks instead of executing them
synchronously, breaking the test double contract. Now properly
executes blocks immediately in the same call stack.
Fixes #45
---
docs(readme): add thread-safe property access example
Add practical example showing how to use serial queues for
thread-safe access to shared mutable state.
---
test(factory): add tests for quality of service configurations
Add tests for:
- All QoS levels
- QoS propagation to created queues
- Default QoS behaviorCommit message rules:
- Use imperative mood ("add" not "added")
- Don't capitalize first letter
- No period at the end
- Keep subject line under 72 characters
- Separate subject from body with blank line
- Reference issues in footer
-
Update your branch
git checkout main git pull upstream main git checkout feature/your-feature git rebase main
-
Run tests and checks
# Run all tests swift test # Check test coverage swift test --enable-code-coverage # Run tests for both targets swift test --filter ConcurrencyTests swift test --filter TestConcurrencyTests
-
Push to your fork
git push origin feature/your-feature
-
Create pull request
- Target the
mainbranch - Provide clear description
- Link related issues
- Include examples if applicable
- Request review from maintainers
- Target the
-
Review process
- Address review comments
- Keep PR up to date with main
- Squash commits if requested
- Wait for CI to pass
-
After merge
# Clean up local branch git checkout main git pull upstream main git branch -d feature/your-feature # Clean up remote branch git push origin --delete feature/your-feature
We follow the Swift API Design Guidelines and Ray Wenderlich Swift Style Guide.
Key points:
-
Naming
// ✅ Good func async(execute work: @escaping () -> Void) let mainQueue: IDispatchQueue // ❌ Bad func doAsync(_ w: @escaping () -> Void) let q: IDispatchQueue
-
Protocols
// ✅ Good - Use "I" prefix for protocols protocol IDispatchQueue { func async(execute work: @escaping () -> Void) } // ❌ Bad protocol DispatchQueue { }
-
Access Control
// ✅ Good - Explicit access control public final class DispatchQueueFactory: IDispatchQueueFactory { public init() {} public func main() -> IDispatchQueue { return DispatchQueue.main } public func global(qos: DispatchQoS.QoSClass) -> IDispatchQueue { return DispatchQueue.global(qos: qos) } }
-
Documentation
/// Creates a new dispatch queue with custom configuration. /// /// This method allows fine-grained control over queue behavior including /// quality of service, serial vs concurrent execution, and memory management. /// /// - Parameters: /// - label: A unique identifier for the queue, useful for debugging /// - qos: The quality of service class for work items /// - attributes: Queue attributes (empty for serial, .concurrent for concurrent) /// - autoreleaseFrequency: How often to drain the autorelease pool /// - target: The target queue on which to execute blocks /// - Returns: A new dispatch queue configured with the specified parameters /// /// - Example: /// ```swift /// let queue = factory.privateQueue( /// label: "com.example.myqueue", /// qos: .userInitiated, /// attributes: .concurrent /// ) /// ``` public func privateQueue( label: String, qos: DispatchQoS, attributes: DispatchQueue.Attributes, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency, target: DispatchQueue? ) -> IDispatchQueue { // Implementation }
- No force unwrapping - Use optional binding or guards
- No force casting - Use conditional casting
- No magic numbers - Use named constants
- Single responsibility - One class, one purpose
- DRY principle - Don't repeat yourself
- SOLID principles - Follow SOLID design
- Protocol-oriented - Favor protocols over concrete types
Example:
// ✅ Good
public protocol IDispatchQueueFactory {
func main() -> IDispatchQueue
func global(qos: DispatchQoS.QoSClass) -> IDispatchQueue
}
public final class DispatchQueueFactory: IDispatchQueueFactory {
public init() {}
public func main() -> IDispatchQueue {
DispatchQueue.main
}
public func global(qos: DispatchQoS.QoSClass) -> IDispatchQueue {
DispatchQueue.global(qos: qos)
}
}
// ❌ Bad
public class QueueFactory {
func getQueue(type: String, qos: Int?) -> Any {
if type == "main" {
return DispatchQueue.main
}
return DispatchQueue.global(qos: DispatchQoS.QoSClass(rawValue: qos!)!)
}
}All code changes must include tests:
- Unit tests - Test individual components
- Integration tests - Test component interactions
- Test double verification - Ensure TestConcurrency works correctly
- Edge cases - Test boundary conditions
- Thread safety - Test concurrent access patterns
Coverage requirements:
- New code: minimum 80% coverage
- Modified code: maintain or improve existing coverage
- Critical paths: 100% coverage
Test structure:
import XCTest
@testable import Concurrency
final class DispatchQueueFactoryTests: XCTestCase {
var sut: DispatchQueueFactory!
override func setUp() {
super.setUp()
sut = DispatchQueueFactory()
}
override func tearDown() {
sut = nil
super.tearDown()
}
// MARK: - Main Queue Tests
func test_thatMainReturnsMainQueue_whenCalled() {
// When
let queue = sut.main()
// Then
XCTAssertTrue(queue is DispatchQueue)
}
// MARK: - Global Queue Tests
func test_thatGlobalReturnsQueueWithCorrectQoS_whenUserInitiatedQoSProvided() {
// When
let queue = sut.global(qos: .userInitiated)
// Then
XCTAssertTrue(queue is DispatchQueue)
}
// MARK: - Private Queue Tests
func test_thatPrivateQueueCreatesSerialQueue_whenSerialAttributesProvided() {
// Given
let label = "com.test.serial"
// When
let queue = sut.privateQueue(
label: label,
qos: .default,
attributes: [],
autoreleaseFrequency: .inherit,
target: nil
)
// Then
XCTAssertTrue(queue is DispatchQueue)
}
func test_thatPrivateQueueCreatesConcurrentQueue_whenConcurrentAttributesProvided() {
// Given
let label = "com.test.concurrent"
// When
let queue = sut.privateQueue(
label: label,
qos: .default,
attributes: .concurrent,
autoreleaseFrequency: .inherit,
target: nil
)
// Then
XCTAssertTrue(queue is DispatchQueue)
}
}- Discussions - Join GitHub Discussions
- Issues - Track open issues
- Pull Requests - Review open PRs
Contributors are recognized in:
- GitHub contributors page
- Release notes
- Project README (for significant contributions)
- Check existing issues
- Search discussions
- Ask in Q&A discussions
- Email the maintainer: nv3212@gmail.com
Thank you for contributing to Concurrency! 🎉
Your efforts help make this project better for everyone.