Live data from Hacker News

Java call stack – from HTTP upto JDBC as a picture (2006)

ptrthomas.wordpress.com

11–20 of 63 posts

Re: Java call stack – from HTTP upto JDBC as a picture (2006)

#11

The fact that Spring even exists should be a big red flag for the value of static typing. People routinely make mistakes using type systems. And when done correctly I see static type systems work very well solving problems that they themselves created.

How do you get from deeply nested method calls to "people routinely make mistakes using type systems"?

Re: Java call stack – from HTTP upto JDBC as a picture (2006)

#12
I'm not sure I really see the problem. They picked a particularly pathological example, with a lot of heavyweight frameworks. It's a choice.

I just counted the frames from my typical stack, a Guice/Hibernate project. It was about 100 lines from a constraint violation handler in the postgres JDBC driver up to Thread.run(). This seems pretty reasonable, especially with the various layers I've added for authentication, declarative transaction management, AOP logging, etc.

Furthermore, IntelliJ is pretty good about only showing me what I care about. Overall I find the debugging experience no worse than Python or Ruby, and much better than exceptions from Python or Ruby native libraries. It's orders of magnitude better than debugging Go, which destroys stack context with every "if err != nil return err".

Re: Java call stack – from HTTP upto JDBC as a picture (2006)

#15
This looks much worse than it actually is. You could implement it in a much flatter way.

  function HandleRequest(request : Request) : Response
  {
    LogRequest(request)
  
    CheckAuthentication(request)
    CheckAuthorization(request)
  
    var response = DispatchAndHandleRequest(request)
  
    LogResponse(response)
  
    return response
  }
This way you would have no deep stack traces and all would be fine. But only until you need to do some additional work somewhere right in the middle, say patch malformed requests between authorization and dispatch. With the above implementation you would be somewhat screwed, the best you could do would be reimplementing HandleRequest() with your additional step in the middle.

But with implementations like those show in the article you just have a list of steps with a common interface, each step does its work and then the next step gets called. If you need to do something new somewhere in the middle, you just add a new step to the list of steps in the right place and you are done, possibly simply by putting the class name of the new step in a configuration file.

  var steps =
  {
    new LogRequestStep(),
    new CheckAuthenticationStep(),
    new CheckAuthorizationStep(),

    // This stupid XYZ client always sends broken requests.
    new PatchMalformedRequestFromXyzStep(),

    new DispatchAndHandleRequestStep(),
    new LogResponseStep()
  }

  function HandleRequest(request : Request) : Response
  {
    var context = new Context(request)

    foreach (var step in steps)
    {
      step.Execute(context)
    }

    return context.Response
  }
This would still avoid deep stack traces because we are iterating over all the steps but note that with this implementation we would not really be able to abort processing the request somewhere in the middle, say if the authorization check failed, but we could fix this by adding a flag to the context and check it inside the loop after a step executed. But a more serious limitation is that every step only gets one chance to act, note for example that we have two separate steps for logging the request and the response.

Imagine we wanted to log the request duration, then we would need a step getting the current time at the beginning and another one getting the current time after the request was handled at the end. And the first step would have to somehow communicate the processing start time to the second one, possibly by storing it in the context. A much more elegant solution is to organize the list of steps as a linked list with all steps looking like this.

  function Execute(request : Request) : Response
  {
    PreprocessRequest(request)

    var response = GetNextStep().Execute(request)

    PostprocessResponse(response)

    return response
  }
This creates those deep stack traces but it also creates a huge amount of flexibility and extensibility. It surly looks crazy if you do not need it, but when you need it, it is really easy with this model.

Re: Java call stack – from HTTP upto JDBC as a picture (2006)

#16
Like what is the problem? Thanks to this stack trace your business logic fits into two lines. Do you want to have lines and lines of your own transaction manager? Lines and lines of your own DI framework? Do you suggest to write a HTTP web server yourself? Why don't we count stack frames in kernel space? And what do we have in JVM underneath us? And libc/Win32 layer?

I'm really annoyed by this kind of things like they have any meaning except "I don't know shit about how abstractions work in computers"

%s/you/picture author

Re: Java call stack – from HTTP upto JDBC as a picture (2006)

#17
post #16

Like what is the problem? Thanks to this stack trace your business logic fits into two lines. Do you want to have lines and lines of your own transaction manager? Lines and lines of your own DI framework? Do you suggest to write a HTTP web server yourself? Why don't we count stack frames in kernel space? And what do we have in JVM underneath us? And libc/Win32 layer? I'm really annoyed by this kind of things like the…

Debugging these stack traces is easy, just look for your packages and classes, and “caused by”. You should never be debugging framework code. Well almost never.

Re: Java call stack – from HTTP upto JDBC as a picture (2006)

#18

The fact that Spring even exists should be a big red flag for the value of static typing. People routinely make mistakes using type systems. And when done correctly I see static type systems work very well solving problems that they themselves created.

It sounds like you once read a blog that you half understood.

Re: Java call stack – from HTTP upto JDBC as a picture (2006)

#19
post #4

Earlier quoted context omitted.

While that's entirely true, the glueing of those frameworks together is very common in the Enterprise Java development space especially around 2006 when this was taken. I'm a big fan of the JVM and the Java ecosystem but in many ways the JVM ecosystem is split into two worlds: frameworks or libraries. This would be an example of a framework heavy development model where god knows what is going on between the outside…

> common in the Enterprise Java development space especially around 2006 Can you mention which frameworks and glues are common today ?

dropwizard.io

Re: Java call stack – from HTTP upto JDBC as a picture (2006)

#20
post #4

Earlier quoted context omitted.

While that's entirely true, the glueing of those frameworks together is very common in the Enterprise Java development space especially around 2006 when this was taken. I'm a big fan of the JVM and the Java ecosystem but in many ways the JVM ecosystem is split into two worlds: frameworks or libraries. This would be an example of a framework heavy development model where god knows what is going on between the outside…

> common in the Enterprise Java development space especially around 2006 Can you mention which frameworks and glues are common today ?

You can get a long way with just Spark: https://github.com/perwendel/spark
Post reply on HN