David Scott Bernstein's Blog, page 31

June 18, 2015

Seven Strategies for Creating Better Names

Naming is a central part of programming and vitally important. Everything has a name and the name we give something should reveal something about what it does. The difference between good names and bad ones is a key factor in the maintainability of the software we write. Here are seven strategies for creating better names.


* Use metaphors

We understand similarities of dissimilar things through metaphor. Using certain metaphors creates expectations that, as long as they are upheld, can define how to interact with a system. Metaphors are a central part of good designs and the names we use should reflect the metaphors we’re following.


* Use the active voice

Create names using the active voice. Methods are verbs, classes are nouns. Let them say what they do. Adopt conventions, like if a method returns boolean start the name with “is” but don’t overdo it, opt for clarity over convention.


* Say things plainly

SpellThingsOutInCamelCase so they’re easy to read. Don’t be afraid to create long names or even long sentences for names. In most IDEs,  you’ll only have to type it once the first time and then subsequently you can type the first few letters and pick it from a popup list. Also, name things for what they do so they’re easy to understand.


* Pluralize names for their manager

Establish conventions that make sense and stick with them. For example, I like to name leaf objects that map to database records for what they represent (e.g. user, auction, etc.) If a manager is needed to aggregate these objects, I’ll simply pluralize the name (e.g. users, auctions, etc.) but if more sophisticated processing is required, for example caching or workload distribution, I’ll call out manager in the name (e.g. userManager, auctionManager, etc.)


* Spell things out

Avoid using acronyms, abbreviations, and lingo. Say what a method does in it’s name but don’t reveal how it does it. Don’t describe implementation details. Try to say what the method does from the caller’s perspective. Generally, name things generically for what they do and the names will have more longevity.


* Make names pronounceable

Naming is a primary means of communication that we are constantly referring to in our heads and among each other. It’s easier to communication and understand names that can easily be pronounced. Unpronounceable names can be confusing to work with and difficult to talk about.


* Use generic or specific names based on scope

Use short generic names for public symbols. For example, even if I’m only using one zipCompress128 object, I’ll call it compress so if I ever need to refactor to a Strategy Pattern, I don’t have to change the name. Conversely, use long specific names for privately scoped symbols so they clearly express what they do.


Naming is a critical skill that makes the software we write understandable and easier to work with. Depend on names over comments to express what code does. This helps embed knowledge in the system and makes code self-expressive instead of having to use comments. It will make all the difference when people go back into the code to work with it.

 •  0 comments  •  flag
Share on Twitter
Published on June 18, 2015 08:54

May 21, 2015

Seven Strategies for Solving Problems Test-First

Using tests to drive development in TDD concertizes abstract requirements making them easier to understand and work with. This is a very powerful way of solving software problems while at the same time creating maintainable code. Here are seven strategies for solving problems test-first:


1. Think outside-in

Before solving a problem we must first understand it. Seeing the problem from the outside looking in is often the best place to start. This helps us understand the “big picture” and gives us a context for understanding how each piece interfaces with the rest of the world.


2. Create tight contracts

A key to well-encapsulated software is having tight contracts with well-defined responsibilities. This helps us focus on defining a useful interface that hide implementation details and decouples code from the rest of the system.


3. Separate knows from unknowns

Usually, problems have parts that are known and parts that are unknown. The goal is to expand the known and contract the unknown so all aspects become known. The first step is to identify the areas that are unknown so they can be explored and then find the right questions to ask to help eliminate unknowns.


4. Fake it the first time

Creating a fake or obvious implementation for the first test of a new behavior let’s you create a second test so you have two examples to generalize from. Generalization is always easier with multiple examples.


5. Try to fake it a second time

For really difficult problems it might be helpful to fake it a second time so you have three tests to generalize from. However, it can be a lot of work to fake something a second time and it’s usnally much more work to fake something a third time than to just create a robust implementation.


6. Remove redundancy

Redundancy in code hides the truth. By eliminating redundancy in code we often gain insights into the true nature of the problem we’re solving and that helps us find more elegant and comprehensive solutions.


7. Generalize

Whenever possible, look for the generalized solution to a specific problem. This can lead to a better solution that will fit in more situations so code is easier to extend and repurpose. It also makes code easier to read and understand.


Solving problems is a central part of programming. TDD provides a disciplined way of solving problems in code while building maintainable solutions. This helps us think about programming problems in ways that give us traction and helps us build good solutions.

 •  0 comments  •  flag
Share on Twitter
Published on May 21, 2015 12:20

April 23, 2015

Seven Strategies for Building Smaller

Big tasks are hard to work on. When we break a big task down into smaller tasks they become much more manageable. Suddenly, insurmountably large tasks become manageable as a series of smaller tasks, each of which is easily achievable on their own. Building smaller simplifies tasks making them easier to define, create, and verify. Here are seven strategies for building smaller.


1. Reduce iteration length

The purpose of time-boxing software development into iterations or sprints is to get us good at task breakdown so we are building in small pieces. Scrum says sprints should be 1-4 weeks. Most teams have 2-week sprints. Some teams tell me they can’t build anything of value in 2 weeks but that doesn’t usually turn out to be true when you get good at task breakdown. Generally, we should think about emerging features a little bit at a time.


2. Identify observable behaviors

One benefit of test-first development is it drives developers to write code that is straightforward to assert against. We start with a failing test that asserts a specific behavior and the go about implementing that behavior, which usually happens in a two-step process. First, we fake the behavior or create “an obvious” implementation. Once we have it working and our tests are passing we can safely refactor the code to be more maintainable.


3. Identify core behaviors

Sometimes we build a bunch of features because no one took the time to consider what parts were most important. Asking what’s the least we can do and still provide some value can give insights into the key pieces to build first. Getting core behaviors working first can oftentimes save redoing a lot of work in the future and provide value to our users more rapidly.


4. Create a “walking skeleton”

Alistair Cockburn coined the phrase *walking skeleton* to mean a system you get working on day one, although it may not do much, and then add to it incrementally. The key is that it may not yet do everything you want it to but it does do something. Building a system out in this way tends to be very efficient. It also gives us constant feedback as we are always able to build and run our automated tests.


5. Peel off exceptions

Another way to build out a feature is to start by implementing the happy path and then peel off exceptions, one at a time. Start by validating constructor arguments then move to validating method parameters. Create conventions for establishing tight contracts between service and clients so exception handling is done only once, generally either during mutation or just before it’s ready to be used.


6. Keep it testable

A task is a task because it is verifiable. A task is too small if it no longer produces a verifiable result and we can’t test it. A task is too big if it is hard to verify. Tasks that are easy to test tend to be the right size.


7. Reduce cyclomatic complexity

McCabe first described cyclomatic complexity as the number of paths through conditional code. Code without conditionals have a cyclomatic complexity of 1, one conditional is 2, two conditionals is 4, and so on. Cyclomatic complexity increases exponentially as conditionals are introduced so keeping as few conditionals as possible in each method is important.


Smaller is better. Building smaller is at the very core of Agile. When we build small we can focus on what’s most important first, get feedback faster, and make work more manageable. Enough said!

 •  0 comments  •  flag
Share on Twitter
Published on April 23, 2015 10:43

March 12, 2015

Seven Strategies for Vanquishing Waterfall

What makes a software development project Waterfall and what makes it Agile? Different people answer this question differently. For a lot of teams, Agile is having a daily stand-up meeting and working in two-week sprints. For other teams, Agile is doing all of the practices in Scrum, Lean, and XP. Which is right? I say Agility is a continuum and we get better at through time. Here are seven strategies for vanquishing Waterfall and becoming more Agile.


1. Replace requirements with stories

Up to half of all development time and effort goes into creating and interpreting requirements and they are the cause of nearly half of all bugs. When we replace written requirements with a product owner who is a subject-matter expert that the team can talk to as they’re building features, development can become much more efficient.


2. Integrate continuously

Building features in iterations isn’t enough unless you also validate that the features work as requested. Taking a task 99% of the way done isn’t Agile. We must fully integrate a feature into the system and make it supportable in order for it to be done. More than anything else, continuous integration is the best first step towards realizing the benefits of agility by creating an infrastructure for doing development correctly.


3. Do test-first development

Getting a task done also means automating validation by having unit tests. The best way to do this is by doing test-first development. Well written unit tests help us in refactoring and give us regression. But the main benefit of doing test-first development is to drive us to write focused, testable code.


4. Automate validation of release candidates

A major goal of doing TDD and continuous integration is to automate the validation of release candidates. This usually involves writing more tests than we got from doing test-first development. There are many forms of testing and QA. All of the testing required to validate a release candidate should be fully automated so that no human intervention is required. If you do this one thing you’ll start to realize huge benefits and save more money releasing and update software than virtually any other thing you could do.


5. Build smaller

Many projects appear so complex that the developers can’t image building it in small pieces. If a feature is too big then break it down into smaller tasks. Ideally, we’d like tasks to have some value to the user or be part of an acceptance criteria but failing that, as long as it produces some observable result that takes us closer to providing value and you can write a test for it, then it’s probably the right size.


6. Shorten feedback cycles

The smaller you build the more frequent you’re feedback will be. There are many feedback cycles in software development: iterations, daily stand-ups, retrospectives, etc. There’re a lot of people who write about these feedback cycles but the most important feedback cycle is often ignored. The most important feedback cycle is the build itself. A fast “one-click” build with good automated unit tests give developers instant feedback on if their approach is a good one. Once recognized, developers depend on this feedback and their productivity skyrockets.


7. Adopt other XP practices

There are many other very important aspects of developing software. Most teams save the above six strategies to do for later, if at all. It’s my experience that these strategies are the highest value ones and should be implemented first. However, they don’t solve all problems. The other practices from XP, Lean, and Scrum can help with many of the other challenges we face when developing software.


Agile includes several lightweight methodologies designed to replace the heavyweight process of Waterfall. Agile is more than building iteratively and having daily stand-up meetings. The real difference between Agile and Waterfall is limiting your work-in-progress by taking tasks to completion and integrating them as they are built with test automation. These things are easier said than done but for most development projects these are the highest value things they can do.

 •  0 comments  •  flag
Share on Twitter
Published on March 12, 2015 08:39

February 19, 2015

Seven Strategies for Fostering Innovation

True innovation means pioneering into territory no one has ever been in order to discover something new. Not everyone can do this but fortunately for the rest of us some can. Still, it can be helpful to find ways of supporting innovation. Here are seven strategies for fostering innovation.


1. Believe it’s possible

There’s a line in a Peter Gabriel song that goes, “All of the buildings and all of the cars were once just a dream in somebody’s head.” All innovation started by someone believing that something is possible that others thought was impossible. See what’s really possible by asking “what if” questions or other empowering questions, like “How can I make this work?”


2. Let people be creative and believe in them

We often don’t know just how powerful and capable we truly are. As managers and coworkers and even as consultants, we must believe in each other to bring out our best. When we achieve things we didn’t think we could, it not only supports the team it also supports our own growth. Personally, I’ve always found when I give people the freedom to do their best they usually do.


3. Spike on unknowns

Being an innovator means dealing with unknowns. I find one technique particularly useful when dealing with unknowns: spiking. Spiking is where one or more people go off for a fixed period of time to research something. They usually have a list of questions they want answered. Spiking is an invaluable technique for researching unknowns that come up in the course of innovating. Spikes can be time boxed to minutes, hours, days, or more but generally the shorter the better and longer spikes should be augmented with periodic check-in’s and retrospectives.


4. Walk the road less traveled

Innovation comes from asking questions others don’t ask. To do this we must think uniquely. Look for connections where others don’t, search for how things are the same, and look for ways of breaking down big problems into smaller ones.


5. Challenge fundamental beliefs

I once saw two-time Nobel Prize Winner Murray Gell-Mann speak. Someone asked him how he came up with the ideas that led to two Nobel Prizes and he said that one thing he does, and I’m paraphrasing, is he challenges fundamental believes and sometimes that gives him new insights.


6. Have a vision of the outcome

Faith is a key ingredient and holding a vision of what you want to accomplish or achieve is an important part of bringing something new into the world. Faith isn’t about hoping or even believing, it’s about passionately knowing that what you want will come to pass. Keep a clear vision, make it sensory-specify and feel it passionately then communicate that passion to others.


7. Stay unattached to the details

Energy always flows along the path of least resistance. When we focus on an outcome it creates energy and the path it takes may be something we didn’t expect so staying unattached to the details can be a good thing. Focus on the benefits and let the details take care of themselves.


Innovation isn’t always easy but there are things we can do to support and foster innovation. Doing these things can make stepping out into the unknown less scary and give us a higher likelihood of coming up with something truly new and innovative.

 •  0 comments  •  flag
Share on Twitter
Published on February 19, 2015 12:35

January 27, 2015

Seven Strategies for Growing as a Software Developer

People end up as software developers from a variety of backgrounds. Regardless of how we became software developers, if we want to stay on the leading edge of the industry we must be constantly learning and growing as developers. Here are seven strategies for growing as a software developer.


1. Do your own project

Having a side project that you can do on your own time can give you the freedom to learn new technologies and approaches that may not be available to you on the job.  Building something of your own can be highly satisfying and possibly provide you with an additional revenue stream. If your current job isn’t stretching you enough then ask yourself what your dream project would be and consider doing it on your own time. After all, you just need an idea and a laptop to get started.


2. Read the classics

Software development is in the midst of a mini-renaissance with new ideas and approaches. Unlike a few decades ago when there were relatively few must-read books on the shelves, today our shelves are filled with important works for developers. Some of my favorite books are listed on my online bookstore. These books provide new insights into building better software.


3. Follow thought leaders

New ideas are emerging so fast that many don’t wait to be incorporated into books for publication. Long before they publish, the thought leaders in our industry write articles, blog posts, tweets, and give seminars and workshops on their ideas. Follow the leaders in our industry to get new information years before it reaches the mainstream.


4. Expand your imagination

Software development requires diverse skills that go beyond mastery of a programming language. We actually spend a great deal of effort visualizing and imagining how we want things to be and so it is very valuable to draw from ideas outside our industry. Even basic visualization exercises can be helpful in expanding our capacity as developers.


5. Ask empowering questions

Very often the quality of the answers we get depend on the quality of questions we ask. This is true for working with others to unleash greater potential and it is also true when we work by ourselves. The way we frame questions to ourselves have a big impact on what we believe is possible. If you’re stuck try asking a “what if…” question to root out any limiting beliefs.


6. Find a mentor

Beyond formal knowledge there’s a great deal of conventions, patterns, and approaches that outstanding developers follow but aren’t written down anywhere. If you can find a mentor or someone with greater skills who is willing to help you then you’ll get the best education of all.


7. Be a mentor

One of the best ways of attracting a mentor is to be a mentor to others less experienced than you. Not only does it send the message that you’re a team player, it is also one of the most valuable ways to learn because when you explain something to someone else it’s solidifies that knowledge for you as well.


Being a software developer means constantly learning and growing. I love looking back at code I wrote a few years ago and thinking how much better I could write it today. It means I’m not stagnating and that’s a good thing in this ever changing industry we’re in.

 •  0 comments  •  flag
Share on Twitter
Published on January 27, 2015 12:32

December 4, 2014

Seven Strategies for Fixing Bugs

Bugs are the bane of the software industry. They can be difficult to find and costly to fix. How we deal with bugs has a big impact on our software development process. We can use bugs to show us ways of improving our process so that similar bugs aren’t created again. Here are seven strategies for fixing bugs.


1. Don’t write them in the first place

You know the old joke: The patient raises his arm and says to his doctor, “Hey Doc, it hurts when I do this,” and the doctor replies, “Well then, don’t do that.” We want to avoid writing bugs in the first place and can do this by focusing on creating high quality code and using our tools to help us prevent mistakes.


2. Catch them as soon as possible

If we’re going to write bugs then we should have a process for finding them as quickly as possible. When time elapses between when a bug is written and when it’s fixed the code containing the bug becomes less familiar to the developer who wrote it and takes longer to fix. But with a set of automated regression tests developers can get instant feedback on whether or not their code has most kinds of bugs. By reducing the cycle time from when a bug is written to when it’s repaired to zero the cost of fixing the bug is the lowest it will ever be.


3. Make bugs findable by design

No matter how good our regression tests are some bugs will get away from us, and when they do it would be good if they were easier to find. Our ability to find bugs in code is directly related to the code’s qualities. For example, software that is highly cohesive and well encapsulated is less likely to have side effects that can cause bugs. Software that is cohesive and well-encapsulated is also easier to read and understand so it’s also easier to find bugs in it.


4. Ask the right questions

Since developers spend most of our time and effort in debugging trying to find bug, figuring out how to quickly locate bugs is important. I had a genetics professor in college, Dr. John Elision, who used to say, “It doesn’t matter if your experiment succeeds or fails, what matters it that you learn something.” This is good advice for debugging too. The rare times that I find myself hunting down a bug I try to construct scenarios that give me good information on where the bug could be or at least where the bug isn’t and I’ll try and narrow down sections of code until I find it.


5. See bugs as missing tests

Once I find a bug and before I fix it I write a failing test for it so that when I fix the bug the test passes. The bug came about because of some false assumption. By figuring out what that false assumption is and embodying it in a unit test we get regression for that issue and will never have to deal with that bug again.


6. Use defects to fix process

When I find a bug I ask why the bug happened in the first place. Sometimes this leads me back to a problem in my software development process and fixing the process can potentially rid me of many future bugs. Look for ways to let our tools help us do the right things.


7. Learn from mistakes

If bugs represent false assumptions or flaws in our development process then it’s not enough to fix bugs, we must fix the environment that allowed the bug to happen in the first place. Use bugs as lessons on vulnerabilities in your design and process so you can look for ways to fix them. Use mistakes as learning opportunities and gain the valuable message each of our problems hold.


Bugs are the single largest expense in software development, costing billions of dollars per year. Bugs aren’t just problems in code they’re also problems in our software development process, and by seeing them as such we can use them to find ways of improving our process thereby eliminating similar bugs in the future.

 •  0 comments  •  flag
Share on Twitter
Published on December 04, 2014 11:24

November 13, 2014

Seven Strategies for Burning Down Risk

Developing software is risky and expensive. Software is formless and hard to understand. Subtle interaction can cause software to affect seemingly unrelated components. A good development process focuses on mitigating risk by finding problems early, before they become showstoppers, and while there’s still time to resolve them.


1. Integrate continuously

Creating a system that can be built from day 1 and continuously integrating software into that system as it’s built is the only way to eliminate risk. Delaying integration until one of the last steps before release is a bad idea because integration is the time when we see how our code behaves with other code in the system. It’s often when the nastiest bugs are found. A feature remains unproven and carries an unknown amount of risk until it’s integrated into the system. Integrating features into releases that are tested in large batches is like going all-in in Vegas. The odds are against you.


2. Avoid branching

When we branch in a version control system by feature, team—or whatever—and then integrating those branches before release we are doing Waterfall development. Agile is about burning down risk and that can only happen when code is integrated as it’s built. Once code is integrated into the system the risk drops to near zero, but when components are built in branches and integrated before release the risk is unknown until the branches are integrated. Instead of branching use feature flags to turn off features in the system while they are being built but not yet ready to be activated.


3. Invest in automated tests

Removing all human intervention for validating a release candidate so tests are entirely automated is essential for dropping the cost of development. Fast automated tests let you run them any time and provide important feedback. If you find it difficult to do test automation in your system then consider a redesign to something more testable. A lack of testability often indicates a poor design.


4. Identify areas of risk

Risk often has to do with unknowns or things out of our direct control. Identify what these things are by asking what could go wrong. Identify external dependencies, the things out of your direct control, and then look for ways to mitigate those risks and decouple dependencies.


5. Spike on unknowns

Once an unknown is identified you can work on it for a short period then check in to measure progress. Spikes are generally focused around a question or series of questions to be answered. By creating short time boxes with check-ins and measuring progress we hope to avoid going down ratholes and wasting time. Try to keep separating the known from the unknown so the unknown becomes smaller and smaller.


6. Build the smallest pieces that show value

The whole premise of Agile is to build in small batches. Smaller problems are easier to understand, solve, prove, and maintain. But how small should you make it? My rule of thumb is to build the smallest thing that shows value. If 80% of the value comes from 20% of the features then let’s build that 20% first. We might not even need the other 80%.


7. Validate often

Our customers may not know what they want until they see it. Getting validation early and often can help us build a higher value product and engages the customer in finding better ways of doing things. When development can become a partnership between the customer or PO and the developers we can often build better features than we could have with all the upfront planning in the world.


Reducing risk in software is about assuring that you’re building the right things and assuring that you’re building the things right. We know we’re building the right things by getting feedback from our users early and often. We know we’re building the things right by following good engineering practices for building changeable code that’s continuously integrated into the build. By doing these two things we can significantly improve our likelihood and degree of success.

 •  0 comments  •  flag
Share on Twitter
Published on November 13, 2014 08:15