Showing posts with label best practices. Show all posts
Showing posts with label best practices. Show all posts

Tuesday, 6 May 2014

Happy customer cocktail recipe

Ingredients 


Recipe 


1 - Take a bit of Kanaban, Scrum retrospectives, XP practices and mix well.


2 - Setup your board. ( You will need an electronic board, so choose between  JIRA agile , Versionone , Leankit , etc. Remember, it's not about how big it is, but how you use it ).

3 - Setup Jenkins. You will need to build the following pipelines : 

The following to run after every commit.

Continuous build job : this is triggered every time there is a commit. It runs unit and acceptance tests against trunk.

Sonar job : If the above passed, then  it's time to check the quality of the code committed. You can use sonar and the sonar plugin for Jenkins.

The following to run every night, each depends on the success of the previous.

Continuous build job : yes again, no point in running the following if this fails.

Release job : this creates a production release (maven release or whatever is your company policy about releases) out of your trunk(svn)/master(git) branch.


Deploy to dev job : This job automatically deploys to dev environments.

Dev System tests job : This will trigger your integration tests against dev environments.

Deploy to perf job : This job automatically deploys to performance environments.

Performance tests job : This run your JMeter tests against perf using the permormance jenkins plugin.


4 - Each business story will need to follow this process :

Pair : If the story is not trivial, do pair programming. It will speedup development and it will reduce dramatically the number of bugs.

Distill the story :  Sit with your pair, QA and the Product Owner and write down all the acceptance criteria. Ask questions here and try to cover all possible scenario.  

ATDD : Write acceptance tests first. It will not compile at first because you do not have any implementation, so write the interfaces that you need in order to make the project to compile. Run the test, it will still fail. 

TDD : Now write the test for the most external part of your code. (implement leaves first). Run the test. Implement the code to make the test pass. Test more. Implement more. Continue until the story is fully tested and implemented.

ATDD : Re run your existing acceptance tests. They should pass now.

Review : Submit the code for review. Once the code has been reviewed you can commit.

Sonar : wait for Sonar to tell you how good you and your pair are.

5 - After the Jenkins nightly pipeline is successful completed, the QA team can pick up the Release and they can deploy to their QA environment. QA will run manual, automate and exploratory tests and if bugs have been found, developers need to act immediately. 

6 - When QAs do not find bugs, the release can be deployed into UAT where the Product owners can verify and accept the stories.

7 - Once POs are happy, Ops team can deploy to Preprod in order to test the deployment scripts and the deployment instructions.

8 - Ops can deploy the release in production.

  
Happy customers can celebrate now.

 







Friday, 10 May 2013

Building smart Builders

When building an API, you should always think about who is going to use it.
When the API is simply and clear to use, then the users are happy. When the users are happy then everyone is happy too :).

But great usability is not always easy to achieve. 

There are patterns that help on this, on this post I will focus on the classic builder pattern and how you can enhance it with the step builder pattern in order to build objects with a no brain interface, easy to use, impossible to get wrong.

So lets start painting some context, we have 2 domain objects representing a user configuration to connect to some remote or local server. When remote credentials are required, when local no.

package com.marco.sbp;
public class UserConfiguration {
        private final String name;
        private ServerDetails serverDetails;

        public UserConfiguration(String name) {
                this.name = name;
        }

        public void setServerDetails(ServerDetails serverDetails) {
                this.serverDetails = serverDetails;
        }

        public String getName() {
                return name;
        }

        public ServerDetails getServerDetails() {
                return serverDetails;
        }
}



package com.marco.sbp;
public class ServerDetails {

        private final String host;
        private String user;
        private String password;

        public ServerDetails(String host) {
                this.host = host;
        }

        public void setUser(String user) {
                this.user = user;
        }

        public void setPassword(String password) {
                this.password = password;
        }

        public String getHost() {
                return host;
        }

        public String getUser() {
                return user;
        }

        public String getPassword() {
                return password;
        }
}


We want to abstract the construction of the objects above using 2 different techniques, the classic builder pattern and the step builder pattern.

The classic builder pattern is pretty straightforward, it works masking the creation of the UserConfiguration and the ServerDetails using properly named methods like onLocalHost, onRemoteHost, etc.
package com.marco.sbp.builder;
import com.marco.sbp.ServerDetails;
import com.marco.sbp.UserConfiguration;
public class ClassicBuilder {
        
        private String name;
        private String host;
        private String user;
        private String password;

        
        public ClassicBuilder(String name){
                this.name = name;
        }
        
        public ClassicBuilder onLocalHost(){
                this.host = "localhost";
                return this;
        }
        
        public ClassicBuilder onRemoteHost(String remoteHost){
                this.host = remoteHost;
                return this;
        }
        
        
        public ClassicBuilder credentials(String user, String password){
                this.user = user;
                this.password = password;
                return this;
        }
        
        public UserConfiguration build(){
                UserConfiguration userConfiguration = new UserConfiguration(name);
                ServerDetails serverDetails = new ServerDetails(host);
                serverDetails.setUser(user);
                serverDetails.setPassword(password);                    
                userConfiguration.setServerDetails(serverDetails);
                return userConfiguration;
        }
}



The step builder pattern is still using smart names to construct the object, but it's exposing these methods only when needed using interfaces and proper encapsulation.
package com.marco.sbp.builder;
import com.marco.sbp.ServerDetails;
import com.marco.sbp.UserConfiguration;

/** "Step Builder" */
public class StepBuilder {
        public static NameStep newBuilder() {
                return new Steps();
        }

        private StepBuilder() {
        }

        public static interface NameStep {
                /**
                 * @param name
                 *            unique identifier for this User Configuration
                 * @return ServerStep
                 */
                ServerStep name(String name);
        }       

        public static interface ServerStep {
                /**
                 * The hostname of the server where the User Configuration file is stored will be set to "localhost".
                 * 
                 * @return BuildStep
                 */
                public BuildStep onLocalhost();

                /**
                 * The hostname of the server where the User Configuration file is stored.
                 * 
                 * @return CredentialsStep
                 */
                public CredentialsStep onRemotehost(String host);
        }

        public static interface CredentialsStep {
                /**
                 * Username required to connect to remote machine Password required to connect to remote machine
                 * 
                 * @return BuildStep
                 */
                public BuildStep credentials(String user, String password);
        }

        public static interface BuildStep {
                /**
                 * @return an instance of a UserConfiguration based on the parameters passed during the creation.
                 */
                public UserConfiguration build();
        }

        private static class Steps implements NameStep, ServerStep, CredentialsStep, BuildStep {

                private String name;
                private String host;
                private String user;
                private String password;

                public BuildStep onLocalhost() {
                        this.host = "localhost";
                        return this;
                }
                
                public ServerStep name(String name) {
                        this.name = name;
                        return null;
                }

                public CredentialsStep onRemotehost(String host) {
                        this.host = host;
                        return this;
                }

                public BuildStep credentials(String user, String password) {
                        this.user = user;
                        this.password = password;
                        return this;
                }

                public UserConfiguration build() {
                        UserConfiguration userConfiguration = new UserConfiguration(name);
                        ServerDetails serverDetails = new ServerDetails(host);
                        serverDetails.setUser(user);
                        serverDetails.setPassword(password);                    
                        userConfiguration.setServerDetails(serverDetails);
                        return userConfiguration;
                }

                
        }
}



Lets see now what is the user experience with both of our builders.

The classic builder  will be constructed using the name of the user configuration, then it will expose all of its methods leaving the user a bit too free to choose what's next.



For example, a not careful user could end up with a UserConfiguration set with localhost where no authentication is required, still passing user and password.
This is confusing and it can lead to run-time exceptions.

These are some of the possible combinations of UserConfigurations that the user can end up with, some are correct, lots are wrong:


A complete different story is with the step builder, here only one step at the time is exposed:

If the credentials are not needed they will not be exposed and the build() method is offered only when the state of the object is sure to be coherent and complete:


Only 2 possible UserConfigurations can be built with this pattern, and both make sense and are clear to the user.

 Conclusion

The step builder pattern is not the replacement of the classic Bloch one, sometimes you want to force the user to fill some parameter before advancing with the creation, in this case the step builder is doing the job, otherwise when a more open approach is required than the classic builder is your guy.





Thursday, 30 August 2012

Some development tips and tricks


These are just some tips and tricks I learnt over my career that I'd like to share. This list does not contains silver bullets and it doesn't pretend to be complete or be an absolute truth. It's just a list that I hope may be helpful for someone.

1 )  Push the coding to the last

This point can be also be read as think before coding. I found myself, lots of times, especially in the beginning of my career, in rush of writing classes, methods, interfaces as soon as I was receiving a spec for a new functionality.
This impulse turned out 90% of the times into a PAINFUL situation. The spec was unclear and so unclear was my code; The spec was too "code oriented" and so blindly coding this was producing wrong design/ implementation that needed to be trashed out and completely re-designed;
Many other are the disadvantages of writing code straight away after receiving a spec. So, lesson learnt and this is what I'm doing now after receiving a spec/story to develop:
  1. I stay away from the keyboard!
  2. I print the spec (sorry amazonian jaguars ) and I take my time to read them carefully. Do not think that everything you will read there is exempt of mistakes or cannot be done in better and simpler ways. At the end of the day, people who wrote the specs, know little or nothing about the software, what they know is how to make more money with new functionality.
  3. If something is not clear to you, it will not clarify magically by itself if you start to code. Ask questions to other colleagues, to the business, clarify as much as possible and only when you feel confident, when you see the real pitcure of what they really want, then and only then you can switch the monitor on and click on the eclipse icon...

2 )  Simple = perfect

Make the 2 famous principles, KISS and YAGNI,   part of your blood, skin and bones. Strive for simplicity, forget about the trends,  focus on the most basic thing that will give you what is needed. Don't think straight about XML configuration, spring/seam framework, drools, aspects, multithreading solutions, ejbs, or whatever complex/cool technology you know or you heard out there, nobody really cares about the technologies you use.
What everyone cares is that your code does what is supposed to do, it is READABLE and it is MAINTAINABLE.
Pure java is enough to cover 90% or more of everything you need. Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live. Make him happy, write simple, clear straightforward code.
I remember I read somewhere that, if you read your code after 1 or 2 years and you immediately understand everything is doing and you cannot simplify it more, than your code is PERFECT.

3 )  Paper and pen

I never found a tool more useful than paper and pen to design software.
Before writing software I usually spend a bit of time trying to put the idea of the design down on paper.
I then , if in doubt, go through it with a colleague. Because it is on paper I can fast go to the point with my pair and he can quick tell me if I'm missing something.
Knowing that you are missing something in a piece of paper, it's far way better then knowing that you are missing something in the code!
So don't waste time using UML tools, unless what you are doing is big-fantastic-amazing-new  architectural prototype.

4 )  Don't leave for tomorrow what you can do today

If you are fixing a bug or adding new functionality and you notice in the existing code, DUPLICATION or BAD NAMES  or a POSSIBLE BUG then FIX IT IMMEDIATELY.
Don't wait for the next sprint and don't add a technical story in the technical backlog. Technical stories laid in the backlog for long time, when/if  it will be the time to work on it, it will be more complicated to re-understand the context of the problem and fix it.
The exception it's when the fix/refactoring is too complex and required long time, then it's appropriate to create a story in the technical backlog!

5 )  You have time!

Really, you have time! Don't rush. There is no competition and you are not at the programming Olympics.
Your job is to deliver good quality code. That's it. This is your job!
If you feel that a task takes longer that what you initially estimated, just make the team aware in the next stand up and that's it.
If a client/manager is screaming above your shoulders because he wants something faster than you can deliver, it's not your problem!!! When they say "I want this functionality to be ready asap" translated in Truthlish it means "I want this functionality to be PERFECT with NO BUGS asap". They will be happier to wait more and have less bugs than having a fast release full of issues.
So take your time and be intransigent on the quality level of your software and forget about external pressures!

6 ) Implement leaves first

So, you just received a brand new story to develop and you want to implement it right.
For example the story is about calculating item prices. One price for each item. Each price is obtained with a different calculation.
Choose one item price logic and as first thing write a unit test against this logic. Don't be stressed about implementing the whole design or writing interfaces, abstract classes etc. Focus on one small leaf per time!
When the first leaf is finished, start with a second test for the second small logic you want to implement. The design will come out almost by itself. The tests will tell you which direction is best to take.

7 ) Do Pair programming!

I fully applied this technique only recently (less than 1 year ago) and I have to say, it's powerful! It is twice productive than working alone, the quality of the code is superior, the development speed is increased.
A strength of this technique is the fact that is funny. being funny and so more stimulating means that you are more focused and you pay more attention to details.
You can learn a lot doing pair programming, so push for it as much as you can!

8 ) Rarely use checked Exceptions

Every time I use an API that force me to put around its method call the try and catch block, it makes me nervous, like a violent psychopath, but often I don't know where they leave. Especially if there is nothing I can do about the exception. What the hell I' m supposed to do with this error?
If you want to use checked Exception used them ONLY if the client can reasonably recover from it at run time! Remember that checked exceptions will spread all over your design in case you need to extend the behavior!

9 ) Say NO to Hacks

Programming is like sex. One mistake and you have to support it for the rest of your life. (Michael Sinz). And Hacks ARE mistakes!

Simply don't implement hacks. I did it in the past, for whatever reasons ( no time,pressure, desire to release a feature as soon as possible, managers screaming, Orcs, Leprechauns, whatever), and now after years we need to maintain them. Hacks are difficult to understand,they break the normal logic flow of your code and they are hard to die! You implement an hack today and tomorrow (1 year after maybe ) someone else will need to fix a bug on this hack and ..well good luck with that!
Spend more time on the spec if the hack is a business request, and explain why this will cost a lot to maintain. Propose other solutions, discuss it with your team, a better solution is on the way!

10 ) Forget about comments, just write proper names!

Write proper names when writing packages, classes, methods and variables.
Write names that make sense, ask a review before committing your code, but don't explain verbally what you have done, try first letting your reviewer read the code, and see how good you were in writing self explanatory code!
Comments need to be maintained, otherwise they are misleading. How often did you fix a bug in the code and you changed the class documentation?me, rarely!Use javadoc only if it is really necessary!and if you do,then remember to update them every time you change the code and enforce the same behavior in your team!

11 ) Reinvent the wheels

Read books, blogs, tutorial, etc as much as possible, but always with a critical and open mind! The same apply when listening to your team or leader. Don't be fooled by authorities, think always with your own mind.
If you decide to go for some approach it must be because you believe in it. Because you see good reasons to do so. If you feel that something could be done better or you see problems in the approach you are using , discuss it with your team and try to clarify your doubts. If after talking to the team you still feel that things should be done differently, then push for better approaches and fight for your ideas!
Sometimes, to progress, you need to reinvent the wheels or at this time we were all developing in FORTRAN.