I agree strongly with returning a struct as a best practice. Returning a
single base type is too constraining and hinders interface evolution.

I also agree that it is often a good design to pass structs as params. In
particular, modeling key parts of your interface as message types in Apache
Thrift IDL makes it easy to use those messages over RPC as well as
messaging systems (RabbitMQ, Apache Apollo, ZeroMQ, etc.) and in streaming
scenarios using UDP multicast and other protocols directly. Many overlook
the fact that Apache Thrift is a standalone serialization tool, RPC being
an optional feature.

I have also found Apache Thrift interfaces to be fairly easy to evolve with
base type Args lists. There is an elegance to calling a function with
direct parameters that works nicely in some settings. If you want a
functional interface, this is a pretty natural way to go. While I am not
promoting it, I would not deprecate it either.

A server compiled with func (1: i32 x) will happily accept calls from a
client compiled for func(1: i32 x, 2: i32 y). Unknown arguments (y in this
case) are ignored by servers. This also works the other way around. If a
client calls a server with func(1: i32 x) and the server was built with
func(1: i32 x, 2: i32 y) the server will receive an uninitialized y. This
is ok in dynamically typed languages where the argument can be tested for a
value of “None” or some such. A better solution would be to give the new
parameter a default value, e.g. func(1: i32 x, 2: i32 y=2). This would
cause the server to receive a y of 2 when the client calls with the old
interface. The server could also be defined with the interface func(2: i32
y=2), ignoring x altogether. Apache Thrift Args lists are pretty flexible
really.

Args lists are implemented as struts. So if you pack all of your params in
a struct param, Apache Thrift is going to put that into an Args list struct
anyway. A little redundant. There is no technical reason for Args lists not
to support all struct features. However, today, the parser does not allow
“optional” requiredness function arguments. Optional struct members
certainly have their place, but I often find folks using optional for
things “default” requiredness does better. Default requiredness is simple
(no optional is_set/unset overhead), consistently implemented across
languages (sadly, it is hard to say that about optional at this point) and
quite elegant in its support for interface evolution. Using args lists lets
applications use functions like functions, leaving Apache Thrift to handle
the RPC and interface evolution details. A nice division of labor.

So whether you like to pass struct params or a mix of base types and
structs, I consider it a matter of preference and use case more than
general best practice.


On Thu, Feb 12, 2015 at 1:17 AM, Denis Samoilov <[email protected]> wrote:

> Jens, Edward, thank you very much!
>
> On February 12, 2015 at 12:09:20 AM, Jens Geyer ([email protected])
> wrote:
>
> We also made good experiences with that approach. I just want to add that
> we do the same with retvals - we always return a struct (or void) which has
> several advantages:
> - you can add more data at any time
> - possibility to retire old elements
> - ability to return a null value for a member is legal, returning null as
> function result is not
>
> Have fun,
> JensG
> ________________________________
> Von: Edward Capriolo
> Gesendet: 12.02.2015 04:49
> An: [email protected]
> Betreff: Re: best practices for methods - to wrap arguments into struct or
> not?
>
> Yes, I believe so. Thrift does not support overloaded methods and thus it
> makes the methods in a service hard to evolve. I prefer to send a a single
> struct with all/mostly optional arguments. This way if service methods get
> new parameters the change does not cause a ripple of API breaking changes
> on the client. Otherwise you end up doing something like:
>
> v1
> int method(int x);
>
> v2
> int method(int x);
> int method_v2(int x, int y);
>
>
> I think this cleaner in the long run:
>
>
> v1
> int method( methodStruct);
>
> v2
> int method( methodStruct);
>
> This is because structs have optional members but functions do no. even
> though they are marked optional no language supports them even languages
> that theoretically could support optional arguments like python.
>
>
> On Wed, Feb 11, 2015 at 10:22 PM, Denis Samoilov <[email protected]>
> wrote:
>
> > hello Thrift Community!
> >
> > Is there best practice to wrap function params into struct? like:
> > struct InfoRequest {
> > 1: required bool getActive
> > 2: required i32 logLimit
> > }
> > ClientsInfoList getExtendedClientsInfo(1: InfoRequest params)
> > vs
> > ClientsInfoList getExtendedClientsInfo(1: bool getActive, 2: i32
> logLimit)
> >
> >
> >
> > because this way i can add more optional (with default values) params in
> > future without breaking backward compatibility, like
> > struct InfoRequest {
> > 1: required bool getActive
> > 2: required i32 logLimit
> > 3: optional i32 newParam
> > }
> >
> > Thank you!
> >
>

Reply via email to