-
Notifications
You must be signed in to change notification settings - Fork 40
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
API/UI Layout and Refactor #8
base: master
Are you sure you want to change the base?
Conversation
Wow! First off, thank you for the thoughtful PR and changes :) I'm busy with $work at the moment, so it will be about a week before I get around to doing a proper PR review. For now, a few high-level comments -
Thanks again for taking the time to assess the current state and design helpful changes! I'll give you detailed feedback on the diff & get this merged as soon as I can context-switch to github code :) |
This project was useful to me for getting access to some files. I saw some opportunities here and thought I'd try to see what I could do and give back. I wouldn't make any feature changes without talking to you first. However, these changes set the stage for coordinating future modifications. Before merging into your Next up, I can put together a GitHub Action that will run fmt, vet, unit tests, build, etc to help validate pull requests. Then after that, start building unit tests bit by bit and as new code is modified or extracted. For example, I already have unit tests that cover all the I agree with most of your bullet points, but the last one (modules) is more of a question that I'll try to answer. Even internally, having a project separated into packages is a good thing. It gives a separation of concerns and coordinates an internal contract between chunks of functionality. For example, setting up the internal Zip packages gives us a single entry point contract to the zip functionality. We can swap out the code behind that and as long as the API signature never changes, any other code that uses it would never know. Yes, you can also do that with a straight function as you have done, but a package truly locks things down so a user can't get at anything internal while providing you more flexibility in that package (package globals, introducing classes, etc). The package For this project's internal use. Suppose you like your current command line interface and want to keep things as is for this CLI executable. But one day you decide you'd like to create a GUI for the functionality using something like Fyne. You could split the cmd directory to contain a For external use. Suppose I'm a random user that has a need for a program like this. I find it here on GitHub, download and run it. It's exactly what I need except I need to hand it to a user where running it from the command line is challenging enough, but throw in all those awesome CLI options and mind blown. But because you've exported your core functionality as a package, I can solve the problem. I spin up a new project. Hardcode all the options to force serving from port 80 and to serve that user's Another external example. I like the executable and it's useful. However, the executable only allows listening on a single endpoint. I want something that listens on both http port 80 and https port 443. By spinning up my own project and using yours as an API, I can code something to do that. I can launch Hopefully this helps you if you still have questions or concerns, then ask away. If you really don't want to export this as an API, we should move it to the I know I'm suddenly barging into this project. Thanks for being ok with it so far. I like that it strikes a balance between useful functionality and bloat. And that I can spot some areas to contribute. |
There are some pretty large changes to the code with this PR, so I can understand why you may not accept them. This project is getting large enough that all the code should not be in a
main
package anymore. These changes set the stage for easier code maintenance and eventual unit tests.I’ve only tested using the examples from the
README
. Maybe these changes will help open up the code for unit tests for us to make changes and feel more confident in them.To summarize these changes:
-
) from the package name as ingo.mod
. These dashes make it impossible to use the package (not allowed in package declarations). Eventually the project name should be changed if other projects wish to import this API.cmd/
directory for the UI code. This code handles command line options and environment variables, passing them to the API code that shouldn’t be bothered with these things.makefile
to handle this change above changeinternal/
directoryroutes/
targz/
zip/
httpfileserver.Config
struct for now, populating the struct in the UI and passing it into the API. With this change almost all global variables have been removed and the configuration is injected via parameter.version
variable for injection with logging at startup.Refactor to remove the
init
function which is nowconfigureRuntime
.init
isn’t really unit testable.<meta name="google" content="notranslate"/>
to the HTML template to prevent this.Having the code divided into these smaller packages with a UI/API separation makes it much more approachable by other contributors and unit tests could add another level of safety net for them. I’ve intentionally left much of the internal code and logic as is to keep this PR mainly as a repository layout change so if I’ve introduced defects, they can be more easily spotted.
I’ve noted there are no external dependencies - it’s a full standard library implementation. Is this intended, or are you open to using other packages such as
spf13/cobra
for the CLI,uber/zap
for loggingmholt/archiver
for archive generation, etc?There are no unit tests and no continuous integration (CI) as in GitHub Actions. Are you interested in having things such as lint, vet, fmt, etc run against the code on pull requests as well as adding unit test code?
Realize that by accepting this PR and then renaming your project to remove the dashes, you are making it easy for other projects to use the API code as an external package. This has “contract” implications that your exported functions (
NewConfig()
,Serve()
and to an extent, the exportedConfig
struct) in that changing the interface in the future is a breaking change, and the major version should be incremented each time this is done. I’ve tried to prevent this from happening by including acontext.Context
as the first parameter toServer()
and placing all the config values into theConfig
struct. While removing a field from that struct would break the contract, adding a field would not as long as it is safely defaulted in the API code. I’ve made an attempt to be more flexible here by providing aNewConfig()
function that can contain defaults in the future. Populating the defaults make using the API easier for the first time user. For example, the code:is enough to get the file server up and running since the proper fields are populated by
NewConfig()
.Another option is to move the code files
httpfileserver.go
andserver.go
into a directory and package ininternal/
so it is no longer exported to other projects. Once you feel things have stabilized, move them back out into the project root directory at which point your initial contract is set. I didn’t include this change in the PR because I felt this PR would be more off-putting than it already is. I can make this change and add it to the PR if that’s desirable.Even if you don’t accept this PR, let me know your thoughts. I enjoyed the refactoring challenges anyway.