4

Intro/Question

I fear that frameworks in many cases have become a fashion or trend and are being abused. In many ways people are sacrificing speed just because they want to keep up with every single lib that comes out. I am for a more conservative approach that only makes use of new libraries and frameworks when it absolutely makes sense.

Related: When NOT to use a framework

Update/Disclaimer (May 18, 2017)

I've come to the conclusion that rapid application development, ease, and maintainability are the targets. So frameworks (new and old) should be used provided they help in reaching a final product quicker. Only when special cases exist (actual measurable performance issues) should we switch to custom code... or when the project itself is legacy and the cost of completely rewriting are too high.

Case

We have a Tomcat6 Servlet production that has been ongoing development since 2008 and there are many hours of work behind it. The code is very mature but it does not use any frameworks.

A new team member loves using frameworks and patterns for everything. Except for the love of frameworks, they also love cutting edge new releases and even proposed migrating from Tomcat6 to somethiong newer (JBOSS,GLASSFISH, or TOMCAT8).

I would never move a core production service to a container/server/web-server that just came out.

Not against refactoring code to keep it clean though!

I am against adding frameworks and patterns that add delay to production code servicing thousands of requests per second.

Serialization to stream (JSON/XML) while maintaining backwards compatibility

When a request comes, we produce both XML and JSON documents containing data related to the request params.

Since we maintain backwards compatibility for older clients changes must not break older support. Since we also support both JSON and XML, we make use of the Jackson but also KXML libraries.

For both formats we have 2 different serialization methods that use the streaming API. Except for being faster, I also find it is MUCH more flexible for maintaining backwards compatibility.

I like to use a sysyem of Major and Minor version. All minor changes to the backend that cause changes to the serialized document I add with IF statements in the serialization method. Once quite a few changes have accomulated (over 1 year), we add a new serialization method. So, all requests specifying version=1.00 to 1.99 are sent to serializeJSON1. All requests using version 2 to 2.99 are sent to serializeJSON2.

I've heard the argument that we should use ANNOTATIONS and MAP to objects. I find this very distastefull as I have read streaming is the fastest.

The streaming API allows you to make necessary changes on the fly while MAPPING would require to store multiple versions of the same data as different objects, or jump through other hoops.

 output.startTag(null, TagTable.PRODUCT);

 output.startTag(null, TagTable.ID);
 output.text(ID);
 output.endTag(null, TagTable.ID);

 output.startTag(null, TagTable.DESCRIPTION);

 if (locale != null && Translations.containsKey(locale) && version >= 1)
     output.text(this.DescriptionURL + "/" + locale);
 else
     output.text(this.DescriptionURL);

 output.endTag(null, TagTable.LONGDESCRIPTION);

 if (version >= 1 && version < 1.5) {
     output.startTag(null, TagTable.POPULARITY);
     output.text(String.valueOf((int) this.pop));
     output.endTag(null, TagTable.POPULARITY);
 } else if (version >= 1.5) {
     output.startTag(null, TagTable.RATING);
     output.text(String.valueOf((int) this.rating));
     output.endTag(null, TagTable.RATING);
 }

In the specific 3 cases above I really don't see the point to replace working mature code with frameworks/libs/patterns that may add additional overhead and cost additional development time.

So, when is it worthwhile to replace working mature code with frameworks+patterns??

Comments?

Update: Some benchmarks

For the first two examples posted previously, using REST and HASHMAPs does not make overly that big a difference in performance but does make the code more readable.

Now for the more interesting issue about serialization when used in a hotspot. Since the actual servlet in question had too much other code I made a toy example to test streaming vs mapping. The code is available at: https://stackoverflow.com/questions/21781540/

By all means test it, change it, run it.

What is very interesting is that the Just in time optimizer in java ends up making the difference negligable over time. So, here is how the percentage between mapping and streaming changes the more iterations there are.

Iter    Stream  Mapping
0       36,71%  63,29%
20      44,75%  55,25%
40      45,65%  54,35%
60      45,95%  54,05%
80      46,24%  53,76%
100     47,09%  52,91%
120     47,09%  52,91%
140     47,37%  52,63%
160     47,64%  52,36%
180     47,92%  52,08%
200     47,64%  52,36%
220     47,92%  52,08%
240     47,92%  52,08%
260     47,92%  52,08%
280     48,19%  51,81%
300     48,45%  51,55%
320     48,45%  51,55%
340     48,45%  51,55%
360     48,45%  51,55%
380     48,45%  51,55%
400     48,45%  51,55%
1000    48,72%  51,28%
2000    49,24%  50,76%
3000    49,24%  50,76%
4000    49,49%  50,51%
5000    49,75%  50,25%
6000    49,75%  50,25%
7000    49,75%  50,25%
8000    49,75%  50,25%
9000    49,75%  50,25%

I also re-ran one more time have first 20 iterations more detailed:

0   39,76%  60,24%
1   41,18%  58,82%
2   40,83%  59,17%
3   40,12%  59,88%
4   40,48%  59,52%
5   40,83%  59,17%
6   40,83%  59,17%
7   40,83%  59,17%
8   40,48%  59,52%
9   40,12%  59,88%
10  41,52%  58,48%
11  42,53%  57,47%
12  42,86%  57,14%
13  42,86%  57,14%
14  43,18%  56,82%
15  43,50%  56,50%
16  43,50%  56,50%
17  43,82%  56,18%
18  43,82%  56,18%
19  43,82%  56,18%
20  44,75%  55,25%

After 10,000 iterations (or calling JSON generation code 1000 times) here is the screenshot from VisualVM profiling (visualVM snapshot NPS file):

enter image description here

So, if this optimization behavior holds up in Tomcat servlets as well, it means there really is no point NOT to use mapping (and many other convenience functions/libs since the JVN will optimize over time).

Conclusions

Based on the answers/comments, I think at the end of the day whether to rewrite working production code is affected by business requirement, and specific cost-benefit analysis for each project.

Based on the benchmarking, it turns out avoiding some libs/frameworks may make no difference in the long run due to JIT JVM optimizations.

Update: After leaving code running all night

enter image description here

After 275,137 iterations and approximately 30,000 MS:

Mapping -   19,80%
Streaming -  80,20%

I really wonder what JIT optimizations happen here and whether the behavior holds for a servlet.

We're looking for long answers that provide some explanation and context. Don't just give a one-line answer; explain why your answer is right, ideally with citations. Answers that don't include explanations may be removed.

  • 2
    Not necessarily. Get back to us with numbers when you've profiled both implementations. – user16764 Feb 10 '14 at 2:26
  • 6
    Frameworks do not always add delay. More often than not, frameworks are written and optimized by specialists dedicated to their function. These specialists will often do better than you will. – Telastyn Feb 10 '14 at 2:37
  • 1
    "It would only add overhead (additional MS delay for every request)" "even if they added 5 to 10 MS" If this estimate is of the cost of adding extra layers of method calls, then it's too high by a factor of a million. – user16764 Feb 10 '14 at 2:47
  • 3
    The estimate is still almost certainly too high by a factor of a million. I'll let you profile and test that though. – user16764 Feb 10 '14 at 2:52
  • 2
    The questions not asked here are what business purpose would be served by rewriting the code and whether or not achieving that purpose justifies the cost of the rewrite. – Blrfl Feb 13 '14 at 14:22
7

They say

a bird in the hand is better than 2 in the bush

Applied here, I take it to mean its better to have something that works and is maintainable than to tear it all down for some fantasy daydream of "but it'll be vaguely better if we use X Y or Z cool new technology for the sake of using the cool new technology".

I mean, you could have rewritten it in a functional language a few years ago, or Ruby on Rails a couple of years ago, or Node.js a year ago or... whatever comes along next that gets attention in the technical blogosphere. None of these things would create you a stable product that satisfies the 'must use new stuff' people as they will be considered old technologies before they're even finished and they'll want to re-rewrite!

So I have to ask "what's your problem?". You have good code that might be a bit mucky here and there, but in my extensive experience, when you start a big rewrite you end up with code that's a bit mucky (often quickly implemented due to inexperience with the tooling or done under time pressure that you will come back to and fix up nicely, promise.)

When you use a framework is when you are doing a new project and you want a load of code written for you, that's the time to go framework, to re-use all that boring boilerplate that you'd have to write yourself. You never go for a framework because its there to be used, especially when you have an existing framework that you know (even if you don't call it a framework because its grown by itself, it's effectively still one).

One thing to note, I do find a lot of the people who insist on using any kind of new technology want to for 1 of 2 reasons: they either want to boost their CV, or they do not want to learn the existing technology you use (after all, learning tech x is way more fun than actually doing work on existing product). I treat all calls with suspicion as in either case their intention is not in the best interest of the product or the business.

Heavy refactoring...that's a different story, and usually a good one.

  • 1
    Joel Spolsky had a lot to say about rewriting production code way back in 2000 – Dan Pichelman Feb 13 '14 at 14:21
  • 1
    @DanPichelman true then as it is today. – gbjbaanb Feb 13 '14 at 15:27
17

Ugh. Some points:

  • "I have read it is fastest". Don't be a cultist. Think for yourself. Measure for yourself. Personally, if you're generating XML by hand, I would question your sanity.
  • who knows what bugs lurk It is foolish and shortsighted to fear what you do not know. This leads to "not invented here" syndrome and quickly being passed by programmers who had the courage to learn better tools.
  • frameworks hinder performance Runtime performance is very often cheap. Programmer time is not. The trade off here is that these frameworks may add a slight performance penalty in exchange for saving you a bunch of time writing and maintaining the code. In the XML example, if you had used annotations and a serialization framework, you wouldn't have to write and test your own XML formatter (read: cost your company all that money).

Look - code that is done and tested is good. And certainly, adopting a framework because "that's what you're supposed to do" is a good way to make bad software. But these examples strike me as simply you making excuses to avoid change. Yes, change is scary. Yes, change can lead to bugs. But change is necessary to eliminate inefficiency, and improve your ability to maintain and extend your code.

  • +1 Indeed, some good points. So, for the JACKSON example how would you go about using mappings/annotations to create something that is both clear but also backwards compatible? The only thing I can think of is creating different classes with different constructors. Based on the requested version create a different object, and call the automated serialize method. – Menelaos Bakopoulos Feb 10 '14 at 2:35
  • Most serialization frameworks have either a dispatch behavior (use A if version 1.x, etc.) or conditional sort of things (include this property if version 2.x, etc.). The main point is I don't know your problem (or Java frameworks) well enough to say. I would prototype a solution and see which solves my problem better. – Telastyn Feb 10 '14 at 2:41
  • In relation to "Personally, if you're generating XML by hand, I would question your sanity.". It seems there are more insane people if you look at stackoverflow.com/search?tab=votes&q=%5bstax%5d%20writing and stackoverflow.com/questions/10299124/… – Menelaos Bakopoulos Feb 10 '14 at 4:02
  • 2
    i updated my jar something broke. another library uses a newer version of a library i use ... but the newer version fixed a bug i was relying on ... no silver bullets ... – tgkprog Feb 13 '14 at 11:25
  • 1
    @maythesource.com: Your code may work but it is naively written, overly verbose, and expensive to maintain. You should listen carefully when your new team member proposes changes. Or you can ignore him until he leaves in frustration, continuing in blissful ignorance until something or someone wakes up your manager and you go away too. – kevin cline Feb 13 '14 at 19:09

protected by maple_shaft Feb 13 '14 at 9:50

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.