When is it worthwhile to replace working mature code with frameworks+patterns

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.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code> 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);
}
</code>
<code> 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); } </code>
 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.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>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%
</code>
<code>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% </code>
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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>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%
</code>
<code>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% </code>
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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>Mapping - 19,80%
Streaming - 80,20%
</code>
<code>Mapping - 19,80% Streaming - 80,20% </code>
Mapping -   19,80%
Streaming -  80,20%

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

25

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.

2

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.

13

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật