Venkat Subramaniam's complete blog can be found at: http://blog.agiledeveloper.com/
2010-08-03 11:28:00.0
2010-05-29 06:56:00.0
Using profanity doesn't make us expressive, it simply shows we're vulgar and lacking.
I think, history will say, Scala & Clojure are to FP as C++ is to OOP.
"safety" in type safety is as comforting as "security" in social security.
Design patterns are the clichés of software design.
I've found intuition and gut feeling to be the most useful tools for design so far.
I don't want my project stakeholders to be guests on my projects, I want them to have a "skin in the game," investing their time & effort.
Learning a lib, a lang is easy. To improve code & change development style is hard-requires discipline & great self awareness.
"My boss is not convinced" is euphemism for "I'm not convinced, but I'm in denial (& it feels good to blame it on the boss)."
Relying heavily on some of our key strengths sometimes tends to be our major weakness.
I prefer a healthy dose of skepticism over naive optimism or incessant pessimism.
As engineers, we're good at telling boss what won't work. We should learn to explain what'd work & how it'll help the business.
Jumping into Scrum without practices to promote sustainable dev is like jumping into marriage with no real commitments.
There's usually a point in time when a project can be turned to success, but that opportune moment is rarely at the end.
Each time someone hears the words "best practice" God kills a few neurons.
You know you work for an enterprise when you dial long distance to schedule guy in the next room to fix your projector.
If work is not "having fun" you're likely holding on to a stinking job than being in pursuit of a passionate profession.
When getting into TDD, be prepared not to learn, but to unlearn; the more experience writing code, the more unlearning there is.
Architecture for a product is like salt for a meal–essential, must be in right proportion, & can't be self-serving.
Shaving head, losing shirt, walking barefoot doesn't make us Gandhi; at best only a cheap imitation of a 1/2 naked fakir.
A professional who doesn't learn to fail, fails to learn.
Given a choice between code that's simply sensible vs. hypothetically extensible, I prefer the former any day.
Let's be driven by inspiration, and not desperation, to attain that success that we can relish.
The words static and synchronized are menace to TDD.
Be opinionated, but unbiased. "The man who never alters his opinion is like standing water, and breeds reptiles of the mind" William Blake.
Continuing to use miserable developer tool is like being complacent in an abusive relationship-why not get out for a better life?
They say "end does not justify the means." But, in agile development, do we expect means that justify the end?
"We learn more by looking for the answer to a question and not finding it than we do from learning the answer itself." Lloyd Alexander
The irony of our industry, we brave to automate the world, yet we fear automating our projects.
IMHO, a great talk/book has both high information density & velocity; how much quality info is given & its pace.
If your company wants you to follow only standard practices, they're asking you to follow the path to mediocracy.
Dear company, owning code your programmers can't understand is worst than losing the code.
Zinnser: "Easy writing makes hard reading; hard writing makes easy reading" Not just writing, it's apt for coding.
If your code is not testable, it simply means your design sucks.
Ignorance is a tumor, remove early.
The only little predictable aspect of our lives is its unpredictability.
"It is the mark of an educated mind to be able to entertain a thought without accepting it." Aristotle.
In Java, you work for the compiler; in Scala the compiler works for you.
Trying to release product fast by compromising quality is like trying to lose weight fast by smoking.
"Methods to gain wisdom: by reflection (noblest), by imitation (easiest), and by experience (bitterest)"—source unknown.
What's the difference between a mafia and the government? Mafia doesn't require you to do paper work for the money they take away from you.
Dear developer, pride not developing complex software; strive instead to develop a capable and useful software.
Two sets of people scare me: those who can't follow instructions and those who can only follow instructions.
A good programmer should never fear throwing away code.
A framework that's your darling today is the one you'll hate in two years (make that four if you're a fanboy).
Some people teach me how to live; others how not to. I learn from both. Thankfully, however, each day I get to meet more of the former.
My mentors did not change the word, but hey they changed my world. Be a mentor.
You can't be Agile if your code sucks
2010-05-18 12:52:00.0
I have no doubt that the managers who place such requirements have really good intentions. They most likely care a lot about their projects. They do not want any broken windows. However, such edict often has negative consequences.
- It leads to a different form of TDD—Threat Driven Development. The programmers are threatened rather than being empowered. I don't want to fear making change to the code on your project. To the contrary, I want to make a lot of changes as I feel fit and rely on my tests and the builds to alert me when I err. The quick automated tests I run on my machine will act as my first line of defense. I expect the continuous build to be my second line of defense.
- They may tend to withhold check-ins. If I'm talked down when I break the build, I am going to be overly cautious and check in less frequently. This slows me down. I don't want to be careful, I want to be productive. I have not lowered the quality to gain speed. To the contrary, I have slowed down already to improve the quality. I don't need to be any slower due to fear of breaking the build.
- It may lead to duplication of effort. I will be forcing myself to run my tests on each supported configuration that the continuous build is checking my code against. This is a wasted and duplicated effort. Each developer has to spend time and effort setting up and then maintaining these different configurations on their own machines or desks.
I care a lot about my projects. I write fairly decent amount of test cases. I run my continuous builds, not on one platform, but on different platforms my application is expected to run. I use these tools to increase my productivity and agility.
Let's ask the Why question: Why do I care to use the Continuous Integration build? The number one reason is to avoid "But it worked on my machine" syndrome. I want to know that when my programmers think they've made progress, that is reflected by a healthy exercise of the application on different machines. It tells me that all the relevant code is checked in, that the code compiles (or in a state ready to execute), runs as currently expected not just on the developers machine, but also on different supported platforms and configurations. If my application has to run on Windows XP, Vista, a flavor of Unix, and needs to work with Oracle, SQL Server, etc., the build machines (physical or virtual) will exercise the application on these different configurations. The feedback I get from these builds will tell me that my application run and continues to run on different configurations that my application is required to support.
In spite of all my good intentions and efforts, there are times when I've broken by builds. Here are a few examples where I did really break my builds.
A. The code I wrote ran fine on one version of Windows, but the API I used does not work the same on another version of Windows. This difference was in a fine print that I did not notice. Unless I ran my test on all supported versions of windows before I checked in code, I would not know this.
In order to run all my tests on all supported versions of Windows, I either have to have multiple machines on my desk, have access to multiple machines I would run over to and test my code on, or have multiple virtual machines I should run on my own machine. There is a cost, effort, and time associated with this when each programmer has to do this before every checkin. Also each of us need to put the effort to maintain these configurations.
On the project with above failure, this failure happened once over the entire period of the project. We have two options on hand. Each time I changed my code, I can take time to run all my tests on different combination of OS, databases, libraries, devices, etc. that my application is supposed to run with. Or, I run tests on my machine, and gain a good bit of confidence that my code works. Then I'll let my CI build machines that are readily waiting to exercise my code to take care of the platform and configuration differences. If it fails due to these differences, then I can immediately know what went wrong and go take care of it. If all goes well (as it does most of the time) then I am not spending any time and effort worrying about these edge cases knowing the build machine is providing me the safety net.
B. The second time I broke the build is when there was a difference in representation of a data type between two version of the database. This case is similar to the above. Such failure was rare and was caught by the build machine within minutes and fixed within minutes after that.
C. The most recent build break occurred a few weeks ago. I added a new unit test, added a little code to satisfy that test. I ran my automated tests on my machine. With a green bar on my hand, I checked in the code. I was quite surprised when the CI build failed. It turned out that when my tests were run standalone, they worked fine. However, when invoked by the build process, it failed due to a class loading conflict. Took me a few minutes to resolve the issue so it runs fine both locally and on the build machines.
I'm sure others have their shared of "Why my build broke" stories to tell (and I sure would be delighted to hear).
So, if I have to work so I never break the build, that is a tall order. I simply can't meet that expectation. Yes, I do not want to be careless and break my builds. However, I should not be punished (or shamed) for breaking the build either. Reserve that when I break the build but do not care to fix it within a reasonable amount of time.
I invite my developers to go ahead and break the build. I then tell them that now they are responsible to fix it, real soon (within minutes). Let them learn from the experience. Soon you will see that the builds don't break so often, but there are frequent checkins at the same time Of course, motivating programmers to check in frequently is another story for another blog, but at least you've not helped hold them back.
Let's not focus on the mechanics. Let's keep the focus on the overall goal—to develop a successful product.
2010-01-24 08:40:00.0
I'm excited the following conferences and user groups have invited me to speak in 2010.
Conferences:
User Groups:
| Java Metroplex User Group | Testing with Groovy | Jan. 13 |
| Memphis Java User Group | How to approach refactoring | Feb. 18 |
| Boston Area Scala Enthusiasts | Scala Idioms and Design Patterns | March 4 |
| Agile India - Bangalore | Test Driving Multithreaded Code | April 21 |
| Agile India - New Delhi | Test Driving Multithreaded Code | May 16 |
| Boulder Java Users Group | What's Brewing in Java? | July 13 |
| New England Java Users Group | Programming Scala | August 12 |
2009-10-11 06:53:00.0
As more programmers are getting excited about test driven development (TDD), one concern
I am
hearing more these days is "my tests and mocks make it hard to refactor code."
Remember we took a while to learn how to write better code. Similarly we will take
a while to learn
how to write better unit tests.
I want to talk about unit testing and mocking here with an example that was brought
up yesterday at
the (#sdtconf). A fine gentleman Zachary
Shaw lead an open space discussion on the Hollywood
Principle
and mocking. A number of very bright programmers who're very passionate about TDD
were in the session.
When talking about the principles, etc. Zack demanded a concrete example. We tossed
around a few examples
and I mentioned my friend David
Bock's Paper
Boy example. Taking that example and tweaking it to our
discussion and desires (as we programmers often do), we ended up with something like
this:
public class PaperBoy {
public void collectPayments(List
customers) {
for(Customer customer : customers) {
customer.getPayment(this, 200);
}
}
//...
David, in his example, does not suggest that getPayment() accept an instance of PaperBoy,
the example in our
discussion deviated from his example rather quickly.
Now, how would the getPayment() method of the Customer look like?
public class Customer {
public void getPayment(PaperBoy paperBoy, int amount) {
if (hasNoMoney || doesNotCareToPay)
paperBoy.stiff(this);
else {
deductMoney(amount);
paperBoy.acceptPayment(this, amount);
}
}
//...
It was suggested in the discussion that, in getPayment() method, the customer may
decide to pay or based on some
condition may decide to stiff the paperboy.
So, how do we unit test this getPayment() method? Most of us readily agreed that we
should mock-out (or stub out
or spy out, it does not matter for our discussion here) the PaperBoy. That will help
us run the unit test on the
getPayment() method by isolating the PaperBoy.
Not so fast. Yes, if the getPayment() method has to be written like above, then mocking
out PaperBoy may be one
way to unit test it. However, there are at least three problem (that I can think of
at the moment) with the above code.
Problem 1. The above code has some unnecessary coupling and bi-directional relationship.
The Customer depends
on PaperBoy. That is a coupling that I would seriously question.
Problem 2. The unit test is now made to do more. It has to create a mock of the PaperBoy.
Even if you tell me it is not
much code, a single line of code that is not absolutely needed is a lot of code IMHO.
You don't have to maintain code
that you do not write.
Problem 3. Are you really stiffing the PaperBoy? Who decides that? Can a paperboy
decide that under very hard economic
conditions, a loyal customer may be deserves a break? I have no problem the customer
deciding to pay or not, but if that is
stiffing or not is for the paperboy to decide IMO.
So, yes, you can certainly consider writing mocks for the PaperBoy, but I would not.
Mocking is a tool I would use as the
last resort when unit testing.
How would I approach the above getPayment() method? Let's take a look:
public class Customer
{
public int getPayment(int amount) {
if (hasNoMoney || doesNotCareToPay)
return 0;
else {
deductMoney(amount);
return amount;
}
}
//...
Here the payment method does not depend on the PaperBoy. (If necessary you can pass
information on what the payment is
for—paper, magazine, lawn moving, ...). The customer focuses on his/her own logic,
whether to pay or not.
Now, how would the PaperBoy's collectPayment look like?
public class PaperBoy {
public void collectPayments(List
customers) {
for(Customer customer : customers) {
int payment = customer.getPayment(200);
if (payment == 0)
if (payment > 0)
acceptPayment(customer, payment);
else
stiff(customer);
}
}
//...
Our paperboy thinks that if payment has not been received, he's been stiffed. He could
change his view at anytime without
affecting the customer class. The paperboy is a bit more complex now, but that decision
as to whether he's been stiffed or not
belongs to him, not the customer.
Now, how would we unit test the getPayment() method of the Customer. That's not a
big deal. No mocking is needed. Simply
run your test on your customer instance.
If you think returning 0 for payment amount is not clear enough, you can return a
Payment object with more details contained
in it like Cash, CreditCard, BrokeCantPay, DontFeelLikePaying, etc. as the type of
payment. It can then include additional details
like credit card number, etc. or you can even extend the payment information object.
That can be used for any payment, not just
payment for paper. The decoupling also makes the code more extensible.
So, when would I use a mock or a stub? I would first try to remove or reduce dependency
as much as I can. After a serious effort
to do that, then for those dependencies that are still left I would do one of the
following:
A. Separate the business logic in my code from the object it collaborates with. That
way, I can run unit test on the logic. Depending
on the situation, I am quite content with integration testing the code that collaborate
and unit test the code that does the important
logic. I do not think 100% of the code needs to be unit tested. I do think that 100%
of the code should be exercised. So, if I can get
coverage of the code that does business logic through unit test and coverage of the
code that collaborates, with the object it depends
on, through integration tests, I'm quite happy assuming it gives me a reasonable (not
necessarily instantaneous) feedback loop.
B. If that separation is hard or if I think I need to really get a quick feedback
on the code while testing the collaboration not just logic,
then and only then will I consider writing a mock. In short, I use mock as the last
option when I do TDD. I will first try to knock it out.
Only if I really can't I will try to mock it out.





