-
-
Notifications
You must be signed in to change notification settings - Fork 486
Clean code improvements #3107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Clean code improvements #3107
Conversation
""" WalkthroughThis update refactors several internal types from exported to unexported, renames various mock and implementation structs for clarity, and adjusts function signatures to return concrete types instead of interfaces. It also improves test robustness by enforcing stricter error handling and updates comments for consistency. Minor Dockerfile and logging changes are included. Changes
Sequence Diagram(s)sequenceDiagram
participant Main
participant Config
participant Database
participant Server
Main->>Config: newConfiguration()
Main->>Database: NewDatabase(ctx, databaseURL)
Database->>Database: Return *DB (wraps concrete Database)
Main->>Server: NewServer(dataSources)
Server->>Server: Register routes and handlers
Main->>Server: app.Listen()
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Tip ⚡️ Faster reviews with caching
Enjoy the performance boost—your workflow just got faster. 📜 Recent review detailsConfiguration used: CodeRabbit UI ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
clean-code/app/datasources/database/memory_db.go (1)
8-8
: Consider whether initial capacity is needed.The capacity hint was removed from the slice initialization. While this isn't a functional issue, if you expect the
records
slice to grow to a known size, providing an initial capacity can be more efficient by reducing reallocations.- records: make([]Book, 0), + records: make([]Book, 0, 10),clean-code/app/config_test.go (1)
29-29
: Consider removing unnecessary deferred cleanupSince
t.Setenv()
on line 28 already handles the cleanup automatically, thisdefer os.Unsetenv("TEST_ENV")
is redundant and can be removed.- defer os.Unsetenv("TEST_ENV")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
clean-code/app/go.mod
is excluded by!**/*.mod
clean-code/app/go.sum
is excluded by!**/*.sum
,!**/*.sum
📒 Files selected for processing (21)
clean-code/Dockerfile-local
(1 hunks)clean-code/app/config.go
(1 hunks)clean-code/app/config_test.go
(1 hunks)clean-code/app/datasources/data_sources.go
(1 hunks)clean-code/app/datasources/database/db.go
(2 hunks)clean-code/app/datasources/database/db_mock.go
(1 hunks)clean-code/app/datasources/database/db_test.go
(1 hunks)clean-code/app/datasources/database/memory_db.go
(1 hunks)clean-code/app/datasources/database/memory_db_test.go
(1 hunks)clean-code/app/datasources/database/postgres_db.go
(4 hunks)clean-code/app/datasources/database/postgres_db_test.go
(5 hunks)clean-code/app/main.go
(1 hunks)clean-code/app/server/domain/books.go
(1 hunks)clean-code/app/server/domain/errors.go
(1 hunks)clean-code/app/server/handlers/books.go
(2 hunks)clean-code/app/server/handlers/books_test.go
(1 hunks)clean-code/app/server/server.go
(1 hunks)clean-code/app/server/server_test.go
(1 hunks)clean-code/app/server/services/books.go
(2 hunks)clean-code/app/server/services/books_mock.go
(1 hunks)clean-code/app/server/services/books_test.go
(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
clean-code/app/datasources/database/memory_db.go (2)
Learnt from: norri
PR: gofiber/recipes#2701
File: clean-code/app/datasources/database/memory_db.go:18-20
Timestamp: 2024-11-25T19:31:36.658Z
Learning: In `clean-code/app/datasources/database/memory_db.go`, the `memoryDB` implementation is intended as an example and not for production use.
Learnt from: norri
PR: gofiber/recipes#2701
File: clean-code/app/datasources/database/memory_db.go:0-0
Timestamp: 2024-11-25T19:31:39.216Z
Learning: The `memoryDB` implementation in `clean-code/app/datasources/database/memory_db.go` is not intended for production use, so input validation, concurrency protection, and context usage are not required in this file.
🧬 Code Graph Analysis (8)
clean-code/app/datasources/database/db_test.go (1)
clean-code/app/datasources/database/db.go (3)
NewDatabase
(38-55)Book
(14-17)NewBook
(20-22)
clean-code/app/datasources/database/postgres_db_test.go (1)
clean-code/app/datasources/database/db.go (1)
NewBook
(20-22)
clean-code/app/main.go (3)
clean-code/app/datasources/database/db.go (2)
NewDatabase
(38-55)DB
(57-59)clean-code/app/server/server.go (1)
NewServer
(12-23)clean-code/app/datasources/data_sources.go (1)
DataSources
(7-9)
clean-code/app/datasources/database/memory_db.go (1)
clean-code/app/datasources/database/db.go (1)
Book
(14-17)
clean-code/app/server/server.go (1)
clean-code/app/datasources/data_sources.go (1)
DataSources
(7-9)
clean-code/app/datasources/database/memory_db_test.go (1)
clean-code/app/datasources/database/db.go (1)
NewBook
(20-22)
clean-code/app/server/services/books.go (2)
clean-code/app/datasources/database/db.go (2)
Database
(26-35)Book
(14-17)clean-code/app/server/domain/books.go (1)
Book
(4-6)
clean-code/app/datasources/database/db_mock.go (2)
clean-code/app/datasources/database/db.go (2)
Book
(14-17)NewBook
(20-22)clean-code/app/server/domain/books.go (1)
Book
(4-6)
🔇 Additional comments (69)
clean-code/app/server/domain/errors.go (1)
3-3
: Good documentation improvement.Adding the period at the end of the comment improves consistency in the codebase documentation style.
clean-code/app/config.go (3)
8-8
: Improved encapsulation by making configuration unexported.Changing from exported
Configuration
to unexportedconfiguration
is a good practice as it restricts access to this type from outside the package, reducing the public API surface.
13-13
: Appropriate constructor visibility change.Making the constructor unexported (
newConfiguration
) aligns with the unexported type it creates, maintaining consistent encapsulation.
18-18
: Return type updated to match renamed struct.This change correctly updates the return type to match the renamed struct.
clean-code/Dockerfile-local (1)
1-1
:❓ Verification inconclusive
Verify Go version downgrade intention.
The Go version has been downgraded from 1.24 to 1.23.3. While 1.23.3 is a stable release, ensure this downgrade is intentional and compatible with your codebase requirements.
🏁 Script executed:
#!/bin/bash # Check if any Go code in the repo uses features from Go 1.24 that aren't in 1.23 echo "Checking for potential Go 1.24 features that might not be compatible with 1.23.3..." rg -l 'go1\.24' --type go || echo "No explicit Go 1.24 references found" # Check the go.mod file to see the required Go version echo -e "\nChecking go.mod for Go version requirement:" cat app/go.mod | grep -E '^go\s+[0-9]+\.[0-9]+' || echo "No explicit Go version requirement found in go.mod"Length of output: 594
Let’s locate any go.mod files and check the Go version requirement:
🏁 Script executed:
#!/bin/bash echo "Searching for go.mod files..." find . -maxdepth 4 -type f -name 'go.mod' echo -e "\nInspecting Go version line in each go.mod:" while IFS= read -r f; do echo "In $f:" grep -E '^go\s+[0-9]+\.[0-9]+' "$f" || echo " No explicit Go version found" done < <(find . -maxdepth 4 -type f -name 'go.mod')Length of output: 363
Let’s remove the depth limit and search the entire repo for any go.mod and inspect its Go version:
🏁 Script executed:
#!/bin/bash echo "Locating all go.mod files in the repo..." find . -type f -name 'go.mod' -print echo -e "\nChecking Go version in each go.mod:" find . -type f -name 'go.mod' -exec sh -c ' for f; do echo "In $f:" grep -E "^go\s+[0-9]+\.[0-9]+" "$f" || echo " No explicit Go version found" done ' sh {} +Length of output: 388
Verify Go version downgrade is intentional and compatible
It looks like you’ve moved the base image fromgolang:1.24
togolang:1.23.3
. Our checks didn’t find:
- Any
go.mod
files in the repo (so no module‐declared Go version)- Any explicit “go1.24” references in the source
Please confirm that:
- None of your code or dependencies rely on Go 1.24-only features
- All tests and builds still pass under Go 1.23.3
clean-code/app/datasources/data_sources.go (1)
5-6
: Improved documentation clarity.The updated comment adds a period for consistency and a new line explaining the purpose of the
DataSources
struct, which improves code documentation quality.clean-code/app/server/handlers/books.go (3)
12-12
: Good documentation improvement.Adding periods at the end of comments aligns with the consistent documentation style throughout the codebase.
27-27
: Good documentation improvement.Adding periods at the end of comments maintains consistency in the documentation style.
35-35
: Good production reminder comment.This is a useful reminder for future developers that proper validation should be implemented in production code.
clean-code/app/server/domain/books.go (2)
3-3
: Good documentation improvement.Adding periods at the end of comments ensures consistent documentation style.
8-8
: Good documentation improvement.Consistent punctuation in comments improves readability and maintains a standardized style.
clean-code/app/datasources/database/memory_db.go (1)
5-6
: Good return type change for better clarity.Changing the return type from an interface to a concrete type (
*memoryDB
) makes the code more explicit and easier to understand. This follows the "return concrete types, accept interfaces" design principle.clean-code/app/server/server_test.go (7)
5-5
: Good import specificity.Using a specific import for the HTTP methods is a good practice.
12-12
: Good addition of require package.Adding the
require
package allows for better error handling in tests.
16-16
: Clean function call without unnecessary context parameter.Removing the context parameter aligns with the updated
NewServer
function signature, making the code cleaner.
18-18
: Good use of HTTP method constant.Using
http.MethodGet
instead of the string literal"GET"
is more idiomatic Go and improves maintainability.
19-19
: Improved error handling in tests.Using
require.NoError
instead ofassert.Nil
for error checking is better as it fails immediately rather than continuing the test when an error occurs.
21-21
: Good resource management.Adding
defer resp.Body.Close()
ensures proper cleanup of resources, preventing potential resource leaks.
24-24
: Consistent error handling approach.Using
require.NoError
consistently for all error checks in the test maintains a uniform error handling pattern.clean-code/app/main.go (4)
16-16
: Reflects visibility change to the configuration functionThe change from
NewConfiguration()
tonewConfiguration()
aligns with the function being converted from exported to unexported, which follows the principle of minimizing the public API surface.
19-19
: Improved error handling with Panic instead of FatalChanged from
log.Fatalf
tolog.Panicf
which allows deferred functions to run before termination. This ensures proper cleanup operations likedb.CloseConnections()
can execute.
23-23
: Simplified server initialization by removing context parameterThe server initialization no longer requires the context parameter, which aligns with the updated
NewServer
function signature in server.go.
24-24
: Consistent error handling approachChanged from
log.Fatal
tolog.Panic
, maintaining consistency with the error handling approach used on line 19, ensuring deferred functions run before termination.clean-code/app/config_test.go (4)
11-12
: Improved test environment variable handlingUsing
t.Setenv()
instead ofos.Setenv()
is a best practice in Go tests. The testing package automatically resets environment variables to their original values after the test completes, eliminating the need for manual cleanup withdefer os.Unsetenv()
.
14-14
: Updated function call to match unexported implementationChanged from
NewConfiguration()
tonewConfiguration()
to match the visibility change of the function in the implementation.
21-21
: Updated function call to match unexported implementationChanged from
NewConfiguration()
tonewConfiguration()
to match the visibility change of the function in the implementation.
28-28
: Improved test environment variable handlingUsing
t.Setenv()
instead ofos.Setenv()
is a best practice in Go tests. The testing package automatically resets environment variables to their original values after the test completes.clean-code/app/server/server.go (1)
11-12
: Improved API design and documentationThe function signature has been simplified by removing the unnecessary context parameter, and the documentation comment has been improved with proper punctuation. This change demonstrates good API design by only requiring the essential parameters.
clean-code/app/server/services/books_test.go (4)
12-12
: Added testify/require package for stronger assertionsGood addition of the require package which provides assertions that stop test execution immediately if they fail, useful for critical assertions where continuing would be meaningless.
16-16
: Consistent mock naming conventionChanged from
database.DatabaseMock
todatabase.MockDatabase
across all test functions, which follows the more common convention of using "Mock" as a prefix rather than a suffix for mock objects.Also applies to: 26-26, 35-35, 44-44
21-21
: Improved error assertion with require.NoErrorChanged from
assert.Nil(t, err)
torequire.NoError(t, err)
which is more expressive and specifically checks for nil errors. This approach also stops test execution immediately if the assertion fails, which is appropriate when further test execution doesn't make sense without this check passing.Also applies to: 40-40
31-31
: More semantic error checking with assert.ErrorChanged from
assert.NotNil(t, err)
toassert.Error(t, err)
which is more expressive and specifically checks that the error is not nil. This makes the test intent clearer.Also applies to: 49-49
clean-code/app/datasources/database/postgres_db.go (3)
20-20
: Improved function signature to return concrete typeChanging the return type from an interface to the concrete
*postgresDB
type follows the Go idiom "accept interfaces, return structs". This is a good practice as it allows the factory pattern inNewDatabase
to create the appropriate concrete implementation.
24-24
: Proper error wrapping with %wUsing
%w
instead of a plain format string allows the original error to be preserved and later examined witherrors.Is()
orerrors.As()
. This is an important improvement for error handling.
35-35
: Improved documentation consistencyAdding periods at the end of comment sentences improves documentation consistency throughout the codebase. This small change enhances readability and professionalism of the code.
Also applies to: 50-50, 59-59
clean-code/app/datasources/database/postgres_db_test.go (4)
9-9
: Added require package for better test assertionsAdding the
require
package is a good improvement as it will halt test execution when assertions fail, preventing cascading test failures that can be hard to debug.
14-14
: Improved error assertions with require.NoErrorReplacing
assert.Nil(t, err)
withrequire.NoError(t, err)
is a significant improvement that:
- Provides more descriptive error messages
- Stops the test on failure, preventing misleading follow-up errors
- Explicitly checks for errors, making the intent clearer
This change improves test robustness and makes failures easier to debug.
Also applies to: 24-24, 28-28, 33-33, 50-50, 60-60, 67-67, 79-79
25-25
: Clearer length assertionUsing
assert.Len(t, result, 1)
instead ofassert.Equal(t, len(result), 1)
is more descriptive and provides better error messages specific to collection length checks.
43-43
: Stricter error assertions with require.ErrorContainsUsing
require.ErrorContains
instead ofassert.ErrorContains
ensures that the test will fail immediately if the error message doesn't contain the expected text, preventing execution of potentially confusing subsequent assertions.Also applies to: 77-77
clean-code/app/datasources/database/memory_db_test.go (4)
8-8
: Added require package for better test assertionsAdding the
require
package enables stricter assertions that halt test execution upon failure, which is especially important for error checking.
14-14
: Improved error assertions with require.NoErrorReplacing
assert.Nil(t, err)
withrequire.NoError(t, err)
is a good practice that provides more descriptive error messages and stops the test on failure, preventing misleading follow-up errors.Also applies to: 22-22, 25-25, 34-34, 38-38, 41-41
15-15
: Better empty collection assertionUsing
assert.Empty(t, books)
is more semantically clear than checking the length explicitly and provides better error messages specific to empty collections.
26-26
: Clearer length assertionsUsing
assert.Len(t, books, n)
instead of checking collection length with equality assertions provides better readability and more specific error messages when tests fail.Also applies to: 42-42
clean-code/app/datasources/database/db_test.go (5)
9-9
: Added require package for better test assertionsAdding the
require
package enables stricter assertions that halt test execution upon failure, which is particularly important for error checking and consistent with the improvements in other test files.
15-15
: Improved error assertions with require.NoErrorReplacing
assert.Nil(t, err)
withrequire.NoError(t, err)
provides more descriptive error messages and stops the test on failure, making tests more robust.Also applies to: 23-23
16-17
: Updated type assertions to match refactored implementationThe type assertions have been updated to check both the outer wrapper type (
*database.DB
) and the inner implementation type. This correctly reflects the structural changes in theNewDatabase
function that now returns aDB
wrapper with an implementation field.Also applies to: 24-25
31-31
: More precise error message assertionUsing
assert.EqualError
instead ofassert.ErrorContains
provides a more precise check by verifying the exact error message rather than just a substring. This is appropriate when the exact error message is known and stable.
35-35
: Added helper function markerAdding
t.Helper()
to theassertBook
function improves error reporting by making the actual test failure line appear in the error output instead of reporting the line in the helper function. This makes test failures easier to locate and debug.clean-code/app/datasources/database/db_mock.go (3)
9-9
: Improved naming convention for mocksRenaming the struct from
DatabaseMock
toMockDatabase
follows the standard Go convention for mock objects (Mock + TypeName) and improves consistency across the codebase.
13-19
: Enhanced type safety with proper error handlingThe improved implementation safely handles type assertion failures by checking the return value of the type assertion with the
ok
variable. This prevents potential panics if the mock returns an unexpected type.
21-24
: Consistent receiver name updatesThe method receivers have been consistently updated to use the new struct name (
MockDatabase
instead ofDatabaseMock
), maintaining coherence throughout the implementation.Also applies to: 26-27
clean-code/app/server/services/books.go (3)
18-20
: Better naming with DefaultBooksServiceRenaming from
booksService
toDefaultBooksService
clearly indicates this is the standard implementation of the interface, making the code more self-documenting.
22-25
: Return concrete type instead of interfaceChanging the return type from the
BooksService
interface to a concrete*DefaultBooksService
follows Go's best practice of "return concrete types, accept interfaces". This makes the code more explicit about what is being created while still allowing it to be used polymorphically where needed.
27-28
: Consistent method documentationAdding periods at the end of comments and updating receiver names to match the new struct type improves documentation consistency and readability throughout the codebase.
Also applies to: 44-45
clean-code/app/server/services/books_mock.go (3)
11-13
: Standardized mock naming conventionThe struct has been renamed from
BooksServiceMock
toMockBooksService
, following the same convention applied to the database mock. This creates a consistent naming pattern for all mock objects across the codebase.
15-22
: Improved type assertion safetyThe
GetBooks
method now properly handles the case where type assertion fails by explicitly checking theok
value and returning an appropriate error response, preventing potential panics during testing.
24-27
: Consistent receiver name updateThe
SaveBook
method receiver has been updated to use the new struct name, maintaining consistency throughout the implementation.clean-code/app/server/handlers/books_test.go (6)
16-16
: Added require package for better test failuresAdding the
require
package from testify allows for immediate test failure when conditions aren't met, improving test clarity by failing fast rather than continuing execution after an error.
19-19
: Changed variable to constant for immutable valueConverting
booksRoute
from a variable to a constant is appropriate since this value should never change during execution.
22-22
: Updated mock service referencesAll references to the mock service have been updated to use the new type name
MockBooksService
, maintaining consistency with the changes in the mock implementation.Also applies to: 38-39, 54-55, 67-68, 82-83
28-30
: Improved HTTP method references and error handlingReplaced string literals for HTTP methods with constants from the
http
package, and changed error assertions fromassert.Nil
torequire.NoError
. These changes improve code readability and ensure tests fail immediately on errors rather than continuing execution.Also applies to: 44-46, 61-62, 72-74, 89-90, 98-99
31-31
: Added proper resource cleanupAdded
defer resp.Body.Close()
after each HTTP request to ensure resources are properly released, preventing potential resource leaks during testing.Also applies to: 47-48, 63-64, 75-76, 91-92
103-109
: Enhanced helper functionThe
bodyFromResponse
helper function has been improved with:
- A
nolint:ireturn
directive to suppress linter warnings about returning interfacest.Helper()
call to properly attribute test failures to the calling test- Updated error handling with
require.NoError
and a descriptive messageThese changes improve both test output clarity and error reporting.
clean-code/app/datasources/database/db.go (6)
5-5
: Good addition of a sentinel error for better error handlingAdding the
errors
package import and creating theErrUnsupportedDatabase
sentinel error improves error handling by allowing callers to check for specific error types usingerrors.Is()
.Also applies to: 11-11
13-13
: Improved documentation clarityGood improvement on the comments for the
Book
andNewBook
types. Clear documentation helps maintainers understand the purpose of each type.Also applies to: 19-19
37-43
: Good refactoring to use wrapper patternChanging the return type from the
Database
interface to a concrete*DB
type implements the adapter pattern effectively. This provides consistency across different database implementations while preserving the abstraction benefits.The in-memory database implementation is properly wrapped in the new
DB
struct.
45-52
: Consistent implementation of the wrapper pattern for PostgreSQLThe PostgreSQL database implementation follows the same pattern as the in-memory implementation, maintaining consistency. Error handling is comprehensive with descriptive error messages.
54-55
: Improved error handling with proper wrappingUsing
fmt.Errorf
with the%w
verb to wrap the sentinel error allows preservation of the error chain. This is a Go best practice that enables callers to useerrors.Is()
for error type checking.
57-71
: Clean implementation of the adapter patternThe
DB
struct and its implementation of theDatabase
interface methods follow the adapter pattern correctly. Each method simply delegates to the wrapped implementation, ensuring consistent behavior while allowing for different database backends.This approach:
- Maintains interface compliance
- Centralizes any cross-cutting concerns that might be added later
- Provides flexibility to extend functionality without modifying the interface
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks mostly good but i left some hints
@norri
Update dependencies and fix errors found by Golangci-lint
Summary by CodeRabbit