Skip to main content
added 2 characters in body
Source Link
G. Sliepen
  • 69.3k
  • 3
  • 75
  • 180

Named parameters are less extensible

The named parameters approach looks nice, as it is a language feature. However, it requires C++20, only works on aggregates, and if you ever want to add more members to SSLctxInit you will break the ABI. I would therefore give a preference to the builder pattern in this case, which can avoid all these issues.

Simplify the builder pattern

You can simplify the builder pattern a little bit. Instead of having a builder object that build()s an SSLctx, I would just have an object representing a set of context parameters that can be modified, and then pass that to the constructor of SSLctx. So in the end you would write:

SSLctx ctx(SSLctxInit(SSLMethodType::Server)
           .setProtocolInfo({TLS_1_0, TLS_1_2})
           .addCertifcateAuthorityFiles("path1", "path2", "path3")
           .addDefaultCertifcateAuthorityDir()
);

Actually, SSLctxInit can still be an aggregate struct, so you could support both the builder pattern and named parameters this way.

Alternatives

I see that in OpenSSL's own API, SSL_CTX_new() only needs the method type, you set other parameters later. So you can mirror that in your interface, and let SSLctx itself implement the builder pattern:

auto ctx = SSLctx(SSLMethodType::Server)
           .setProtocolInfo({TLS_1_0, TLS_1_2})
           .addCertifcateAuthorityFiles("path1", "path2", "path3")
           .addDefaultCertifcateAuthorityDir();

Another completely different possibility is to have a variadic constructor, where you can pass whatever information you want in arbitrary order:

class SSLctx
{
    …
    template<typename Param...> Params>
    SSLctx(SSLMethodType methodType, Param&&Params&&... params);
    …
};

And then use it like so:

SSLctx ctx(SSLMethodType::Server,
           ProtocolInfo(TLS_1_0, TLS_1_2),
           CertifcateAuthorityDataInfo<File>CertifcateAuthorityFiles("path1", "path2", "path3"),
           DefaultCertificateAuthorityDir()
);

Named parameters are less extensible

The named parameters approach looks nice, as it is a language feature. However, it requires C++20, only works on aggregates, and if you ever want to add more members to SSLctxInit you will break the ABI. I would therefore give a preference to the builder pattern in this case, which can avoid all these issues.

Simplify the builder pattern

You can simplify the builder pattern a little bit. Instead of having a builder object that build()s an SSLctx, I would just have an object representing a set of context parameters that can be modified, and then pass that to the constructor of SSLctx. So in the end you would write:

SSLctx ctx(SSLctxInit(SSLMethodType::Server)
           .setProtocolInfo({TLS_1_0, TLS_1_2})
           .addCertifcateAuthorityFiles("path1", "path2", "path3")
           .addDefaultCertifcateAuthorityDir()
);

Actually, SSLctxInit can still be an aggregate struct, so you could support both the builder pattern and named parameters this way.

Alternatives

I see that in OpenSSL's own API, SSL_CTX_new() only needs the method type, you set other parameters later. So you can mirror that in your interface, and let SSLctx itself implement the builder pattern:

auto ctx = SSLctx(SSLMethodType::Server)
           .setProtocolInfo({TLS_1_0, TLS_1_2})
           .addCertifcateAuthorityFiles("path1", "path2", "path3")
           .addDefaultCertifcateAuthorityDir();

Another completely different possibility is to have a variadic constructor, where you can pass whatever information you want in arbitrary order:

class SSLctx
{
    …
    template<typename Param...>
    SSLctx(SSLMethodType methodType, Param&&... params);
    …
};

And then use it like so:

SSLctx ctx(SSLMethodType::Server,
           ProtocolInfo(TLS_1_0, TLS_1_2),
           CertifcateAuthorityDataInfo<File>("path1", "path2", "path3"),
           DefaultCertificateAuthorityDir()
);

Named parameters are less extensible

The named parameters approach looks nice, as it is a language feature. However, it requires C++20, only works on aggregates, and if you ever want to add more members to SSLctxInit you will break the ABI. I would therefore give a preference to the builder pattern in this case, which can avoid all these issues.

Simplify the builder pattern

You can simplify the builder pattern a little bit. Instead of having a builder object that build()s an SSLctx, I would just have an object representing a set of context parameters that can be modified, and then pass that to the constructor of SSLctx. So in the end you would write:

SSLctx ctx(SSLctxInit(SSLMethodType::Server)
           .setProtocolInfo({TLS_1_0, TLS_1_2})
           .addCertifcateAuthorityFiles("path1", "path2", "path3")
           .addDefaultCertifcateAuthorityDir()
);

Actually, SSLctxInit can still be an aggregate struct, so you could support both the builder pattern and named parameters this way.

Alternatives

I see that in OpenSSL's own API, SSL_CTX_new() only needs the method type, you set other parameters later. So you can mirror that in your interface, and let SSLctx itself implement the builder pattern:

auto ctx = SSLctx(SSLMethodType::Server)
           .setProtocolInfo({TLS_1_0, TLS_1_2})
           .addCertifcateAuthorityFiles("path1", "path2", "path3")
           .addDefaultCertifcateAuthorityDir();

Another completely different possibility is to have a variadic constructor, where you can pass whatever information you want in arbitrary order:

class SSLctx
{
    …
    template<typename... Params>
    SSLctx(SSLMethodType methodType, Params&&... params);
    …
};

And then use it like so:

SSLctx ctx(SSLMethodType::Server,
           ProtocolInfo(TLS_1_0, TLS_1_2),
           CertifcateAuthorityFiles("path1", "path2", "path3"),
           DefaultCertificateAuthorityDir()
);
Source Link
G. Sliepen
  • 69.3k
  • 3
  • 75
  • 180

Named parameters are less extensible

The named parameters approach looks nice, as it is a language feature. However, it requires C++20, only works on aggregates, and if you ever want to add more members to SSLctxInit you will break the ABI. I would therefore give a preference to the builder pattern in this case, which can avoid all these issues.

Simplify the builder pattern

You can simplify the builder pattern a little bit. Instead of having a builder object that build()s an SSLctx, I would just have an object representing a set of context parameters that can be modified, and then pass that to the constructor of SSLctx. So in the end you would write:

SSLctx ctx(SSLctxInit(SSLMethodType::Server)
           .setProtocolInfo({TLS_1_0, TLS_1_2})
           .addCertifcateAuthorityFiles("path1", "path2", "path3")
           .addDefaultCertifcateAuthorityDir()
);

Actually, SSLctxInit can still be an aggregate struct, so you could support both the builder pattern and named parameters this way.

Alternatives

I see that in OpenSSL's own API, SSL_CTX_new() only needs the method type, you set other parameters later. So you can mirror that in your interface, and let SSLctx itself implement the builder pattern:

auto ctx = SSLctx(SSLMethodType::Server)
           .setProtocolInfo({TLS_1_0, TLS_1_2})
           .addCertifcateAuthorityFiles("path1", "path2", "path3")
           .addDefaultCertifcateAuthorityDir();

Another completely different possibility is to have a variadic constructor, where you can pass whatever information you want in arbitrary order:

class SSLctx
{
    …
    template<typename Param...>
    SSLctx(SSLMethodType methodType, Param&&... params);
    …
};

And then use it like so:

SSLctx ctx(SSLMethodType::Server,
           ProtocolInfo(TLS_1_0, TLS_1_2),
           CertifcateAuthorityDataInfo<File>("path1", "path2", "path3"),
           DefaultCertificateAuthorityDir()
);