Warning: Table './devblogsdb/cache_page' is marked as crashed and last (automatic?) repair failed query: SELECT data, created, headers, expire, serialized FROM cache_page WHERE cid = 'http://www.softdevblogs.com/?q=aggregator/categories/2&page=1' in /home/content/O/c/n/Ocnarfparking9/html/softdevblogs/includes/database.mysql.inc on line 135

Warning: Cannot modify header information - headers already sent by (output started at /home/content/O/c/n/Ocnarfparking9/html/softdevblogs/includes/database.mysql.inc:135) in /home/content/O/c/n/Ocnarfparking9/html/softdevblogs/includes/bootstrap.inc on line 729

Warning: Cannot modify header information - headers already sent by (output started at /home/content/O/c/n/Ocnarfparking9/html/softdevblogs/includes/database.mysql.inc:135) in /home/content/O/c/n/Ocnarfparking9/html/softdevblogs/includes/bootstrap.inc on line 730

Warning: Cannot modify header information - headers already sent by (output started at /home/content/O/c/n/Ocnarfparking9/html/softdevblogs/includes/database.mysql.inc:135) in /home/content/O/c/n/Ocnarfparking9/html/softdevblogs/includes/bootstrap.inc on line 731

Warning: Cannot modify header information - headers already sent by (output started at /home/content/O/c/n/Ocnarfparking9/html/softdevblogs/includes/database.mysql.inc:135) in /home/content/O/c/n/Ocnarfparking9/html/softdevblogs/includes/bootstrap.inc on line 732
Software Development Blogs: Programming, Software Testing, Agile, Project Management
Skip to content

Software Development Blogs: Programming, Software Testing, Agile Project Management

Methods & Tools

Subscribe to Methods & Tools
if you are not afraid to read more than one page to be a smarter software developer, software tester or project manager!

Testing & QA
warning: Cannot modify header information - headers already sent by (output started at /home/content/O/c/n/Ocnarfparking9/html/softdevblogs/includes/database.mysql.inc:135) in /home/content/O/c/n/Ocnarfparking9/html/softdevblogs/includes/common.inc on line 153.

Effective Programmers Learning

From the Editor of Methods & Tools - Tue, 05/03/2016 - 08:50
Allison Kaptur gave a keynote at Kiwi PyCon 2015 in New Zealand on effective learning for programmers. There were two pieces to the talk: one about the mindset needed by programmers for learning and one about particular strategies that software developers can use. Video Producer: https://nzpug.org/ Slides of the presentation: http://www.slideshare.net/akaptur/effective-learning-strategies-for-programmers Further reading: http://akaptur.com/blog/2015/10/10/effective-learning-strategies-for-programmers/

Software Development Conferences Forecast April 2016

From the Editor of Methods & Tools - Tue, 04/26/2016 - 10:09
Here is a list of software development related conferences and events on Agile project management ( Scrum, Lean, Kanban), software testing and software quality, software architecture, programming (Java, .NET, JavaScript, Ruby, Python, PHP), DevOps and databases (NoSQL, MySQL, etc.) that will take place in the coming weeks and that have media partnerships with the Methods […]

Software Development Linkopedia April 2016

From the Editor of Methods & Tools - Wed, 04/20/2016 - 09:07
Here is our monthly selection of knowledge on programming, software testing and project management. This month you will find some interesting information and opinions about scaling Agile, Test-Driven Development, recruiting developers, managing technical debt, distributed teams, breaking the rules, test automation, Agile metrics and machine learning. Web site: Agile Scaling Knowledgebase Blog: What do you […]

LDAP server setup and client authentication

Agile Testing - Grig Gheorghiu - Fri, 04/15/2016 - 19:24
We recently bought at work a CloudBees Jenkins Enterprise license and I wanted to tie the user accounts to a directory service. I first tried to set up Jenkins authentication via the AWS Directory Service, hoping it will be pretty much like talking to an Active Directory server. That proved to be impossible to set up, at least for me. I also tried to have an LDAP proxy server talking to the AWS Directory Service and have Jenkins authenticate against the LDAP proxy. No dice. I ended up setting up a good old-fashioned LDAP server and managed to get Jenkins working with it. Here are some of my notes.

OpenLDAP server setup
I followed this excellent guide from Digital Ocean. The server was an Ubuntu 14.04 EC2 instance in my case. What follows in terms of the server setup is taken almost verbatim from the DO guide.

Set the hostname

# hostnamectl set-hostname my-ldap-server

Edit /etc/hosts and make sure this entry exists:
LOCAL_IP_ADDRESS my-ldap-server.mycompany.com my-ldap-server
(it makes a difference that the FQDN is the first entry in the line above!)

Make sure the following types of names are returned when you run hostname with different options:


# hostnamemy-ldap-server
# hostname -fmy-ldap-server.mycompany.com
# hostname -dmycompany.com

Install slapd

# apt-get install slapd ldap-utils# dpkg-reconfigure slapd
(here you specify the LDAP admin password)

Install the SSL Components

# apt-get install gnutls-bin ssl-cert

Create the CA Template
# mkdir /etc/ssl/templates
# vi /etc/ssl/templates/ca_server.conf# cat /etc/ssl/templates/ca_server.confcn = LDAP Server CAcacert_signing_key

Create the LDAP Service Template

# vi /etc/ssl/templates/ldap_server.conf# cat /etc/ssl/templates/ldap_server.conforganization = "My Company"cn = my-ldap-server.mycompany.comtls_www_serverencryption_keysigning_keyexpiration_days = 3650

Create the CA Key and Certificate

# certtool -p --outfile /etc/ssl/private/ca_server.key# certtool -s --load-privkey /etc/ssl/private/ca_server.key --template /etc/ssl/templates/ca_server.conf --outfile /etc/ssl/certs/ca_server.pem
Create the LDAP Service Key and Certificate

# certtool -p --sec-param high --outfile /etc/ssl/private/ldap_server.key# certtool -c --load-privkey /etc/ssl/private/ldap_server.key --load-ca-certificate /etc/ssl/certs/ca_server.pem --load-ca-privkey /etc/ssl/private/ca_server.key --template /etc/ssl/templates/ldap_server.conf --outfile /etc/ssl/certs/ldap_server.pem

Give OpenLDAP Access to the LDAP Server Key

# usermod -aG ssl-cert openldap# chown :ssl-cert /etc/ssl/private/ldap_server.key# chmod 640 /etc/ssl/private/ldap_server.key

Configure OpenLDAP to Use the Certificate and Keys
IMPORTANT NOTE: in modern versions of slapd, configuring the server is not done via slapd.conf anymore. Instead, you put together ldif files and run LDAP client utilities such as ldapmodify against the local server. The Distinguished Name of the entity you want to modify in terms of configuration is generally dn: cn=config but it can also be the LDAP database dn: olcDatabase={1}hdb,cn=config.
# vi addcerts.ldif# cat addcerts.ldifdn: cn=configchangetype: modifyadd: olcTLSCACertificateFileolcTLSCACertificateFile: /etc/ssl/certs/ca_server.pem-add: olcTLSCertificateFileolcTLSCertificateFile: /etc/ssl/certs/ldap_server.pem-add: olcTLSCertificateKeyFileolcTLSCertificateKeyFile: /etc/ssl/private/ldap_server.key

# ldapmodify -H ldapi:// -Y EXTERNAL -f addcerts.ldif# service slapd force-reload# cp /etc/ssl/certs/ca_server.pem /etc/ldap/ca_certs.pem# vi /etc/ldap/ldap.conf
* set TLS_CACERT to following:TLS_CACERT /etc/ldap/ca_certs.pem
# ldapwhoami -H ldap:// -x -ZZAnonymous

Force Connections to Use TLS
Change olcSecurity attribute to include 'tls=1':

# vi forcetls.ldif# cat forcetls.ldifdn: olcDatabase={1}hdb,cn=configchangetype: modifyadd: olcSecurityolcSecurity: tls=1

# ldapmodify -H ldapi:// -Y EXTERNAL -f forcetls.ldif# service slapd force-reload# ldapsearch -H ldap:// -x -b "dc=mycompany,dc=com" -LLL dn(shouldn’t work)
# ldapsearch -H ldap:// -x -b "dc=mycompany,dc=com" -LLL -Z dn(should work)

Disallow anonymous bind
Create user binduser to be used for LDAP searches:


# vi binduser.ldif# cat binduser.ldifdn: cn=binduser,dc=mycompany,dc=comobjectClass: topobjectClass: accountobjectClass: posixAccountobjectClass: shadowAccountcn: binduseruid: binduseruidNumber: 2000gidNumber: 200homeDirectory: /home/binduserloginShell: /bin/bashgecos: suseruserPassword: {crypt}xshadowLastChange: -1shadowMax: -1shadowWarning: -1

# ldapadd -x -W -D "cn=admin,dc=mycompany,dc=com" -Z -f binduser.ldifEnter LDAP Password:adding new entry "cn=binduser,dc=mycompany,dc=com"
Change olcDissalows attribute to include bind_anon:


# vi disallow_anon_bind.ldif# cat disallow_anon_bind.ldifdn: cn=configchangetype: modifyadd: olcDisallowsolcDisallows: bind_anon

# ldapmodify -H ldapi:// -Y EXTERNAL -ZZ -f disallow_anon_bind.ldif# service slapd force-reload
Also disable anonymous access to frontend:

# vi disable_anon_frontend.ldif# cat disable_anon_frontend.ldifdn: olcDatabase={-1}frontend,cn=configchangetype: modifyadd: olcRequiresolcRequires: authc

# ldapmodify -H ldapi:// -Y EXTERNAL -f disable_anon_frontend.ldif# service slapd force-reload

Create organizational units and users
Create helper scripts:

# cat add_ldap_ldif.sh
#!/bin/bash

LDIF=$1

ldapadd -x -w adminpassword -D "cn=admin,dc=mycompany,dc=com" -Z -f $LDIF

# cat modify_ldap_ldif.sh#!/bin/bash

LDIF=$1

ldapmodify -x -w adminpassword -D "cn=admin,dc=mycompany,dc=com" -Z -f $LDIF

# cat set_ldap_pass.sh#!/bin/bash

USER=$1PASS=$2

ldappasswd -s $PASS -w adminpassword -D "cn=admin,dc=mycompany,dc=com" -x "uid=$USER,ou=users,dc=mycompany,dc=com" -Z
Create ‚Äėmypeople‚Äô organizational unit:


# cat add_ou_mypeople.ldifdn: ou=mypeople,dc=mycompany,dc=comobjectclass: organizationalunitou: usersdescription: all users
# ./add_ldap_ldif.sh add_ou_mypeople.ldif
Create 'groups' organizational unit:


# cat add_ou_groups.ldifdn: ou=groups,dc=mycompany,dc=comobjectclass: organizationalunitou: groupsdescription: all groups

# ./add_ldap_ldif.sh add_ou_groups.ldif
Create users (note the shadow attributes set to -1, which means they will be ignored):


# cat add_user_myuser.ldifdn: uid=myuser,ou=mypeople,dc=mycompany,dc=comobjectClass: topobjectClass: accountobjectClass: posixAccountobjectClass: shadowAccountcn: myuseruid: myuseruidNumber: 2001gidNumber: 201homeDirectory: /home/myuserloginShell: /bin/bashgecos: myuseruserPassword: {crypt}xshadowLastChange: -1shadowMax: -1shadowWarning: -1
# ./add_ldap_ldif.sh add_user_myuser.ldif# ./set_ldap_pass.sh myuser MYPASS

Enable LDAPS
In /etc/default/slapd set:

SLAPD_SERVICES="ldap:/// ldaps:/// ldapi:///"

Enable debugging
This was a life saver when it came to troubleshooting connection issues from clients such as Jenkins or other Linux boxes. To enable full debug output, set olcLogLevel to -1:

# cat enable_debugging.ldifdn: cn=configchangetype: modifyadd: olcLogLevelolcLogLevel: -1
# ldapadd -H ldapi:// -Y EXTERNAL -f enable_debugging.ldif
# service slapd force-reload

Configuring Jenkins LDAP authentication
Verify LDAPS connectivity from Jenkins to LDAP server
In my case, the Jenkins server is in the same VPC and subnet as the LDAP server, so I added an /etc/hosts entry on the Jenkins box pointing to the FQDN of the LDAP server so it can hit its internal IP address:

IP_ADDRESS_OF_LDAP_SERVER my-ldap-server.mycompany.com
I verified that port 636 (used by LDAPS) on the LDAP server is reachable from the Jenkins server:
# telnet my-ldap-server.mycompany.com 636Trying IP_ADDRESS_OF_LDAP_SERVER...Connected to my-ldap-server.mycompany.com.Escape character is '^]'.
Set up LDAPS client on Jenkins server (StartTLSdoes not work w/ Jenkins LDAP plugin!)
# apt-get install ldap-utils
IMPORTANT: Copy over /etc/ssl/certs/ca_server.pem from LDAP server as /etc/ldap/ca_certs.pem on Jenkins server and then:
# vi /etc/ldap/ldap.confset:TLS_CACERT /etc/ldap/ca_certs.pem
Add LDAP certificates to Java keystore used by Jenkins
As user jenkins:
$ mkdir .keystore$ cp /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/security/cacerts .keystore/(you may need to customize the above line in terms of the path to the cacerts file -- it is the one under your JAVA_HOME)

$ keytool --keystore /var/lib/jenkins/.keystore/cacerts --import --alias my-ldap-server.mycompany.com:636 --file /etc/ldap/ca_certs.pemEnter keystore password: changeitOwner: CN=LDAP Server CAIssuer: CN=LDAP Server CASerial number: 570bddb0Valid from: Mon Apr 11 17:24:00 UTC 2016 until: Tue Apr 11 17:24:00 UTC 2017Certificate fingerprints:....Extensions:....
Trust this certificate? [no]:  yesCertificate was added to keystore
In /etc/default/jenkins, set JAVA_ARGS to:
JAVA_ARGS="-Djava.awt.headless=true -Djavax.net.ssl.trustStore=/var/lib/jenkins/.keystore/cacerts -Djavax.net.ssl.trustStorePassword=changeit"  
As root, restart jenkins:

# service jenkins restart
Jenkins settings for LDAP plugin
This took me a while to get right. The trick was to set the rootDN to dc=mycompany, dc=com and the userSearchBase to ou=mypeople (or to whatever name you gave to your users' organizational unit). I also tried to get LDAP groups to work but wasn't very successful.
Here is the LDAP section in /var/lib/jenkins/config.xml:
 <securityRealm class="hudson.security.LDAPSecurityRealm" plugin="ldap@1.11">    <server>ldaps://my-ldap-server.mycompany.com:636</server>    <rootDN>dc=mycompany,dc=com</rootDN>    <inhibitInferRootDN>true</inhibitInferRootDN>    <userSearchBase>ou=mypeople</userSearchBase>    <userSearch>uid={0}</userSearch> <groupSearchBase>ou=groups</groupSearchBase> <groupMembershipStrategy class="jenkins.security.plugins.ldap.FromGroupSearchLDAPGroupMembershipStrategy"> <filter>member={0}</filter> </groupMembershipStrategy>    <managerDN>cn=binduser,dc=mycompany,dc=com</managerDN>    <managerPasswordSecret>JGeIGFZwjipl6hJNefTzCwClRcLqYWEUNmnXlC3AOXI=</managerPasswordSecret>    <disableMailAddressResolver>false</disableMailAddressResolver>    <displayNameAttributeName>displayname</displayNameAttributeName>    <mailAddressAttributeName>mail</mailAddressAttributeName>    <userIdStrategy class="jenkins.model.IdStrategy$CaseInsensitive"/>    <groupIdStrategy class="jenkins.model.IdStrategy$CaseInsensitive"/>
 </securityRealm>

At this point, I was able to create users on the LDAP server and have them log in to Jenkins. With CloudBees Jenkins Enterprise, I was also able to use the Role-Based Access Control and Folder plugins in order to create project-specific folders and folder-specific groups specifying various roles. For example, a folder MyProjectNumber1 would have a Developers group defined inside it, as well as an Administrators group and a Readers group. These groups would be associated with fine-grained roles that only allow certain Jenkins operations for each group.
I tried to have these groups read by Jenkins from the LDAP server, but was unsuccessful. Instead, I had to populate the folder-specific groups in Jenkins with user names that were at least still defined in LDAP.  So that was half a win. Still waiting to see if I can define the groups in LDAP, but for now this is a workaround that works for me.
Allowing users to change their LDAP password
This was again a seemingly easy task but turned out to be pretty complicated. I set up another small EC2 instance to act as a jumpbox for users who want to change their LDAP password.
The jumpbox is in the same VPC and subnet as the LDAP server, so I added an /etc/hosts entry on the jumpbox pointing to the FQDN of the LDAP server so it can hit its internal IP address:

IP_ADDRESS_OF_LDAP_SERVER my-ldap-server.mycompany.com
I verified that port 636 (used by LDAPS) on the LDAP server is reachable from the jumpbox:
# telnet my-ldap-server.mycompany.com 636Trying IP_ADDRESS_OF_LDAP_SERVER...Connected to my-ldap-server.mycompany.com.Escape character is '^]'.
# apt-get install ldap-utils
IMPORTANT: Copy over /etc/ssl/certs/ca_server.pem from LDAP server as /etc/ldap/ca_certs.pem on the jumpbox and then:
# vi /etc/ldap/ldap.confset:TLS_CACERT /etc/ldap/ca_certs.pem
Next, I followed this LDAP Client Authentication guide from the Ubuntu documentation.
# apt-get install ldap-auth-client nscd
Here I had to answer the setup questions on LDAP server FQDN, admin DN and password, and bind user DN and password. 
# auth-client-config -t nss -p lac_ldap
I edited /etc/auth-client-config/profile.d/ldap-auth-config and set:
[lac_ldap]nss_passwd=passwd: ldap filesnss_group=group: ldap filesnss_shadow=shadow: ldap filesnss_netgroup=netgroup: nis
I edited /etc/ldap.conf and made sure the following entries were there:
base dc=mycompany,dc=comuri ldaps://my-ldap-server.mycompany.combinddn cn=binduser,mycompany,dc=combindpw BINDUSERPASSrootbinddn cn=admin,mycompany,dc=comport 636ssl ontls_cacertfile /etc/ldap/ca_certs.pemtls_cacertdir /etc/ssl/certs
I allowed password-based ssh logins to the jumpbox by editing /etc/ssh/sshd_config and setting:
PasswordAuthentication yes
# service ssh restart

IMPORTANT: On the LDAP server, I had to allow users to change their own password by adding this ACL:
# cat set_userpassword_acl.ldif
dn: olcDatabase={1}hdb,cn=configchangetype: modifyadd: olcAccessolcAccess: {0}to attrs=userpassword by dn="cn=admin,dc=mycompany,dc=com" write by self write by anonymous auth by users none
Then:
# ldapmodify -H ldapi:// -Y EXTERNAL -f set_userpassword_acl.ldif

At this point, users were able to log in via ssh to the jumpbox using a pre-set LDAP password, and change their LDAP password by using the regular Unix 'passwd' command.
I am still fine-tuning the LDAP setup on all fronts: LDAP server, LDAP client jumpbox and Jenkis server. The setup I have so far allows me to have a single sign-on account for users to log in to Jenkins. Some of my next steps is to use the same user LDAP accounts  for authentication and access control into MySQL and other services.

Quote of the Month April 2016

From the Editor of Methods & Tools - Tue, 04/12/2016 - 08:44
Having conversations is more important than capturing conversations is more important than automating conversations. Liz Keogh, “Behavior Driven Development”, http://www.slideshare.net/lunivore/behavior-driven-development-11754474, slide 14 mentioned in “More Agile Testing: Learning Journeys for the Whole Team”, Janet Gregory & Lisa Crispin

Joining an EC2 Windows instance to an AWS Directory Service domain

Agile Testing - Grig Gheorghiu - Wed, 04/06/2016 - 21:53
I've been struggling with the existing documentation on how to join an EC2 instance running Windows Server 2012 to an AWS Directory Service domain, so I am hastening to jot down some notes on how I got it to work.

1) Create an AWS Directory Service domain

There is good documentation on doing this. I chose the Microsoft Active Directory option.

A few notes on the creation of an AWS Directory Service:

  • I created a new VPC with 2 subnets for the Directory Service usage
  • I made sure each subnet has an Internet gateway associated so that it can be reachable from the outside
During the creation of the Directory Service, you'll be asked to specify an administrator-type user name and password. Make sure you remember what you specified there because you'll need this info in a subsequent step. Also make note of the DNS server IP addresses that were set during the Directory Service creation.
2) Create an IAM role to be associated with the EC2 Windows instance
  • the IAM role needs to be associated with the AmazonEC2RoleforSSM and AmazonSSMFullAccess policies
  • the IAM role also needs to have a trust relationship with ec2.amazonaws.com

3) Launch EC2 Windows instance associated with the AWS Directory Service domain
I chose the Windows_Server-2012-R2_RTM-English-64Bit-Base-2016.03.09 AMI.  In Step 3 of the AWS launch instance wizard ("Configure instance details") I made sure I specified the following:
  • Network: the VPC created in step 1) above
  • Subnet: one of the 2 subnets created in step 1) above
  • Domain join directory: the directory name for the Directory Service created in step 1) above
  • IAM role: the IAM role created in step 2) above
4) Connect to EC2 Windows instance via RDP
First get the administrator password via the AWS console (you'll need to paste the contents of the private key corresponding to the EC2 key you used when launching the Windows instance). Then connect to the Windows instance as the local administrator user.
Verify that you see the fully qualified domain name of your Directory Service (whatever you indicated in step 1) as the domain of the Windows instance (in Server Manager -> Local Server). If you don't, something went wrong with joining the domain during the instance launch. You can see the system log of that instance in the AWS console by selecting the instance, then going to Actions->Instance Settings->Get System Log. For example, in one of my failed attempts to get all of this working I saw errors related to the IAM role I was using, which at the time didn't have the correct SSM policies attached.
If the Windows instance is correctly joined to the domain, you need to install the Active Directory management tools in order to actually manage the AWS Directory Service. Here is a Rackspace article I found with good instructions.

5) Log in to the EC2 Windows instance as the domain admin to manage AD
After the EC2 Windows instance was rebooted, I managed to log in via RDP as my.aws.directory.fqdn\myusername (where both of these values are the ones chosen in Step 1 above) with the password also chosen in Step 1. At this point I was able to use the Active Directory management tools to add new AD users etc.
Here are some other good resources I found:


Design Principles for Software Developers

From the Editor of Methods & Tools - Mon, 04/04/2016 - 16:01
Writing code is easy. Writing good quality code is an entirely different story. How can we measure quality of design? How do we know we’re doing the right set of things that will leads us to a better design? This video presents some core software design principles that help programmers everyday. Instead of talking about […]

Software Development Conferences Forecast March 2016

From the Editor of Methods & Tools - Tue, 03/29/2016 - 14:41
Here is a list of software development related conferences and events on Agile project management ( Scrum, Lean, Kanban), software testing and software quality, software architecture, programming (Java, .NET, JavaScript, Ruby, Python, PHP), DevOps and databases (NoSQL, MySQL, etc.) that will take place in the coming weeks and that have media partnerships with the Methods […]

From QA to Engineering Productivity

Google Testing Blog - Tue, 03/29/2016 - 01:38
By Ari Shamash

In Google’s early days, a small handful of software engineers built, tested, and released software. But as the user-base grew and products proliferated, engineers started specializing in roles, creating more scale in the development process:

  • Test Engineers (TEs) --  tested new products and systems integration
  • Release Engineers (REs) --  pushed bits into production
  • Site Reliability Engineers (SREs) --  managed systems and data centers 24x7.

This story focuses on the evolution of quality assurance and the roles of the engineers behind it at Google.  The REs and SREs also evolved, but we‚Äôll leave that for another day.

Initially, teams relied heavily on manual operations.  When we attempted to automate testing, we largely focused on the frontends, which worked, because Google was small and our products had fewer integrations.  However, as Google grew, longer and longer manual test cycles bogged down iterations and delayed feature launches.  Also, since we identified bugs later in the development cycle, it took us longer and longer to fix them.  We determined that pushing testing upstream via automation would help address these issues and accelerate velocity.

As manual testing transitioned to automated processes, two separate testing roles began to emerge at Google:

  • Test Engineers (TEs) -- With their deep product knowledge and test/quality domain expertise, TEs focused on what should be tested.
  • Software Engineers in Test (SETs) -- Originally software engineers with deep infrastructure and tooling expertise, SETs built the frameworks and packages required to implement automation.

The impact was significant:

  • Automated tests became more efficient and deterministic (e.g. by improving runtimes, eliminating sources of flakiness, etc.) 
  • Metrics driven engineering proliferated (e.g. improving code and feature coverage led to higher quality products).

Manual operations were reduced to manual verification on new features, and typically only in end-to-end, cross product integration boundaries.  TEs developed extreme depth of knowledge for the products they supported.  They became go-to engineers for product teams that needed expertise in test automation and integration. Their role evolved into a broad spectrum of responsibilities: writing scripts to automate testing, creating tools so developers could test their own code, and constantly designing better and more creative ways to identify weak spots and break software.

SETs (in collaboration with TEs and other engineers) built a wide array of test automation tools and developed best practices that were applicable across many products. Release velocity accelerated for products.  All was good, and there was much rejoicing!

SETs initially focused on building tools for reducing the testing cycle time, since that was the most manually intensive and time consuming phase of getting product code into production.  We made some of these tools available to the software development community: webdriver improvements, protractor, espresso, EarlGrey, martian proxy, karma, and GoogleTest. SETs were interested in sharing and collaborating with others in the industry and established conferences. The industry has also embraced the Test Engineering discipline, as other companies hired software engineers into similar roles, published articles, and drove Test-Driven Development into mainstream practices.

Through these efforts, the testing cycle time decreased dramatically, but interestingly the overall velocity did not increase proportionately, since other phases in the development cycle became the bottleneck.  SETs started building tools to accelerate all other aspects of product development, including:

  • Extending IDEs to make writing and reviewing code easier, shortening the ‚Äúwrite code‚ÄĚ cycle
  • Automating release verification, shortening the ‚Äúrelease code‚ÄĚ cycle.
  • Automating real time production system log verification and anomaly detection, helping automate production monitoring.
  • Automating measurement of developer productivity, helping understand what‚Äôs working and what isn‚Äôt.

In summary, the work done by the SETs naturally progressed from supporting only product testing efforts to include supporting product development efforts as well. Their role now encompassed a much broader Engineering Productivity agenda.

Given the expanded SET charter, we wanted the title of the role to reflect the work. But what should the new title be?  We empowered the SETs to choose a new title, and they overwhelmingly (91%) selected Software Engineer, Tools & Infrastructure (abbreviated to SETI).

Today, SETIs and TEs still collaborate very closely on optimizing the entire development life cycle with a goal of eliminating all friction from getting features into production. Interested in building next generation tools and infrastructure?  Join us (SETI, TE)!

Categories: Testing & QA

Message Obsession

Mistaeks I Hav Made - Nat Pryce - Wed, 03/23/2016 - 23:19
I‚Äôve noticed a ‚Äúcode smell‚ÄĚ in object-oriented code that I call ‚ÄúMessage Obsession‚ÄĚ. I find Message Obsession causes similar difficulties to Primitive Obsession. However, Message Obsession appears to be the complete opposite of Primitive Obsession. Refactoring to address the difficulties caused by either Primitive Obsession or Message Obsession leads to the same design. To demonstrate the Message Obsession, and to compare it to Primitive Obsession, imagine a game in which a robot moves around a grid of tiles. Primitive Obsession The code below, which moves the robot east and then north, suffers from Primitive Obsession. Domain concepts ‚Äď direction of movement, in this case ‚Äď are held as multiple primitive data types instead of being modelled explicitly. robot.move(0,1) robot.move(-1,0) It‚Äôs awkward to work with this interface because you have to pass the deltaX and deltaY coordinates around as a pair of values instead of as a single Direction value. This can lead to code duplication. Any code that has to store moves will have to define a structure to do so. Code that has to perform calculations on directions ‚Äď to add, invert or rotate directions, for example ‚Äď will do so via helper functions or inline calculations. This logic ends up duplicated all over the code because programmers working in one area do not know that programmers working in other areas are writing the the same calculations. Primitive Obsession can also lead to errors. Are the coordinates passed to the move function as x and y or row and column? The type system won‚Äôt catch the error because both coordinates are integers. Named parameters help, of course, but not all languages support them. Message Obsession Programmers know about the drawbacks of Primitive Obsession, but sometimes create designs that go too far the other way, to the smell I call ‚ÄúMessage Obsession‚ÄĚ. A design that suffers from Message Obsession does not pass around primitive values ‚Äď it does not pass around values at all. Instead, objects implement several similar methods, each of which manipulates the same fields used to store primitive values inside the object. Message Obsession leads to code like: robot.moveEast() robot.moveNorth() It‚Äôs awkward to work with this kind of interface because you can‚Äôt pass around, store or perform calculations on the direction at all. Symptoms Symptoms caused by this smell include‚Ķ ‚Ķclass hierarchies that mirror the direction methods. For example, a hierarchy of Command classes with a concrete class for each direction the robot can move: interface MoveCommand { fun apply(r: robot) } object MoveNorth : MoveCommand { fun applyTo(r: robot) = r.moveNorth() } object MoveSouth : MoveCommand { fun applyTo(r: robot) = r.moveSouth() } ... etc. ... ‚Ķdispatching with conditional statements: when (keyCode) { UP_ARROW -> robot.moveNorth() DOWN_ARROW -> robot.moveSouth() ... etc. ... } ‚Ķusing anonymous functions to treat directions as first-class values. val movesByKeyCode : MapUnit> = mapOf( UP_ARROW to {robot -> robot.moveNorth()}, DOWN_ARROW to {robot -> robot.moveSouth()}, ... etc. ... ) Cure The duplication in the method names shows that, as with primitive obsession, there‚Äôs a value type to be factored out. Let‚Äôs call it ‚ÄúDirection‚ÄĚ. The names of the methods show that we‚Äôll need some constant Direction values and what those constants should be called. We really want code that moves the robot to look like: robot.move(east) robot.move(north) We could define the Direction type as: data class Direction(val deltaX: Int, val deltaY: Int) And direction constants as: val north = Direction( 0, -1) val east = Direction( 1, 0) val south = Direction( 0, 1) val west = Direction(-1, 0) Now directions are first class values, they can be stored in collections, mapped to and from user input events, rotated, inverted, etc. For example: val movementKeyBindings: Map The value type acts as an ‚Äúattractor‚ÄĚ for behaviour. We can add operations to it to rotate or invert directions, for example. fun Direction.inverse() = Direction(-deltaX, -deltaY) fun Direction.rotatedClockwise() = Direction(deltaY, -deltaX) fun Direction.rotatedAnticlockwise() = Direction(-deltaY, deltaX) ... etc. ... Those rotatedClockwise and rotatedAnticlockwise methods also exhibit Message Obsession! Maybe we will need to introduce a RightAngleTurn type as the system evolves‚Ķ Implicit Duplication Sometimes the Message Obsession smell is not obvious from the names. The duplication in naming is missing or implicit. For example, in the term ‚Äúmove‚ÄĚ is not used in following code, but is implied by the behaviour of the east and north methods. robot.east() robot.north() The missing concept of ‚Äúmove‚ÄĚ has to be named before the duplication stands out. Refactoring too Far, and Back Again I‚Äôm struck by how Message Obsession acts as an opposite of primitive obsession. I have often seen Message Obsession appearing as a reaction to Primitive Obsession, pushing the design too far in the opposite direction. The design eventually settles on a compositional style as the need for first-class values arises and the drawbacks of Message Obsession become clear.
Categories: Programming, Testing & QA

Load Testing, Communication and #NoProjects in Methods & Tools Spring 2016 issue

From the Editor of Methods & Tools - Mon, 03/21/2016 - 12:01
Methods & Tools has published its Spring 2016 issue that discusses the load testing scripts, communications in project teams, the Kano model for requirements and #NoProjects. Methods & Tools is a free e-magazine for software developers, testers and project managers. * Eradicating Load Test Errors – Part 1: Correlation Errors * Breaking Bad – The […]

Writing Easy to Maintain Code

From the Editor of Methods & Tools - Wed, 03/16/2016 - 20:43
Wikimedia software developer and Software Craftmanship advocate Jeroen De Dauw discusses about how to maintain code. A significant amount of time is spend on reading code, sometimes more than on writing code. Jeroen asks questions like how does elegant code tend to rot over time, and what can we do to make this clearer? In […]

Software Development Linkopedia March 2016

From the Editor of Methods & Tools - Wed, 03/09/2016 - 10:03
Here is our monthly selection of knowledge on programming, software testing and project management. This month you will find some interesting information and opinions about retrospectives, keeping a zen programming attitude, learning organization, project teams a Google, product backlog refinement, mobile testing, scaling agile, pair testing, software development automation and programming with Java. Web site: […]

How many builds?

Actively Lazy - Tue, 03/08/2016 - 21:38

I’m always amazed at the seemingly high pain threshold .net developers have when it comes to tooling. I’ve written before about the poor state of tooling in .net, but just recently I hit another example of poor tooling that infuriates me: I have too many builds, and they don’t agree whether my code compiles.

One of the first things that struck me when starting to develop on .net was that¬†compiling code was still a thing. An actual step that had to be thought about. Incremental compilers in Eclipse and the like have been around for ages – to the point where, generally, Java developers don’t actually have to instruct their IDE to compile code for them. But in Visual Studio? Oh it’s definitely necessary. And time consuming. Oh my god is it slow. Ok, maybe not as slow as Scala. But still unbelievably slow when you’re used to working at the speed of thought.

Another consequence of the closed, Microsoft way of doing things is that tools can’t share the compiler’s work. So ReSharper have implemented their own compiler, effectively. It incrementally parses source code and finds compiler errors. Sometimes it even agrees with the Visual Studio build. But all too often it doesn’t. From the spurious not-actually-an-error that I have to continually instruct ReSharper to ignore; to the warnings-as-errors build failures that ReSharper doesn’t warn me about; to the random why-does-ReSharper-not-know-about-that-NuGet-package-errors.

This can be infuriating when refactoring. E.g. if an automated refactor leaves a variable unused, I will now have a compiler warning; since all my projects run with warnings-as-errors switched on, this will fail the build. But ReSharper doesn’t know that. So I apply the refactoring, code & tests are green: commit. Push. Boom! CI is red.¬†But it was an automated refactor for chrissakes, how’ve I broken the build?!

I also use NCrunch, an automated test runner for Visual Studio (like Infinitest in the Java world). NCrunch is awesome, by the way; better even than the continuous test runner in ReSharper 10. If you’ve never used a continuous test runner and think you’re doing TDD, sort your life out and setup Infinitest or NCrunch. It doesn’t just automate pressing the shortcut key to run all your tests. Well, actually that is exactly what it does – but the impact it has on your workflow is so much more than that. When you can type a few characters, look at the test output and see what happened you get¬†instant feedback. This difference in degree changes the way you write code and makes it so much easier to do TDD.

Anyway I digress – NCrunch, because Microsoft, can’t use the result of the compile that Visual Studio does.¬†So it does its own. It launches MSBuild in the background, continually re-compiling your code. This is not exactly kind on your CPU. It also introduces inconsistencies. Because NCrunch is running a slightly different MSBuild on each project¬†to the build¬†VisualStudio does you get subtly different results sometimes; which is different again from¬†ReSharper with¬†its own compiler that isn’t even using MSBuild. I now have¬†three builds. Three compilers. It is honestly a miracle when they all agree that my code compiles.

An all-too-typical dev cycle becomes:

  • Write test
  • ReSharper is happy
  • NCrunch build is failing, force reload NCrunch project
  • NCrunch builds, test fails
  • Make test pass
  • Try to run app
  • VisualStudio build fails
  • Fix NuGet problems
  • NCrunch build is now failing
  • Force NCrunch to reload at least one project again
  • Force VisualStudio to rebuild the project
  • Then the solution
  • Run app to sanity check change
  • ReSharper now shows error
  • Re-ignore perennial ReSharper non-error
  • All three compilers agree, quick: commit!

Normally then the build fails in CI because I still screwed up the NuGet packages.

Then recently, as if this wasn’t already one of the outer circles of hell. The CI build was failing for a bizarre reason. We have a command line script which applies the same build steps that CI runs, so I thought I’d run that to replicate the problem. Unfortunately the command line build was failing on my machine for a spectacularly spurious reason that was different again than the failure in CI. Great. I now have¬†five builds which don’t all agree on whether my code compiles.

Do you really hate computers? Do you wish you had more reasons to defenestrate every last one of them? Have you considered a career in software development?


Categories: Programming, Testing & QA

Quote of the Month March 2016

From the Editor of Methods & Tools - Mon, 03/07/2016 - 14:46
Large organizations present serious challenges, but for the manager of such an organization they typically revolve around managing managers, not just programmers. Source: Managing the Unmanageable, Mickey W. Mantle & Ron Lichty, Addison-Wesley

Longevity of Source Code

Actively Lazy - Wed, 02/24/2016 - 22:10

Take a look at the code you work in day-to-day. How long has it been there? How old is it? Six months old? A year? Maybe five years old? Ten? Twenty?! How much of the code is old? Less than 10%? Half? Or as much as 90%? Curious to know the answers to these questions I’ve been investigating how long code sticks around.

Software archeology

Work for any company that’s been around for more than a couple of years and there will be source code that’s been there¬†for a while. Writing software¬†in an environment like this is often an exercise in software archeology – digging down into the application is like digging down into an old city, slowly uncovering the past layer by layer.

Once you get past the shiny new containerized micro-services, you start delving into the recent past: perhaps the remnants of the company’s first foray into a Service Oriented Architecture; now a collection of monolithic services¬†with a complex tangle of business logic, all tied together with so much¬†Spring. Dig deeper still and we get back to the EJB era; some long-forgotten beans still clinging on to life, for lack of any developer’s appetite to understand them again.¬†Down here is where the skeletons are.

If it ain’t broke, don’t fix it

What’s so bad about old code? It’s fulfilling some important purpose, no doubt. At least, some of it probably is.

If you look at code you wrote a year ago and can’t see anything to change, you haven’t learnt a thing¬†in the last year

We’re always learning more: a better understanding of the domain, a better understanding of how our solution models the domain, new architectural styles, new tools, new approaches, new standards and new ideas.¬†It is inevitable the code you wrote a year ago could be improved¬†somehow. But how much of it have you gone back and improved recently?

The trouble with old code is that it gets increasingly hard to change. What would happen if a change in business requirements led you all the way down to the Roman-era sewers that are the EJBs? Would you implement the change the way it would have been done a decade ago? Or would you spend time trying to extract the parts that need to change? Perhaps building another shiny, new containerized micro-service along the way? That change isn’t going to be cheap though.

And this is the problem: paying back this “technical debt” is the right thing to do, but it will be slower to change this ancient code than the stuff you wrote last week or last month. The more ancient code you have the slower it will be to make changes, the slower you can develop new features. The worst part of maintaining a long running code base isn’t just paying back the debt from the things we know we did wrong; it’s the debt from things that were done¬†right (at the time), but¬†only now seem wrong.

How old is our code?

I’ve been looking through a variety of source code: some commercial, some open source. Across a variety of languages (Java, C#, Ruby). Generally it seems that most code bases follow a pretty similar pattern:

About 70% of the lines of code you wrote today will still be in head, unchanged, in 12 months time

Perhaps unsurprisingly, code changes most often in the first couple of months after being written. After that, it seems to enter a maintenance mode, where code changes relatively rarely.

image

I found this pretty surprising: after a year around 75% of the code I’ve written is still there. Imagine how much better I understand the problem today. Imagine the since-forgotten design ideas, the changed architectural vision, the new tools and libraries it could be refactored to use¬†today. Imagine how much better every single one of those lines could be. And yet, even in a code base where we’re constantly working to pay back technical debt, we’re barely¬†making a dent in how old the code is.

The how

How did I do this analysis? Thanks to the magic power of git, it is surprisingly easy. I can use git to do a recursive git blame on the entire repo. This lists, for each line currently in head, the commit that introduced it, who made it and when. With a bit of shell-fu we can extract a count by day or month:

git ls-tree -r -rz --name-only HEAD -- | xargs -0 -n1 git blame -f HEAD | sed -e 's/^.* \([0-9]\{4\}-[0-9]\{2\}\)-[0-9]\{2\} .*$/\1/g' | sort | uniq -c

This outputs a nice table of lines of code last touched by month, as of today. But, I can just as easily go back in history, e.g. to go back to the start of 2015:

git checkout `git rev-list -n 1 --before="2015-01-01 00:00:00" master`

I can then re-run the recursive git blame. By comparing the count of lines last checked in each month I can see how much of the code written before 2015 still exists today. With more detailed analysis I can see how the number of lines last touched in a given month changes over time to see how quickly (or not!) code decays.

Conclusion

Code is written to serve some purpose, to deliver some business value. But it quickly becomes a liability. As this code ages and rots it becomes harder and harder to change. From the analysis above it is clear to understand why a code base that has been around for a decade is mostly all archaic: with so little of the old code being changed each year it just continues to hang around, all the while we’re piling up new legacy on top – most of which will still be here next year.

What are we to do about it? It seems to be a natural law of software that over time it only accumulates. From my own experience it seems that even concerted efforts on refactoring make little impact. What are we to do? Do we just accept that changes become progressively harder as source code ages? Or do we need to find a way to encourage software to have a shorter half-life, to be re-written sooner.


Categories: Programming, Testing & QA

Longevity of Source Code

Actively Lazy - Wed, 02/24/2016 - 22:10

Take a look at the code you work in day-to-day. How long has it been there? How old is it? Six months old? A year? Maybe five years old? Ten? Twenty?! How much of the code is old? Less than 10%? Half? Or as much as 90%? Curious to know the answers to these questions I’ve been investigating how long code sticks around.

Software archeology

Work for any company that’s been around for more than a couple of years and there will be source code that’s been there¬†for a while. Writing software¬†in an environment like this is often an exercise in software archeology – digging down into the application is like digging down into an old city, slowly uncovering the past layer by layer.

Once you get past the shiny new containerized micro-services, you start delving into the recent past: perhaps the remnants of the company’s first foray into a Service Oriented Architecture; now a collection of monolithic services¬†with a complex tangle of business logic, all tied together with so much¬†Spring. Dig deeper still and we get back to the EJB era; some long-forgotten beans still clinging on to life, for lack of any developer’s appetite to understand them again.¬†Down here is where the skeletons are.

If it ain’t broke, don’t fix it

What’s so bad about old code? It’s fulfilling some important purpose, no doubt. At least, some of it probably is.

If you look at code you wrote a year ago and can’t see anything to change, you haven’t learnt a thing¬†in the last year

We’re always learning more: a better understanding of the domain, a better understanding of how our solution models the domain, new architectural styles, new tools, new approaches, new standards and new ideas.¬†It is inevitable the code you wrote a year ago could be improved¬†somehow. But how much of it have you gone back and improved recently?

The trouble with old code is that it gets increasingly hard to change. What would happen if a change in business requirements led you all the way down to the Roman-era sewers that are the EJBs? Would you implement the change the way it would have been done a decade ago? Or would you spend time trying to extract the parts that need to change? Perhaps building another shiny, new containerized micro-service along the way? That change isn’t going to be cheap though.

And this is the problem: paying back this “technical debt” is the right thing to do, but it will be slower to change this ancient code than the stuff you wrote last week or last month. The more ancient code you have the slower it will be to make changes, the slower you can develop new features. The worst part of maintaining a long running code base isn’t just paying back the debt from the things we know we did wrong; it’s the debt from things that were done¬†right (at the time), but¬†only now seem wrong.

How old is our code?

I’ve been looking through a variety of source code: some commercial, some open source. Across a variety of languages (Java, C#, Ruby). Generally it seems that most code bases follow a pretty similar pattern:

About 70% of the lines of code you wrote today will still be in head, unchanged, in 12 months time

Perhaps unsurprisingly, code changes most often in the first couple of months after being written. After that, it seems to enter a maintenance mode, where code changes relatively rarely.

image

I found this pretty surprising: after a year around 75% of the code I’ve written is still there. Imagine how much better I understand the problem today. Imagine the since-forgotten design ideas, the changed architectural vision, the new tools and libraries it could be refactored to use¬†today. Imagine how much better every single one of those lines could be. And yet, even in a code base where we’re constantly working to pay back technical debt, we’re barely¬†making a dent in how old the code is.

The how

How did I do this analysis? Thanks to the magic power of git, it is surprisingly easy. I can use git to do a recursive git blame on the entire repo. This lists, for each line currently in head, the commit that introduced it, who made it and when. With a bit of shell-fu we can extract a count by day or month:

git ls-tree -r -rz --name-only HEAD -- | xargs -0 -n1 git blame -f HEAD | sed -e 's/^.* \([0-9]\{4\}-[0-9]\{2\}\)-[0-9]\{2\} .*$/\1/g' | sort | uniq -c

This outputs a nice table of lines of code last touched by month, as of today. But, I can just as easily go back in history, e.g. to go back to the start of 2015:

git checkout `git rev-list -n 1 --before="2015-01-01 00:00:00" master`

I can then re-run the recursive git blame. By comparing the count of lines last checked in each month I can see how much of the code written before 2015 still exists today. With more detailed analysis I can see how the number of lines last touched in a given month changes over time to see how quickly (or not!) code decays.

Conclusion

Code is written to serve some purpose, to deliver some business value. But it quickly becomes a liability. As this code ages and rots it becomes harder and harder to change. From the analysis above it is clear to understand why a code base that has been around for a decade is mostly all archaic: with so little of the old code being changed each year it just continues to hang around, all the while we’re piling up new legacy on top – most of which will still be here next year.

What are we to do about it? It seems to be a natural law of software that over time it only accumulates. From my own experience it seems that even concerted efforts on refactoring make little impact. What are we to do? Do we just accept that changes become progressively harder as source code ages? Or do we need to find a way to encourage software to have a shorter half-life, to be re-written sooner.


Categories: Programming, Testing & QA

Old Age Code

Actively Lazy - Wed, 02/10/2016 - 22:34

Is your code ready for retirement? Is it suffering from the diseases of old age?¬†Do you have code you can’t even imagine retiring? It’s just too critical? Too pervasive? Too legacy?

Jon & The Widgets //www.flickr.com/photos/qchristopherConveyor Belt – thanks to https://www.flickr.com/photos/qchristopher

Jon’s first job out of school was in the local widget factory, WidgetCo. Jon was¬†young, enthusiastic and quickly took to the job of making widgets. The company was¬†pleased with Jon and he grew in experience, learning more about making widgets, taking on ever more responsibility; until eventually Jon was responsible for all widget production.

After a couple of years one of WidgetCo’s¬†biggest customers started asking about a new type of square widget. They had only made circular widgets before, but with Jon’s expertise they thought they¬†could take on this¬†new market. The design team got started, working closely with¬†Jon to design a new type of square widget¬†for Jon to produce. It was a great success, WidgetCo¬†were the first to market with a square widget and sales went through the roof.

Unfortunately the new more complex widget production pipeline was putting a lot of pressure on the packing team. With different shape widgets and different options all needing to be sorted and packed properly mistakes were happening and orders being returned. Management needed a solution and turned to Jon. The team realised that if Jon knew a bit more about how orders were going to be packed he could organise the widget production line better to ensure the right number of each shape widget with the right options were being made at the right time. This made the job much easier for the packers and customer satisfaction jumped.

//www.flickr.com/photos/foshydogSneeze – thanks to https://www.flickr.com/photos/foshydog

A few years down the line and Jon was now a key part of the company. He was involved in all stages of widget production from the design of new widgets and the tools to manufacture them through to the production and packaging. But one day Jon got sick. He came down with a virus and was out for a couple of days: the company stopped dead. Suddenly management realised how critical Jon was to their operations Рwithout Jon they were literally stuck. Before Jon was even back up to speed management were already making plans for the future.

Shortly after, the sales team had¬†a lead that needed a new hexagonal widget. Management knew¬†this was a golden opportunity to try and remove some of their reliance on Jon. While Jon was involved in the initial design, the team commissioned a new production line and hired some new, inexperienced staff¬†to run it. Unfortunately hexagonal widgets were vastly more complex than the square ones and, without Jon’s experience the new widget production line struggled. Quality was too variable, mistakes were being made and production was much too slow. The¬†team were confident they could¬†get better over time but management were unhappy. Meanwhile, Jon was still churning out his regular widgets, same as he always had.

But the packing team were in trouble again – with two, uncoordinated production lines at times they were inundated with widgets and at other times they were idle. Reluctantly, management agreed that the only solution was for Jon to take responsibility for coordinating both production lines. Their experiment to remove their reliance on Jon had failed.

//www.flickr.com/photos/neilmoraleeThe Deckhand – thanks to https://www.flickr.com/photos/neilmoralee

A few years later still and the new production line had settled down; it never quite reached the fluidity of the original production line but sales were ok. But there was a new widget company offering a new type of octagonal widget. WidgetCo¬†desperately needed to catch up. The design team worked with Jon but, with his workload coordinating two production lines, he was always busy – so the designers were always waiting on Jon for feedback. The truth was: Jon was getting old. His eyes weren’t what they used to be and the arthritis in his fingers made working the prototypes for the incredibly complex new widgets difficult. Delays piled up and management got ever more unhappy.

So what should management do?

Human vs Machine

When we cast a human in the central role in this story it sounds ridiculous. We can’t imagine a company being so reliant on one frail human being that it’s brought to its knees by an illness. But read the story as though Jon is a software system and suddenly it seems totally reasonable. Or if not reasonable, totally familiar. Throughout the software world we see vast edifices of legacy software, kept alive way past their best because nobody has the appetite to replace them. They become too ingrained, too critical:¬†too big to fail.

14256058429_f7802658c8_zFor all it’s artificial construct, software is not so different from a living organism. A large code base will be of a level of complexity comparable with an organism – too complex for any single human being to comprehend in complete detail. There will be outcomes and responses that can’t be explained completely, that require detailed research to understand the pathway that leads from stimulus to response.

But yet we treat software like it is immortal. As though once written software will carry on working forever. But the reality is that within a few years software becomes less nimble, harder to change. With the growing weight of various changes of direction and focus software becomes slower and more bloated. Each generation piling on the pounds. Somehow no development team has mastered turning back time and turning a creaking, old age project into the glorious flush of youth where everything is possible and nothing takes any time at all.

It’s time to accept that software needs to be allowed to retire. Look around the code you maintain: what daren’t you retire? That’s where you should start. You should start planning to retire it¬†soon, because if it’s bad now it is only getting worse. As the adage goes: the best time to start fixing this was five years ago; the second best time is now.

//www.flickr.com/photos/ewwhiteSad dog – thanks to https://www.flickr.com/photos/ewwhite

After five years all software is a bit creaky; not so quick to change as it once was. After ten years it’s well into legacy; standard approaches have moved on, tools improved, decade old software just feels dated to work with. After twenty years it really should be allowed to retire already.

Software ages badly, so you need to plan for it from the beginning. From day one start thinking about how you’re going to replace this system. A monolith will always be impossible to replace, so constantly think about breaking out separate components that could be retired independently. As soon as code has got bigger than you can throw away, it’s too late. Like a black hole a monolith sucks in functionality, as soon as you’re into run away growth your monolith will consume everything in it’s path. So keep things small and separate.

What about the legacy you have today? Just start. Somewhere. Anywhere. The code isn’t getting any younger.


Categories: Programming, Testing & QA

Tooling in the .net World

Actively Lazy - Wed, 02/03/2016 - 21:51

As a refugee Java developer first washing up on the shores of .net land, I was pretty surprised at the poor state of the tools and libraries that seemed to be in common use. I couldn’t believe this shanty town was the state of the art; but with a spring in my step I marched inland. A few years down the road, I can honestly say it really isn’t that great – there are some high points, but there are a lot of low points.¬†I hadn’t realised at the time but as a Java developer I’d been incredibly spoiled by a vivacious open source community producing loads of great software. In the .net world there seem to be two ways of solving any problem:

  1. The Microsoft way
  2. The other way*

*Note: may not work, probably costs money.

IDE

The obvious place to start is the IDE. I’m sorry, but Visual Studio just isn’t good enough. Compared to Eclipse and IntelliJ for day-to-day development Visual Studio is a poor imitation. Worse, until recently, it was¬†expensive as a lone developer. While there were community editions of Visual Studio, these were even more pared down than the unusable professional edition. Frankly, if you can’t run ReSharper, it doesn’t count as an IDE.

I hear there are actually people out there who¬†use Visual Studio without ReSharper. What are these people? Sadists? What do they do? I hope it isn’t writing software. Perhaps this explains the poor state of so much software; with tools this bad – is it any wonder?

But finally Microsoft have seen sense and recently the free version of Visual Studio supports plugins – which means you can use ReSharper. You still have to pay for it,¬†but with their recent licensing changes I don’t feel quite so bad handing over a few quid a month renting ReSharper before I commit to buying an outright license.¬†Obviously the situation for companies is different – it’s much easier for a company to justify spending the money on Visual Studio licenses and ReSharper licenses.

With ReSharper Visual Studio is at least closer to Eclipse or IntelliJ. It still falls short, but there is clearly only so much lipstick that JetBrains can put on that particular pig. I do however have great hope for Project Rider, basically IntelliJ for .net.

Restful Services

A few years back another Java refugee and I started trying to write a RESTful, CQRS-style web service in C#. We’d done the same in a previous company on the Java stack and expected our choices to be similarly varied. But instead of a vast plethora of approaches from basic HTTP listeners to servlet containers to full blown app servers we narrowed the field down to two choices:

  1. Microsoft’s WCF
  2. ServiceStack

My fellow developer played with WCF and decided he couldn’t make it easily fit the RESTful, CQRS style he had in mind. After playing with ServiceStack we found it could. But then begins a long, tortuous process of finding all the things ServiceStack hadn’t quite got right; all the things we didn’t quite agree with. Now, this is not entirely uncommon in any technology selection process. But we’d already quickly narrowed the field to two. We were now committed to a technology that at every turn was causing us new, unanticipated problems (most annoyingly, problems that other dev teams weren’t having with vanilla WCF services!)

We joked (not really joking) that it would be simpler to write our own service layer on top of the basic HTTP support in .net. In hindsight, it probably would have been. But really, we’d paid the price for having the temerity to step off the One True Microsoft Way.

Worse, what had started as an open source project went paid for during the development of our service – which meant that our brand new web service was immediately legacy as the service layer it was built on was no longer officially supported.

Dependency Management

The thing I found most surprising on arrival in .net land was that people¬†were checking all their¬†third party binaries into version control like it was the 1990s! Java developers might complain that Maven is nothing more than a DSL for downloading the internet. But you know what, it’s bloody good at downloading the internet. Instead, I had the internet checked in to version control.

However, salvation was at hand with NuGet. Except, NuGet really is a bit crap. NuGet doesn’t so much manage my dependencies as break them. All the damned time. Should we restrict all versions of a library (say log4net) to one version across the solution? Nah, let’s have a few variations. Oh, but nuget, now I get random runtime errors because of method signature mis-matches. But it doesn’t make the build fail? Brilliant, thank you, nuget.

So at my current place we’ve written a pre-build script to check that nuget hasn’t screwed the dependencies up. This pre-build check fails more often than I would like to believe.

So managing a coherent set of dependencies isn’t the job of the dependency tool, so what does it do? It downloads one file at a time from the internet. Well done. I think wget can do that, too. It’s a damned sight faster than the nuget power shell console, too. Nuget: it might break your builds, but at least it’s slow.

The Microsoft Way

And then I find things that blow me away. At my current place we’ve written some add-ins to Excel so that people who¬†live and die by Excel can interact with our software. This is pretty cool: adding buttons and menus and ribbons into Excel, all integrated to my back-end services.

In my life as a Java developer I can never even imagine attempting this. The hoops to jump through would have been far too numerous. But in Visual Studio? Create a new, specific type of solution, hit F5, Excel opens. Set a breakpoint, Excel stops. Oh my God –¬†this is an integrated development environment.

Obviously our data is all stored in Microsoft SQLServer. This also has brilliant integration with Visual Studio. For example, we experimented with creating a .net assembly to read some of the binary data we’re storing in the DB. This way we could run efficient queries on complex data types directly in the DB. The dev process for this? Similarly awesome: deploy to the DB and run directly from within Visual Studio. Holy integrated dev cycle, batman!

When there is a Microsoft way, this is why it is so compelling. Whatever they do will be brilliantly integrated with everything else they do. It might not have the flexibility you want, it might not have all the features you want. But it will be spectacularly well¬†integrated with everything else you’re already using.

Why?

Why does it have to be this way? C# is really awesome language; well designed with a lot of expressive power. But the open source ecosystem around it is barren. If the Microsoft Way doesn’t fit the bill, you are often completely stuck.

I think it comes down to the history of Visual Studio being so expensive. Even as a C# developer by day, I am not spending the thick end of ¬£1,000 to get a matching dev environment at home,¬†so I can¬†play. Even if I had a solid idea of an open source project to start, I’m not going to invest a thousand quid just to see.

But finally Microsoft seem to be catching on to the open source thing. Free versions of Visual Studio and projects like CoreCLR can only help. But the Java ecosystem has a decade head start and this ultimately creates a network effect: it’s hard to write good open source software for .net because there’s so little good open source tooling for .net.


Categories: Programming, Testing & QA

Rich domain objects with DivineInject

Actively Lazy - Thu, 01/28/2016 - 22:01

DivineInject is a .net dependency injection framework, designed to be simple to use and easy to understand.

You can find the source for DivineInject on github. In this second part in the series we’ll look at creating rich domain objects, the first part covers getting started with Divine Inject.

Simple Domain Objects

As an example, imagine I have a simple shopping basket in my application. The shopping basket is encapsulated by a Basket object, for which the interface looks like this:

interface IBasket
{
    IList<IBasketItem> GetBasketContents();
    void AddItemToBasket(IBasketItem item);
}

The contents of the basket are actually backed by a service to provide persistence:

interface IBasketService
{
    IList<IBasketItem> GetBasketContents(Guid basketId);
    void AddItemToBasket(Guid basketId, IBasketItem item);
}

I can create a very simple implementation of my Basket:

class Basket : IBasket
{
    private readonly IBasketService _basketService;
    private readonly Guid _basketId = Guid.NewGuid();

    public Basket(IBasketService basketService)
    {
        _basketService = basketService;
    }

    public IList<IBasketItem> GetBasketContents()
    {
        return _basketService.GetBasketContents(_basketId);
    }

    public void AddItemToBasket(IBasketItem item)
    {
        _basketService.AddItemToBasket(_basketId, item);
    }
}

Since I’m using dependency injection, IBasketService sounds like a dependency, so how do I go about creating an instance of Basket? I don’t want to create it myself, I need the DI framework to create it for me, passing in dependencies.

I want to do something with how the Basket is created, so let’s¬†start with a simple interface for creating baskets:

interface IBasketFactory
{
    IBasket Create();
}

When I’m creating a basket I¬†don’t¬†care about IBasketService or other dependencies; calling code just wants to be able to create a new, empty basket on demand. How would we implement this interface? Well, I¬†could do the following – although I shouldn’t.

class BadBasketFactory : IBasketFactory
{
    public IBasket Create()
    {
        // DON'T DO THIS - just an example
        return new Basket(
            DivineInjector.Current.Get<IBasketService>());
    }
}

Now I’d never suggest actually doing this, explicitly calling the dependency injector. The last thing I want from my DI framework is to have references to it smeared all over the application. However, what this class does is¬†basically what I want to happen.

DivineInject however can generate a class like this for you; this is configured at the same time you define the rest of your bindings:

DivineInjector.Current
    .Bind<IBasketFactory>().AsGeneratedFactoryFor<Basket>();

This generates an IBasketFactory implementation, which can create new IBasket implementations on demand (they will all actually be instances of Basket); all without having references to the DI framework smeared across my code. If I want to use the IBasketFactory, for example from my Session class, I declare it as a constructor arg the same as I would any other dependency:

public Session(IAuthenticationService authService, 
               IBasketFactory basketFactory)
{
    _authService = authService;
    _basketFactory = basketFactory;
}

The DI framework takes care of sorting out dependencies and I get a Session class with no references to DivineInject. When I need a new basket I just call _basketFactory.Create(). Since I have nice interfaces everywhere, everything is easy to mock so I can TDD everything.

Rich Domain Objects

Now what happens as my domain object becomes more complex? Say, for example, I want to be able to pass in some extra arguments to my constructor. Returning to our basket example: as well as starting a new, empty basket – isn’t there a possibility that I want to continue using an existing basket? E.g. in case of load balanced servers or fail-over. What do I do then?

I start by changing Basket, to allow me to pass in an existing basket id:

private readonly IBasketService _basketService;
private readonly Guid _basketId;

public Basket(IBasketService basketService)
{
    _basketService = basketService;
    _basketId = Guid.NewGuid();
}

public Basket(IBasketService basketService, Guid basketId)
{
    _basketService = basketService;
    _basketId = basketId;
}

I now have two constructors, one of which accepts a basket id. Since all Basket instances are created by an IBasketFactory, I need to change the factory interface, too:

interface IBasketFactory
{
    IBasket Create();
    IBasket UseExisting(Guid id);
}

I now have a new method on my IBasketFactory, if I was hand-coding the factory class I’d expect this second method¬†to call the second constructor, passing in the basket id.

What do we need to tell DivineInject to make it generate this¬†more complex IBasketFactory implementation?¬†Nothing!¬†That’s right, absolutely nothing – DivineInject will already generate a suitable IBasketFactory. Our original declaration above, is still sufficient:

DivineInjector.Current
    .Bind<IBasketFactory>().AsGeneratedFactoryFor<Basket>();

This generates an IBasketFactory implementation, returning a Basket instance for each method it finds on the interface. Since one of these methods takes a Guid, it tries to find a matching constructor which also takes a Guid, plus any dependencies it knows about. DivineInject can automatically wire up the right factory method to the right constructor, using the arguments it finds in each. Now, when a session wants to re-use an existing basket it just calls:

_basketFactory.UseExisting(existingBasketId)

This creates a new Basket instance, with dependencies wired up, passing in the basket id. Everything is still using interfaces so all your collaborations can be unit tested. Behind the scenes DivineInject generates the IL code to implement your factory interfaces, leaving you free to worry about your design.

By following this pattern we can create rich domain objects that include both state and dependencies: it becomes possible to create stateful objects that have behaviours (methods) that make sense in the domain. Successfully modelling your domain is critical to creating code that’s easy to understand and easy to change. DivineInject helps you model your domain better.


Categories: Programming, Testing & QA