2024 DevOps Lifecycle: Share your expertise on CI/CD, deployment metrics, tech debt, and more for our Feb. Trend Report (+ enter a raffle!).
Kubernetes in the Enterprise: Join our Virtual Roundtable as we dive into Kubernetes over the past year, core usages, and emerging trends.
Software Engineer at IBM
Saddle Brook, US
Joined May 2013
About
I am devoted to continuously learning and improving as a software developer and sharing my experience with others in order to improve their expertise. I am also dedicated to personal and professional growth through diligent studying, discipline, and meaningful professional relationships. When not writing, I can be found playing hockey, practicing Brazilian Jiu-jitsu, watching the NJ Devils, reading, writing, or drawing. ~II Timothy 1:7~ Twitter: @justinmalbano
Education
Embry-Riddle Aeronautical University · Software Engineering
Master's, Bachelor's
Sep 2010 - May 2015
Stats
Reputation: | 9613 |
Pageviews: | 3.7M |
Articles: | 49 |
Comments: | 229 |
Articles
Refcards
Design Patterns
Cloud-Based Automated Testing Essentials
Getting Started With GitHub Actions
JavaScript Test Automation Frameworks
End-to-End Testing Automation Essentials
Automated Testing at Scale
Node.js
Trend Reports
DevOps
The DevOps movement has paved the way for CI/CD and streamlined application delivery and release orchestration. These nuanced methodologies have not only increased the scale and speed at which we release software, but also redistributed responsibilities onto the developer and led to innovation and automation throughout the SDLC.DZone's 2023 DevOps: CI/CD, Application Delivery, and Release Orchestration Trend Report explores these derivatives of DevOps by diving into how AIOps and MLOps practices affect CI/CD, the proper way to build an effective CI/CD pipeline, strategies for source code management and branching for GitOps and CI/CD, and more. Our research builds on previous years with its focus on the challenges of CI/CD, a responsibility assessment, and the impact of release strategies, to name a few. The goal of this Trend Report is to provide developers with the information they need to further innovate on their integration and delivery pipelines.
Enterprise Application Security
Data breaches, ransomware attacks, and other security vulnerabilities have become the norm in recent years. Hackers have become shrewder. And with that, development teams bear the responsibility of ensuring that all stages of the SDLC have strong security.DZone's 2022 Trend Report, Enterprise Application Security: Building Secure and Resilient Applications, focuses on key factors of security practices including supply chain security, principles of zero-trust security, how to secure mobile applications, common DevSecOps practices, and what to do after your organization experiences a security breach. Our research dives into sentiments on perceived application security risks, development techniques for securing applications, and where the role of security lies for teams within today's organizational structures. The goal of this Trend Report is to equip developers with the tools, best practices, and advice they need to help implement security at every stage of the SDLC.
Low Code and No Code
As the adoption of no-code and low-code development solutions continues to grow, there comes many questions of its benefits, flexibility, and overall organizational role. Through the myriad of questions, there is one main theme in the benefit of its use: leveraging no-code and low-code practices for automation and speed to release.But what are the pain points that these solutions seek to address? What are the expected vs. realized benefits of adopting a no- or low-code solution? What are the current gaps that these solutions leave in development practices? This Trend Report provides expert perspectives to answer these questions. We present a historical perspective on no and low code, offer advice on how to migrate legacy applications to low code, dive into the challenges of securing no- and low-code environments, share insights into no- and low-code testing, discuss how low code is playing a major role in the democratization of software development, and more.
DevOps
With the need for companies to deliver capabilities faster, it has become increasingly clear that DevOps is a practice that many enterprises must adopt (if they haven’t already). A strong CI/CD pipeline leads to a smoother release process, and a smoother release process decreases time to market.In DZone’s DevOps: CI/CD and Application Release Orchestration Trend Report, we provide insight into how CI/CD has revolutionized automated testing, offer advice on why an SRE is important to CI/CD, explore the differences between managed and self-hosted CI/CD, and much more. The goal of this Trend Report is to offer guidance to our global audience of DevOps Engineers, Automation Architects, and all those in between on how to best adopt DevOps practices to help scale the productivity of their teams.
Low-Code Development
Development speed, engineering capacity, and technical skills are among the most prevalent bottlenecks for teams tasked with modernizing legacy codebases and innovating new solutions. In response, an explosion of “low-code” solutions has promised to mitigate such challenges by abstracting software development to a high-level visual or scripting language used to build integrations, automate processes, construct UI, and more. While many tools aim to democratize development by reducing the required skills, others seek to enhance developer productivity by eliminating needs such as custom code for boilerplate app components. Over the last decade, the concept of low code has matured into a category of viable solutions that are expected to be incorporated within mainstream application development. In this Trend Report, DZone examines advances in the low-code space, including developers' perceptions of low-code solutions, various use cases and adoption trends, and strategies for successful integration of these tools into existing development processes.
CI/CD
In 2020, DevOps became more crucial than ever as companies moved to distributed work and accelerated their push toward cloud-native and hybrid infrastructures. In this Trend Report, we will examine what this acceleration looked like for development teams across the globe, and dive deeper into the latest DevOps practices that are advancing continuous integration, continuous delivery, and release automation.
Modern Web Development
The web is evolving fast, and developers are quick to adopt new tools and technologies. DZone’s recent 2021 Modern Web Development survey served to help better understand how developers build successful web applications, with a focus on how decisions are made about where computation and storage should occur.This Trend Report will help readers examine the pros and cons of critical web development design choices, explore the latest development tools and technologies, and learn what it takes to build a modern, performant, and scalable web application. Readers will also find contributor insights written by DZone community members, who cover topics ranging from web performance optimization and testing to a comparison of JavaScript frameworks.Read on to learn more!
API Design and Management
Discover what you need to know about the state of API design and management. This report explores a wide range of topics from REST API discovery and navigation to common integration pain points and how developers are thinking about APIs.This report covers in-depth original research on developer preferences surrounding API programs and integrated systems. Additionally, experts in the field share their perspectives on effective API design as well as secure API strategies and best practices.
JavaScript Frameworks
JavaScript is constantly at the top of developer surveys. With the rise of Single Page Applications and front-end frameworks, and the onslaught of languages that now compile into JS, it's easy to see that JavaScript will continue to play a pivotal role in front-end and back-end development for the foreseeable future. What that future looks like exactly is in flux, especially as it relates to which frameworks are in vogue and which are on their way out. DZone’s JavaScript Frameworks Trend Report provides the perspectives of industry professionals and leaders, detailing the latest news and trends concerning JavaScript frameworks, all with the hope of giving readers a better understanding of which of these frameworks is right for their specific development needs.
Application Security
DZone Trend Reports will expand on the content from DZone Research Guides that our readers have told us is most useful. The Application Security Trend Report analyzes new developments in the increasingly important field of AppSec to predict what's next.
Comments
Feb 09, 2022 · Justin Albano
Thank you!
Nov 20, 2021 · Justin Albano
Glad this was able to help you. Thank you for the feedback.
Sep 23, 2021 · Justin Albano
Thank you, I appreciate your feedback and I'm glad you are enjoying the article.
And I appreciate you letting me know about the misspelling. It has now been corrected. Thank you!
Jul 29, 2021 · Justin Albano
That's an awesome tip I wasn't aware of! That makes life a lot easier. I've updated the article with that information and credited you with that tip and cited the source you mentioned. Thank you again, that's a great tip.
Jul 29, 2021 · Justin Albano
Thank you for the heads up. I appreciate you taking the time to make the correction. System.in is an InputStream, not a PrintStream, so you are correct that it does not have a format() method. I've updated the article to reflect that.
Jul 23, 2021 · Justin Albano
Thank you, and thanks for taking the time to read and comment.
Jul 22, 2021 · Justin Albano
Thank you, and thank you for taking the time to read and comment.
Jul 22, 2021 · Justin Albano
Thank you. I appreciate you taking the time to read it and comment.
May 20, 2021 · Melissa Habit
Thanks for taking the time you provide your thoughts, Robert. I really appreciate it.
All of the points you bring up are very good points. Generally, when I refer to the "customer" in this article, it's not the customer of our product per-say, it's the person or software written by a person that consumes the API.
In perfect software style, the answer to your question of who decides to use the API is: It depends. Sometimes it's the developer who gets to decide, sometimes it's a business person (or persons), and sometimes it's both. In the case of the developer, sometimes we're asked to decide on an API that works best to solve the problem (or never asked at all, we just find the one we think works best). Sometimes it's a business person who wants to build a relationship with a company, so they agree to use their API without much knowledge of how well that API is written. In a lot of cases, it's some combination of these scenarios.
The design principles listed in this article are intended for the development side of the decision, but they also aid in the business side as well (i.e., if the API is easy to consume, this will likely lead to a less-expensive implementation cost on the part of the consumer).
Mar 08, 2021 · Justin Albano
Again, I appreciate you taking the time to comment.
When did I compare Parler's banning to Nazism (the Niemoller quote is simply the wisdom of a person who lived under Nazism, but that does not mean I am calling these companies Nazis)? You also claim that Parler is "the gathering place for white supremacists and anarchist militia"; what evidence do you have to support that claim? As I stated in the article, according to a US FBI investigation of the how the Capitol Riots were organized, Facebook (as a company) was cited 93 times, while Parler was only cited 8. Based on that evidence, Facebook is nearly 12 times more likely to be a gathering place for insurrectionists.
Secondly, stating that geographic proximity provides authority in an argument is a fallacy of authority. If that were the case, I would be much more of an authority on Donald Trump then you would be (which I don't believe to be the case). Location can provide perspective, but at the same time, it does not (in and of itself) provide authority. The statements I make are either true or false, regardless of where I live.
Thirdly, I do believe (as I stated numerous times in the article) that these private companies do have the right to make decisions on their own, but that does not absolve them of moral responsibility. Just because we can do something does not make it right to do so. There are plenty of actions that are simultaneously legal and wrong.
Respectfully, I think you are countering arguments that I have not made. It is not my position that Facebook and Twitter are akin to National Socialists or that private businesses do not have the right to make decisions about what they do with their own business. However, I do believe that if we do not exit this road soon, they (with all of the good intentions in the world) will be responsible for ushering in an authoritarianism that will make the authoritarians of the previous century jealous.
Mar 06, 2021 · Justin Albano
While context does play a major role, it can also be a distraction from the principle. I do not think that speech has changed much recently. Sure, the rate at which speech travels has increased, but the effect of speech has not. The Declaration of Independence and The Communist Manifesto are just two examples of speech that completely altered the world (I would argue in a good and bad way, respectively). The maxim that "the pen is mightier than the sword" is much older than the internet. I do not personally think the debate over free speech changes much due to the speed of communication today. I think we need to decide on a principle, rather than decide by anecdote.
As far as moral, free speech: I think there is an important difference between "moral" speech and "free" speech. There is plenty of speech I vehemently disagree with that I still think should be "free." I.e., the person has the right to say it, no matter how much I agree with it. My worry is that we are creeping the line of "it is universally known that that is not protected speech" to subjectively blocking speech. For example, is a MAGA hat racist? Is AOC a communist? I think we need to tread lightly on banning those types of speech, because although they are visceral, they are far from claims counter to universal truths (i.e., the classic fire in a crowded theater).
Mar 05, 2021 · Justin Albano
Respectfully, I believe you are playing a fallacy by not balancing the scales: Your argument rests on comparing the downside of free speech against the upside of speech suppression (a case which you will win every time). My argument is not that there is not damage that can be done by allowing free speech. It is that the benefits of free speech outweigh the benefits of speech suppression and the damage of speech suppression outweigh the damage of free speech.
In essence, free speech can be dangerous, but not nearly as dangerous as speech suppression.
Free speech, on the positive side, has brought about scientific discovery, challenged archaic norms, and brought about liberty and freedom throughout the world. Speech suppression has (ironically) unsuccessfully limited the spread of damaging speech. In most cases, the speech that is limited becomes more acute until it burst out into the open (see speech suppressed during revolutions and religious suppression in authoritarian countries).
At the same time, we are trying to weigh what could have happened had speech been allowed. What if we suppress unpopular claims about COVID-19 and later find out that they were correct? How many lives could have been saved had that message been available? On the other hand, what if we failed to censor incorrect information? How many lives could have been lost had that information not been sent out? In both cases, it's difficult to tell. The only difference is that free speech allows for people to make their own decision. With censorship, the decision has already been made for us (and by who, with what authority?).
The only argument I usually see to rebut that final point is that people cannot be trusted with all of the information. They are not doctors (a lot of times, this is phrased as, "They are too stupid") or they don't have the time to do the research themselves. In either case, that is their own choice to make. Those who wish to do so at least have the option of educating themselves and putting the time into making the correct decision. With censorship, this is no such option.
Mar 04, 2021 · Justin Albano
Thank you for taking the time to read the article and taking the time to comment.
Which two examples in particular are you referring to?
Mar 04, 2021 · Justin Albano
Thanks for the discussion, Rob.
It's good to hear that there are voices who don't agree but still want to have a civil, spirited debate.
Mar 04, 2021 · Justin Albano
Thanks for taking the time to read the article and comment. I appreciate it.
As far as newspapers go, newspapers are considered publishers and are responsible for the content that they publish. For example, if they post an article that slanders a person, the victim can sue the paper for damages. This is not the case with social media companies. These companies (under Section 230 referenced in the article) are platforms. Thus, they are granted special protections from litigation. For example, if a Facebook user posts slander, Facebook cannot be sued (although the user may still be sued). In essence, social media platforms are treated as pass-throughs and they are not responsible for moderating all of the posts on their application (which would be infeasible).
But these social media companies do remove posts they do no approve, which is the job of a publisher.
In essence, they have their cake and eat it too. They have the protection of a platform with the freedom to censor of a publisher.
Mar 04, 2021 · Justin Albano
I agree that evidence has to be brought forth. In the case of the Steven Crowder video, Twitter banned the promotion of the video that provided the evidence. They did not claim he did not provide evidence. Instead, they determined that his conclusion was false from the start (i.e., they claim no voter fraud exists), so there could not exist such evidence (i.e., since fraud does not exist, any evidence of fraud therefore must be false). No matter what the video showed (he had his staff drive to the location of the fake addresses and take a photo of an empty lot or the underside of an overpass). But that was of no concern to Twitter.
They had already deemed there was no election fraud, so any video or post to the contrary must be wrong. Based on the premise, there was no way for the evidence to exist.
(I'm not claiming their was widespread voter fraud or enough fraud to change the outcome of the election. But in this particular case, Steven found 10 or so addresses that were fake. Thus, those votes were fake. For all we know, it could have just been those 10. Regardless, Twitter is not interested in the truth, they are interested in supporting their already-forgone conclusion that no such fraud exists.)
I appreciate your cordial discourse. I agree with many of your points. I just think that we are headed in a scary direction very fast and these are the first steps down that road (even if they only look like benign steps.
Mar 03, 2021 · Justin Albano
I appreciate the honest conversion and assessment.
I think we are conflicted on the meaning of "free" in "free speech." I use that term in the normal sense: People in the United States are "free." That does not mean that they can do whatever they want. Instead, there are reasonable restrictions on behavior (i.e., murder is illegal). But I still think that we can consider US citizen free in the sense that the rule is that they may act as they please, but we institute some specific exceptions that reasonably restrain certain behaviors or actions.
Mar 03, 2021 · Justin Albano
Thank you for taking the time to read my article and comment.
In no way does "freedom of speech" allow us to "say anything at any time." Speech -- such as calls for violence or damaging someone's character with falsehoods -- is not protected. Any speech that violates another person's rights is not protected. I don't think anyone would argue that a discussion of the worthiness of Micky or Bugs as Present should go unrestricted (it is subjective opinion), but what about a video by doctors that is counter to the scientific "consensus" on COVID-19? That is a lot more meaningful and that will come much closer to home for many.
But that begs the question: Should the doctors be believed or the scientific community? I don't have the answer, but I would rather see both sides remain visible and let people decide for themselves. I would much rather people do their own research and inquire themselves (or at least have the ability to) than have a fallible company (see the admission of a mistake on the part of Twitter about lock the NY Post's account) deem one acceptable and the other not. At least with the first scenario, I have a choice; with the second, I have had the choice made for me.
Mar 03, 2021 · Justin Albano
Jim, you captured a lot of what I wanted to say on the strawman argument.
I appreciate your understanding of my argument and the position that I am taking.
As far as the argument that I have presented free speech as a good thing without justification, I believe I have by two separate arguments. The first argument I make is that speech suppression is "bad." Censorship comes from a self-ordained position of superiority, where the censor assumes that he or she is endowed with a preeminent ability to judgment what speech is permissible. There is no foundation for the preeminence; it is simply assumed a priori. Any justification for it would have to be unique to him or her (or the group to which he or she belongs) and not to the victim of the suppression. Such uniqueness (of course, self-bestowed by the censor) is ego-centric at best.
But that only "proves" that censorship is wrong. Strictly speaking, that does not prove that free speech is "good." Free speech is good because it aligns with the Laws of Nature: That all men and women have rights. One of them is to speak their mind freely. Hence why we use the words "suppression" (which provides the imagery that we are forcibly trying to hold back against something that is trying to bust forth) and "censor" (which ensures that "unacceptable" parts are removed). That does not mean without responsibility or consequence. I address the consequence portion in Appendix A when speaking about "accountability," but responsibility has a much more stringent definition. If I say something hurtful, I may be breaking a moral law and be responsibility to law giver (whether that is God, as I believe, or society as some believe), but that does not mean I do not have the right to speak it. In essence, we all have the right to speak our minds, even it is offends someone else.
There are times when speech should reasonably be suppressed: When they directly violate the rights of another person. To threaten violence directly against another and to slander his or her character with known falsehoods are just two examples. I am entirely in agreement with you on that. But that is not what is being suppressed today. What is being suppressed is speech that does not violate someone's rights (at least without making convoluted arguments). Why should a video by doctors touting what is deemed false information be removed from YouTube? What if that is their scientific judgment of the matter? Is YouTube in a position, morally, to state that these doctors should be believed over those doctors? Essentially, we are saying that people "are too stupid" to make the decision for themselves. Had we taken the same approach, Newton's Laws would probably not become "Laws" (as they were highly counter to the scientific convention at the time) and Einstein would probably not have excelled in his theory of General and Special Relativity (as it was counter to Newtonian mechanics). Free speech can be very dangerous sometimes, but speech suppression can be much more dangerous.
I also agree there is a balance between freedom and security, but I think that the scale should tip towards the freedom side much more than the security side. I am in agreement with Ben Franklin:
"Those who would give up essential Liberty, to purchase a little temporary Safety, deserve neither Liberty nor Safety."
Much more damage and destruction has been brought upon the world under the guise of security than liberty.
Mar 03, 2021 · Justin Albano
I have addressed these companies' right to deny speech on their platforms (as private businesses) in Appendix A, so I won't rehash that argument. My argument is different: Not can they, but should they? You also make a false equivalence and conflate two types of speech. The peeing example you give is an example of something that nearly all people agree upon. That is a factual falsehood. Anyone who has eyes can see that that is a lie. Even so, unless that claim is harming someone, why bother removing it? It starts us down a slippery slope (i.e., even though this example is clear, what about the examples that aren't so clear)?
But that is not the type of speech I'm worried about denying. Saying something as despicable as a racial slur (that can be easily agreed upon as racist) is a clear case of that type of speech. But what about a photo of a MAGA hat? Is that racist language? Many on the left would say so, but many on the right would not. Whose opinion should we take? Taken from the other side, a Federal investigation has determined that there is no evidence of Trump colluding with Russia in the 2016 election. Should we remove all posts that claim otherwise? Should celebrities who made such "provably false" claims have their Twitter accounts removed? The only difference is that we either agree or disagree with the statement and want it protected. Essentially, we don't want our guy banned, but feel free to ban the other guy. That sets up a bad precedent. At that point, we aren't following a universal moral principle; we are following a principle of might is right (whoever is at the top wins).
You claim: "you don’t get banned from Twitter and Facebook for expressing an opinion however you do get banned for deliberately, repeatedly and unrepentantly misstating the facts (or for inciting violence, promoting hate or other breaches of the terms of service)." That is simply not true. This article, and Appendix B, is filled with examples of just those types of actions:
- Twitter locking the NY Post account and later admitting that they should not have done it
- Twitter locking Steven Crowder's for posting information about US election fraud, even with his proof and evidence directly in the video
- YouTube reducing the spread of Tulsi Gabbard's campaign videos (targeted against her specifically)
- Amazon removing Ryan J. Anderson's book
The list goes on and the examples continue by the day. If I published the article today, I would have to expand Appendix B to accommodate the new examples that pour in by the day.
Lastly, you claim, "I am just denying him access to the audience I have built up and I am preventing him from tarnishing my brand by association." That is not entirely true. What if the banned account brought people to Twitter? In addition, what alternative is there? Parler attempted to create an alternative platform but Google, Apple, and Amazon (as well as Facebook besmirching the Parler's name) conspired to remove the platform. Essentially, these companies say, "If you don't like it, then go elsewhere" while at the same time destroying any alternative.
My fear is that we go one step further. If your speech is deemed damaging, do we notify your bank and freeze your ability to get a mortgage? Do we freeze your assets (what if those assets could be used to further the spread of these "lies"? Do we instruct ISPs to not allow your personal blog to be reached? Should your blog be removed from a Google search? Do we instruct your cell carrier to drop your service so that you cannot spread the misinformation? Edwin Black said it best when he called it "digital ghettoization." You will be allowed to exist, but you will have no reach and you will not be allowed to be in contact (and pollute) other people. You can yell, but no one will hear you.
This does not also account for the special protections these companies receive under Section 230. They are having their cake and eating it, too: They are provided the special protections so long as they don't active edit or filter posts, but then they go and filter those posts anyway.
Are they within their rights to do so? Yes. Should they? No.
Mar 02, 2021 · Justin Albano
I appreciate you taking the time to read the article and comment on it.
Can I ask you two honest questions: (1) What makes you believe that I'm a support of Q, and (2) why take the worst, most vile speech, and equate it to debatable speech?
Not all -- or even a small fraction -- of the censored speech of late has been equivalent to "espousing and inciting young people to kill (themselves or others)." What should be made of that speech that is not equivalent to that extreme example but is still censored?
Mar 02, 2021 · Justin Albano
I appreciate that you took the time to read the article and took the time to comment.
I do think you misunderstand my stance, though. I do not embrace factual relativism. I do however understand that people differ in their opinions of the truth. There is only one truth (or Truth), but our opinions do differ. Otherwise, we would never debate. For example, I think your comment is wrong and it is spreading "misinformation" about my stance. Even so, I don't think I should delete your comment and quell your voice. Instead, I trust that readers can read both my article and your comment and make the determination for themselves.
"I have no problem with the censoring of people making false, self-serving, specious claims and I have no problem taking away the virtual bull-horn from those that do it repeatedly." The rubber meets the road when I turn this exact argument around and state that I believe your comment to be incorrect. Does that give me the moral permission to delete your comment so that no one else reads it? Does my opinion override yours in the same way that you are claiming your opinion overrides someone else's?
(For the record, I support free speech so I have no intention of removing your comment. I appreciate any comment from my readers, regardless of disagreement. This is simply an example.)
Dec 08, 2020 · Justin Albano
Thank you! I really appreciate it!
Oct 07, 2020 · Justin Albano
Thank you for catching that. It has been corrected. I appreciate the sharp eye.
Aug 10, 2020 · Justin Albano
Thank you, Dilek! I appreciate the feedback
Aug 04, 2020 · Justin Albano
I appreciate taking the time to provide your feedback and catching those typos. They have been corrected. Thank you.
Jun 26, 2020 · Justin Albano
You're welcome! Thanks for the feedback
Jun 16, 2020 · Justin Albano
First, I appreciate your feedback.
I agree. Non-reified types and nullity are two of the larger difficulties to work around in Java. This article, though, is intended to explain how to use Java as it is. While I hope improvements (even if they will leave old Java versions behind) are made, I am hoping to help those who are programming in Java as it is today.
Although I do agree that Optional does introduce some overhead (mentioned in the Alternatives section), in many cases, it's minimal. As stated, only when used in large scale or in performance-critical sections does Optional seriously impact performance.
Again, thank you for your feedback. I appreciate you taking the time to comment.
Apr 29, 2020 · Justin Albano
You are correct. Thank you for catching that mistake (it has now been corrected). I appreciate your feedback (and your sharp eye).
Apr 28, 2020 · Justin Albano
You're welcome. I'm very glad it was useful for you. Thanks for the feedback!
Jan 25, 2020 · Gaurav Kukade
Great article and great explanation.
One more thing to consider are null values. I.e., when comparing a String variable (str) to a known String, oftentimes it will be written as "foo".equals(str) rather than str.equals("foo") since there is a possibility that str may be null (and calling equals() would through an NPE).
Another way to solve this is by using the Objects.equals method: Objects.equals(str, "foo"). This method will return true if both arguments are null, though, so that logic may not be applicable in all scenarios.
Jan 09, 2020 · Justin Albano
Dec 03, 2019 · Lauren Forbes
From experience on a microservices HATEOAS project, one way is to provide URLs that route through the gateway. For example, instead of http://localhost:8080/users, we would use https://mygateway.com/users, where users/ is a route known by the gateway. Maybe the gateway has load-balancing or directly routes to a single microservice, but those are internal details that are abstracted.
In general, the idea is to always use externally-addressable links that hide the details of the gateway (and even hide that a gateway is in use). The details are too nuanced for a single comment, but that's the basic approach we used (not perfect and it has its downsides).
Oct 30, 2019 · Justin Albano
Thanks, Dieter. I appreciate your feedback.
Sep 04, 2019 · Justin Albano
Thank you. I appreciate the feedback.
Jul 11, 2019 · Justin Albano
For the case of brevity, I did not include Spring Boot and auto-configuration annotations in this article, but I may do a follow-up article that includes these topics (these concepts can leverage the concepts explained in this article).
Thank you for the suggestion and I appreciate your feedback!
Jul 02, 2019 · Justin Albano
Definitely right. For this article, I tried to keep it to the most common ones, but I may write a follow-up article and include more annotations, such as @RestController. I will definitely keep your suggestion in mind. Thanks!
Jun 10, 2019 · Justin Albano
Honestly, not sure. At the moment, it is looking like another Google+. Unless something changes (or Microsoft botches it), xCloud appears to be outmatching Stadia.
Apr 24, 2019 · Justin Albano
Thank you! I'm glad you enjoyed it!
Apr 14, 2019 · Justin Albano
Thank you! Glad you enjoyed it.
Apr 11, 2019 · Justin Albano
Thank you! I appreciate the feedback.
Apr 11, 2019 · Justin Albano
Thanks for the feedback. And you are correct: I made a static import when creating the example, but when I posted it, I forgot to add the class name back in.
Thanks for find that. It has been corrected.
Dec 24, 2018 · Justin Albano
Thanks for the feedback, Michael. I'm glad it helped!
Dec 07, 2018 · Justin Albano
Thanks. I appreciate the feedback.
Nov 25, 2018 · Justin Albano
Thank you! I appreciate your feedback.
Sep 17, 2018 · Justin Albano
A full description of the proposed bytecode changes can be found in The State of the Values article.
Sep 14, 2018 · Justin Albano
A link to the source code for this article has now been added to the introduction and can be found here: https://github.com/albanoj2/dzone-intro-json-with-java
Sep 14, 2018 · Justin Albano
I appreciate the feedback. You're right, it's good to have full, complete examples. I will attach a completed set of examples (based on the snippets in the article) as soon as possible. Thank you again for the feedback.
Sep 14, 2018 · Justin Albano
Thanks. I appreciate the feedback and I'm glad the article could help.
Aug 02, 2018 · Justin Albano
I'm glad you enjoyed it. Thanks for the feedback!
Jul 25, 2018 · Justin Albano
Thanks for the feedback. I will definitely consider creating an article on heap dumps in the future.
Jul 23, 2018 · Justin Albano
For most applications, the memory and allocation overhead is likely negligible, especially since the created empty list contains zero elements. If this becomes a performance bottleneck (after some performance profiling) or if the application is extremely performant in terms of memory, returning null would be an acceptable technique.
Basically, in a large majority of cases, returning an empty list is logically more consistent, but if high performance is required, nulls can still be used.
Thank you for taking the time to comment.
Jul 14, 2018 · Justin Albano
Thanks for the feedback. I appreciate you taking the time to comment and thank you for catching those typos. They have been corrected.
Jun 26, 2018 · Justin Albano
Thank you. I appreciate you taking the time to provide feedback.
Jun 19, 2018 · Michael_Gates
Totally understand (and agree with a good amount of what you said). The reason I asked is that you are another developer "in the trenches" so I wanted to get your take on why type inference was acceptable for Python but less acceptable for Java (which is a legitimate argument, depending on the rationale).
Thanks for your feedback. I sincerely appreciate it.
Jun 19, 2018 · Michael_Gates
I personally think overuse of var can cause some serious headache, but at the same time, there are some very specific areas where type inference can help (e.g. iterators, maps that contain key or value types that have generic arguments, etc.).
This is an honest question: If missing LHS types is an issue in Java, why suggest a language that has no LHS types? The reason I ask is to understand your thought process (i.e. is it because Java is not a scripting language that it gets this scrutiny but Python does not, is it because Python performs type inference in a more effective way, etc.).
Jun 15, 2018 · Michael_Gates
Having come from a similar C++ background, I agree with you that type inference can cause serious readability issues. At the same time, though, there are cases where the type is redundant due to the context. For example, using an "old-style" for loop to loop over an iterator: The type of the iterator, being generic, is often times long and distracting. Replacing it with "var" is much more concise and does not detract much from its meaning since its type is implicitly known (i.e. the context provides a notable clue as the to the type of the iterator, especially if the variable is named "it" as is often the case).
Whether type inference increases readability is a matter of discretion and good judgment, although, I agree with you: In practice, type inference can be overused and lead to some seriously unreadable code.
Jun 07, 2018 · Justin Albano
Glad it helped and glad you were able to get your first annotation working
Jun 07, 2018 · Michael_Gates
Personally, I agree. I think having the option of both would have been valuable (as Kotlin and Scala decided). Nonetheless, although I don't agree with the decision, I think the JEP tried to keep it as simple as possible, for better or for worse.
Apr 22, 2018 · Justin Albano
Glad you enjoyed it. Thank you for the feedback.
Apr 21, 2018 · Justin Albano
Good catch. Uses of updateAnimalAdded have been changed to onAnimalAdded for consistency. Thank you for the feedback.
Apr 09, 2018 · Robin Rizvi
Great article: Really comprehensive. Also, kudos on the clever title.
Apr 03, 2018 · Justin Albano
Duly noted. (Although, there are two types of PaymentMethodFactory objects in this article: One for selecting a payment method through reflection and another for selecting one through a configuration file.)
Apr 01, 2018 · Justin Albano
What topics or details would you like to see so that I can include them in future articles and better incorporate your criticism? Again, I appreciate you taking the time to reach out and provide your feedback.
Mar 30, 2018 · Justin Albano
Providing dynamic parameters can be complex, depending on how you decide to do did. For example, using OSGi, using some external service, etc. Within the context of the Strategy Pattern, so long as the dynamic parameters can be provided, a new payment method (such as credit card) can either be instantiated manually (either using the new keyword or through a factory method) or through reflection, as described in this article.
Mar 29, 2018 · Justin Albano
Thank you for the feedback. To answer your question better, what you do specifically mean by "dynamic parameters?"
Mar 28, 2018 · Justin Albano
Glad you enjoyed the article.
Truth be told, these 5 points on not really "secrets" since they are only "hidden" in plain sight in the Java Language Specification, but they were just 5 topics that I came across in the last few weeks that I had not known before and had not seen other articles or books spend much time on them. I'm sure they will be known to others, but I had personally never seen some of these points before.
Mar 28, 2018 · Justin Albano
Very true. I've updated the listings to use capital L to make it more obvious that the literals are longs.
Mar 28, 2018 · Justin Albano
Strictly speaking, no. There are right there in the JLS for anyone to see (if they so choose to read it), but many of them are not used on a daily basis, and just anecdotally, many developers do not know they exist (myself included until recently).
Mar 26, 2018 · Jordan Baker
It is difficult to tell what the setter is doing just by inspection. In general, boolean arguments for any method (even more so with other arguments besides the boolean flag) can be difficult to read. For example, setComplete(true) is less intelligible than markComplete() (since we have to think about what true or false means and how that will effect the call), or in a case with more arguments, setOrderStatus(someStatus, true), it is difficult to tell what the boolean means. In essence, it is hard to grasp the meaning of the call just from the call itself.
I appreciate you taking the time to ask this and I appreciate you working through this series of articles.
Mar 25, 2018 · Jordan Baker
Thanks for compliment and thanks for the hands-on information about the POM. To add to James's comment, the parent POM for Spring should include the spring-plugin-core dependency, but if it does not work, the dependency entry for that JAR is:
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
Thanks again for the information. I appreciate you taking the time to contribute and help out others who read this series.
Mar 15, 2018 · Justin Albano
How so?
Mar 14, 2018 · Justin Albano
Thank you. Glad you enjoyed it.
Mar 14, 2018 · Justin Albano
Thank you for finding that typo. It has been corrected.
Mar 14, 2018 · Justin Albano
Thank you. Glad you enjoyed it.
Mar 14, 2018 · Justin Albano
Thank you, Denis. I appreciate your feedback and I'm glad you enjoyed the article.
Mar 09, 2018 · Justin Albano
Glad you enjoyed it and thanks for the feedback.
Mar 09, 2018 · Justin Albano
Glad you enjoyed it and it was helpful for you. Thanks for the feedback. There are also more parts to this series:
- The Developer's Guide to Collections: Lists
- The Developer's Guide to Collections: Sets
- The Developer's Guide to Collections: Queues
Mar 07, 2018 · Justin Albano
The requireNonNullElse method was added in JDK 9. I updated the article to explicitly mention that this method was not added until JDK 9. Unfortunately, I didn't originally make a distinction between the requireNonNull method (which was added in JDK 7) and the requireNonNullElse method (which was added in JDK 9). Thanks for taking the time to bring up this issue. I appreciate it.
Mar 07, 2018 · Justin Albano
I'm glad you enjoyed the article. Thanks for catching those two mistakes: They have been corrected.
Mar 06, 2018 · Thomas Krieger
Removing the getter methods would remove the need to return a copy of the original list, but the problem still exists since there is a constructor that takes a list of emails and assigns the list to an internal field. Once the list is passed to the Person class, the client that passed the list to the constructor of the Person object can then modify the list, changing the state of the immutable Person object underneath it: See Gist.
This occurs because the list passed to the constructor is the same list (has the same reference) as the original list: See Gist. To resolve this, the Person class has to make a copy of the email list passed to its constructor: See Gist.
Mar 05, 2018 · Justin Albano
Thank you. I'm glad you enjoyed it.
Mar 03, 2018 · Justin Albano
Thank you for the feedback.
Mar 02, 2018 · Justin Albano
Looking back on it, you are correct. What I really meant to say was that C# classes have non-virtual methods by default. You are correct: That is not the same as saying the class is final (or non-overridable). I revised the article and took out the statement about C# since it would require too much explanation and would detract from the intent of the article.
Thanks for catching that and that's not nit-picking in my book: You are correct about that misstatement in the article and I'm glad you took the time to give me constructive criticism.
Mar 02, 2018 · Justin Albano
You are correct. Thank you for catching that typo and thank you for your feedback.
Mar 01, 2018 · Justin Albano
You are correct, that was a typo. I had created the copy static method for Transmission but accidentally did not use it in the constructor for Car. That snippet has been updated. Thank you for finding that error.
Feb 28, 2018 · Justin Albano
That is very true in a lot of cases. The case that Josh Bloch uses is that of a Point object and CountedPoint object, where the counted point simply increments a static counter variable. In that case, Point(0, 1) and CountedPointer(0, 1) both represent the same Cartesian location, but do not collide in the same manner as a matching Car and Dog with different names. Just wanted to include this to make the example that Bloch gives explicit.
Feb 28, 2018 · Justin Albano
I agree, although a obj.getClass() != getClass() style comparison does have the side-effect seen in the set example above.
(For the record, this is only an issue if providing a custom equals method implementation. If no such override is warranted, and the default implementation (obj == this) suffices, it should be used. It avoids a great deal of the confusion of extra-linguistic documentation.)
Feb 28, 2018 · Justin Albano
You are correct that there is a violation of symmetry here, but it is a very specific violation: Creating a subclass with a new field not present in the superclass. If the subclass does not add new fields and require the equals method to be overridden (or explicitly overrides the equals method), no issue occurs (Gist found here).
In that case, there is no issue, but if we add a new field, we introduce an issue (Gist found here):
The trade-off is that if we do not use instanceof and allow for subclasses to match superclasses (upholding the Liskov Substitution Principle), then Java frameworks that use the equals method will break. For example, if we use the first equals, where Bar does not add any fields and uses the equals method implementation from the Foo class, the following does not work as expected (Gist found here).
Notice that the Bar class does not behave in the same manner as the Foo class (it is allowed to be added to the Set even though an identical Foo object was rejected), thus violating the Liskov Substitution Principle. I do not do this discussion justice in this comment, but Josh Bloch provides a much better description of this problem in Item 10 of Effective Java, 3rd Edition. His suggestion is the following:
Unfortunately, the symmetry rule is not as clear-cut as it should be due to competing interests. There is a trade-off to be had here between satisfying the Liskov Substitution Principle and upholding strict equals symmetry with subclasses with new fields.
Feb 26, 2018 · Justin Albano
This is very wise advice
Feb 26, 2018 · Justin Albano
Correct. I should have made a distinction (the Arrays.asList uses the private inner class ArrayList).
Feb 25, 2018 · Justin Albano
I think there may be a misunderstanding here. In the particular instance that you quote, I refer to the of static methods included in the List and Map interfaces, both of which were added in Java 9, as denoted by the @since JavaDoc annotation in each of these methods (see the List documentation). This does not preclude or refer to any implementations of a simplified list creation method present in Java, of which, many have existed before JDK 9, as you rightly noted.
There have existed methods such as Arrays.asList for many years (or the ArrayList constructor itself), but this method differs in many important ways from the List.of method. In particular, the contract for this method is different in that it always creates a mutable List backed by the supplied array. As a matter of fact, it returns an ArrayList, using the ArrayList constructor that accepts a variable number of arguments:
It's intended purpose is not to create lists, but rather, bridge the gap between arrays and their Collection counterparts (such as List). In contrast, the List.of method returns an immutable List that contains the supplied elements. It also has multiple overloadings to ensure that in most cases (of less than 10 elements), an intermediate array is not created to store the variable number of arguments:
In writing these articles, I do my best to be diligent, precise, and well-researched. As seen from the constructive comments by many astute readers, I make mistakes and many of the readers are kind enough to bring them to my attention, and critically correct them. If there is some error in my article, I am glad to discuss it and learn from any reader, for they have a lot to teach me and I do my best to learn from them.
Feb 23, 2018 · Justin Albano
I agree in many cases, but it depends on the context. Addressing the quote: That quote does not mean only use one or the other or that FP and traditional programming are mutually exclusive. They can be mixed and matched. I.e. if a for loop is easier to read, use it. If a lambda makes it easier, use it. Even if those usages are 2 lines apart.
Feb 23, 2018 · Justin Albano
Thank you for that optimization (you are correct: The Iterable interface includes the forEach method). Although it does reduce the clutter, the reliability issue with the nested iteration still holds.
Feb 23, 2018 · Justin Albano
That method is just a stub for demonstration purposes so it does not have a stated implementation. Many times, lower-level methods (such as those used by databases or over-the-wire protocols) will return null to denote that something is not available. If an error occurred, they would throw an exception, but in many cases, these methods do not consider "no data" an error.
Feb 23, 2018 · Justin Albano
Well-written will be subjective, but it's worth it to browse through some of the following:
- Spring
- JUnit
- Apache Kafka
Again, well-written is subjective, but there's a lot that can be gained by looking at code written to solve monumental problems (such as Spring or many of the Apache projects).
Feb 23, 2018 · Justin Albano
Thank you for the feedback. Glad you enjoyed it.
Feb 23, 2018 · Justin Albano
Thanks for catching that. That was a typo and it has been fixed.
Feb 23, 2018 · Justin Albano
Either one would work. Personally, I find it more readable to include the else, but that's just a personal preference. You could also remove the braces for both if statements and it would work as well:
public boolean equals(Object o){
if (o==this) return true;
if (!(o instanceof Exam)) return false;
...
Feb 23, 2018 · Justin Albano
Be sure to include two braces. I.e., ArrayList<>() {{ /*...*/ }; Also, depending on which version of JDK you are using, the compiler may not be able to infer the type of the generic argument for the ArrayList. Thus, using the diamond operator ("<>") may cause the error you see. The source code in this article was written using JDK 9.
Feb 23, 2018 · Justin Albano
I agree and your points are well taken. From personal experience, along with the opinion of others I've seen, Scala can be difficult to pick up because it does so many thing (well). The volume of learning can at first be a big hurdle to surmount. I agree that it has great benefits, but it does take a lot of work (in terms of learning) to become proficient.
Feb 22, 2018 · Justin Albano
From what I can tell, the reason that the requireNonNull method was created was not necessary to reduce the number of explicitly thrown exceptions, but because the method returns the supplied object if it is not null. That allows the null check and assignment to be shrunk to one line. More of convenience than to remove explicit throw statements. That's my understanding: I would have to look at what the JDK developers said to get a better idea of why they did it.
Personally, I try to do whatever is the most readable. If explicitly throwing an exception works, then I'll use it. If it reads better to have a method that throws the exception, then I'll go with that. I apologize for not giving a very objective answer, but I just try to make a judgment call depending on the context.
Feb 22, 2018 · Justin Albano
That was a typo. Thanks for the catch. The constructor should have a Transmission parameter.
Feb 22, 2018 · Justin Albano
I agree with you both that Scala is a very good language, but just telling people to migrate is not a very good way to win fans. In a production environment with tight deadlines and reliance on Java, it may not be practical, or at least just yet. Learning Scala is not trivial. In order for people to latch on, Scala advocates have to meet developers where they are at in a practical way.
Feb 22, 2018 · Justin Albano
Thanks for the feedback. It is a quirky trick, but I wouldn't suggest it in practice.
Feb 22, 2018 · Justin Albano
Glad you enjoyed it. Thanks for taking the time to provide feedback and ask questions.
Feb 21, 2018 · Justin Albano
Completely agree. Especially with the new List.of and Map.of methods, the syntactic appeal of double-bracing becomes almost non-existent.
Feb 21, 2018 · Justin Albano
Glad you enjoyed the article.
In this case, I made the copy() method static because it represents a named constructor. I could have also made it an instance method. This was more of a personal choice, since the method involved the creation of a new object (closely associated with construction/instantiation). Either one would have worked and in some cases, the instance method may be better.
Feb 21, 2018 · Justin Albano
Thanks, Denis. I'm glad you enjoyed it.
Feb 21, 2018 · Justin Albano
I definitely agree. Learning a JVM language beyond Java is a great way to become a better Java programmer. I would even go one step further and say that learning a (or more than one) non-JVM language. Each has its own quirks and "culture" and learning these helps to break out of the box of "we do it this way because that's the way we've always done it."
Feb 21, 2018 · Justin Albano
Thanks for the feedback. And you are correct. I over-generalized on that statement.
Feb 20, 2018 · Justin Albano
I can understand your point. Total ordering a bit more general, since it can be accomplished using either a Comparator or through natural ordering. I may not have been as explicit as I should have. Merging your idea with the suggestions in the article, the suggestion in the article could be rephrased the suggestion to: Use TreeSet when a Comparator or natural ordering is needed (either of which constitutes total ordering).
Feb 19, 2018 · Justin Albano
Thanks for the feedback. Glad you enjoyed it.
Feb 19, 2018 · Justin Albano
These are both very good options. I tried to keep this article focused on techniques that are within the language itself, but if a team is all using the same IDE, both of the annotations-based techniques you described are good options.
Feb 19, 2018 · Justin Albano
Thank you. I'm glad you enjoyed it.
Feb 18, 2018 · Justin Albano
Thanks for the comment. It's never too late and I appreciate the feedback. You are right about the typos and I have corrected them in the article. Thanks for finding those.
Feb 18, 2018 · Justin Albano
Okay, that part I understand. You're right. Since the removeIf method does an in-place modification, it is not side-effect free. Many of the methods of the Collection interface (removeIf being one of them) have side-effects because it is assumed the collection is mutable. If collections were immutable, they could be made side-effect free, but that would also be very inefficient (i.e. a new collection is made every time new items are added). For that decision, I'd have to defer to the JDK team. That's a decision they made for better or worse.
In either case, I appreciate you're constructive criticism.
Feb 18, 2018 · Justin Albano
Thanks for the feedback. To my understanding, the item in Effective Java is centered around using "side-effect free functions." In that respect, so long as the Predicate for removeIf does not have side-effects, it follows this item. In what respect do you see the removeIf example breaking the side-effect free item? (This is a sincere question so I can understand where you are coming from.)
Feb 18, 2018 · Justin Albano
Thank you, Denis. I'm glad you enjoyed it. Thank you for the feedback.
Feb 17, 2018 · Justin Albano
It matters what context the language is used in. Some think C++ is too expressive or too verbose (I.e. The Rule of 3 and manual memory management), but if you're putting a military aircraft into flight, that may be what you need.
I agree with you that Java is far from a perfect language, but being supremacist about any language is an unwise decision.
Feb 17, 2018 · Justin Albano
Thanks for the feedback. The public final fields are actually typos and should be private final. Thanks for catching that. Those typos have been corrected in both the article and the accompanying Github repository.
Feb 16, 2018 · Justin Albano
Although Scala does have many benefits over Java, a list of 3 things not to do in Scala can be created just as easily. Every language has its trade-offs.
Feb 16, 2018 · Justin Albano
I agree. Having a getter or setter should give pause. In some cases, there may be good reasons to have one or the other, or both, but in most cases, they are unneeded. It should not be the default to include them.
Feb 16, 2018 · Justin Albano
Although I agree that there are some great benefits to other JVM languages, there are also some disadvantages as well. While a lot of these problems are solved with languages such as Kotlin, there just as easily be a list of things not to do in Kotlin.
Feb 15, 2018 · Justin Albano
Thanks for the feedback and thanks for catching that. The typo has been corrected.
Feb 14, 2018 · Justin Albano
Hahaha. Thanks for the catch. Learned something new today (about the Havard Bridge). I appreciate the feedback, as well.
Feb 14, 2018 · Justin Albano
Thank you for the feedback. I'm glad you enjoyed the article.
Feb 14, 2018 · Justin Albano
Thank you for feedback. Glad you found it useful.
Feb 13, 2018 · Justin Albano
Thank you. I'm glad you enjoyed it. Thanks for the feedback.
Feb 12, 2018 · Justin Albano
Thank you. That is a great complement. I really appreciate it.
Feb 12, 2018 · Justin Albano
Thanks for the information. I decided to leave out a discussion of the TCK for this article due to length constraints, but you are right about both the TCK and existing reactive libraries. I tried to convey that the standard Java version is a common set of interfaces so that all of the implementations do not have to rewrite them (since they are all identical). I will add a mention that these interfaces are not intended for standalone use.
Again, thank you for the suggestion.
Feb 11, 2018 · Justin Albano
You are correct: That's a typo that should be "subscriber," not "subscription." Thanks for catching that.
Feb 10, 2018 · Justin Albano
Thanks for the feedback. Glad you enjoyed it.
Feb 10, 2018 · Justin Albano
Thank you for your feedback. I appreciate it.
Feb 09, 2018 · Justin Albano
Although there are multiple libraries that would solve the problem, I decided not to use them, as they would include 3rd party dependencies in the example and would hide details that accompany the explanation.
Feb 09, 2018 · Justin Albano
Thank you. I appreciate your feedback.
Feb 09, 2018 · Justin Albano
Thank you for the feedback.
Feb 09, 2018 · Justin Albano
I agree. It is also an overlooked step in that TDD process. Before moving onto the next feature, there should be some refactoring, if needed.
Feb 08, 2018 · Justin Albano
I appreciate the compliment. If I can improve in anyway, please feel free to let me know.
Feb 08, 2018 · Justin Albano
Thank you. I appreciate your feedback.
Feb 06, 2018 · Justin Albano
I have added an explicit mention of this brevity. Thank you again.
Feb 06, 2018 · Justin Albano
I understand. You are correct, for the sake of simplicity, I combined more than one responsibility into the serializer class. The logic for obtaining the fields to be serialized can be extracted and the JsonSerializer can be refactored to simply create a JSON string from a list of serializable fields.
These changes have been made on a new branch of the repository. This could also be taken one step further, where a strategy implementation can be injected into the serializer, depending on if JSON, XML, or another output format is desired.
Again, I really appreciate the feedback and your constructive criticism.
Feb 06, 2018 · Justin Albano
I apologize. One of the more common arguments (justifiably) against annotations is the use of the annotations themselves. So I can understand your point of view, what part of the JsonSerializer do you believe is a violation of the SRP?
Feb 06, 2018 · Justin Albano
Thank you. I appreciate the feedback.
Feb 05, 2018 · Justin Albano
Thank you for the feedback. You are correct that the annotations attached to the Car class do violate the Single Responsibility Principle (SRP). In general, annotations are an extra-object-oriented means of conveying information (more like meta-programming), but sometimes the trade-off may be worth it. For example, we could create an immutable CarDto class that has a toJson() method and accepts a Car object in its constructor. That would abstract the logic for JSON serialization into the CarDto class and leave the Car class to perform its domain logic.
While this technique maintains the SRP, it can become cumbersome when used in a large system. For example, if there are hundreds of domain classes, each with its own DTO class, it is easy to make a mistake (there is also a great deal of duplication). Whatsmore, it's easy to have the domain class and DTO fall out of sync. Using annotations, the serialization information is found within the class, and thus, is much more difficult to fall out of sync.
Which solution is better depends on the context of the problem being solved, so a developer would need to rely on his or her judgment to decide which option is better.
Feb 05, 2018 · Justin Albano
Thank you. Glad you enjoyed it.
Jan 21, 2018 · Jordan Baker
I created a series of articles on how the REST service was created (the first article can be found here). The repository for this REST service also has implemented JUnit tests for the each of the layers in the service (repository can be found here). For the automated acceptance testing of the REST service, I wrote an article (found here) on how to accomplish this type of testing with Cucumber.
Jan 07, 2018 · Jordan Baker
A common issue is that an exception may be occurring in the web service. You can check the output of the web service in the terminal in which it was started to see if such an exception is occurring. Also, be sure that the request you are making through Postman is correct. An incorrectly formatted request can cause the web service to fail.
Dec 04, 2017 · Justin Albano
Thank you for catching that. The unit area should have been (pi)(r^2), where r = 1, or just pi, not pi^2.
Dec 01, 2017 · Jordan Baker
Thank you. Your feedback and view is prize enough. I appreciate it.
Nov 29, 2017 · Hussein Terek
One of the simpler ways to describe pass semantics in Java is that all values are passed by value, even if it is more nuanced than that. In the case of primitive values, the immediate value (the 7 in int x = 7) is passed. In the object reference case, the reference is passed by value. Reassigning the reference does not change the original reference, but dereferencing it and changing the state of the dereferenced object does change the state of the shared object.
You are correct in saying that "objects" are not truly passed by value (the entire object is not "recreated" and no copy-constructor is invoked), but Java does not deal in objects per-say. Rather, it deals with "object references." Again, a simple way I use to teach the passing semantics of Java is that there are two fundamental, passable types: (1) primitives and (2) object references, and both are passed by value.
Nov 26, 2017 · Justin Albano
Thank you for your feedback. Yes, the VisualComponentFactory is an abstract factory. Many of the original GoF patterns blend into one another and the distinction between them starts to fade when they are applied to real systems. For example, if the factory method is made abstract and used in a non-abstract method, it can be simultaneously thought of as a step in a template method.
For the Encryptor interface, breaking the SRP depends on its purpose. Sometimes, encryption to disk may be a complex process (i.e. where is the key stored, how is it written to disk, etc.). To more clearly define the responsibility of the Encryptor, we could reduce the visibility of the creation method, thus turning it into more of a class with a template method (its main, externally visible responsibility would solely be the writing of encrypted data to disk). There are multiple ways to solve this problem, but in order to maintain the simplicity of the example, I opted to go with an answer that required a fewer number of classes.
Nov 25, 2017 · Justin Albano
Thank you for the feedback.
Nov 25, 2017 · Justin Albano
Thank you for the feedback.
Nov 25, 2017 · Justin Albano
Thank you for the feedback. This article only covers what is officially targetted for JDK 10. I have written a previous article on Project Valhalla, but there is as of yet to official release JDK set for the project. Hopefully, as more information is released, more official inclusions can be added to JDK 10.
Nov 22, 2017 · Justin Albano
I'm glad you enjoyed the article.
Nov 19, 2017 · Justin Albano
Thank you. I'm glad you enjoyed the read.
Nov 18, 2017 · Justin Albano
Although I agree that there are some flaws in the Java technique for generics (non-reified types, type erasure, etc.), it's still good, even for a Scala developer, to know this information as it plays a part in the development of the JVM bytecode to support generics.
Nov 18, 2017 · Justin Albano
Thank you! I appreciate the feedback.
Nov 18, 2017 · Justin Albano
Thank you for catching that: I inverted the direction of the composition to correctly follow the UML convention. Thank you for the feedback.
Nov 09, 2017 · Justin Albano
Thank you for the feedback. In the case you mentioned, Node.js checks if there are any completed promises and handles them. I've changed the article to use "completed" rather than "resolved" to make the point clearer. Thanks for bringing that to my attention.
Nov 04, 2017 · Justin Albano
Thank you for the feedback. The typos have been corrected. I have also added an explicit mention of Uncle Bob's book into the article. I originally left out mention of the original proponents of clean code because I did not want to focus the article on the general principles of clean code, rather than on this specific, actionable way to reduce the issues with writing numerous comments in code.
Again, thank you for pointing out the typos. It is always helpful to have yet another set of eyes to find those types of errors.
Nov 03, 2017 · Justin Albano
Thank you for the feedback!
Nov 03, 2017 · Justin Albano
Thank you. I appreciate the feedback.
Nov 01, 2017 · Jordan Baker
You shouldn't hate to make a suggestion. I appreciate the correction and updated the article to include the correct command. Thank you for giving me a second set of eyes.
Oct 31, 2017 · Justin Albano
Glad you enjoyed it. Thanks for the feedback.
Oct 31, 2017 · Justin Albano
Correct. Code without comments should be the norm unless there is a pressing reason (like an assumption) that requires the rule to be broken.
Oct 30, 2017 · Justin Albano
Java-based configuration is the norm now, but for this example, I used the XML-based alternative because it can be changed without having to recompile any code. The same can be done using a configuration file (as you mentioned with the application.properties file), but that type of change (albeit for reflection rather than the fields of a credit card) is covered in the reflection sections. The choice of XML was simply for brevity so that the example did not become focused on Spring rather than the pattern itself. You are correct in your thought process on how this would work in a real system.
Oct 30, 2017 · Justin Albano
You're very welcome. I appreciate the feedback. If there is anything that you wish to see more of (on this article or in general), let me know.
Oct 27, 2017 · Justin Albano
You're very welcome. Thank you for the feedback.
Oct 25, 2017 · Justin Albano
Thank you for the constructive feedback. I've updated the section on Passing Data in Java to make the fact that object variables store references more explicit. I also included an example of a primitive value (which holds the primitive literal) and an object (which holds a reference to the object) to illustrate the difference.
Oct 25, 2017 · Justin Albano
Thank you for the feedback. I appreciate it.
Oct 25, 2017 · Justin Albano
Thank you. I appreciate the feedback.
Oct 20, 2017 · Justin Albano
Thanks for the feedback. I agree that suppressing warnings should be a last resort. In cases where the warnings are difficult to resolve, such as unchecked casts, it may be necessary. First instinct should be to resolve the warnings, or else, change the situation to ensure that the warning is no longer applicable (i.e. upgrading a library so that an unchecked cast is no longer necessary). If all else fails, and we are aware of the warning, it can be suppressed or the settings for the IDE is changed.
The trick is to leave the code without warnings so that the next person comes along and has some pressure/tendency to leave it without warnings as well. The goal is to stop the following thought: "If there are already 10 warnings (and the project has a little caution sign on it already), what's another 1 or 2?" If changing the IDE settings solves that problem more effectively, go with it.
Oct 12, 2017 · Justin Albano
Thank you. Part 3 has been posted.
Oct 11, 2017 · Justin Albano
Good catch. I've updated the command to no longer include the "s": Thank you.
Oct 11, 2017 · Justin Albano
Glad you enjoyed it. Thank you for the feedback.
Oct 09, 2017 · Justin Albano
Part 2 has just been posted. Thank you for the feedback.
Oct 05, 2017 · Justin Albano
You're very welcome. Thank you for the feedback.
Oct 04, 2017 · Justin Albano
Thank you for the feedback.
Sep 28, 2017 · Justin Albano
You're welcome. Thank you for the feedback.
Sep 28, 2017 · Justin Albano
The code for this tutorial can be found by clicking the Github image at the top. The URL is https://github.com/albanoj2/order-rest-backend.
Sep 27, 2017 · Jordan Baker
When starting the Spring boot application (mvn spring-boot:run), include -Dserver.port=<port_number>, where <port_number> is the desired port number. For example:
mvn spring-boot:run -Dserver.port=1234
Sep 26, 2017 · Justin Albano
The second part of this article can be found here. Part 3 and Part 4 also go into the implementation of the presentation layer and the deployment of the web service, respectively.
Sep 25, 2017 · Justin Albano
Hi Anna, thank you for your feedback. This part of the article focuses on the concepts in general, rather than the specific concepts as they pertain to Java. For that information (along with the specificity that you requested) can be found in Part 3 of this series.
Sep 21, 2017 · Justin Albano
Due to the length of the article, it has been divided into three parts. The first part (this article) focuses on the design and the thought process behind the development of the web service, while the second and third articles will focus on the implementation of the web service and testing the deployed service. Although creating a Spring web service is a short task, this series of articles take the time to delve into the systematic thought process behind making the web service. Our goal is not to create automatons that go through the motions: Our goal is to teach creativity and understanding of the fundamental decisions required to make a solid web service.
Sep 17, 2017 · Justin Albano
Good catch. I've made the correction in the article. Thank you.
Sep 17, 2017 · Justin Albano
I agree with you completely. I wouldn't want that code in a system either (it was included in the article as to be provocative). Although, removing it as a performance enhancement could be wasted effort. The only way to know is by profiling the code.
Also, how do you see that algorithm being cubic (an honest question; I want to make sure I correct the article if it is in fact not square)?
Sep 17, 2017 · Justin Albano
Good catch. I've updated those two factory calls to be static. Thanks for the feedback, Sam.
Sep 17, 2017 · Justin Albano
Good catch. I updated that code snippet. Thanks for the feedback, Sam.
Sep 16, 2017 · Justin Albano
Although I do appreciate the tongue-in-cheek nature of this comment, Java is still one of the most used languages (it commonly sits in 2nd place on Github, behind Javascript) and it would take a serious shake-up to get people to make the move to another language (even another JVM language).
Sep 16, 2017 · Justin Albano
Thanks for the feedback. A disclaimer has been added to the article to make that suggestion explicit.
Sep 16, 2017 · Justin Albano
Thank you for the feedback. If that rule is used as an excuse to not think about the code that is being written, then it is being applied incorrectly. If there is a performance optimization that reduces the complexity of the code and improves its readability, it should be made, but on the grounds of its reduced complexity and increased readability, not on the grounds of enhanced performance. Why? We do not know if is actually increased performance until we profile in a production environment. We may, in fact, be increasing the performance of that method or class, but if there is another class in which 50% of the execution time is spent (and the class we touched only accounts for 1% of the execution time), wouldn't it be more worthwhile to target the class with 50% of the performance bottleneck?
In the cases in your article, I completely agree that doing those optimizations are smart, since they require very little time to perform and don't change the functionality of the system (while at the same time, improving the readability and clarity of the system), but doing them for performance reasons may be unfounded, unless we have context (some performance metric provided by profiling). On large-scale systems, we would want some tangible evidence that our time was well-spent on increasing the performance of each portion we touch.
In general, I don't subscribe to dogmatic rules (as reiterated throughout the article) such as turning one's brain off while programming because "premature optimization is evil." Instead, the thought process should be, "This will take me 10 minutes to make this optimization change, and it may reduce the clarity of what I am trying to accomplish. I'll wait until I see the performance report and come back to it if I need to." That 10 minutes may be spent more effectively elsewhere.
Sep 16, 2017 · Justin Albano
Thank you for the feedback. In the case that there are simultaneously two or more views of identity, the identity of that object should be worked out prior to trying to define an equals method. That being said, there should be some logic behind the identity that can be captured in the equals method. For example, we could create pkMatches(T other) and ukMatches(T other) methods, and the logic for the equals method could be pkMatches(other) || ukMatches(other).
On the immutability of objects dealing with hash codes, it is not immutability of the object itself that is as much of an issue as the immutability of the identifier or the origin of the hash code that is the issue. For example, we could have a mutable object, but if its ID (used for its hash code) is immutable (or more precisely, marked as final), changing the state of the object will not change its hash code. That is the same behavior that would be expected from the default hashCode method. Also, it is a good idea to override the hashCode method when overriding the equals method, but not doing so is not an error per say (the compiler will not stop that class from being compiled); it is likely a logical issue, though, and usually the two are done in tandem.
There are benefits to implementing the equals method: Java and any other third party that relies on the equals method will view the identity of our objects the same way we do. As exemplified in the article, a Set know considers our objects equal in the same way that we used to implicitly consider them equal (our identity logic used to be external, but we internalized it into the equals method).
Sep 16, 2017 · Justin Albano
Thank you again for the feedback. The example I provided is terse in order to keep the article brief, but at the same time, it illustrates the principle in action. Even if the code is "unprofessional," replacing it with a O(nlog n) algorithm does not actually add any performance gain if it is never called. Moreover, development time is finite, and if there is another algorithm that is causing more performance problems elsewhere in the code, replacing this O(n^2) algorithm is not a good use of time. Additionally, if we only ever have a few items in the list, in a practical sense, there is no serious performance gain using O(n log n) over O(n^2). Only if the context is provided (performance profiling) do any of those changes truly provide a performance increase (the context provides the measurement to say if or if not our change actually improved performance in the production environment).
Strictly speaking, if a programmer wrote this algorithm and it passed the written functional tests, it is correct (in the functional sense). To refactor it for simplicity may be wise, but to do it for performance reasons may be a misuse of time. That being said, as iterated continuously throughout the article, that is not always true.
Sep 13, 2017 · Justin Albano
Thank you for the feedback, Keith. I will make sure to work this style into future articles.
Sep 13, 2017 · Justin Albano
Thank you for the feedback. I tried to keep this series as concise as possible, which meant that I could not include all principles and best practices. Although composition over inheritance is a good principle, it is very nuanced (when to use it and when it is valid to use inheritance). Discussing it would require an article in-and-of-itself. Therefore, I left it out for the sake of focus and concision.
Sep 13, 2017 · Justin Albano
Thank you for the feedback. That is a fair point. I now added in a disclaimer that this null-terminated scheme is not how Java stores strings. Although it was my intent to demonstrate a generic memory scheme (in this case, the C string memory scheme), I did not make that point explicit. Thank you for helping me improve this article. It is much appreciated.
Sep 11, 2017 · Justin Albano
Thanks for the feedback. The next article in the series is posted here.
Sep 11, 2017 · Justin Albano
Thank you, Kunle. I'm glad that it's been useful. I appreciate the feedback.
Sep 07, 2017 · Justin Albano
Thank you for the input. Your insight is much appreciated.
Note that this article does not describe the actual implementations of memory management used by a JVM, but rather, a general scheme that is used as the basis for memory management.
Sep 05, 2017 · Justin Albano
Thanks for the feedback, Gemma. Are you looking for a video tutorial simply walking through how the specification was created, or walking through the thought process behind each of the additions to the specification?
Sep 05, 2017 · Justin Albano
Hi QingYu, I do not mind, but I would contact a DZone representative to make sure that DZone is okay with translating an article on their site.
Aug 03, 2017 · Arani Chatterjee
I very much agree with your points (previously I wrote an article on this topic as well). I also think that when it comes time to learn a language, it is important to select a wide array of languages and learn them how the masters in those languages understand them. For example, when writing C++, follow the Rule of 3. While it's important to have a general understanding, it is important to know the idiosyncracies of each language (including the naming conventions of each).
Jul 21, 2017 · Justin Albano
Okay, now I understand what you are saying. The case I stated before is a templated class (i.e. C++ or C#), but you are right, generics in Java do not incur any runtime overhead since they are erased.
Jul 21, 2017 · Justin Albano
To my understanding, there is a type created to represent generic, with the actual type filled in. For example, a type similar to CustomCloneable_with_Vehicle, since the type information must be represented at runtime once the type has been erased. I would need to inspect the actual bytecode generated to see where this generation takes place and how much bytecode is generated. For example, if we had a Car and Truck class that subclassed Vehicle, I'm not sure if there would be a CustomCloneable_with_Car and CustomCloneable_with_Truck class generated, which represents 2 more classes than the non-generic technique. (I don't have a specification, but there's a mention of it in the tutorials.)
In this particular case, or especially when the top-level interface, such as Cloneable, is not modifiable, then covariant return types are a simple option (or the only option, since the top of the hierarchy does not have a generic parameter).
Again, I appreciate your feedback: I've learned a lot from it.
Jul 21, 2017 · Justin Albano
For the new type, I mean that bytecode must be generated to represent each of the implementations. For example, a CustomCloneable<Car> type must be generated by the JVM. This process gets repeated for each of the types that are passed into the generic. At a JVM level, there is more that must be done to support generics (type erasure, etc.) rather than a simple compile-type constraint such as covariant return types. That's not to say that generics and covariance with generics aren't useful, but for the purpose of this article, I used the simpler route to demonstrate the principle.
For the "Joint-Union" terminology, it's more colloquial:
https://www.reddit.com/r/programming/comments/1fr8fv/little_known_java_feature_joint_union_in_type/
I agree with you, though: This technique is an intersectional generic type. I've updated the article to reflect the better terminology. I even included your link for reference. Thank you. I appreciate your feedback and helping me improve the article.
Jul 21, 2017 · Justin Albano
Thank you. I'm glad it was helpful.
Jul 21, 2017 · Justin Albano
I avoided generics because they didn't add any capability. In fact, they would have added bloat, since the subclasses would have extended CustomCloneable<T extends Vehicle> when they could have just as easily have extended CustomCloneable (the non-generic form). Using generics would have also created a new type for each and every class that performs a covariant override, rather than derive from a single class (creating a cohesive class hierarchy).
As for the Joint-union types, you are correct: In following the vernacular of set theory, the generic types are intersected, but after doing some research, the most common name I found for that technique was "Joint-union." I did not create the name, I simply followed existing nomenclature.
Jul 20, 2017 · Justin Albano
Thank you for the feedback. The error has been corrected.
Jul 20, 2017 · Justin Albano
Thank you, Paul. Your feedback is greatly appreciated.
Jul 20, 2017 · Justin Albano
By overriding the Object::clone method, there would have involved the restriction of the exception types thrown, since Object::clone throws a CloneNotSupportedException in its declared signature. I did not want to involve the restriction of the exception type (for brevity, I would have removed the declared exception from the overridden signature).
Instead of mentioning qualifications on the overridden method, I wanted to avoid it entirely. Introducing Object::clone would have muddied the waters of the simple covariant example.
Jul 19, 2017 · Justin Albano
Thank you. I appreciate your feedback.
Jul 19, 2017 · Justin Albano
Thank you. And good catch. The CustomCloneable method is correct, but the overridden method is incorrect (it should be customClone). I didn't use the clone() method because it would implicitly override the Object::clone() method and would confuse the intent of the code snippet.
Aug 10, 2016 · Sam Atkinson
Source code and tests included: https://github.com/albanoj2/dzone_splurth_periodic_table
Jun 07, 2016 · Matthew Casperson
This is true in particular for Java, but not in the general case of all object-oriented languages. In the case of C++, an object can be returned as a read-only refenece to the object. For example:
const SomeObj& getSomeObj () { ... }
. In this case, the exact attribute is returned, but the client accessing it cannot alter the state of it. This is different than returning a copy: The copy represents the state of the object at the time when the copy was obtained, not when a call is made to it.Feb 11, 2016 · Matt Werner
Interesting take. It was made even worse in C and C++, where NULL was only a directive for the integer value of
0
. A very perplexing problem was the creation of two methods, one that accepted an int and another that accepted a pointer:If a value of NULL was supplied to
someMethod
, which one was called? C++11 solved this by introducing an entirely new construct that represented a null pointer:nullptr
.Jan 26, 2016 · Matt Werner
I think you are right that deviations are a good indicator that an issue is starting to arise, but I do not think that is a sufficient solution in-and-of-itself. For example, if a pipeline is configured to ensure that some metric, such as complexity, does not increase by more than 1%, at worst, each checking can increase the complexity by 1%. After 10 commits at this rate, the complexity increases by 10.5%. After 50 commits, the complexity increases by 64.5%.
In general, there needs to be some indicator measured in absolute terms. Am I misunderstanding?
Great article!
Jan 20, 2016 · Justin Albano
You are correct. For the sake of brevity, I did not include synchronization logic for the list of animals, since there is superfluous to the observer pattern itself. In order to protect against this race condition, you would need to add some means of synchronization mechanism (such as in this Stackoverflow post).
Again, your observation is correct, but since we can have an observer pattern without access to a list of managed objects, this is left to the reader as an exercise.
Jan 18, 2016 · Alex Theedom
Very useful way of creating a known set of strategies. The upside is that this approach is that the operations known now can be implemented without the boilerplate code of creating a new class for each operation, but this still allows for extension (future operations can be created; i.e., this approach does not stop others from creating their own operations).
Thanks for the cool approach!
Jan 13, 2016 · Dave Fecak
Well said. Going off of The Pragmatic Programmer's idea of Don't Repeat Yourself (DRY), anytime you hit Ctrl+C and then Ctrl+V, you should hesitate. Even if it's a single line, a programmer should hesitate about copying and pasting code: It's likely that this code can be extracted into a function or a new class with a method that can be used in multiple locations. This doesn't mean you can never copy and paste, it just means you should think about it before you do it.
Jan 06, 2016 · John Vester
Very cool article. I like that you pointed out that the program is "self-contained." Some projects are tied to the IDE that was used to develop it, but that not only marries a project to an IDE (which is essentially an arbitrary dependency, based on the opinion of the developer), but also makes automation very difficult. For example, if the application is a stand-alone application, as in the case of this article, it is much easier to use a deployment pipeline, such as GoCD, to test and deploy your application.
Dec 30, 2015 · Justin Albano
Very true. It is a difficult balance, and I completely agree that it takes many years to become truly competent in a language. It is difficult enough to become an expert in even a single language, let alone many languages. In most cases, a person will use a specific language on a daily basis (for example, Java) and will become very experienced with that language.
As suggested in The Pragmatic Programmer, getting a taste of other languages is more important than becoming an expert. For example, I normally program in C++, but I do know that in Ruby and Scala, everything, including a numeric literal, is an object (in C++, there are "special" basic types, such as int and char, that are not objects). Just that basic knowledge brings a bit of perspective to the table. As another example, in C++, nearly everything is accomplished at compile-time (i.e., metaprogramming is used rather than a reflection mechanism), but I know from Java that this is not the only way of doing things. Just that knowledge allows a developer to say, "Wait, this program needs to be portable between Windows and Linux, so a run-time oriented language, like Java, may be a better bet." There's some balance that must be struck between digging a hole a mile deep and an inch wide, or a hole a mile wide and an inch deep.
You are definitely right that learning many languages is not easy, and it is not easy to become an expert in multiple, but in my opinion, even a cursory knowledge of other languages makes a developer more flexible.
Dec 29, 2015 · Justin Albano
Very much appreciated, Jim.
Dec 29, 2015 · Justin Albano
On your first point, I'll leave the tenure comparison to others: When it pertains to the topic, I will mention it. Otherwise, it would be a side-track to the discussion (and, in any case, a fallacy of authority).
On the car analogy, I meant for it to be a comparison, rather than suggest equality. I realize you understand that, based on your first statement about the analogy matching with the trade-offs between languages, but I wanted to be explicit in that. There are many differences between the car market and programming language development, but my statements on the topic were just a measured continuation of his original analogy.
On the point about SQL not being Turing Complete, I agree. I should have been more direct in saying that it was my intent to note that all the main programming languages (i.e., C, C++, Java, Python, Ruby, etc.) are Turing Complete, so they could theoretically get the job done, but that some jobs were easier to get done in specific languages. The way I said it in my comment made it easy to conflate the point that all programming languages (i.e., any programming acronym that ends in L, e.g., SQL, XML, etc.) are Turing Complete. In my mind, those are more of representational languages, rather than computational languages (for example, I can represent data in those languages, or a DSL, more naturally than in one of the programming languages I mentioned above).
Thank you for your feedback, Jim. I appreciate the perspective you bring. Even though I fall under the, "young gun" group of software developers, I've always enjoyed hearing from the more storied developers.
Dec 29, 2015 · Justin Albano
You have been working in the field much longer than I have, so I will leave the historical information in your court (as my tenure is not as lengthy). I agree: There's a sense of dogmatism for some of the newest technologies on the market. Personally, I like Python, but I have met many people that think you need no other language but Python (ironically, the langauge is based largely on C and Python's most effictive libraries are usually written directly in C; see the last 3 points in the article). To me, that's an issue with the people using the language, not the language itself. As an acedote, if you will: I had someone tell me that the fact that Python doesn't allow for explicit typing is a benefit and that, "We are all adults and can police ourselves." That is fine in some cases. In others (the embedded, safety-critical, real-time realm I'm accustomed to), that's not acceptable. Period. I'm not willing to risk lives on my "adulthood." I want the compiler to catch as much as possible, because, be-that-as-it-may, I am an adult that makes mistakes.
On the cars topic, I partially agree. The portion I agree with you is that, at the heart of it, they are all languages. The fact that all cars have tires and an internal combustion engine (the majority, at least) is akin to saying all languages have something similar to functions and all OO languages have the concept of objects. The part I disagree with is the lack of detail presented. In your comparison between GM and Porsche, they are similiar, but not the same. I know how to drive a car (gas, brake, clutch, steering wheel, etc.), but there in fact is a difference between driving a GM and Porsche. For example, if I try to corner a turn in a GM the way I would in a Porsche, I'm likely to end up in the guardrail. If I try to pack 6 people in a Porsche (a nice one, at least), I'm likely going to be putting people in the trunk. The reason? The GM is meant for economy. The Porsche is meant for performance. In the context of performance, I'll take the Porsche over the GM any day of the week. If I need good gas-milage, the ability carry 6 people, and a reasonable price, I'll likely take the GM. There is no silver-bullet: If you find a car that is cheap, can have the performance of a Ferrari, holds 6 people, and gets 35+ MPG, let me know...I'll buy 2.
To me, it's the same with the languages we use. In the context of a big-data system, I'm more likely to pick a NoSQL database, since it lends itself to that application. For example, if I'm building a social networking application, I'm likely to use something like a graph database (the language being the query language used by the graph database), since they are tuned for those type of applicatons. If I was building a small office application that manages the employees at a company (say the company had less than 1,000 employees and was not likely to grow to a 10,000+ employee company), I would likely stick with a relational (SQL) database, since it lends itself well to that application. It all depends on the context of the problem.
I was told once, "If the only tool you have is a hammer, then every problem looks like a nail." If I'm honest with myself, it's true. If I know C++ and SQL, I see every problem as a problem that can be solved with C++ and SQL. But, what if I need to use AMQP with my application (an external constraint placed on me by my customer)? If I use C++, I have to struggle and write my own implementation of AMQP. If I use Java, Python, or C#, I can simply use the well-tested and proven implementations. By simply changing the language I used, I may have saved weeks or months on my project schedule.
This is the point of the article: Many times, there are statements like, "This is the best tool ever" (such as with your SOA and NoSQL statements you brought up), but it's only good in a certain context. Just like the car, there is no silver-bullet. If you find a language that has the efficiency of C, the type safety of C++, the compile-time nature of C++, the libraries of Java, the ease of programming of Python, the flashiness of Ruby, and the "how did I just do that in 2 lines?" of JavaScript, everyone would be using it. The issue is that all of these languages can solve all those problems (they are all Turing Complete), but some are better than others at solving certain problems. The problem is that we take them out of their contexts and say that they are the best in absolute terms.
Dec 29, 2015 · Justin Albano
Thanks for the comments, Ash. On your first point about the proliferation of languages, each has its own benefits and drawbacks and each language author thinks they can solve the outstanding problems better than the other. The point of the article is that some languages solve different problems better than others. For example, if I'm looking for a good web-language that lends itself well to an MVC type of architecture, then I'm more likely to use JavaScript with AngularJS or Dart with AngularDart. Notice it was the goal of the task that drove that decision, not the fact that it was the sole language I knew (or was comfortable with).
Strictly speaking, almost every programming language is Turing Complete (I cannot think of one of note that is not), so any programming language can solve any Turing computable problem, but that does not mean it is easy to do so. The company I work at specializes in embedded system, and in most cases, their language of choice is C or C++. On some projects, though, with a "get it donewell enough" qualifier, I'm more likely to use Python if possible, since I can complete the same task much quicker, albeit not as efficiently, but efficiency is not as much of a concern. I could complete the same task in C++, and have actually conceived of a solution in C++, but I understood that I could meet the requirements much quicker if I used Python, and thus, that is the language I selected. I could have completed the task using any number of languages (Ruby, Perl, Algol, Fortran, JavaScript, Dart, Java, etc.), so the selection of the language was based on my judgment of which language would complete the task quickest, since that was our goal.
Every language has its trade-offs: The fact that Python is not explicitly typed and is a predominantly run-time language was a huge advantage in me completing my task much quicker, but on projects were safety is a must, the compile-time nature of C++ shows its advantages. It all depends on the context in which the task at hand is being completed.
On the topic of investing in a single language or small set of languages (hopefully I understood you correctly, since you appear to have an issue with the number of languages available today and the lack of investment in language development), I do not foresee that being the case. It's very similar to car companies: Each thinks, rightly or wrongly, that they can design a better car than the other. I.e., Chevy thinks Ford does X, Y, and Z wrong, and they can build a better car by improving on X, Y, and Z. Whatsmore, one company may solve different problems better than others: One company may make a better pickup truck better than another, but continuously fails to make a better car than that company. There is no single automobile that can carry many people, haul a sufficient amount of weight, and get great gas milage: The trick is prioritizing your needs and selecting the type of car accordingly.
Dec 22, 2015 · Sam Atkinson
I agree with the BDD-specific naming convention: The Given, Then, When naming convention has a place, but it can be overly-complex for a unit test, which is testing at the unit level, rather than the acceptance (or system) level.
I usually have a test name that starts with the action executed, Ensure, and then the action I expect. For example, fireCannonEnsureBallCaught. If I am using a language that does not have a test annotation like Java, I will usually preceed the name of the test with test; i.e., testFireCannonEnsureBallCaught to make it explicit that the method is a test. If the unit test library explicitly denotes that the method is a test (such as GoogleTest for C++), then I will leave off the test prefix.
Dec 18, 2015 · Sam Atkinson
I agree: If the compiler can be used to ensure that you have completed what you intended to do, it should be used (particularly since the @Override annotation is simple and concise).