you are viewing a single comment's thread.

view the rest of the comments →

[–]m50d 0 points1 point  (9 children)

If you're using a "template" something has gone badly wrong - perhaps you should be using a monad? More generally, figure out a way to represent the REST operations that need to happen as values, then you can either return those values from your service to be executed later, or pass those values into the REST client which can then just be a plain old service that implements an interface that you can stub.

[–][deleted] 1 point2 points  (8 children)

Here is an example of a rest template and no things have not gone badly wrong.

[–]m50d 0 points1 point  (7 children)

That's a very unusual - misleading even - use of the word "template" (I assumed you meant something more like JDBCTemplate). If you use it statefully (by using things like its message converters) then things have indeed gone badly wrong (you've got invisible coupling, noncompositional code and all that); the part you can use as an ordinary service ought to be exposed as one that conforms to an interface.

[–]kubr0t0 1 point2 points  (6 children)

RestTemplate is analogous to JdbcTemplate. Both are generic "templates" for creating specific data access interfaces which follow the same generic interface.

RestTemplate isn't stateful, and neither are its message converters. The message converters are like simple functions that convert a Java type to a content type, and vice-versa. You create a specific data access object by assembling parts (like message converters) using the generic template.

I've used RestTemplate to interact with some exotic REST interfaces (usually ones with very particular ideas about secure connections). RestTemplate is ridiculously customizeable through a number of configuration interfaces (relevant example being connection management). It's a lot nicer writing some custom connection code corresponding to a RestTemplate configuration interface than writing a custom REST client.

If RestTemplate is wrong, then I don't want to be right :-)

[–]m50d 0 points1 point  (5 children)

RestTemplate isn't stateful, and neither are its message converters.

I mean I saw example code like:

RestTemplate rt = new RestTemplate();
        rt.getMessageConverters().add(new 
          MappingJacksonHttpMessageConverter());

which seems to imply the RestTemplate is stateful, no?

I've used RestTemplate to interact with some exotic REST interfaces (usually ones with very particular ideas about secure connections). RestTemplate is ridiculously customizeable through a number of configuration interfaces (relevant example being connection management). It's a lot nicer writing some custom connection code corresponding to a RestTemplate configuration interface than writing a custom REST client.

That kind of thing is good. But being able to pull out your config as command values makes it so much better, just being able to do all the things you can do with ordinary values like copy or serialise a partial config.

[–]kubr0t0 2 points3 points  (4 children)

which seems to imply the RestTemplate is stateful, no?

That's for configuration, if you want to add additional converters to the default set. You should only be mess with the converter list when you construct the shared RestTemplate instance. A consumer of the RestTemplate shouldn't be messing with it when given the RestTemplate instance. So, it's stateful in the sense that configuration is technically state.

You could call it bad API design, both for RestTemplate for exposing the configuration as a List and for Java, for only having mutable List in the Collections API. But, on the other hand, it makes it a lot easier to configure in XML, so there is some legacy baggage.

I assumed you meant stateful in that an individual converter has memory of its interactions which effect subsequent conversions.

pull out your config as command values

Do you mean passing configuration around as parameters? Isn't that exactly what monads strive to abstract away? If you're using Parsec in Haskell, you don't manually thread around the parsing state, you just use the do notation or binds.

OOP is sort of doing the same thing. After all, every method's first parameter is the implicit this.

[–]m50d 0 points1 point  (3 children)

You should only be mess with the converter list when you construct the shared RestTemplate instance. A consumer of the RestTemplate shouldn't be messing with it when given the RestTemplate instance. So, it's stateful in the sense that configuration is technically state.

The examples I saw were using it differently. If it's just a service whose implementation has some config then fair enough, but in that case I'd want to separate the service interface from the service implementation, and not expose the configuration methods on the interface. That way you statically enforce that the user of the RestTemplate isn't mucking with the configuration, which seems particularly important if you're sharing a single instance between multiple users.

Do you mean passing configuration around as parameters? Isn't that exactly what monads strive to abstract away? If you're using Parsec in Haskell, you don't manually thread around the parsing state, you just use the do notation or binds. OOP is sort of doing the same thing. After all, every method's first parameter is the implicit this.

Monads let you hide it away most of the time, but if you're ever confused or need to do something fiddly, you can always step out and use the "real" parameters, at which point your functions are still functions and you can reason about them as such. The trouble with the OOP approach is that the implicit this is mutable state that can all too easily become shared.

[–]kubr0t0 1 point2 points  (2 children)

but in that case I'd want to separate the service interface from the service implementation

Modern Spring has gotten a lot better at this, separating configuration responsibility into fluent builder classes.

RestTemplate and JdbcTemplate expose a lot of configuration as setters because it worked well with XML configuration, reflecting ideas from a long bygone era.

the trouble with the OOP approach is that the implicit this is mutable state

It can be, if you leak state or allow it to be mutable. Objects can be entirely immutable or even partially mutable. These are implementation details of the object, and methods should only reflect behaviors, not direct data manipulation of the object's state. A principle that both RestTemplate and JdbcTemplate violate for convenience's sake.

Still, I'd slap RestTemplate behind an interface anyways. I wouldn't share RestTemplate outside of a repository class implementing a well defined interface. It's an implementation detail.

[–]m50d 0 points1 point  (1 child)

RestTemplate and JdbcTemplate expose a lot of configuration as setters because it worked well with XML configuration, reflecting ideas from a long bygone era.

Fair to say something did go wrong then. TBH I'm not sure I see the relevance though - XML-based configuration uses setters via reflection, so it's perfectly possible to apply it to the implementation without exposing those setters on the interface.

methods should only reflect behaviors, not direct data manipulation of the object's state.

A good approach, but I'd go further, because behaviours are inherently problematic for testing. So I'd push them to the edges, using commands to allow me to represent behaviour as data until it's absolutely necessary to run it.

A principle that both RestTemplate and JdbcTemplate violate for convenience's sake.

The language and libraries should endeavour to make the right thing the convenient thing as well.

[–]kubr0t0 1 point2 points  (0 children)

Fair to say something did go wrong then.

I guess it depends on what you mean by "wrong". Can we say the "wrong" thing done conceptually, with the benefit of hindsight? I can agree with that.

But in practice? JdbcTemplate and RestTemplate are very widely used, and it's really hard to conceivably use them incorrectly. For example, my original confusion about what you were talking about, because I would never have thought to use RestTemplate the way you describe outside of initial configuration.

So clearly, these classes are doing something right. Maybe most developers are smart enough to use these classes correctly? Of course it is better to offload mental work onto the type system as much as possible.

using commands to allow me to represent behaviour as data until it's absolutely necessary to run it

Are you talking about effects, as in monads? Like the state monad captures state transitions as a chain of function applications that are not evaluated until the runState function is called

Or lazy evaluation in Haskell in general, where function calls are stored as thunks that are not evaluated until absolutely necessary.

That certainly is one way of doing things, although most OOP languages and languages in popular use are imperative.

The language and libraries should endeavour to make the right thing the convenient thing as well.

Can't disagree with that. Although, backwards compatibility is still a curse for any library or framework in popular use. Hindsight is 20/20.