`
|
|
Archive for the ‘Programming’ Category
Friday, August 5th, 2016
Year 2016 is special for Eclipse users and community in India – we have the first ever conference focused on Eclipse Technologies, Eclipse Summit India, scheduled for Aug 25th to 27th in Bangalore at the Hotel Chancery Pavilion. Eclipse Summit India is being organized in collaboration with the Eclipse Foundation and will feature some of the best speakers from the past EclipseCon conferences around the world.
In 2010, we organized the first “Eclipse Day” – a day for the Eclipse community in Bangalore to get together and share expertise. We still remember that day at a small but cozy hotel on Infantry Road in Bangalore, when we kicked off the very first “Eclipse Day” in India. We followed the tradition in 2011, when SAP came forward to organize it in their campus. There were two more Eclipse Day editions in Bangalore in subsequent years – one organized at IBM and the other one at BOSCH. Each year we raised the bar in terms of content as well as participation. Thus the idea of Eclipse Summit was born!
The conference is spread across 3 days – Thursday, Friday and Saturday. Day-1, Thursday, is dedicated for pre-conference paid workshops. We have lined up 4 workshops by technical leaders in Eclipse space in some of the key Eclipse technologies – Eclipse IoT, Eclipse e4 Platform, Eclipse JDT and Eclipse Modeling Framework. The next two days are dedicated for conference tracks – we have two tracks each on Friday and Saturday. On each of the days, we kick off the proceedings with keynotes by thought leaders in the Industry.
On Friday, we are privileged to have Mike Milinkovich, Executive Director of Eclipse Foundation deliver the Keynote. On Saturday, we have two keynotes – Sumit Rao, VP of Engineering at Cerner Corporation, as the first keynote speaker and Viral Shah, co-creator of the Julia Language as the second keynote speaker. You can find the complete program here: https://confengine.com/eclipse-summit-2016/schedule/rich
Friday Aug 26th, we have two tracks – one focusing on Language Runtime (Java, Node.js, Mobile) and the other on Eclipse IoT Technology. We are fortunate to have leaders from each of these areas – Srikanth Sankaran, whose talks at past EclipseCon were rated amongst the best, will take us through the evolution of Java beyond Java-9, while Benjamin Cabé, Eclipse IoT expert at Eclipse Foundation will unveil the power of Eclipse IoT technologies. These talks are followed by a variety of talks and demonstrations that will expose you to the latest developments and trends in these areas.
On Saturday, the event continues with the focus on language technologies in one of the tracks, while Eclipse Platform focus on the other track. In the language track, Stephan Hermann, Java language guru, will take you through the dynamism in Java language while in the platform track, we have Prouvost, an expert on Eclipse e4 Platform unraveling the mystery of e4. Don’t know what e4 is? Well, now you have a reason to not miss this!
Eclipse Summit India is a conference organized by the Eclipse community for the community. Organizers have done their bit in lining up some of the eminent speakers, who are experts in their own domains. Now it is your, Eclipse community’s – turn, to contribute to it by actively participating to make it a success. Eagerly looking forward to meet you all at the conference!
We’ve last few seats left, register here: https://confengine.com/eclipse-summit-2016/register
Posted in Agile, Community, Conference, Programming, Programming Languages | No Comments »
Saturday, August 1st, 2015
In software world we call this speculative generality or YAGNI or over engineering.
IMHO we should not be afraid to throw parts of your system out every 6-8 months and rebuild it. Speed and Simplicity trumps everything! Also in 6-8 months, new technology, your improved experience, better clarity, etc. will help you design a better solution than what you can design today.
Just to be clear, I’m not suggesting that we do a sloppy job and rewrite the system because of sloppiness. I’m recommending, let’s solve today’s problem in the simplest, cleanest and most effective/efficient way. Let’s not pretend to know the future and build things based on that, because none of us know what the future looks like. Best we can do is guess the future, and we humans are not very good at it.
Posted in Agile, Design, Planning, Product Development, Programming | No Comments »
Monday, October 28th, 2013
In the Agile India Submission system, we had a feature which would accept different url path to show matching proposals.
For example:
http://present.agileindia.org/agile-india-2014/agile-lifecycle/45_mins –> will return all 45 mins proposals under the Agile-Lifecycle track for the Agile India 2014 Conference.
http://present.agileindia.org/agile-india-2014/beyond-agile/90_mins –> will return all 90 mins proposals under the Beyond-Agile track for the Agile India 2014 Conference.
If we remove the last part .i.e. http://present.agileindia.org/agile-india-2014/agile-lifecycle –> will return all proposals under the Agile-Lifecycle track for the Agile India 2014 Conference.
and http://present.agileindia.org/agile-india-2014 –> will return all proposals for the Agile India 2014 Conference (could be other conferences as well.)
To achieve this, we had the following routes defined:
//URL Path = /agile-india-2014
app\get("/{conference}", function($req) {
$query_params = structure_request_params($req['matches']);
...
});
//URL Path = /agile-india-2014/agile-lifecycle
app\get("/{conference}/{track}", function($req) {
$query_params = structure_request_params($req['matches']);
...
});
//URL Path = /agile-india-2014/agile-lifecycle/45_mins
app\get("/{conference}/{track}/{label}", function($req) {
$query_params = structure_request_params($req['matches']);
...
}); |
//URL Path = /agile-india-2014
app\get("/{conference}", function($req) {
$query_params = structure_request_params($req['matches']);
...
});
//URL Path = /agile-india-2014/agile-lifecycle
app\get("/{conference}/{track}", function($req) {
$query_params = structure_request_params($req['matches']);
...
});
//URL Path = /agile-india-2014/agile-lifecycle/45_mins
app\get("/{conference}/{track}/{label}", function($req) {
$query_params = structure_request_params($req['matches']);
...
});
In our database we had the following:
CREATE TABLE `conference` (
`key` VARCHAR(255) NOT NULL,
...
PRIMARY KEY (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `track` (
`conference` VARCHAR(255) NOT NULL,
`key` VARCHAR(255) NOT NULL,
...
PRIMARY KEY (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `label` (
`conference` VARCHAR(255) NOT NULL,
`track` VARCHAR(255) NOT NULL,
`key` VARCHAR(255) NOT NULL,
...
PRIMARY KEY (`conference`,`track`,`key`)
) ENGINE= InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `conference` VALUES ('agile-india-2014', ...);
INSERT INTO `track` VALUES ('agile-india-2014', 'agile-lifecycle', ...);
INSERT INTO `label` VALUES ('agile-india-2014', 'agile-lifecycle', '45_mins', ...); |
CREATE TABLE `conference` (
`key` varchar(255) NOT NULL,
...
PRIMARY KEY (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `track` (
`conference` varchar(255) NOT NULL,
`key` varchar(255) NOT NULL,
...
PRIMARY KEY (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `label` (
`conference` varchar(255) NOT NULL,
`track` varchar(255) NOT NULL,
`key` varchar(255) NOT NULL,
...
PRIMARY KEY (`conference`,`track`,`key`)
) ENGINE= InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `conference` VALUES ('agile-india-2014', ...);
INSERT INTO `track` VALUES ('agile-india-2014', 'agile-lifecycle', ...);
INSERT INTO `label` VALUES ('agile-india-2014', 'agile-lifecycle', '45_mins', ...);
And some really complicated logic:
// For example URL Path /agile-india-2014 will result in
// $req_params = array('conference'=>'agile-india-2014')
// And URL Path /agile-india-2014/agile-lifecycle will result in
// $req_params = array('conference'=>'agile-india-2014', 'track'=>'agile-lifecycle')
// And URL Path /agile-india-2014/agile-lifecycle/45_mins will result in
// $req_params = array('conference'=>'agile-india-2014', 'track'=>'agile-lifecycle', 'label'=>'45_mins') |
// For example URL Path /agile-india-2014 will result in
// $req_params = array('conference'=>'agile-india-2014')
// And URL Path /agile-india-2014/agile-lifecycle will result in
// $req_params = array('conference'=>'agile-india-2014', 'track'=>'agile-lifecycle')
// And URL Path /agile-india-2014/agile-lifecycle/45_mins will result in
// $req_params = array('conference'=>'agile-india-2014', 'track'=>'agile-lifecycle', 'label'=>'45_mins')
function structure_request_params($req_params){
$query_params = array();
if(isset($req_params['label'])){
if(Conference::exists($req_params['conference'])){
$query_params['conference'] = $req_params['conference'];
if(Track::exists(array('conference' => $req_params['conference'], 'key' => $req_params['track']))){
$query_params['track'] = $req_params['track'];
if(Label::exists(array(
'conference' => $req_params['conference'],
'track' => $req_params['track'],
'key' => $req_params['label'])
)) {
$query_params['label'] = $req_params['label'];
}
else{
$query_params['search_term'] = array($req_params['label']);
}
}
else{
$query_params['search_term'] = array($req_params['track'], $req_params['label']);
}
}
else{
$query_params['search_term'] = array($req_params['conference'], $req_params['track'], $req_params['label']);
}
}
else{
if(isset($req_params['track'])){
if(Conference::exists($req_params['conference'])){
$query_params['conference'] = $req_params['conference'];
if(Track::exists(array('conference' => $req_params['conference'], 'key' => $req_params['track']))){
$query_params['track'] = $req_params['track'];
}
else{
$query_params['search_term'] = array($req_params['track']);
}
}
else{
if(Track::exists(array('key' => $req_params['conference']))){
$query_params['track'] = $req_params['conference'];
if(Label::exists(array('track' => $req_params['conference'], 'key' => $req_params['track']))){
$query_params['label'] = $req_params['track'];
}
else{
$query_params['search_term'] = array($req_params['track']);
}
}
else{
$query_params['search_term'] = array($req_params['conference'], $req_params['track']);
}
}
}
else{
if(isset($req_params['conference'])){
if(Conference::exists($req_params['conference'])){
$query_params['conference'] = $req_params['conference'];
}
elseif(Track::exists(array('key' => $req_params['conference']))){
$query_params['track'] = $req_params['conference'];
}
elseif(Label::exists(array('key' => $req_params['conference']))){
$query_params['label'] = $req_params['conference'];
}
else{
$query_params['search_term'] = array($req_params['conference']);
}
}
}
}
return $query_params;
} |
function structure_request_params($req_params){
$query_params = array();
if(isset($req_params['label'])){
if(Conference::exists($req_params['conference'])){
$query_params['conference'] = $req_params['conference'];
if(Track::exists(array('conference' => $req_params['conference'], 'key' => $req_params['track']))){
$query_params['track'] = $req_params['track'];
if(Label::exists(array(
'conference' => $req_params['conference'],
'track' => $req_params['track'],
'key' => $req_params['label'])
)) {
$query_params['label'] = $req_params['label'];
}
else{
$query_params['search_term'] = array($req_params['label']);
}
}
else{
$query_params['search_term'] = array($req_params['track'], $req_params['label']);
}
}
else{
$query_params['search_term'] = array($req_params['conference'], $req_params['track'], $req_params['label']);
}
}
else{
if(isset($req_params['track'])){
if(Conference::exists($req_params['conference'])){
$query_params['conference'] = $req_params['conference'];
if(Track::exists(array('conference' => $req_params['conference'], 'key' => $req_params['track']))){
$query_params['track'] = $req_params['track'];
}
else{
$query_params['search_term'] = array($req_params['track']);
}
}
else{
if(Track::exists(array('key' => $req_params['conference']))){
$query_params['track'] = $req_params['conference'];
if(Label::exists(array('track' => $req_params['conference'], 'key' => $req_params['track']))){
$query_params['label'] = $req_params['track'];
}
else{
$query_params['search_term'] = array($req_params['track']);
}
}
else{
$query_params['search_term'] = array($req_params['conference'], $req_params['track']);
}
}
}
else{
if(isset($req_params['conference'])){
if(Conference::exists($req_params['conference'])){
$query_params['conference'] = $req_params['conference'];
}
elseif(Track::exists(array('key' => $req_params['conference']))){
$query_params['track'] = $req_params['conference'];
}
elseif(Label::exists(array('key' => $req_params['conference']))){
$query_params['label'] = $req_params['conference'];
}
else{
$query_params['search_term'] = array($req_params['conference']);
}
}
}
}
return $query_params;
}
And supporting model classes:
class Conference{
static function exists($conference){
DB::query('SELECT * FROM conference WHERE conference.key = %s', $conference);
return (DB::count() > 0);
}
}
class Track{
static function exists($query_params){
$search_query = Track::create_search_query($query_params);
DB::query("SELECT * FROM track WHERE $search_query");
return (DB::count() > 0);
}
private static function create_search_query($query_params){
$search_query = array();
foreach($query_params as $key => $value){
$search_query[] = "$key='$value'";
}
return join(' AND ', $search_query);
}
}
class Label{
static function exists($query_params){
$search_query = Label::create_search_query($query_params);
DB::query("SELECT * FROM label WHERE $search_query");
return (DB::count() > 0);
}
private static function create_search_query($query_params){
$search_query = array();
if(!empty($query_params)){
foreach($query_params as $key => $value){
$search_query[] = "$key='$value'";
}
return join(' AND ', $search_query);
}
return '';
}
} |
class Conference{
static function exists($conference){
DB::query('SELECT * FROM conference WHERE conference.key = %s', $conference);
return (DB::count() > 0);
}
}
class Track{
static function exists($query_params){
$search_query = Track::create_search_query($query_params);
DB::query("SELECT * FROM track WHERE $search_query");
return (DB::count() > 0);
}
private static function create_search_query($query_params){
$search_query = array();
foreach($query_params as $key => $value){
$search_query[] = "$key='$value'";
}
return join(' AND ', $search_query);
}
}
class Label{
static function exists($query_params){
$search_query = Label::create_search_query($query_params);
DB::query("SELECT * FROM label WHERE $search_query");
return (DB::count() > 0);
}
private static function create_search_query($query_params){
$search_query = array();
if(!empty($query_params)){
foreach($query_params as $key => $value){
$search_query[] = "$key='$value'";
}
return join(' AND ', $search_query);
}
return '';
}
}
This was extremely hard to understand, so I decided to clean it up and get rid of the conditional complexity code smell.
Refactored code:
function structure_request_params($req_params){
$criteria = array('conference', 'track', 'label');
$params = array_values($req_params);
return build_search_query_params($criteria, $params, array());
}
function build_search_query_params($criteria, $params, $results) {
if(empty($params)) return $results;
if(empty($criteria)) {
if(!empty($params)) {
$results['search_term'] = $params;
}
return $results;
}
if(is_present_in_db($criteria[0], $params[0])) {
$results[$criteria[0]] = $params[0];
array_shift($params);
}
array_shift($criteria);
return map_criteria_params($criteria, $params, $results);
}
function is_present_in_db($table_name, $value){
return (DB::queryFirstField("SELECT count(*) FROM $table_name WHERE `key` = %s", $value) > 0);
} |
function structure_request_params($req_params){
$criteria = array('conference', 'track', 'label');
$params = array_values($req_params);
return build_search_query_params($criteria, $params, array());
}
function build_search_query_params($criteria, $params, $results) {
if(empty($params)) return $results;
if(empty($criteria)) {
if(!empty($params)) {
$results['search_term'] = $params;
}
return $results;
}
if(is_present_in_db($criteria[0], $params[0])) {
$results[$criteria[0]] = $params[0];
array_shift($params);
}
array_shift($criteria);
return map_criteria_params($criteria, $params, $results);
}
function is_present_in_db($table_name, $value){
return (DB::queryFirstField("SELECT count(*) FROM $table_name WHERE `key` = %s", $value) > 0);
}
Also with this, we were able to delete the Model classes as they were not required.
Posted in Agile, Code Smells, Design, Programming | No Comments »
Friday, October 25th, 2013
One fine morning, you wake up to see that Skype has been extremely generous to give you $4.29 Million Dollar Skype credit.
And you start to wonder, what good karma has resulted in this reward?
Have we finally found an Utopian World where companies are generous and caring towards their loyal customers? I guess not. So I quickly ran a test. Tried to call my cell phone from Skype using my Skype credit. And guess what I see:
What does this mean? I have $4.29 Million Dollars of Skype Credit, but I need more to call my cell?
By now it must be obvious to you that this was a stupid front-end bug. When I logged into their site to check what was my real credit, I discovered:
Interesting, my real credit is $-0.05, which is being displayed as $4,294,967.50 in their UI. What is going on?
Well, turns out their UI developer made an assumption that Skype credit can’t be negative, so the developer decided to use 32-bit unsigned integers to represent Skype Credit. While the backend actually uses 32-bit signed integers. So -0.05 is getting displayed as 4294967.50.
Damn it! My Skype Credit is $-0.05, now I’m going into a depression.
Posted in Bugs, Programming | 1 Comment »
Tuesday, March 19th, 2013
It’s easy to speak of test-driven development as if it were a single method, but there are several ways to approach it. In my experience, different approaches lead to quite different solutions.
In this hands-on workshop, with the help of some concrete examples, I’ll demonstrate the different styles and more importantly what goes into the moment of decision when a test is written? And why TDDers make certain choices. The objective of the session is not to decide which approach is best, rather to highlight various different approaches/styles of practicing test-driven development.
By the end of this session, you will understand how TTDers break down a problem before trying to solve it. Also you’ll be exposed to various strategies or techniques used by TDDers to help them write the first few tests.
Posted in Agile, Design, Programming, Testing | No Comments »
Tuesday, March 19th, 2013
Recently at the Agile India 2013 Conference I ran an introductory workshop on Behavior Driven Development. This workshop offered a comprehensive, hands-on introduction to behavior driven development via an interactive-demo.
Over the past decade, eXtreme Programming practices like Test-Driven Development (TDD) and Behaviour Driven Development (BDD) have fundamentally changed software development processes and inherently how engineers work. Practitioners claim that it has helped them significantly improve their collaboration with business, development speed, design & code quality and responsiveness to changing requirements. Software professionals across the board, from Internet startups to medical device companies to space research organizations, today have embraced these practices.
This workshop explores the foundations of TDD & BDD with the help of various patterns, strategies, tools and techniques.
Posted in Agile, Continuous Deployment, Design, Programming | No Comments »
Thursday, March 7th, 2013
Is writing inline comments always bad? Are comments really evil? I keep getting these questions over and over again.
Often you see code like this:
// If the item is taxable, get the taxed amount using tax calculator
if( objItem.bTaxable )
{
objItem.fTax = objCalculator.TaxForLocal(objItem.fItemRate);
}
// Additional tax is applicable if the item is an imported one
if( objItem.bImported )
{
objItem.fTax += objCalculator.TaxForImported(objItem.fItemRate);
}
// Add tax to item rate
objItem.fTaxedRate = objItem.fItemRate + objItem.fTax;
// Return the final amount
double fFinalAmount = objItem.fTaxedRate * objItem.nNumberOfItems;
return fFinalAmount; |
// If the item is taxable, get the taxed amount using tax calculator
if( objItem.bTaxable )
{
objItem.fTax = objCalculator.TaxForLocal(objItem.fItemRate);
}
// Additional tax is applicable if the item is an imported one
if( objItem.bImported )
{
objItem.fTax += objCalculator.TaxForImported(objItem.fItemRate);
}
// Add tax to item rate
objItem.fTaxedRate = objItem.fItemRate + objItem.fTax;
// Return the final amount
double fFinalAmount = objItem.fTaxedRate * objItem.nNumberOfItems;
return fFinalAmount;
What is the real value of these comments?
When I see stuff like this, I usually tell people
When I was learning programming, I was thought that great programmers write great comments. These days I tell people lousy programmer write comments.
Immediately people who write inline-comments get defensive. And that’s completely understandably. I don’t think we’ve really explained our rationale for making such a ridiculous statement. So let me step back and explain the rationale.
Folks in the extreme-programming community will tell you:
Comments are often used as deodorant. Comments represent a failure to express an idea in the code. Try to make your code self-documenting or intention-revealing. When you feel like writing a comment, first try to refactor so that the comment becomes superfluous.
Most people will also tell you, that the biggest problem with comments is that they soon become outdated. The original intent of the person writing the comment was to help a developer who comes later to understand the code better. But unfortunately over a period of time, the comments get outdated and it adds more to the confusion. Speaking to many programmer, they simply delete or ignore the comments because they find them ambiguous. Even though the person who wrote the comments wrote them with a good intension, one needs to ask if it really solved any problem?
And then they question, why not put the same effort and time to write well-crafted code so that comments are never required? Is it impossible to do so?
While this argument is a good one, I find it hard to connivence people just based on this argument.
I’ve found the following approach work really well for me. First let’s understand why programmers write comments. Based on my experience, programmer write in-line comments for 3 different reasons:
- To explain what the code does
- To descrive how the code does what is does
- Why the code is written the way its written
If you think about it, the “what” and “how” of the code should really be expressed by self-documented code. IMHO its simply a failure on part of the programmer if they cannot express the “what” and “how” in the code itself.
However the “why” is little bit more tricky. It’s a reminder, telling us: “Hey, you are doing something complicated and someone else will not understand why. Even if you wrote a comment, they might not necessarily understand it.” At this point I might stop and see if there is a better way to design/model/code this, such that the why becomes obvious via the code. This is certainly more challenging and time consuming than to write a comment and moving on. However this short-term hack might bite me back. Luckily, most often than not, I can find a way to avoid the comment. But there are special cases when I need a comment to explain the why. Let’s see a few examples:
- There is a bug in the underlying framework/library I’m using. Searching on the net, I found the bug report and a workaround. Looking at just the code might not help someone understand the need for the workaround. Generally I would write a small comment saying Workaround with the version number of the framework/library and add the link to the workaround and continue. In future, someone can remove the workaround & delete the comment if the issue is fixed.
- I’m implementing a complex algo and its not common that everyone understands it. I would add a link to the Algo description (rather than duplicating the algo description in the code. DRY principle applies to comments as well.) and continue with my coding.
- And so on…
So think again before you leave a comment 😉
Posted in Agile, Code Smells, Programming | No Comments »
Sunday, November 11th, 2012
Should you consider BDD for your team? I just wanted to share my experience with BDD, which you could consider as food for thoughts:
- Why? – How often does your development team ask the business team why certain feature is important? More importantly, why now and how much of it is enough? In my experience with BDD, the approach naturally lends the teams to have a constructive discussion about this. I’ve seen this leading to a genuine collaboration between business and development. In short, BDD helps getting the right people to discuss the right amount (depth) of things at the right time.
- Better commitment and buy-in: BDD lays very heavy emphasis on Business value. It forces the Business to justify the priority by showing concrete value. Also it helps the development teams to embrace the prioritizes set by Business, because they understand the thinking process much better. Interestingly, I’ve noticed that teams that practice BDD, I rarely see either sides throwing their weight around to push their pet features through. Also due to the focus on value, rarely I find teams building useless feature for the sake of proving productivity.
- Ubiquitous domain language: By working together, the business team & the development team build a shared understanding by using tools/techniques like product discovery, story maps, user stories, acceptance criteria and scenarios to create an ubiquitous domain language. The ubiquitous language is usable/understandable not only by domain experts, but also by every member of the team. This goes a long way in reducing the complexity in the domain and making the barrier-to-entry much lower for new members.
- Right focus: BDD can help you focus on the user’s needs and the expected behavior instead of jumping ahead and getting caught up in implementation details upfront. Also I’ve seen teams which are new to Test Driven Development (TDD), seem to focus too much on “testing” missing the point. BDD helps the teams focus on system’s behavioral aspects rather than focusing on testing your implementation. Over the years, we’ve learned that up-front analysis, design, planning and test planning, all have a diminishing return. In my experience BDD helps strike the balance.
- Evolutionary Design: Agile (eXtreme Programming in particular) has killed the notion of “fully-specified, completely-detailed-out requirements upfront.” It is a well accepted fact that we won’t be able to figure out all the requirements when we are starting off with a project. BDD, at its very crux, embraces the fact of evolving product understanding and hence helps your system’s design evolve to keep pace with the changing needs.
- Breaking the knowledge silos in distributed team: Having worked with distributed teams for over a decade, due to the distributed nature, one common problem I see is domain knowledge gap between the team members. Esp. teams which are away from the real business, have a hard time understanding and questioning the business requirements. Usually there are gaps or misunderstanding, leading to rework and frustration. Even if your team is not distributed, you might be familiar with the problems of knowledge silos. I don’t think BDD alone solves this problem, but at least it encourage teams to work more closely and reduces the gap. It also encourages a generalizing specialist attitude in team members, helping with other eXtreme programing practices like pairing, collective ownership, etc.
- Greater ROI: Behavior has a much longer shelf life than your implementation and implementation related documentation. Also as the business rules change, BDD captures it better than it being lost in documents and code.
- Predictability & Confidence: Also in my experience working with teams using BDD, I see that they have much better (or at least feel they have better) predictability and confidence in their work.
What’s your experience?
Also to clarify, what I mean by Business team and Development team, my definitions below:
Business Team: Folks who focus on “Are we building the right product.” This usually includes the following roles: Product Owner/Manager, Stakeholders, Product Designer (User Experience), Subject Matter Expert, Business Analysts, and so on.
Development Team: Folks who focus on “Are we building the product right.” This usually includes the following roles: Architects, Tech Leads, Developers, Testers, Graphics designers, Database administrators and so on.
Posted in Agile, Design, Programming | No Comments »
Tuesday, October 9th, 2012
I’ve come to believe that Code is a liability. The less of it we have, the better off we are. Since code is a liability, would you not take extra care to keep it minimal and simple?
However I keep running into code shown below. I still wonder what drives developers to write more code, when they can do away with a fraction of it?
public class Calendar {
List<Integer> busySlots;
public void addBusySlot(int i) {
if(busySlots==null){
busySlots=new ArrayList<Integer>();
}
busySlots.add(i);
}
public boolean isFree(int time) {
if(busySlots==null)
return true;
return (!(busySlots.contains(time)));
}
} |
public class Calendar {
List<Integer> busySlots;
public void addBusySlot(int i) {
if(busySlots==null){
busySlots=new ArrayList<Integer>();
}
busySlots.add(i);
}
public boolean isFree(int time) {
if(busySlots==null)
return true;
return (!(busySlots.contains(time)));
}
}
vs.
public class Calendar {
private final List<Integer> busySlots = new ArrayList<Integer>();
public void addBusySlot(int time) {
busySlots.add(time);
}
public boolean isFree(int time) {
return (!(busySlots.contains(time)));
}
} |
public class Calendar {
private final List<Integer> busySlots = new ArrayList<Integer>();
public void addBusySlot(int time) {
busySlots.add(time);
}
public boolean isFree(int time) {
return (!(busySlots.contains(time)));
}
}
In fact I would argue that this is a Lazy Class and you can simply use the list directly where ever you need the Calendar.
Another example:
if(some_condition == true) {
return true;
} else {
return false;
} |
if(some_condition == true) {
return true;
} else {
return false;
}
vs.
Posted in Agile, Code Smells, Programming | 1 Comment »
Saturday, July 14th, 2012
Suppose we had the following (utterly) simplistic requirement:
@Test
public void politiciansDontNeedToPayTax() {
whenIncomeIs(10000).verify(POLITICIANS).pay(0);
}
@Test
public void residingAliensGetAwayByPayingLittleTax() {
whenIncomeIs(10000).verify(ALIENS).pay(1000);
}
@Test
public void richPeopleArePunishedWithHighestTax() {
whenIncomeIs(10000).verify(RICH_PEOPLE).pay(3000);
} |
@Test
public void politiciansDontNeedToPayTax() {
whenIncomeIs(10000).verify(POLITICIANS).pay(0);
}
@Test
public void residingAliensGetAwayByPayingLittleTax() {
whenIncomeIs(10000).verify(ALIENS).pay(1000);
}
@Test
public void richPeopleArePunishedWithHighestTax() {
whenIncomeIs(10000).verify(RICH_PEOPLE).pay(3000);
}
where:
TaxPayer RICH_PEOPLE = new RichPeople();
TaxPayer ALIENS = new ResidingAliens();
TaxPayer POLITICIANS = new Politicians(); |
TaxPayer RICH_PEOPLE = new RichPeople();
TaxPayer ALIENS = new ResidingAliens();
TaxPayer POLITICIANS = new Politicians();
To fullfil this requirement, we’ve the following code:
Parent Class:
public abstract class TaxPayer {
protected abstract double getTaxPercentage();
public double calculateTaxAmount(final long income) {
if (getTaxPercentage() == 0)
return 0;
return income * getTaxPercentage() / 100.0;
}
} |
public abstract class TaxPayer {
protected abstract double getTaxPercentage();
public double calculateTaxAmount(final long income) {
if (getTaxPercentage() == 0)
return 0;
return income * getTaxPercentage() / 100.0;
}
}
Each child class:
public class Politicians extends TaxPayer {
private double taxPercentage = 0;
@Override
protected double getTaxPercentage() {
return taxPercentage;
}
} |
public class Politicians extends TaxPayer {
private double taxPercentage = 0;
@Override
protected double getTaxPercentage() {
return taxPercentage;
}
}
public class RichPeople extends TaxPayer {
private final double taxPercentage = 30;
@Override
protected double getTaxPercentage() {
return taxPercentage;
}
} |
public class RichPeople extends TaxPayer {
private final double taxPercentage = 30;
@Override
protected double getTaxPercentage() {
return taxPercentage;
}
}
public class ResidingAliens extends TaxPayer {
private final double taxPercentage = 10;
@Override
protected double getTaxPercentage() {
return taxPercentage;
}
} |
public class ResidingAliens extends TaxPayer {
private final double taxPercentage = 10;
@Override
protected double getTaxPercentage() {
return taxPercentage;
}
}
One would wonder what good are these child classes? Feels like a class explosion. Sure enough! This is the pathetic state of Object Oriented programming in many organizations, esp. the Enterprise software side of the world.
One could have easily used an enum to solve this problem:
public enum TaxPayer {
Politicians(0), Aliens(.1), RichPeople(.3);
private double taxPercentage;
private TaxPayer(double taxPercentage) {
this.taxPercentage = taxPercentage;
}
public double calculateTaxAmount(final long income) {
return income * taxPercentage;
}
} |
public enum TaxPayer {
Politicians(0), Aliens(.1), RichPeople(.3);
private double taxPercentage;
private TaxPayer(double taxPercentage) {
this.taxPercentage = taxPercentage;
}
public double calculateTaxAmount(final long income) {
return income * taxPercentage;
}
}
Posted in Agile, Code Smells, Design, Programming, Training | 2 Comments »
|