[GH-ISSUE #1407] Package naming is too generic for a library #1110

Closed
opened 2026-05-05 12:42:51 -06:00 by gitea-mirror · 6 comments
Owner

Originally created by @velovix on GitHub (Aug 24, 2019).
Original GitHub issue: https://github.com/fatedier/frp/issues/1407

Package names like server, client, and config make a lot of sense for internal development of FRP, but are too generic when FRP is used as a library in another system. When reading non-FRP code, it's not clear that these names are related to FRP.

To address this, a new package could be created, maybe named frp, where all interfaces intended to be used as a library are stored. Code could be migrated to this new package or we could use type aliases, like this:

package frp

import (
    "github.com/fatedier/frp/server"
    "github.com/fatedier/frp/client"
    "github.com/fatedier/frp/models/config"
)

type Server = server.Service
type ServerCommonConf = config.ServerCommonConf

func NewServer(cfg ServerCommonConf) (*Server, error) {
    return server.NewService(cfg)
}

type Client = client.Service
type ClientCommonConf = config.ClientCommonConf
type ProxyConf = config.ProxyConf
type VisitorConf = config.VisitorConf

func NewClient(cfg ClientCommonConfig, pxyCfgs map[string]ProxyConf, visitorCfgs map[string]config.VisitorConf, cfgFile string) (*Client, error) {
    return client.NewService(cfg)
}

This would give us a lot of control over which APIs should be exposed for library usage and which should not, and would lead to less ambiguous naming for users. Compare server.Service to frp.Server.

I'm not sure whether type aliasing or code migration is more preferable. My first impression is that I would rather migrate the code as I think it would lead to more code clarity. Internal types like server.Control would stay where they are, as I don't think there's any reason why a library user would need them.

If this or an alternative proposal that addresses the same problem looks good, I would be happy to send a pull request.

Originally created by @velovix on GitHub (Aug 24, 2019). Original GitHub issue: https://github.com/fatedier/frp/issues/1407 Package names like `server`, `client`, and `config` make a lot of sense for internal development of FRP, but are too generic when FRP is used as a library in another system. When reading non-FRP code, it's not clear that these names are related to FRP. To address this, a new package could be created, maybe named `frp`, where all interfaces intended to be used as a library are stored. Code could be migrated to this new package or we could use type aliases, like this: ```go package frp import ( "github.com/fatedier/frp/server" "github.com/fatedier/frp/client" "github.com/fatedier/frp/models/config" ) type Server = server.Service type ServerCommonConf = config.ServerCommonConf func NewServer(cfg ServerCommonConf) (*Server, error) { return server.NewService(cfg) } type Client = client.Service type ClientCommonConf = config.ClientCommonConf type ProxyConf = config.ProxyConf type VisitorConf = config.VisitorConf func NewClient(cfg ClientCommonConfig, pxyCfgs map[string]ProxyConf, visitorCfgs map[string]config.VisitorConf, cfgFile string) (*Client, error) { return client.NewService(cfg) } ``` This would give us a lot of control over which APIs should be exposed for library usage and which should not, and would lead to less ambiguous naming for users. Compare `server.Service` to `frp.Server`. I'm not sure whether type aliasing or code migration is more preferable. My first impression is that I would rather migrate the code as I think it would lead to more code clarity. Internal types like `server.Control` would stay where they are, as I don't think there's any reason why a library user would need them. If this or an alternative proposal that addresses the same problem looks good, I would be happy to send a pull request.
Author
Owner

@fatedier commented on GitHub (Aug 25, 2019):

I think it's common to import github.com/fatedier/frp/server and call server.NewService
or import github.com/fatedier/frp/client and call client.NewService

frp is included in the import path, you know it when you import this package.

You can also change import path to this format:

import (
    frps "github.com/fatedier/frp/server"
    frpc "github.com/fatedier/frp/client"
)

So it looks like frps.NewService and frpc.NewService

I prefer not to affect current code structure.

<!-- gh-comment-id:524597117 --> @fatedier commented on GitHub (Aug 25, 2019): I think it's common to import `github.com/fatedier/frp/server` and call `server.NewService` or import `github.com/fatedier/frp/client` and call `client.NewService`。 `frp` is included in the import path, you know it when you import this package. You can also change import path to this format: ```golang import ( frps "github.com/fatedier/frp/server" frpc "github.com/fatedier/frp/client" ) ``` So it looks like `frps.NewService` and `frpc.NewService`。 I prefer not to affect current code structure.
Author
Owner

@velovix commented on GitHub (Aug 26, 2019):

frp is included in the import path, you know it when you import this package.

That's true, but it requires that you look at the import path to find out what server or client we're talking about in code, which seems like an ergonomics problem to me.

As an example, the standard library uses the package name net/http, so users type http.Client and http.Server. What makes net/http unique isn't that it provides a server and client, lots of packages do that. What makes it unique is that it offers HTTP implementations of network concepts. I think the same reasoning holds for FRP.

I also think that these names don't fit with this guideline from the Package Names blog post:

Don't steal good names from the user. Avoid giving a package a name that is commonly used in client code. For example, the buffered I/O package is called bufio, not buf, since buf is a good variable name for a buffer.

You can also change import path to this format:

This is a decent solution, and the one I will probably use if the current package naming scheme stays the way it is.

I prefer not to affect current code structure.

I respect that, and I understand that FRP is a tool first and a library second. I'm hoping that the aliasing solution would be a reasonable middle ground, because it allows for current code structure to remain the same while exposing a select group of APIs in a way that's more consumable as a library.

<!-- gh-comment-id:524959094 --> @velovix commented on GitHub (Aug 26, 2019): > `frp` is included in the import path, you know it when you import this package. That's true, but it requires that you look at the import path to find out what server or client we're talking about in code, which seems like an ergonomics problem to me. As an example, the standard library uses the package name `net/http`, so users type `http.Client` and `http.Server`. What makes `net/http` unique isn't that it provides a server and client, lots of packages do that. What makes it unique is that it offers HTTP implementations of network concepts. I think the same reasoning holds for FRP. I also think that these names don't fit with this guideline from the [Package Names blog post](https://blog.golang.org/package-names): > Don't steal good names from the user. Avoid giving a package a name that is commonly used in client code. For example, the buffered I/O package is called bufio, not buf, since buf is a good variable name for a buffer. > You can also change import path to this format: This is a decent solution, and the one I will probably use if the current package naming scheme stays the way it is. > I prefer not to affect current code structure. I respect that, and I understand that FRP is a tool first and a library second. I'm hoping that the aliasing solution would be a reasonable middle ground, because it allows for current code structure to remain the same while exposing a select group of APIs in a way that's more consumable as a library.
Author
Owner

@fatedier commented on GitHub (Aug 27, 2019):

OK. Maybe we can create a new package sdk/frp with client.go, server.go and config.go.

Type alias and nested structs are all optional.

<!-- gh-comment-id:525117944 --> @fatedier commented on GitHub (Aug 27, 2019): OK. Maybe we can create a new package `sdk/frp` with `client.go`, `server.go` and `config.go`. Type alias and nested structs are all optional.
Author
Owner

@velovix commented on GitHub (Oct 28, 2019):

Unfortunately, we're no longer using FRP, so I don't have a good use-case to work on these kinds of issues anymore. Please feel free to close this issue if you don't foresee anybody else wanting to use FRP as a library.

<!-- gh-comment-id:547086677 --> @velovix commented on GitHub (Oct 28, 2019): Unfortunately, we're no longer using FRP, so I don't have a good use-case to work on these kinds of issues anymore. Please feel free to close this issue if you don't foresee anybody else wanting to use FRP as a library.
Author
Owner

@fatedier commented on GitHub (Oct 29, 2019):

Just keep it open, it may help other peoples with same requirement.

Thanks for all your contribution.

<!-- gh-comment-id:547234394 --> @fatedier commented on GitHub (Oct 29, 2019): Just keep it open, it may help other peoples with same requirement. Thanks for all your contribution.
Author
Owner

@0x76long commented on GitHub (Aug 4, 2021):

支持 go mod 模式引入吗

<!-- gh-comment-id:892327733 --> @0x76long commented on GitHub (Aug 4, 2021): 支持 go mod 模式引入吗
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: github-starred/frp#1110
No description provided.