Leading the Transformation: Applying Agile and DevOps Principles at Scale Notes

My personal notes from Leading the Transformation by Gary Gruver

  • Additional reading – Many specifics referenced in this book are leveraged from a case study of transformation at HP, detailed in A Practical Approach to Large-Scale Agile Development, by Gary Gruver, Mike Young, and Pat Fulghum.
  • How teams come together to deliver value in large organizations is a first-order effect. How individual teams work is a second-order effect
  • Done means
    • feature is signed off
    • defect free
    • test automation is complete
  • Software development is such a discover process that many assumptions made in planning can quickly become obsolete during development
  • Capacity of an organization to absorb change is the biggest constraint to rolling out improvements
  • Should always set objective and review at the end of each iteration
  • When estimates are off many organizations react by spending more and more in planning instead of focusing on delivering software
  • Instead of scolding people who commit on a red build, create a process that eliminates the problem
    • Usually roll back the last commit
  • Many organizations ask their manual testers to learn to automation what they have been doing manually for years. Some orgs buy tools to record what the manual testers are doing and that’s even worse
    • Record and playback is awful because if any UI changes the whole test is trash
  • An acceptance test should test one thing and one thing only.
  • All configurations should be in version control
    • You can automate checking successful deployments by querying your log management software for a successful deployment
  • Developers want to do a good job, and they assume they have until they get feedback to the contrary
  • ROI on DevOps is substantial but you will never achieve full benefit until you get your automated testing built out and integrated into the development pipeline
  • Applying DevOps principles at scale really requires the executive to drive the cultural and technical changes for improving the stability of trunk. This is vitally important because of the productivity gains that are possible when you eliminate branches and integrate all work across the teams on trunk. To get your code trunk to this level of quality and to keep it there, you need to begin using a CD pipeline with both code and component-level gating. This pipeline must incorporate a robust test automation framework. You will need to have component-based automated tests. Executives will need some simple metrics that are auto-generated each day to understand what is working and what is not so that they can focus resources in the right place every day.


Eric Ries – The Lean Startup Notes

My personal notes from The Lean Startup by Eric Ries

  • Identify where you’ve made assumptions instead of using facts. Make your assumptions facts by getting customer feedback
  • Early adopters are suspicious of something with too much polish.
    • If it’s ready for everyone to adopt how much advantage can they get?
    • Additional features or polish added is a waste
  • When in doubt simplify.
  • Any additional work beyond what was required to get feedback is a waste
  • Customers don’t care how much time something takes to build they care that it solves their needs
  • Everyone thinks their recent innovation is why the numbers went up. It’s everyone else’s fault when numbers go down.
  • Toyota Andon Cord
    • Defective change is removed immediately and automatically
    • Everyone on the relevant team is notified of the problem
    • Team is blocked from introducing any new changes
    • Root cause analysis performed
  • Dealerships sometimes have just in case inventory which cost a lot of money to keep stock on hand that we never be needed switch to just-in-time inventory and only have a one what you need
  • Use 5 why’s? to answer questions
    • “We didn’t do x”, “Why didn’t you do x?”
    • “We didn’t do x because of y”, “Why didn’t you do y?”
  • LTSE long term stock exchange

Adding java properties to Websphere Liberty

My latest project was moving a bunch of applications from running on WebSphere using Java 6 to running on Liberty running Java 8. For the most part this was pretty straightforward, but one major issue we ran into was a bean defined like so

<bean id="environment" class="org.springframework.jndi.JndiObjectFactoryBean">
  <property name="jndiName" value="java:comp/env/string/nw/environment"/>

What the heck does java:comp/env/string mean?

Turns out it’s pretty obvious once you know. It’s a JNDI Entry in Liberty (Namespace binding in WebSphere). You need to enter a new JNDI entry with a name of string/nw/environment with a value of dev, it, pt, prod, whatever your environment name is. This is generally something you’d add to a properties file, but considering this app is crazy old maybe that wasn’t an option.

What LDAP groups am I in?

Ever wonder what LDAP groups you’re a part of? There’s a super simple command that will tell you

net user ${windowsUsername} /domain

In my case

net user mrbusche /domain

Keep in mind this will run against your current domain on your computer, so if you’re a VPN user this may not work correctly if you’re computer domain is not your companies LDAP domain

Importing an SSL certificate into WebSphere

If you are receiving SSL handshake issues when connecting to a webservice you need to import the SSL certificate into WebSphere.

  1. Open WebSphere console
  2. Security
  3. SSL certificate and key management
  4. Key stores and certificates
  5. NodeDefaultTrustStore (or maybe CellDefaultTrustStore)
  6. Signer Certificates
  7. Retrieve from port
  8. Host: your.host.name (without https:// and any endpoints)
  9. Port: 443
  10. Retrieve signer information
  11. Click Ok
  12. Save
  13. Restart WebSphere

Trusting SSL certs on Pivotal Cloud Foundry

If you run into a scenario where you’re using a temporary SSL cert or a wildcard cert with Pivotal Cloud Foundry you may run into an issue where your cert is not being trusted. This is NOT something you should use in production, but if you’re trying to get things up and running for a proof of concept the solution below should get you past an SSL errors.

Note: the TRUST_CERTS: is indented under the env: and since this would be going into a yaml file the indentation does matter

- name: mbusche
  instances: 1
  memory: 1024M
  disk_quota: 1024M
  buildpack: java_buildpack
  path: target/myapp.jar
  stack: cflinuxfs2
  timeout: 180
  - mbusche-config-server
    TRUST_CERTS: test.matthewbusche.com

Count occurrences of string in a return, comma or pipe delimited list

I needed to take a large list of usernames that were return delimited and count how many times each one showed up in that list. Took me about 10 minutes do it manually the first time and after I was asked to do it again I had to write something to make it easier. I couldn’t find something that already existed, so I created something. Presenting Occurrence Counter! Simply paste in a return, comma, or pipe delimited list of strings and it will show you how many times each item was in the list. I’ve put this over on Github in case anyone has any issues or features requests.


Adding rows to an excel spreadsheet using apache poi

In a recent project for a client I was tasked with modifying an existing excel spreadsheet to add data from a query. Being familiar with Java and ColdFusion I assumed this would be a pretty trivial exercise. Read the existing file, get the sheet and then write the data, but I ran into an issue where adding rows using shiftRows didn’t make them writable and/or visible to apache poi. I realized I needed to literally add the rows and the columns to the excel spreadsheet to be able to change the values. Not a big deal code-wise and also really fast to complete, but frustrating to figure out.

currentCharterTemplate = 'existingWorkbook.xlsx';
currentFilePath = getDirectoryFromPath(getCurrentTemplatePath());
javaFile = createObject('java', 'java.io.File').init(currentFilePath & currentCharterTemplate);
excelFile = createObject('java', 'java.io.FileInputStream').init(javaFile);
xssfWorkbook = createObject('java', 'org.apache.poi.xssf.usermodel.XSSFWorkbook').init(excelFile);

summarySheet = xssfWorkbook.getSheetAt(0);
totalColumns = 12;
rowsToAdd = query.recordCount;
//add enough rows/columns to the spreadsheet to handle the record count of the query and the sort fields
for (rows = 1; rows <= rowsToAdd; rows++) {
  theCurrentRow = summarySheet.getRow(rows);
  for (columns = 0; columns <= totalColumns; columns++) {

Finding the version of a jar file

I needed to find the version of a jar file I was using to help out our middleware team at work and had never needed to do so before, so I went to googling. I figured it would be pretty straightforward and it is, once you find the correct commands. I initially started out unzipping the jar file and found the version that way through the manifest file by looking at the Implementation-Version. It wasn’t too much work, but I knew there had to be a better way and I stumbled upon this stackoverflow answer

If you open a terminal window and cd to the directory with your jar file you can do unzip -p file.jar META-INF/MANIFEST.MF to view the manifest file without manually unzipping the file.

Filtering Amazon Wishlist items with price drops

Amazon has recently changed their filters on wish list items so you can no longer view items with price drops (useful for books) or sort price from low to high. I wrote up some fairly crappy JavaScript that scrolls to the end of your wish list then removes all the items that don’t have  “Price dropped” in the div. I sometimes need to run the code more than once to get all items to be removed, so this is far from perfect, but works for what I was intending it to do. If you have a few hundred items on your list it will take a few seconds to run the script, but each subsequent run should run pretty quick.

Update: I added this to github.

function removeItemsWithoutPriceDrops() {
  var lowPrice = 999999;
  var anyRemoved = false;
  var listItems = document.getElementsByClassName('a-spacing-none g-item-sortable');

  for (var i = 0; i &lt; listItems.length; i++) { var priceDrop = listItems[i].querySelectorAll('.itemPriceDrop'); var price = listItems[i].querySelectorAll('span.a-offscreen'); if (price.length) { price = price[0].innerHTML; price = price.replace('$', ''); } else { price = 0; } if (priceDrop.length == 0 || price &gt; lowPrice) {
      anyRemoved = true;

  if (anyRemoved) {


You can also add the following code directly to a bookmark by copy and pasting the code into this generator