How to implement a complex algorithm with TDD - java

I have a fairly complex algorithm I would like to implement (in Java) with TDD. The algorithm, for translation of natural languages, is called stack decoding.
When I tried to do that I was able to write and fix some simple test cases (empty translation, one word, etc'..), but I am not able to get to the direction of the algorithm I want. I mean that I can't figure out how to write a massive amount of the algorithm as described below in baby steps.
This is the pseudo code of the algorithm:
1: place empty hypothesis into stack 0
2: for all stacks 0...n − 1 do
3: for all hypotheses in stack do
4: for all translation options do
5: if applicable then
6: create new hypothesis
7: place in stack
8: recombine with existing hypothesis if possible
9: prune stack if too big
10: end if
11: end for
12: end for
13: end for
Am I missing any way I can do the baby steps, or should I just get some coverage and do the major implementation?

TL;DR
Recast your task as testing an implementation of an API.
As the algorithm is expressed in terms of concepts (hypothesis, translation option) that are themselves quite complicated, program it bottom-up by first developing (using TDD) classes that encapsulate those concepts.
As the algorithm is not language specific, but abstracts language specific operations (all translation options, if applicable), encapsulate the language specific parts in a separate object, use dependency injection for that object, and test using simple fake implementations of that object.
Use your knowledge of the algorithm to suggest good test cases.
Test the API
By focusing on the implementation (the algorithm), you are making a mistake. Instead, first imagine you had a magic class which did the job that the algorithm performs. What would its API be? What would its inputs be, what would its outputs be? And what would the required connections between the inputs and outputs be. You want to encapsulate your algorithm in this class, and recast your problem as generating this class.
In this case, its seems the input is a sentence that has been tokenized (split into words), and the output is a tokenized sentence , which has been translated into a different language. So I guess the API is something like this:
interface Translator {
/**
* Translate a tokenized sentence from one language to another.
*
* #param original
* The sentence to translate, split into words,
* in the language of the {#linkplain #getTranslatesFrom() locale this
* translates from}.
* #return The translated sentence, split into words,
* in the language of the {#linkplain #getTranslatesTo() locale this
* translates to}. Not null; containing no null or empty elements.
* An empty list indicates that the translator was unable to translate the
* given sentence.
*
* #throws NullPointerException
* If {#code original} is null, or contains a null element.
* #throws IllegalArgumentException
* If {#code original} is empty or has any empty elements.
*/
public List<String> translate(List<String> original);
public Locale getTranslatesFrom();
public Locale getTranslatesTo();
}
That is, an example of the Strategy design pattern. So your task becomes, not "how do I use TDD to implement this algorithm" but rather "how do I use TDD to implement a particular case of teh Strategy design pattern".
Next you need to think up a sequence of test cases, from easiest to hardest, that use this API. That is, a set of original sentence values to pass to the translate method. For each of those inputs, you must give a set of constraints on the output. The translation must satisfy those constraints. Note that you already have some constraints on the output:
Not null; not empty; containing no null or empty elements.
You will want some example sentences for which you know for sure what the algorithm should output. I suspect you will find there are very few such sentences. Arrange these tests from easiest to pass to hardest to pass. This becomes your TODO list while you are implementing the Translator class.
Implement Bottom Up
You will find that making your code passes more than a couple of these cases very hard. So how can you thoroughly test your code?
Look again at the algorithm. It is complicated enough that the translate method does not do all the work directly itself. It will delegate to other classes for much of the work
place empty hypothesis into stack 0
Do you need a Hypothesis class. A HypothesisStack class?
for all translation options do
Do you need a TranslationOption class?
if applicable then
Is there a method TranslationOption.isApplicable(...)?
recombine with existing hypothesis if possible
Is there a Hypothesis.combine(Hypothesis) method? A Hypothesis.canCombineWith(Hypothesis) method?
prune stack if too big
Is there a HypothesisStack.prune() method?
Your implementation will likely need additional classes. You can implement each of those individually using TDD. Your few tests of the Translator class will end up being integration tests. The other classes will be easier to test than the Translator because they will have precisely defined, narrow definitions of what they ought to do.
Therefore, defer implementing Translator until you have implemented those classes it delegates to. That is, I recommend that you write your code bottom up rather than top down. Writing code that implements the algorithm you have given becomes the last step. At that stage you have classes that you can use to write the implementation using Java code that looks very like the pseudo code of your algorithm. That is, the body of your translate method will be only about 13 lines long.
Push Real-Life Complications into an Associated Object
Your translation algorithm is general purpose; it can be used to translate between any pair of languages. I guess that what makes it applicable to translating a particular pair of languages is for all translation options and if applicable then parts. I guess the latter could be implemented by a TranslationOption.isApplicable(Hypothesis) method. So what makes the algorithm specific to a particular language is generating the translation options. Abstract that to a a factory object that the class delegates to. Something like this:
interface TranslationOptionGenerator {
Collection<TranslationOption> getOptionsFor(Hypothesis h, List<String> original);
}
Now so far you have probably thinking in terms of translating between real languages, with all their nasty complexities. But you do not need that complexity to test your algorithm. You can test it using a fake pair of languages, which are much simpler than real languages. Or (equivalently) using a TranslationOptionGenerator that is not as rich as a practical one. Use dependency injection to associate the Translator with a TranslationOptionGenerator.
Use Simple Fake Implementations instead of Realistic Associates
Now consider some of the most extreme simple cases of a TranslationOptionGenerator that the algorithm must deal with:
Such as when there are no options for the empty hypothesis
There is only one option
There are only two options.
An English to Harappan translator. Nobody knows how to translate to Harappan, so this translator indicates it is unable to translate every time.
The identity translator: a translator that translates English to English.
A Limited English to newborn translator: it can translate only the sentences "I am hungry", "I need changing" and "I am tired", which it translates to "Waaaa!".
A simple British to US English translator: most words are the same, but a few have different spellings.
You can use this to generate test cases that do not require some of the loops, or do not require the isApplicable test to be made.
Add those test cases to your TODO list. You will have to write fake simple TeranslatorOptionGenerator objects for use by those test cases.

The key here is to understand that "baby steps" do not necessarily mean writing just a small amount of production code at a time. You can just as well write a lot of it, provided you do it to pass a relatively small & simple test.
Some people think that TDD can only be applied one way, namely by writing unit tests. This is not true. TDD does not dictate the kind of tests you should write. It's perfectly valid to do TDD with integration tests that exercise a lot of code. Each test, however, should be focused in a single well-defined scenario. This scenario is the "baby step" that really matters, not the number of classes that may get exercised by the test.
Personally, I develop a complex Java library exclusively with integration-level tests, rigorously following the TDD process. Quite often, I create a very small and simple-looking integration test, which ends up taking a lot of programming effort to make pass, requiring changes to several existing classes and/or the creation of new ones. This has been working well for me for the past 5+ years, to the point I now have over 1300 such tests.

TL;DR: Start with nothing and don't write any code that a test does not call for. Then you can't help but TDD the solution
When building something via TDD, you should start with nothing then implement test cases until it does the thing you want. That's why they call it red green refactoring.
Your first test would be to see if the internal object has 0 hypothesis (an empty implementation would be null. [red]). Then you initialize the hypothesis list [green].
Next you would write a test that the hypothesis is checked (it's just created [red]). Implement the "if applicable" logic and apply it to the one hypothesis [green].
You write a test that when a hypothesis is applicable, then create a new hypothesis (check if there's > 1 hypothesis for a hypothesis that's applicable [red]). Implement the create hypothesis logic and stick it in the if body. [green]
conversely, if a hypothesis is not applicable, then do nothing ([green])
Just kinda follow that logic to individually test the algorithm over time. It's much easier to do with an incomplete class than a complete one.

Related

AssertJ testing on a collection: what is better: 'extracting' or Java8 forEach

I'm new to AssertJ and using it to unit-test my written code and was thinking how to assert a list.
Lets assume we have a list of Consumers Entities. each Entity has it own Phone, own ServiceProvider which has it own Name and EntityName.
Now we want to assert that each Entity from a repository gets the right data, so we want to test that each item on list has equal Phone.
ConsumerEntity savedConsumer1 = Consumer(phone, name, serviceProvider)
List<ConsumerEntity> consumerListFromRepository = repository.findAllByPhone(phone)
Now I want to test that the data given from Repository is correct,
I can use this:
assertThat(consumerListFromRepository)
.extracting(ConsumerEntity::getPhone())
.containsOnly(savedConsumer1.getPhone());
Or I can do this with forEach (java 8):
consumerListFromRepository.forEach(consumerEntity ->
assertThat(consumerEntity.getPhone()).isEqualTo(savedConsumer1.getPhone()));
1. Which one is faster/simple-r/readable? I will go for the forEach for less lines of code but less read-ability as well.
2. Is there any other way to do it 1liner like the foreach but with asserThat? so it will be readable and simple - and without the need to use EqualTo each
time? something like:
asserThat(list).forEach........
3. Which one is faster? Extracting or forEach?
Thanks!
I'm not sure that "faster" is a primary concern here. It's likely that any performance difference is immaterial; either the underlying implementations are ~equivalent in terms of non-functionals or - since the context here is a unit test - the consumerListFromRepository is trivially small thereby limiting the scope for any material performance differences.
I think your main concerns here should be
Making it as easy as possible for other developers to:
Understand/reason about your test case
Edit/refactor your test case
Ensuring that your approach to asserting is consistent with other test cases in your code base
Judging which of your two approaches best ticks this box is somewhat subjective but I think the following considerations are relevant:
The Java 8 forEach construct is well understood and the isEqualTo matcher is explicit and easily understood
The AssertJ extracting helper paired with the containsOnly is less common that Java8's forEach construct but this pairing reads logically and is easily understood
So, IMHO both approaches are valid. If your code base consistently uses AssertJ then I'd suggest using the extracting helper paired with the containsOnly matcher for consistency. Otherwise, use whichever of them reads best to you :)

Randomized testing in Java

I write a lot of unit tests. Often, you need to write carefully considered test cases by hand, a form of whitebox testing. If you are lucky enough to work for a company with a separate quality assurance engineers, perhaps someone else writes test cases for you (kind of a mix between white and black box testing).
Many times, however, randomized testing would find many bugs and would serve as a great complement to hand-written cases.
For example, I might have a self-contained class and be able to express the invariants and broad-stroke behavior of the class simply (such as "this method never throws an exception" or "this method always returns a positive value"). I would like a test framework that just bashes on my class and checks the invariants.
A similar case: I often have a class which implements similar functionality to another class (but does it with different performance characteristics or with some added functionality). I would to A vs B test the two classes in a randomized way. For example, if I was implementing TreeMap, I could use HashMap as a comparable implementation (modulo a few differences due to the sorted behavior of TreeMap) and check most of the basic functionality in a randomized way. Simlarly, someone implementing LinkedList could use ArrayList as a comparable implementation and vice-versa.
I've written some basic stuff to do this in the past, but it is painstaking to set to up all the boilerplate to:
Create objects with random initial state
Apply random mutations
Create mappings between "like" objects for A vs B testing
Define invariants and rules such as "when will exceptions be thrown"
I still do it from time to time, but I want to reduce my effort level. For example, are there frameworks that remove or simplify the required boilerplate?
Otherwise, what techniques are used to do randomized testing in Java?
This is related, but not the same as fuzz testing. Fuzz testing seems to focus on random inputs to a single entity, in hope of triggering bad behavior, often with an adaptive input model based on dynamic coverage observations. That's covers a lot of the above, but doesn't cover, stuff like A vs B testing when comparable implementations exist, or invariant checking. In any case, I'm also interested in decent fuzz testing libraries for Java.
I think what you're trying to find is a library for Property Based Testing in Java (see types of randomized testing). Shortly: instead of testing the value of the result you're testing a property of it. E.g. instead of checking that 2+2 is 4 you're checking properties like:
random1 + 0 = random1
random1 + random2 >= random1
...
Take a look at this article that explains Property Based Testing in details.
Another option that you mention is to check with your Test Oracle - something that knows the true answer (e.g. old bullet-proof algorithm). So you pass a random variable both to old and new algorithm and you check that the results are equal.
Couple of Java libraries:
JUnit QuickCheck - a specialized lib for Property Based Testing. Allows you to define the properties and passes random values for these properties to check. So far (06/2016) it's pretty young, so you may want to check out ScalaCheck since it's possible to write Scala tests for Java code.
Datagen - random values generator for Java in case standard randomizers are not enough. Disclaimer: I'm the author.

Mocking a bit stream reader with Mockito

I am currently debugging a rather complicated algorithm that fixes errors in a bit stream. A BitReader interface is quite simple, and the main reading method is like this:
/**
Reads bits from the stream.
#param length number of bits to read (<= 64)
#return read bits in the least significant bits
*/
long read(int length) throws IOException;
The objective is to test whether BitStreamFixer actually fixes the stream (in a way that is too hard to describe here). Basically I need to provide “broken” inputs to it and test whether its output is as correct as it can be (some inputs can't be fixed completely), like this:
BitStreamFixer fixer = new BitStreamFixer(input);
int word1 = fixer.readWord();
int word2 = fixer.readWord();
// possibly a loop here
assertEquals(VALID_WORD1, word1);
assertEquals(VALID_WORD2, word2);
// maybe a loop here too
Now, the BitStreamFixer class accepts an instance of BitReader. When unit testing the fixer, I obviously need one such instance. But where do I get one? I have two obvious options: either give it a real implementation of BitReader or mock it.
The former option is not really appealing because it would create a dependency on another object which has nothing to do with the class being tested. Moreover, it's not that easy because existing BitReader implementations read form input streams, so I'll need either a file or somehow prepared byte array, which is a tedious thing to do.
The latter option looks better and fits the usual unit testing approach. However, since I'm not even supposed to know what arguments the fixer will give to read, mocking it is not easy. I'll have to go with when(bitReader.read(anyInt())).thenAnswer(...) approach, implementing a custom answer that will create a lot of bit-fiddling logic to spoon-feed the object under test with proper bits in chunks of whatever size it asks for. Considering that bit streams I'm working with have rather complicated higher-level structure, it's not easy. And introducing logic in unit tests also doesn't smell good.
What do you think, is there any other option? Or maybe one of these can be improved in a way I fail to notice?
Write, test, and use a clear reusable test helper.
In a general sense, in unit testing, you're supposed to establish confidence in a system by watching it successfully interact with systems that you DO have confidence in. Of course you also want the system to be fast, deterministic, and easy to read/modify, but ultimately those come secondary to the assertion that your system work.
You've listed two options:
Use a mock BitReader, where you have enough confidence in predicting your system's interactions that you can set up the entire "when A then B" conversation. Mocking can be pretty easy when you have a small API surface of independent methods, like an RPC layer, but mocking can be very difficult when you have a stateful object with unpredictable method calls. Mocking is further useful to deterministically stub nondeterministic systems, like external servers or pseudorandom sources, or systems that don't exist yet; none of those is the case for you.
Because your read method can take a wide variety of parameters, each of which is valid and changes your system's state, then it's probably not a smart idea to use mocking here. Unless the order of calls that BitStreamFixer makes to BitReader is deterministic enough to make part of its contract, a mock BitReader will likely result in a brittle test: one that breaks when the implementation changes even if the system is perfectly functional. You'll want to avoid that.
Note that mocking should never yield "complicated logic", only complicated set-up. You're using mocks to avoid using real logic in your tests.
Use a real BitReader, which sounds like it will be painful and opaque to construct. This is probably the most realistic solution, though, especially if you've already finished writing and testing it.
You worry about "introducing new dependencies", but if your BitReader implementation exists and is fast, deterministic, and well-tested, then you shouldn't feel any worse about using it than using a real ArrayList or ByteArrayInputStream in your test. It sounds like the only real problem here is that creating the byte array would make it hard to maintain your test, which is a valid consideration.
In the comments, though, the real answer comes through: Build the BitWriter you're missing.
#Test public void shouldFixBrokenStream() {
BitReader bitReader = new StreamBitReader(BitWriter.create()
.pushBits(16, 0x8080)
.pushBits(12, 0x000) // invalid 12-bit sequence
.pushBits(16, 0x8080)
.asByteArrayInputStream());
BitStreamFixer fixer = new BitStreamFixer(bitReader);
assertEquals(0x80808080, fixer.read(32));
}
/** Of course, you could skip the BitReader yourself, and just make a new one. */
#Test public void shouldFixBrokenStream_bitReader() {
BitReader bitReader = new InMemoryBitReader();
bitReader.pushBits(16, 0x8080);
bitReader.pushBits(12, 0x000); // invalid 12-bit sequence
bitReader.pushBits(16, 0x8080);
BitStreamFixer fixer = new BitStreamFixer(bitReader);
assertEquals(0x80808080, fixer.read(32));
}
This is more readable than constructing an opaque bitstream offline and copy-pasting it into your test (particularly if well-commented), less brittle than mocks, and much more testable itself than an anonymous inner class (or Answer-based version of the same). It is also likely that you can use a system like that across multiple test cases, and possibly even multiple tests.

Generate random but static test data

When designing test cases, I want to be able to use data that is random but static.
If I use data that is not random, then I will use trivial examples that are representative of the data I expect, rather than the data I have guarded against in my code. For example, if my code is expecting a string with a max length of 15 characters then I would rather specify these constraints and have the data generated for me, within those constraints, rather than some arbitrary example which may be, due to my expectations, within a more strict set of constraints.
If I use data that is not static, then my tests won't be repeatable. It is no good using a string that changes every time the test is run f the test then fails occasionally. It would be much better to use a consistent string and then specify more constraints upon how that string is generated (and obviously make the same checks in my code), if and when a bug is found.
Is this a good strategy for test data?
If so, then I know how to achieve both of these goals independently. For static, but non-random data I just enter something arbitrary e.g. foo. For something random but not static, I just use apache random utils e.g. randomString(5). How can I get both?
Note that when data must be unique, it would also be handy to have some way to specify that two pieces of generated data must be distinct. Randomness does this most of the time but cannot be relied upon, obviously, without having unreliable tests!
TL;DR: How can I specify the type of data I want to generate, without having randomised generated data?
Use a random with a constant seed. You can use the Random(long seed) constructor for it.
The RandomStringUtils.random() method can accept a Random source, which you could have created with a constant seed as described.
Using a constant seed is very useful for making experiments reproduceable - and using them is a very good practice, IMO.
don't do it. it gives you a headache, makes your tests unreadable and gives you no benefit. you already see the problems: specification of constraints. so let's go to the imaginary benefits. you worry about that manually you provide more constrained data then random data. but you want to use same data every time (same seed). so how do you know that random data are better than your manually provided data? how do you know that you chose seed properly? if you are not sure if your test data are good enough then:
simplify your code (extract methods/classes, avoid ifs, avoid nulls, be more immutable and functional)
look at edge cases and include them in your tests
look at generated data and check if some of them differs from what you were thinking of and add those data to your tests
use mutation testing
whenever a bug is discovered dufing development, uat or production, add those data to your tests
do truly random (not repetitive), long running tests. every generated data that breaks the tests should be logged and add to your deterministic unit tests.
by pretending to use random data you just lie to yourself. the data is not random, you don't control it and it makes you stop thinking about edge cases of your code. so don't do it, face the truth and make your tests readable and check more conditions
What you are describing is property based testing - the best known example being Haskell's quickcheck.
http://www.haskell.org/haskellwiki/Introduction_to_QuickCheck1
There have been a number of java ports such as
https://bitbucket.org/blob79/quickcheck
https://github.com/kjw/supercheck
https://github.com/pholser/junit-quickcheck
The Quickcheck philosophy emphasises the use of random data, but most (all?) of the java ports allow you to set a fixed seed so that the generated values are repeatable.
I've never got round to actually trying this approach, but I would hope it would make your tests more readable (rather than less readable as piotrek suggests), by separating the values from the tests.
If knowledge of the values is important to understand the test/SUT behavior then it is the wrong approach.
Instancio is a data generation library for unit tests that does what you are looking. E.g. if you need a random string of certain length:
Foo foo = Instancio.of(Foo.class)
.generate(field("fooString"), gen -> gen.string().length(10))
.create();
To generate a random predictable values, you can supply a seed:
Foo foo = Instancio.of(Foo.class)
.generate(field("fooString"), gen -> gen.string().length(10))
.withSeed(123)
.create();
Or if you use JUnit 5:
#ExtendWith(InstancioExtension.class)
class ExampleTest{
#Seed(1234)
#Test
void example {
Foo foo = Instancio.of(Foo.class)
.generate(field("fooString"), gen -> gen.string().length(10))
.create();
// ...
}
}
If you need predictable data always, you can configure a global seed value through a properties file. This way you won't need to specify it in the code.
https://github.com/instancio/instancio/

When is a Java method name too long? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
In the last weeks I've seen some guys using really long names for a Method or Class (50 characters), this is usually under the premise that it improves readability, my opinion is that a long name like this is an indicator that we are trying to do a lot or too much in a method class if we need such a long name, however I wanted to know what do you guys think about it.
An Example is:
getNumberOfSkinCareEligibleItemsWithinTransaction
A name in Java, or any other language, is too long when a shorter name exists that equally conveys the behavior of the method.
Some techniques for reducing the length of method names:
If your whole program, or class, or module is about 'skin care items' you can drop skin care. For example, if your class is called SkinCareUtils,
that brings you to getNumberOfEligibleItemsWithinTransaction
You can change within to in, getNumberOfEligibleItemsInTransaction
You can change Transaction to Tx, which gets you to getNumberOfEligibleItemsInTx.
Or if the method accepts a param of type Transaction you can drop the InTx altogether: getNumberOfEligibleItems
You change numberOf by count: getEligibleItemsCount
Now that is very reasonable. And it is 60% shorter.
Just for a change, a non-subjective answer: 65536 characters.
A.java:1: UTF8 representation for string "xxxxxxxxxxxxxxxxxxxx..." is too long
for the constant pool
;-)
I agree with everyone: method names should not be too long. I do want to add one exception though:
The names of JUnit test methods, however, can be long and should resemble sentences.
Why?
Because they are not called in other code.
Because they are used as test names.
Because they then can be written as sentences describing requirements. (For example, using AgileDox)
Example:
#Test
public void testDialogClosesDownWhenTheRedButtonIsPressedTwice() {
...
}
See "Behavior Driven Design" for more info on this idea.
Context "...WithinTransaction" should be obvious. That's what object-orientation is all about.
The method is part of a class. If the class doesn't mean "Transaction" -- and if it doesn't save you from having to say "WithinTransaction" all the time, then you've got problems.
Java has a culture of encouraging long names, perhaps because the IDEs come with good autocompletion.
This site says that the longest class name in the JRE is InternalFrameInternalFrameTitlePaneInternalFrameTitlePaneMaximizeButtonWindowNotFocusedState which is 92 chars long.
As for longest method name I have found this one supportsDataDefinitionAndDataManipulationTransactions, which is 52 characters.
Never use a long word when a diminutive one will do.
I don't think your thesis of "length of method name is proportional to length of method" really holds water.
Take the example you give: "getNumberOfSkinCareEligibleItemsWithinTransaction". That sounds to me like it does just one thing: it counts the number of items in a transaction that fall into a certain category. Of course I can't judge without seeing the actual code for the method, but that sounds like a good method to me.
On the other hand, I've seen lots of methods with very short and concise names that do way to much work, like "processSale" or the ever popular "doStuff".
I think it would be tough to give a hard-and-fast rule about method name length, but the goal should be: long enough to convey what the function does, short enough to be readable. In this example, I'd think "getSkinCareCount" would probably have been sufficient. The question is what you need to distinguish. If you have one function that counts skin-care-eligible items in transactions and another that counts skin-care-eligible items in something else, then "withinTransactions" adds value. But if it doesn't mean anything to talk about such items outside of a transaction, then there's no point cluttering up the name with such superfluous information.
Two, I think it's wildly unrealistic to suppose that a name of any manageable length will tell you exactly what the function does in all but the most trivial cases. A realistic goal is to make a name that gives a reader a clue, and that can be remembered later. Like, if I'm trying to find the code that calculates how much antimatter we need to consume to reach warp speed, if I look at function names and see "calibrateTransporter", "firePhasers", and "calcAntimatterBurn", it's pretty clear that the first two aren't it but the third one might be. If I check and find that that is indeed the one I'm looking for, it will be easy to remember that when I come back tomorrow to work on this problem some more. That's good enough.
Three, long names that are similar are more confusing than short names. If I have two functions called "calcSalesmanPay" and "calcGeekPay", I can make a good guess which is which at a quick glance. But if they are called "calculateMonthlyCheckAmountForSalesmanForExportToAccountingSystemAndReconciliation" and "calculateMonthlyCheckAmountForProgrammersForExportToAccountingSystemAndReconciliation", I have to study the names to see which is which. The extra information in the name is probably counter-productive in such cases. It turns a half-second think into a 30-second think.
I tend use the haiku rule for names:
Seven syllable class names
five for variables
seven for method and other names
These are rules of thumb for max names. I violate this only when it improves readability. Something like recalculateMortgageInterest(currentRate, quoteSet...) is better than recalculateMortgageInterestRate or recalculateMortgageInterestRateFromSet since the fact that it involves rates and a set of quotes should be pretty clear from the embedded docs like javadoc or the .NET equivalent.
NOTE: Not a real haiku, as it is 7-5-7 rather than 5-7-5. But I still prefer calling it haiku.
Design your interface the way you want it to be, and make the implementation match.
For example, maybe i'd write that as
getTransaction().getItems(SKIN_CARE).getEligible().size()
or with Java 8 streams:
getTransaction().getItems().stream()
.filter(item -> item.getType() == SKIN_CARE)
.filter(item -> item.isEligible())
.count();
My rule is as follows: if a name is so long that it has to appear on a line of its own, then it is too long. (In practice, this means I'm rarely above 20 characters.)
This is based upon research showing that the number of visible vertical lines of code positively correlates with coding speed/effectiveness. If class/method names start significantly hurting that, they're too long.
Add a comment where the method/class is declared and let the IDE take you there if you want a long description of what it's for.
The length of the method itself is probably a better indicator of whether it's doing too much, and even that only gives you a rough idea. You should strive for conciseness, but descriptiveness is more important. If you can't convey the same meaning in a shorter name, then the name itself is probably okay.
When you are going to write a method name next time , just think the bellow quote
"The man who is going to maintain your code is a phyco who knows where you stay"
That method name is definitely too long. My mind tends to wander when I am reading such sized method names. It's like reading a sentence without spaces.
Personally, I prefer as few words in methods as possible. You are helped if the package and class name can convey meaning. If the responsibility of the class is very concise, there is no need for a giant method name. I'm curious why "WithinTransaction" on there.
"getNumberOfSkinCareEligibleItemsWithinTransaction" could become:
com.mycompany.app.product.SkinCareQuery.getNumEligibleItems();
Then when in use, the method could look like "query.getNumEligibleItems()"
A variable name is too long when a shorter name will allow for better code readability over the entire program, or the important parts of the program.
If a longer name allows you to convey more information about a value. However, if a name is too long, it will clutter the code and reduce the ability to comprehend the rest of the code. This typically happens by causing line wraps and pushing other lines of code off the page.
The trick is determining which will offer better readability. If the variable is used often or several times in a short amount of space, it may be better to give it a short name and use a comment clarify. The reader can refer back to the comment easily. If the variable is used often throughout the program, often as a parameter or in other complicated operations, it may be best to trim down the name, or use acronyms as a reminder to the reader. They can always reference a comment by the variable declaration if they forget the meaning.
This is not an easy trade off to make, since you have to consider what the code reader is likely to be trying to comprehend, and also take into account how the code will change and grow over time. That's why naming things is hard.
Readability is why it's acceptable to use i as a loop counter instead of DescriptiveLoopCounterName. Because this is the most common use for a variable, you can spend the least amount of screen space explaining why it exists. The longer name is just going to waste time by making it harder to understand how you are testing the loop condition or indexing into an array.
On the other end of the spectrum, if a function or variable is used rarely as in a complex operation, such as being passed to a multi-parameter function call, you can afford to give it an overly descriptive name.
As with any other language: when it no longer describes the single action the function performs.
I'd say use a combination of the good answers and be reasonable.
Completely, clearly and readably describe what the method does.
If the method name seems too long--refactor the method to do less.
It's too long when the name of the method wraps onto another line and the call to the method is the only thing on the line and starts pretty close to the margin. You have to take into account the average size of the screen of the people who will be using it.
But! If the name seems too long then it probably is too long. The way to get around it is to write your code in such a way that you are within a context and the name is short but duplicated in other contexts. This is like when you can say "she" or "he" in English instead of someone's full name.
It's too long when it too verbosively explains what the thing is about.
For example, these names are functionally equivalent.
in Java: java.sql.SQLIntegrityConstraintViolationException
in Python/Django: django.db.IntegrityError
Ask yourself, in a SQL/db package, how many more types of integrity errors can you come up with? ;)
Hence db.IntegrityError is sufficient.
An identifier name is too long when it exceeds the length your Java compiler can handle.
There are two ways or points of view here: One is that it really doesn't matter how long the method name is, as long as it's as descriptive as possible to describe what the method is doing (Java best practices basic rule). On the other hand, I agree with the flybywire post. We should use our intelligence to try to reduce as much as possible the method name, but without reducing it's descriptiveness. Descriptiveness is more important :)
A name is too long if it:
Takes more than 1 second to read
Takes up more RAM than you allocate for your JVM
Is something absurdly named
If a shorter name makes perfect sense
If it wraps around in your IDE
Honestly the name only needs to convey its purpose to the the Developers that will utilize it as a public API method or have to maintain the code when you leave. Just remember KISS (keep it simple stupid)

Categories

Resources