Java static methods can be a code smell

Definition of code smell (from Wikipedia):



“any symptom in the source code of a program that possibly indicates a deeper problem.”

In Java,
static methods allow you to execute code at a “class scope” as opposed to an instance scope like member methods. This means, they rely on class-level variables (if any), parameters passed to the static method, or any other globally accessible data. They are NOT object oriented. An object has state associated with it and can be manipulated only through methods that implement the object’s “behavior.” Static methods do not operate on state, they are not object oriented, and in fact they are procedural.

Is this bad?

No. Although Java is object oriented, there will be times when procedural-like programming in Java is necessary and/or preferred. The real power in any object-oriented language is the ability to closely implement a model of real-life systems in code (see my
post about object-oriented modeling). But even in the most hard-core object models, there will mostly likely be some glue code, or infrastructure code that will be implemented in a procedural style.

So if procedural-like programming in Java isn’t “that bad” and static methods are a form of procedural programming, are static methods bad?

Ahh… the answer isn’t as simple as a “yes”, or a “no” regardless of what you may read on other blogs But I could probably ramble on and on about why it’s really a decision that has to be made in context, so let’s keep this article focused by examining a set of statements that I encountered in
“How to Mock Static Methods” from Michael Minella’s blog:

“Something that has become a fundimental [sic] piece of the language (all you need to do is look at the Apache Commons project to see that) is so bad that it must be avoided at all costs in the name of testing. Gosling (or someone on his team) put it in the language for a reason and to avoid those uses solely because your toolset doesn’t support the testing of it is nonsense. Time to get a new toolset.”

First, I’d like to point out that just because something has become a fundamental piece of a language doesn’t mean it’s “good” or something that should be done. Take a look at
checked exceptions for reference. I recall EJB 1.x and 2.x becoming a “fundamental” piece of Java EE in the past, so look at that for reference too.

Second, although I do agree with Michael in theory that avoiding a particular language feature because your tools don’t support it is silly, his premise is focused on static methods. Avoiding static methods because your tooling doesn’t support them is NOT nonsense at all. In fact, the type of impedance caused by some of the good testing and/or mocking frameworks (of which
Mockito is my favorite
:) ) and static methods can be confidently identified as a code smell. This does not mean we should not do it, but we should exert extra effort to understand why we are doing it and explore alternatives if there are “deeper problems.”

There are at least two types of static methods that I would like to point out don’t usually show much impedance with testing/mocking frameworks. The first type is static methods used as utility methods, as those found in a lot of the
apache commons libraries, or your own internal commons libraries. These are usually routines that are supportive of a particular method’s objective, and mocking/stubbing them out of a unit test wouldn’t make sense. They are part of the implementation, and should be tested as such. The second type is static methods used in place of constructors as Joshua Bloch showed in his book
“Effective Java.” This use of static methods allows you to construct a new object using a method with a very descriptive name, among some other advantages. An offshoot of this second type of static method could include factory methods, but that would depend on context.

The most glaring code smell as a result of static methods and testing-framework impedance arises when a unit relies on a static method that performs logic outside the scope of the responsibility of that unit. In these cases, your testing framework will fight you because you cannot stub/mock the out-of-scope logic because it is “hardcoded” via a static method. This can be considered a “deeper problem” and is the focus of most blogs that tell you not to use static methods because testing becomes abnormally difficult or impossible. Changing the design approach to follow the Dependency Inversion Principle is one alternative. A better understanding of how to test the unit is yet another.

I assert strongly that in the case of static methods, the push-back you may get from your testing frameworks is indicative of a code smell, not that you need to try and find a framework that uses complex trickery with class loader remapping as a solution. One should be poised to evaluate the use and fundamental drawbacks of a particular approach in their design. Michael’s blog entry lends the reader to too easily assume a new tool/framework just because Java supports static methods and your current testing frameworks illuminate an impedance — in this case, the impedance reflects a code smell and some deeper, more critical thinking is required.


Reference:
Java static methods can be a code smell from our
JCG partner Christian Posta at the
Christian Posta Software blog.

Source : http://www.javacodegeeks.com/2012/05/java-static-methods-can-be-code-smell.html

Advertisements

Programs and Technical Debt

Once you have a program (a collection of interrelated projects focused on one business goal) and you have technical debt, you have a much bigger problem. Not just because the technical debt is likely bigger. Not just because you have more people. But because you also geographically distributed teams, and those teams are almost always separated by function and time zone.

So, my nice example of a collocated team in
Thoughts on Infrastructure, Technical Debt, and Automated Test Framework, rarely occurs in a program, unless you have cross-functional teams collocated in a program. If they do, great. You know what to do.

But let’s assume you don’t have them. Let’s assume you have what I see in my consulting practice: an architecture group in one location, or an architect in one location and architects around the world; developers and “their” testers in multiple time zones; product owners separated from their developers and testers. The program is called agile because the program is working in iterations. And, because it’s a program, the software pre-existed the existence of the agile transition in the organization, so you have legacy technical debt up the wazoo (the technical term). What do you do?

Let’s walk through an example, and see how it might work. Here’s a story which is a composite from several clients; no clients were harmed in the telling of this story.

Let’s also assume you are working on release 5.0 of a custom email client. Release 4 was the previous release. Release 4 had trouble. It was late by 6 months and quite buggy. Someone sold agile as the way to make software bug-free and on-time.

You do not have automated tests for much of the code, unit tests or system tests. You have a list of defects that make Jack the Ripper’s list of killings look like child’s play. But agile is your silver bullet.

The program manager is based in London. The testers for the entire program are in Bangalore because management had previously fired all the testers and outsourced the testers. That was back in release 2. They have since hired all the Bangalore testers as employees of the Bangalore subsidiary. The program architect is based in San Francisco, and there is an architect team that is dispersed into 4 other teams: Denver, LA, Munich, and Paris. The developers are clustered in “Development Centers of Excellence:” Denver, LA, Cambridge, Paris, London, Munich, and Milan. That’s 8 development teams.

Oh, and if you think I’m kidding with this scenario, I’m not. This is what most of my clients with geographically distributed teams and programs face on a daily basis. They deserve your sympathy and empathy. Do not tell them, “Don’t go agile.” That’s nuts. They have a right to go agile. You can tell them, “Don’t go Scrum.” That’s reasonable. Scrum is for a cross-functional co-located team. Agile is for everyone. Scrum is for a specific subset.

What do you do?
  1. Assign specific testers to specific development teams. No calling people resources; that allows managers to treat people like resources and plug-and-play them. You need to get rock-solid teams together. Once you have teams together, you can name them.
  2. Name teams so the teams reflect the feature groups they work on. What does an email product do? It gets email, it sorts email, it deletes, it forwards, it creates new mailboxes, and so on. The eight feature teams had to be named for the feature areas: Platform for the general features, Sort, Delete, Forward. There were two teams who worked on Platform. They were called Platform 1 and Platform 2. At one point, someone suggested they call themselves Thing1 and Thing2 from the Dr. Seuss book.
  3. Make sure you have enough product owners so they can develop roadmaps for each feature area. With a roadmap, the teams know where they are going. Even more importantly, the architects know where the program is going.
  4. Architects think and provide just enough guidance ahead. In a small project, the architecture can probably evolve with the project. In a larger program, that risk is too large. You have too many people developing in parallel for the architecture to evolve on its own with no guidance. But I do not mean there should a Master Architect Who Knows All Handing Down the Architecture From On High. NO NO NO.
    I want the architect who is a working member of the development team, who also is part of an architecture community of practice team, who curates the architecture, who guides the business value of the architecture. I do not want Big Architecture Up Front. But Thinking Up Front? Sure, that’s a great idea. Stuck on only one idea? Bad. Willing to spike an idea? Great. Willing to play in a sandbox and debate several ideas? Great. I wrote about this before, in
    How Agile Architects Lead.
  5. Decide what done means for every feature. You must have acceptance criteria for each feature. What does that mean? You need a product owner present for each team. You still need the conversations with each team to discuss what done means. Especially with a geographically distributed team, you need the conversation when you create the backlog at the beginning of the iteration.
  6. The US development teams had trouble planning their iterations with their testers, because of the time zone differences with the testers. So, they asked their product owners if the product owner would write more than just a few phrases on the cards, because that would help them get through the iteration planning meeting faster. Someone was going to get up early or stay up late, and either way, someone was going to suffer. It made more sense to have a little bit more preparation than less sleep.
  7. Decide to do continuous integration and stick with it. Especially if you know you have technical debt and you don’t want to create more, you have to do continuous integration now. That prevents more technical debt.
  8. I have recommended to some teams that they have one-week iterations so that they stop the estimation nonsense and make their stories small. The point of estimation is so that you have an idea of what you can do as a team and not commit to more than that. The idea is that if you know what it takes to make your stories small, you will.
    Instead, we have all these crazy rituals around estimation and management tracking velocity of all things. (Yes, I’ve been drafting this post for a long time, and I wrote
    Why Does Management Care About Velocity? last week.) You know, velocity is a little like weight. Only you and your doctor need to know your weight. If you are healthy, you are fine. If you are not, you need to change something.If your team velocity is not healthy, you, as a team, need to change it. But, your management has no business butting its head in. Only you can change it.
  9. When you limit the iteration length, you tend to have the team swarm around a story. This is a tendency, not a given. If I really was the Empress of the Universe, I would decree this, but I’m not, so I won’t. If you want to decrease technical debt, or even eliminate it on your program, explain that your team will only work on one story at a time until that story is done. That story will be polished and gleaming. Fast. You will not have to worry about what kinds of testing will be done. All if it will be done.
  10. Explicitly discuss what you will automate for testing and when. In a program, I assume we will have automated system tests first. I assume we will do exploratory tests later. That’s because if you don’t start building something for test automation when you start the program and refactor as you proceed, you can never catch up. I assume every time we fix a defect, we will have an automated test for it. I also assume we build these assumptions into how we develop 🙂

So far, this is all about preventing more technical debt, not what happens when you trip over technical debt as you enter code or tests you never looked at before.

If you expected to walk into a closet, take out a shirt, and close the closet door, that’s one thing. But now, you stepped into something out of one of those death-by-hoarding shows on TV, you have an obligation to do something. You can document the problem as you encounter it; you can let the product owner know; file a defect report; write a test so you can contain the debt; and maybe you have more options. Whatever you do, make sure you have done something. Do not open the door, see the mess inside and close the door on the mess. It’s tempting. Oh my, it is tempting.

See, on programs because of the size, everything is magnified. With more people and more teams, everything is harder. Things happen faster. If you have co-located cross-functional teams, no problem. But if you don’t have co-located cross-functional teams, you have to work with what you have. And, if you already have a big legacy product, you want to address technical debt in small chunks, refactoring in small bits, integrating as you proceed.

My philosophy is this: the bigger the program, the more you need to become accustomed to working in small chunks, integrating as you go. Fully implement a small story, integrate it on the mainline. Everyone on the program does that. If you need help from an integration team, so be it.

But, if everyone only implements small stories, and everyone takes care of their own technical debt as they discover it, you don’t need an army of integration people. You only need an army of integration people when you have technical debt around integration and release. Fix that, and everyone can become responsible for their own integration.

And, if you can’t release, that’s where the architects should start. If you can’t do continuous integration, that’s where the architects should start. Because that’s what’s preventing you from making progress on the product. Work backwards from release, and then the architects can work on the rest of the product. Until you can release and build reliably, the rest of the product doesn’t matter.


Reference:
Programs and Technical Debt from our
JCG partner Johanna Rothman at the
Managing Product Development blog.

Source : http://www.javacodegeeks.com/2012/05/programs-and-technical-debt.html

Publishing Play 2 modules on github

Now you’ve doubtless followed my
earlier
guides on writing modules for
Play 2, I imagine you’re keen to show your coding chops to the world. The problem is – and this is quite a big one, I’m afraid – there is no place to publish your modules to. When I first starting writing Play modules, the repository was already set-up and ready to go – however, it used a custom format (state of the art download-and-unzip). This changed to some degree with Play 1.2, but I have to say I’m not a fan of that dependency management mechanism; I’m just too damn old to learn these shiny new things.

With Play 2, things swung around again and the dependency mechanism is compliant with Maven and Ivy. I can hear enterprises up and down the planet rejoicing.

However, this still doesn’t help you achieve your well-deserved glory and fame, unless you happen to host your own Maven/Ivy repo or feel like hacking the auto-generated artifact models that Play generates. Help is hand, until Play 2 modules have an official release mechanism, using GitHub’s Pages feature. Very simply, we’ll use Play’s publish-local task to generate all the files we need in the correct directory structure, and then copy that structure as-is directly into GitHub pages. A publish in this manner can be done in less than a minute, after you’ve done the initial set-up in GitHub.

Creating the repository in GitHub

If your GitHub user name is, for example,
foo, then creating a repository called
foo.github.com hooks you into Pages – what you commit here will be available at http://foo.github.com. There’s no GitHubby goodness when it comes to displaying files here – what you commit is what’s available in its native form. Commit a HTML file (let’s call it bar.html), and point your browser at http://foo.github.com/bar.html and you’ll see the rendered HTML – not the source of it. This makes it ideal for exposing files that you want represented in their raw form – say, the jar file containing your Play 2 module.

So, go ahead and create a

.github.com repository and clone it to your workspace, and cd into it. In here, you can replicate (kind of – see later) a meven repository.

To keep things nice, the first directory you should create is
releases. If you also want to add a snapshot directory, do it at this level.

Note: When you first create the repository in GitHub, it can take up to 10 minutes for it to become available. If you haven’t changed your email preferences, you should receive a notification when it is ready. This doesn’t stop you committing to the repository in the meantime.

Publish the files locally

Let’s assume your module name is
hurdy as the artifact name. Your Build.scala looks like this:

import sbt._
import Keys._
import PlayProject._

object ApplicationBuild extends Build {

    val appName         = "hurdy"
    val appVersion      = "1.0"

    val appDependencies = Seq(
    )

    val main = PlayProject(appName, appVersion, appDependencies, mainLang = JAVA).settings(
    )
}

(The mainLang value may be something else, depending on your primary language).

In the root of your module, start up Play and publish it locally:

steve@hex:/tmp/hurdy$ play
[info] Loading project definition from /tmp/hurdy/project
[info] Set current project to hurdy (in build file:/tmp/hurdy/)
       _            _
 _ __ | | __ _ _  _| |
| '_ \| |/ _' | || |_|
|  __/|_|\____|\__ (_)
|_|            |__/ 

play! 2.0, http://www.playframework.org

> Type "help play" or "license" for more information.
> Type "exit" or use Ctrl+D to leave this console.

[hurdy] $ clean
[success] Total time: 0 s, completed Apr 21, 2012 9:49:00 AM
[hurdy] $ compile
[info] Updating {file:/tmp/hurdy/}hurdy...
[info] Done updating.
[info] Compiling 4 Scala sources and 2 Java sources to /tmp/hurdy/target/scala-2.9.1/classes...
[success] Total time: 7 s, completed Apr 21, 2012 9:49:08 AM
[hurdy] $ publish-local
[info] Packaging /tmp/hurdy/target/scala-2.9.1/hurdy_2.9.1-1.0-SNAPSHOT-sources.jar ...
[info] Done packaging.
[info] Wrote /tmp/hurdy/target/scala-2.9.1/hurdy_2.9.1-1.0-SNAPSHOT.pom
[info] :: delivering :: hurdy#hurdy_2.9.1;1.0-SNAPSHOT :: 1.0-SNAPSHOT :: release :: Sat Apr 21 09:49:12 CEST 2012
[info]  delivering ivy file to /tmp/hurdy/target/scala-2.9.1/ivy-1.0-SNAPSHOT.xml
[info] Generating API documentation for main sources...
[info] Packaging /tmp/hurdy/target/scala-2.9.1/hurdy_2.9.1-1.0-SNAPSHOT.jar ...
[info] Done packaging.
model contains 23 documentable templates
[info] API documentation generation successful.
[info] Packaging /tmp/hurdy/target/scala-2.9.1/hurdy_2.9.1-1.0-SNAPSHOT-javadoc.jar ...
[info] Done packaging.
[info]  published hurdy_2.9.1 to /home/steve/development/play/play-2.0/framework/../repository/local/hurdy/hurdy_2.9.1/1.0-SNAPSHOT/poms/hurdy_2.9.1.pom
[info]  published hurdy_2.9.1 to /home/steve/development/play/play-2.0/framework/../repository/local/hurdy/hurdy_2.9.1/1.0-SNAPSHOT/jars/hurdy_2.9.1.jar
[info]  published hurdy_2.9.1 to /home/steve/development/play/play-2.0/framework/../repository/local/hurdy/hurdy_2.9.1/1.0-SNAPSHOT/srcs/hurdy_2.9.1-sources.jar
[info]  published hurdy_2.9.1 to /home/steve/development/play/play-2.0/framework/../repository/local/hurdy/hurdy_2.9.1/1.0-SNAPSHOT/docs/hurdy_2.9.1-javadoc.jar
[info]  published ivy to /home/steve/development/play/play-2.0/framework/../repository/local/hurdy/hurdy_2.9.1/1.0-SNAPSHOT/ivys/ivy.xml
[success] Total time: 3 s, completed Apr 21, 2012 9:49:15 AM


Move the published files into GitHub

The files have been published to
${PLAY_HOME}/repository/local, and are contained in the
hurdy directory. Move this entire directory to your new git repository

cp -rv ${PLAY_HOME}/repository/local/hurdy <your username>.github.com/releases

Change directory to

.github.com
, and add all the files to the git repository, commit and push them.

steve@hex:/tmp/schaloner.github.com$ git add .
steve@hex:/tmp/schaloner.github.com$ git commit -m "Added release 1.0 to repository"
steve@hex:/tmp/schaloner.github.com$ git push -u origin master


Use the dependency

Create a new project (or open up an old one), and add the dependency and its location.

object ApplicationBuild extends Build {

    val appName         = "my-cool-project"
    val appVersion      = "2.1"

    val appDependencies = Seq(
      "hurdy" %% "hurdy" % "1.0"
    )

    val main = PlayProject(appName, appVersion, appDependencies, mainLang = JAVA).settings(
      resolvers += Resolver.url("My GitHub Play Repository", url("http://<your username>.github.com/releases/"))(Resolver.ivyStylePatterns)
    )
}

Note: Play has published the files in an Ivy style pattern, so this needs to be specified in your Build.scala

Start Play in your application root, and run the “dependencies” task. If all goes well – and I’m sure you’ll let me know if it doesn’t – your module will be pulled from GitHub and made available to your application.

Specifiying an organisation

Because there’s no organisation specified in Build.scala, the organisation (repository/local/
hurdy/hurdy_2.9.1) is taken to be the same as the module name. If you want an organisation, add it in the
main definition:

val main = PlayProject(appName, appVersion, appDependencies, mainLang = JAVA).settings(
      organization := "com.example"
    )

Now, when you publish locally the files will be placed in repository/local/
com.example/hurdy_2.9.1. In this case, it’s the
com.example directory that should copied from the local repository to your GitHub repo. The Build.scala of any application using your dependency will be similarly different:

val appDependencies = Seq(
      "com.example" %% "hurdy" % "1.0"
    )


Real-world proof this works

Deadbolt 2 is currently available using this mechanism, using
http://schaloner.github.com as the repository. Here, there are release and snapshot versions so the Build scala of the sample applications looks like this:

import sbt._
import Keys._
import PlayProject._

object ApplicationBuild extends Build {

    val appName         = "deadbolt-usage"
    val appVersion      = "1.1.3-SNAPSHOT"

    val appDependencies = Seq(
      "be.objectify" %% "deadbolt-2" % "1.1.3-SNAPSHOT"
    )

    val main = PlayProject(appName, appVersion, appDependencies, mainLang = JAVA).settings(
      // Change this to point to your local play repository
      resolvers += Resolver.url("Objectify Play Repository", url("http://schaloner.github.com/releases/"))(Resolver.ivyStylePatterns),
      resolvers += Resolver.url("Objectify Play Repository", url("http://schaloner.github.com/snapshots/"))(Resolver.ivyStylePatterns)
    )
}

If I change the required version from 1.1.3-SNAPSHOT (which is in the snapshots/ directory) to 1.1.3 (which will be in the releases/ directory), the dependency will be resolved correctly.


Reference:
Publishing Play 2 modules on github from our
JCG partner Steve Chaloner at the
Objectify blog.

Source : http://www.javacodegeeks.com/2012/05/publishing-play-2-modules-on-github.html