Hacker News new | past | comments | ask | show | jobs | submit login

When I did a bit of Play 1.2 dev, I ran into two serious annoyances.

First, static actions make for untestable code. The only way to test this in 1.2 was to do full integration tests. You can't unit test controllers/actions, which to me is a horrible "opinion" to have. Looking at the docs, 2.0 [appears] to make an attempt via the callAction helper [1], but you still can't inject dependencies via a constructor and call instance methods. Static members in static languages make testing a real pain.

Second, JSON felt like a 2nd-class citizen. Dealing with JSON in either the request or the response felt barbaric. I don't see that they've improved things. Auto binding from a JSON request to an object should exist without having to write a bunch of custom JSON serializers...doubly so for outputting json.

[1] http://www.playframework.org/documentation/2.0/JavaFunctiona...

I can't agree more - I've been doing a non-trivial bit of scala work in the past six months, and the part that seems the most lacking to me is JSON support. Every scala JSON library I've used (spray-json, sbjson, lift-json and the like) requires you to define a concrete serializer class for every single type you would like to move across the wire. I really miss the ease of use of reflection-based parsers like Jackson. I've alleviated a bit of this by writing a generic serializer that uses Jackson under the hood, but that requires every class to use a java bean pattern, and not the more elegant scala case class (or frankly plain old scala object) patterns.

There's a project called Jerkson that is attempting to fix this, but I'd like to see all the major scala frameworks just settle on something good and simple and go from there.

You might want to check out lift-json again. It can easily serialize and deserialize case classes. https://github.com/lift/lift/tree/master/framework/lift-base...

Also, Play 2.0 includes Jerkson, so whatever Jerkson can do, Play 2.0 can do. They just happened to add some helper utilities that made it very similar to lift-json. So I think the community is settling on something good and simple.

I disagree on the fact that JSON is a second-class citizen. A lot of effort went into good support of JSON. But obviously, Scala and Java being statically typed languages, you can't expect to use JSON in those languages like you use them in Javascript.

The reason why everyone encourage you to do so is because typeclass serialization is much more robust that introspection. With introspection you may have runtime exceptions, but with typeclass serialization you know at compile time when something is wrong.

Also, Jerkson is included in Play 2 (that's what we use as base for the Json lib) so you can use it directly if you want introspection.

But if you choose typeclass serialization, you can still define serializers easily, in one line, without losing the type-safety: https://github.com/playframework/Play20/blob/master/framewor...

Jerkson works really well. Can convert JSON into case-classes really nicely and handles snake-types.

I agree about the testing. It is also really annoying that you can't run a test as a "single, isolated test". I read a few articles on Play 2.0 and Scala, but haven't come across any additions on testing. Without decent testing integrated, this framework has no real production use. I agree that it all looks nice and shiny though.

in play 2.0 (using computer-database java sample app):

  $ play
  [computer-database] $ test-only ModelTest

  or from the command line:
  $ play "test-only ModelTest"

Some interesting criticism of Play here - seems similar to what's been said about the lack of unit tests.


Please note, this blog post is related to Play 1.2.X, not 2.0

I don't understand why you would want static methods everywhere in this age of dependency injection everywhere.

Can you elaborate more on the untestable code point, for those of us who've been spending more time on ruby lately? I find play very interesting, but it's great to hear about its warts as well.

This is the first controller I opened from their samples[1] :

  public class Forums extends Application {
    public static void index() {
      List forums = Forum.findAll();
      long topicsCount = Topic.count();
      long postsCount = Post.count();
      render(forums, topicsCount, postsCount);

You can't mock out Forum, Topic or Post. You can't inject some type of "FormRepository" or whatever pattern you want to gain some type of control. In Ruby, or most dynamic languages, this wouldn't be a problem, since a class method can (and should) be mocked. Even if a static language allows for that sort of trickery (for example, there are a couple ways to test the above in C#), it's the wrong approach. Dependencies should be injected and thus controlled. I guess you could inject using static setters, but that's just a bad workaround to what, in my opinion, is a fundamental misunderstanding of how to write testable code.

[1] https://github.com/playframework/play/blob/master/samples-an...

If you wanted to unit test this I'm confident you could do it using JMockit [1] without changing the code. JMockit allows you to mock just about anything (static methods, final methods, constructor invocations). The unit test might look something like:

  public void checkIndexRenders()
    final List expectedforums= new ArrayList(asList(TEST_FORUM)); 
    new NonStrictExpections()
      @Mocked Forum forum;
      @Mocked Topic topic;
      @Mocked Post post;
        Forum.findAll(); result = expectedforums;
        Topic.count(); result = 5;
        Post.count(); result = 10;

    // your assertions ...
I come from a DI background, but the JMockit framework has changed my view of what untestable code is.

[1] http://code.google.com/p/jmockit/

Apologies for the tangent, but is this considered idiomatic Java these days? As a person who knows/knew Java pretty well but has been out of the game for a few years, this code seems highly surprising. Instantiating an anonymous subclass with a static initializer to... I suppose be able to use those @Mocked annotations. Then assigning result in that anonymous initializer block, which I must assume works through black magic.

No criticism of your code example. I think figuring out how to make Java do this is very impressive. I just wonder if it's considered wise to do this sort of thing in production code?

(Edited to correct that I don't think that's a static initializer block.)

Generally this would not be done in production code. jMockit is pretty out there, syntax - wise, and the anonymous inner classes are generally discouraged in production code. In tests are generally fine though. which is why jMockit can get away with it.

What, exactly, is the POINT of unit-testing that function, other than patting yourself on the back? You might as well unit test that 1+1 = 2.

Unit testing isn't really about ensuring correctness.

First and foremost, it's a design tool. Code that can't easily be unit tested is often poorly designed. The most common example in the MVC-world is a fat controller. It's hard to test any method that does too much because of all the setup that you'll have to do. If an action is doing too much, dependent on too many parts, and not very cohesive, you'll feel the pain when you try to test it.

Of course, it's just an indicator...a warning symbol. Some times method need to do a lot...sometimes they do a lot while being cohesive and not having a lot of dependencies. Ultimately, your brain is the judge, a unit test is just a tool to help measure a method's entropy.

Secondly, it's a refactoring tool. Or, put differently, it's about future correctness. Broadly speaking, in this sense, it's also documentation. At a unit test level, this is tricky...and I've struggled with it quite a bit...if you overly concern yourself with internals (using a strict mock), you'll have a brittle test which is largely focused on the current correctness. However, using loose stubs, it really can prevent the introduction of bugs without being overly brittle.

So would the appropriate approach in this case be to create IForum, ITopic and IPost interfaces and, instead of calling findAll() or count() directly on the class, call it on the interface so a class can be injected? Sorry...this is all a bit hazy to me. It's been years since I've had to deal with these sorts of concerns.

Something like that..but then the question is: how do you get the instance in there? Normally through DI (ideally at the constructor level)...but the static method screws that up.

I agree that worrying about this is silly, but such is the life of someone who uses static languages.

What you're complaining about is just the data access which happens to be used in this sample (particularly some convenience methods which aren't even necessary), which you can freely change out with any technology that you please, because it's completely orthogonal to the rest of the framework. The framework has no abstractions over or requirements for the data access framework.

Or without even changing the data access calls you could just put them behind a DAO object, which would have been injected and therefore easily replaced for testing. But that wouldn't have made the sample any clearer.

I use PowerMock with Mockito for this kind of thing.

well, that's for play 1.

This looks pretty much like standard JPA stuff.

I don't think JPA requires or encourages you to use static methods.

Can't you mock out the calls with something like http://code.google.com/p/powermock/? Or introduce an intermediate object? Or use Spring? Or test using groovy which i think you can redefine methods.

"resort to another framework to reach a goal that I expect to be easy"

is a perfectly good reason to state something is a "serious annoyance".

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact