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!

Feed aggregator

100 Top Agile Blogs

Luis Goncalves has put together a list called the 100 Top Agile Blogs:

If you don't know Luis, he lives and breathes driving adoption of Agile practices.

Luis is also an Agile Coach, Co-Author, Speaker, and Blogger.  He is also the co-founder of a MeetUp group called High Performing Teams, and he is a certified Scrum Master and Product Owner.

Here is a preview of the list of top 100 Agile Blogs:

image

 

For the rest of the list, check out 100 Top Agile Blogs.

Lists like these are a great way to discover blogs you may not be aware of.  

While there will be a bunch of blogs you already know, chances are, with that many at a glance, there will be at least a few new ones you can add to your reading list.

Categories: Architecture, Programming

SPaMCAST 313 – Initial Backlogs

www.spamcast.net

http://www.spamcast.net

Listen to the Software Process and Measurement Cast now!

SPaMCAST 313 features our essay on developing an initial backlog.  Developing an initial backlog is an important step to get projects going and moving in the right direction. If a project does not start well, it is hard for it to end well.  We will provide techniques to help you begin well!

The essay begins:

Many discussions of Agile techniques begin with the assumption that a backlog has magically appeared on the team’s door step. Anyone that has participated in any form of project, whether related to information technology, operations or physical engineering, knows that requirements don’t grow on trees. They need to be developed before a team can start to satisfy those requirements.  There are three primary ways to gather requirements based on how information is elicited.

Listen to the rest on the Software Process and Measurement Cast!

Call to action!

What are the two books that have most influenced you career (business, technical or philosophical)?  Send the titles to spamcastinfo@gmail.com.  What will we do with this list?  We have two ideas.  First, we will compile a list and publish it on the blog.  Second, we will use the list to drive “Re-read” Saturday. Re-read Saturday is an exciting new feature we will begin in November with a re-read of Leading Change. More on this new feature next week. So feel free to choose you platform and send an email, leave a message on the blog, Facebook or just tweet the list (use hashtag #SPaMCAST)!

Next

SPaMCAST 314 features our interview with Janet Gregory and Lisa Crispin.  We discussed their new book More Agile Testing. Agile testing is evolving at the same rate as Agile or maybe faster! Testing is still critical for delivering business value.  Buy and read the book this week before listening to the interview!

 

The Software Process and Measurement Cast has a sponsor.

As many you know I do at least one webinar for the IT Metrics and Productivity Institute (ITMPI) every year. The ITMPI provides a great service to the IT profession. ITMPI’s mission is to pull together the expertise and educational efforts of the world’s leading IT thought leaders and to create a single online destination where IT practitioners and executives can meet all of their educational and professional development needs. The ITMPI offers a premium membership that gives members unlimited free access to 400 PDU accredited webinar recordings, and waives the PDU processing fees on all live and recorded webinars. The Software Process and Measurement Cast some support if you sign up here. All the revenue our sponsorship generates goes for bandwidth, hosting and new cool equipment to create more and better content for you. Support the SPaMCAST and learn from the ITMPI.

Shameless Ad for my book!

Mastering Software Project Management: Best Practices, Tools and Techniques co-authored by Murali Chematuri and myself and published by J. Ross Publishing. We have received unsolicited reviews like the following: “This book will prove that software projects should not be a tedious process, neither for you or your team.” Support SPaMCAST by buying the book here.

Available in English and Chinese.


Categories: Process Management

SPaMCAST 313 – Initial Backlogs

Software Process and Measurement Cast - Sun, 10/26/2014 - 22:00

SPaMCAST 313 features our essay on developing an initial backlog.  Developing an initial backlog is an important step to get projects going and moving in the right direction. If a project does not start well, it is hard for it to end well.  We will provide techniques to help you begin well!

The essay begins:

Many discussions of Agile techniques begin with the assumption that a backlog has magically appeared on the team’s door step. Anyone that has participated in any form of project, whether related to information technology, operations or physical engineering, knows that requirements don’t grow on trees. They need to be developed before a team can start to satisfy those requirements.  There are three primary ways to gather requirements based on how information is elicited.

Listen to the rest on the Software Process and Measurement Cast!

Call to action!

What are the two books that have most influenced you career (business, technical or philosophical)?  Send the titles to spamcastinfo@gmail.com.  What will we do with this list?  We have two ideas.  First, we will compile a list and publish it on the blog.  Second, we will use the list to drive “Re-read” Saturday. Re-read Saturday is an exciting new feature we will begin in November with a re-read of Leading Change. More on this new feature next week. So feel free to choose you platform and send an email, leave a message on the blog, Facebook or just tweet the list (use hashtag #SPaMCAST)!

Next

SPaMCAST 314 features our interview with Janet Gregory and Lisa Crispin.  We discussed their new book More Agile Testing. Agile testing is evolving at the same rate as Agile or maybe faster! Testing is still critical for delivering business value.  Buy and read the book this week before listening to the interview!

 

The Software Process and Measurement Cast has a sponsor.

As many you know I do at least one webinar for the IT Metrics and Productivity Institute (ITMPI) every year. The ITMPI provides a great service to the IT profession. ITMPI’s mission is to pull together the expertise and educational efforts of the world’s leading IT thought leaders and to create a single online destination where IT practitioners and executives can meet all of their educational and professional development needs. The ITMPI offers a premium membership that gives members unlimited free access to 400 PDU accredited webinar recordings, and waives the PDU processing fees on all live and recorded webinars. The Software Process and Measurement Cast some support if you sign up here. All the revenue our sponsorship generates goes for bandwidth, hosting and new cool equipment to create more and better content for you. Support the SPaMCAST and learn from the ITMPI.

Shameless Ad for my book!

Mastering Software Project Management: Best Practices, Tools and Techniques co-authored by Murali Chematuri and myself and published by J. Ross Publishing. We have received unsolicited reviews like the following: “This book will prove that software projects should not be a tedious process, neither for you or your team.” Support SPaMCAST by buying the book here.

Available in English and Chinese.

Categories: Process Management

Anecdotal Evidence is not Actually Evidence

Herding Cats - Glen Alleman - Sun, 10/26/2014 - 16:25

Untitled When we hear I know a CEO that uses this method and she's happy with the outcomes, has several core fallacies wrapped into one.

The first is the self-selection problem of statistics. This is the Standish problem. Send out a survey, tally the results from those that were returned. Don't publish how many surveys went out and how many came back.

The next is the Anecdotal sample. I know a guy that... in support of the suggestion that by knowing someone that supports you're conjecture, your conjecture is some how supported.

These are both members of the cherry picking process. The result is lots of exchanges of questions to the original conjecture that have not basis in evidence for the conjecture.

When you encounter such a conjecture, apply the Sagan's BS detection kit

  • Seek independent confirmation of alleged facts.
  • Encourage an open debate about the issue and the available evidence.
  • In our domain and most other there are no authorities. At most, there are experts.
  • Come up with a variety of competing hypotheses explaining a given outcome. Considering many different explanations will lower the risk of confirmation bias.
  • Quantify whenever possible, allowing for easier comparisons between hypotheses' relative explanatory power.
  • Every step in an argument must be logically sound; a single weak link can doom the entire chain.
  • When the evidence is inconclusive, use Occam's Razor to discriminate between hypotheses.
  • Pay attention to falsifiability. Science does not concern itself with unfalsifiable propositions.

When there is push back from hard questions, you'll know those making the claims have no evidence and are essentially BS'ing their constituents.

Categories: Project Management

Agile Concepts: Notes on Scrum of Scrums

The city is a town at scale.

The city is a town at a different scale.

The Scrum of Scrums is a common tool to scale Agile. In many cases the technique works admirably, however as Scrum-based Agile is applied to larger and larger projects, the Scrum of Scrums technique becomes stressed. The most significant issues include:

  1. As the number of Scrum teams involved on a project increases, the number of attendees increase. As the number of attendees that must talk in a meeting increases, the length of the meeting increases. The length of meeting is perfectly correlated to the number of emails sent by participant during the meeting. In other words, it is difficult to hold the attention of participants in larger, long meeting meetings. As projects grow, curtail the active participants to the team Scrum master /representative. In organizations where product owners wish to hold a Scrum of Scrum type meeting make sure those sessions are separated. I have also seen organizations experiment with hierarchies of Scrum of Scrums meetings.
  2. Project Coordination. Both Scrum of Scrum meetings and their cousins, daily stand-up meetings, are coordination and planning meetings. As the project size grows, coordination and planning meetings require greater context (status) to be effective, which can shift the focus towards informational or status meetings thereby reducing the effectiveness of the technique. Large projects need to have a mechanism for sharing context/status outside of planning and coordination meetings. One interesting solution I have observed (for a large program) was a daily program e-newsletter akin to the newsletter large conferences publish daily. I have also seen status wikis used to great effect. Status and news is easily consumed asynchronously therefore meeting time can be avoided.
  3. The Scrum of Scrums meeting infers a hierarchy in Scrum teams that does not exist. Scrum masters become the conduit of information between teams. Team communicate with their Scrum masters, Scrum masters communicate with other Scrum Masters then to the team they are part of and then the cycle reverses. A few years ago I read an article by Mike Cohn that suggested rotating participation. While rotation might impact the consistency, it would send a message that participation is a role rather than a status level.

Scaling Agile requires thought and planning. A Scrum of Scrums that includes product owners and other participants that worked for a handful of teams might need to be tailored when the project grows to include two or three handfuls of teams. Very few human institutions are linearly scalable forever. When using Scrum of Scrums for larger programs scale the technique rather than just moving to a larger conference room.


Categories: Process Management

Trust but Verify

Herding Cats - Glen Alleman - Sat, 10/25/2014 - 18:28

There is this notion in some circles that trust trumps all business management processes.

Screen Shot 2014-10-24 at 4.35.37 PMThe Russian proverb is

"Доверяй, но проверяй, Лучше перебдеть, чем недобдеть"

Who's butchered translation is Trust but Verify, don't rely on chance.

President Regan used that proverb reflected back to the Russian in the SALT I treaty. So what does it mean trust that people can think for themselves and decide if it applies to them ... that not making estimates of the cost, performance and schedule for the project are needed?

The first question is - what's the value at risk? Trust alone is likely possible in low value at risk. In that case the impact of not showing up on or before the needed time, at or below the needed cost, and with ot without all the needed capabilities for the mission or business case fulfillment has much less impact and therefore is acceptable.

Trust

Trust but Verify

6 week DB update with 3 developers

18 month ERP integration with 87 developers whose performance is reported to the BoD on a quarterly basis

Water filter install in kitchen using the local handyman

Water filter install in kitchen with wife testing to see if it does what it said in the brochure

Install the finch feeder on the pole attached to the back deck in front of the kitchen window over looking the golf course.

Design and build the 1,200 square foot deck attached to the second floor on the back of the house using the architects plans and schedule the county for the inspection certificate so it can be used last summer.

Arrange for a ride in a glider at the county airport sometime Saturday afternoon

Plan departure from DIA and check for departure delay of SWA flight DEN to DCA.

In the first instances (left column) trust us, we'll be done in the 6 week window probably means that team doesn't need to do much estimating other than the agree among themselves that the Promise made to the manager has a good chance of coming true.

The second (right column) $178M ERP integration project in a publicly traded firm, filing their 10K and subject to FASB 86, and having promised the shareholders, insured, and the provider network that the new system will remove all the grief of the several dozen legacy apps will be made all betteron or before  the Go Live date announced at the Board Meeting and in the Press has a good chance of coming true. 

To assess that chance, more that Trust is needed. Evidence of the probability of completing on or before the go live date and at or below the target budget is needed. That probability is developed with an estimating process and updated on a periodic basis - in this case every month, with a mid-month assessment of the month end's reportable data. 

So next time you hear...

Screen Shot 2014-10-24 at 5.27.28 PM

...think of the Value at Risk, the fiduciary responsibility to those funding your work, to ask and produce an answer to the question of how much, when, and what will be delivered. And even possibly the compliance responsibility - SOX, CMS, FAR/DFARS, ITIL - for knowing to some degree of confidence the Estimate To Complete and the Estimate at Complete for your project. Writing 6 week warehouse apps, probably not much value. Spending 100's of millions of stock holders money and betting the company likely knowing something like those numbers is needed.

Trust Alone is Open Loop Trust but Verify is Closed Loop

Control systems from Glen Alleman   Without knowing the Value At Risk it's difficult if not impossible to have a conversation about applying any method of managing the spend of other peoples money. Here's a clip from another book that needs to be on the shelf of anyone accoutable for spending money in the presence of a governance process. Practical Spread Sheet Risk Modeling. Don't do risk management of other peoples money? Then you don't need this book or similar ones, and likley don't need to estimate the impact of decisions made using other peoples money. Just keep going, your customer will tell you when to stop. Screen Shot 2014-10-25 at 11.21.45 AM  
Categories: Project Management

Agile Concepts: Scaling Agile and the Scrum of Scrums

Don't let conversation wander, or the participants will lose focus (and maybe take a nap).

Don’t let conversation wander, or the participants will lose focus (and maybe take a nap).

In the long run it probably would be possible deliver all projects or releases with a single Agile team. Unfortunately “the long run” and the dynamic business environment are archenemies. Some degree of speed is required to bring the functionality that stakeholders require to market. For larger projects or releases, speed generally requires more than one team and coordination to deliver. Cadence and synchronization are the goals. One of the techniques used to affect synchronization is the Scrum of Scrums.

A Scrum of Scrum is very similar to the daily Scrum (also known as daily stand-up). At a very basic level a representative from each Scrum team gathers and reviews what each team accomplished, what will be done in the next time period and impediments or blockers. At this level the focus tends to be on coordinating challenges between teams. A backlog of the impediments and challenges is generally kept.

The concept of a Scrum of Scrums in theory is simple and to the point. In practice there are generally a few questions that have to ironed out. Questions typically include:

  1. Different frameworks recommend different frequencies. For example, SAFe recommends twice a week, however the Agile Alliance suggests daily. Scrum of Scrums in practice are generally held on a less frequent basis than the daily stand-up. I use attributes such as project criticality, complexity and Agile maturity to help guide frequency decisions. The more critical, complexity or the less mature, the more frequent the Scrum of Scrums.
  2. The Scrum of Scrums is typically attended by each of the Scrum masters from the teams. Alternate practices include having a technical lead attend when group share Scrum masters, having product owners attend as participants or having all team members attend (this last one is a horrible idea). A warning: the larger the number of active participants, the longer the meeting will be and the less likely the participants will stay focused. Remember, just like the daily stand-up, anyone can attend and listen.
  3. Each framework has a role that chairs the Scrum of Scrums. In SAFe, the Release Train Engineer facilitates the meeting, in other frameworks a program manager or lead Scrum master can fill the role. Alternate practices I have observed include rotating facilitation between Scrum masters (tends to lack consistency), having the lead product owner facilitate (they usually have a too much on their plate) or having an IT manager chair (can curtails discussion). While all of these alternatives can work, rotating is the best of a bad lot.
  4. The classic three questions typically dominate any stand-up like meetings: what did I do, what am I going to do and what is in my way. The Scrum of Scrum generally spins the questions towards information that other teams need to know. Alternative meeting content additions I have observed include adding a question about risks, maintaining a team event calendar (business, environment and social) and overall confidence polling. Every addition increases the possibility of increasing the time spent in meetings and content that is not relevant to everyone involved.

The Scrum of Scrums is sort like a league meeting, or as Mike Cohen calls it, “a team of teams.” The technique is a tried and true mechanism for coordinating multiple Agile teams. Like any meeting, conversation can wander away from the goal of coordination. Push any side discussion not on the agenda to “meet afters” (meetings held after the Scrum of Scrums) or other venues. Mentally recite the mantra, “coordination, coordination, coordination” and stay focused on the agenda.


Categories: Process Management

Implementing material design in your Android app

Android Developers Blog - Fri, 10/24/2014 - 20:18
By Chris Banes and Nick Butcher, Android Developer Relations

Material design is a comprehensive approach to visual, interaction and motion design for the multi-screen world. Android 5.0 Lollipop and the updated support libraries help you to create material UIs. Here’s a rundown of some of the major elements of material design and the APIs and widgets that you can use to implement them in your app.

Tangible surfaces

In material design, UIs are composed of pieces of digital paper & ink. The surfaces and the shadows they cast provide visual cues to the structure of the application, what you can touch and how it will move. This digital material can move, expand and reform to create flexible UIs.

Shadows

A surface’s position and depth result in subtle changes in lighting and shadows. The new elevation property lets you specify a view’s position on the Z-axis and the framework then casts a real-time dynamic shadow on items behind it. You can set the elevation declaratively in your layouts, defined in dips:

<ImageView …
    android:elevation="8dp" />

You can also set this from code using getElevation()/setElevation() (with shims in ViewCompat). The shadow a view casts is defined by its outline, which by default is derived from its background. For example if you set a circular shape drawable as the background for a floating action button, then it would cast an appropriate shadow. If you need finer control of a view’s shadow, you can set a ViewOutlineProvider which can customise the Outline in getOutline().

Cards

Cards are a common pattern for creating surfaces holding a distinct piece of information. The new CardView support library allows you to create them easily, providing outlines and shadows for you (with equivalent behaviour on prior platforms).

<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <!-- Your card content -->

</android.support.v7.widget.CardView>

CardView extends FrameLayout and provides default elevation and corner radius for you so that cards have a consistent appearance across the platform. You can customise these via the cardElevation and cardCornerRadius attributes, if required. Note that Cards are not the only way of achieving dimensionality and you should be wary of over-cardifying your UI!

Print-like Design

Material utilises classic principles from print design to create clean, simple layouts that put your content front and center. Bold deliberate color choices, intentional whitespace, tasteful typography and a strong baseline grid create hierarchy, meaning and focus.

Typography

Android 5.0 updates the system font Roboto to beautifully and clearly display text no matter the display size. A new medium weight has been added (android:fontFamily=”sans-serif-medium”) and new TextAppearance styles implement the recommended typographic scale for balancing content density and reading comfort. For instance you can easily use the ‘Title’ style by setting android:textAppearance=”@android:style/TextAppearance.Material.Title”. These styles are available on older platforms through the AppCompat support library, e.g. “@style/TextAppearance.AppCompat.Title”.

Color

Your application’s color palette brings branding and personality to your app so we’ve made it simple to colorize UI controls by using the following theme attributes:

  • colorPrimary. The primary branding color for the app; used as the action bar background, recents task title and in edge effects.
  • colorAccent. Vibrant complement to the primary branding color. Applied to framework controls such as EditText and Switch.
  • colorPrimaryDark. Darker variant of the primary branding color; applied to the status bar.

Further attributes give fine grained control over colorizing controls, see: colorControlNormal, colorControlActivated, colorControlHighlight, colorButtonNormal, colorSwitchThumbNormal, colorEdgeEffect, statusBarColor and navigationBarColor.

AppCompat provides a large subset of the functionality above, allowing you to colorize controls on pre-Lollipop platforms.

Dynamic color

Material Design encourages dynamic use of color, especially when you have rich images to work with. The new Palette support library lets you extract a small set of colors from an image to style your UI controls to match; creating an immersive experience. The extracted palette will include vibrant and muted tones as well as foreground text colors for optimal legibility. For example:

Palette.generateAsync(bitmap,
        new Palette.PaletteAsyncListener() {
    @Override
    public void onGenerated(Palette palette) {
         Palette.Swatch vibrant =
                 palette.getVibrantSwatch();
          if (swatch != null) {
              // If we have a vibrant color
              // update the title TextView
              titleView.setBackgroundColor(
                  vibrant.getRgb());
              titleView.setTextColor(
                  vibrant.getTitleTextColor());
          }
    }
});
Authentic Motion

Tangible surfaces don’t just appear out of nowhere like a jump-cut in a movie; they move into place helping to focus attention, establish spatial relationships and maintain continuity. Materials respond to touch to confirm your interaction and all changes radiate outward from your touch point. All motion is meaningful and intimate, aiding the user’s comprehension.

Activity + Fragment Transitions

By declaring ‘shared elements’ that are common across two screens you can create a smooth transition between the two states.

album_grid.xml
…
    <ImageView
        …
        android:transitionName="@string/transition_album_cover" />
album_details.xml
…
    <ImageView
        …
        android:transitionName="@string/transition_album_cover" />

AlbumActivity.java
Intent intent = new Intent();
String transitionName = getString(R.string.transition_album_cover);
…
ActivityOptionsCompat options =
ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
    albumCoverImageView,   // The view which starts the transition
    transitionName    // The transitionName of the view we’re transitioning to
    );
ActivityCompat.startActivity(activity, intent, options.toBundle());

Here we define the same transitionName in two screens. When starting the new Activity and this transition is animated automatically. In addition to shared elements, you can now also choreograph entering and exiting elements.

Ripples

Materials respond to users’ touch with an ink ripple surface reaction. Interactive controls such as Buttons exhibit this behaviour by default when you use or inherit from Theme.Material (as will ?android:selectableItemBackground). You can add this feedback to your own drawables by simply wrapping them in a ripple element:

<ripple
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/accent_dark">
    <item>
        <shape
            android:shape="oval">
            <solid android:color="?android:colorAccent" />
        </shape>
    </item>
</ripple>

Custom views should propagate touch location down to their drawables in the View#drawableHotspotChanged callback so that the ripple can start from the touch point.

StateListAnimator

Materials also respond to touch by raising up to meet your finger, like a magnetic attraction. You can achieve this effect by animating the translationZ attribute which is analogous to elevation but intended for transient use; such that Z = elevation + translationZ. The new stateListAnimator attribute allows you to easily animate the translationZ on touch (Buttons do this by default):

layout/your_layout.xml
<ImageButton …
    android:stateListAnimator="@anim/raise" />
anim/raise.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_enabled="true" android:state_pressed="true">
        <objectAnimator
            android:duration="@android:integer/config_shortAnimTime"
            android:propertyName="translationZ"
            android:valueTo="@dimen/touch_raise"
            android:valueType="floatType" />
    </item>
    <item>
        <objectAnimator
            android:duration="@android:integer/config_shortAnimTime"
            android:propertyName="translationZ"
            android:valueTo="0dp"
            android:valueType="floatType" />
    </item>
</selector>
Reveal

A hallmark material transition for showing new content is to reveal it with an expanding circular mask. This helps to reinforce the user’s touchpoint as the start of all transitions, with its effects radiating outward radially. You can implement this using the following Animator:

Animator reveal = ViewAnimationUtils.createCircularReveal(
                    viewToReveal, // The new View to reveal
                    centerX,      // x co-ordinate to start the mask from
                    centerY,      // y co-ordinate to start the mask from
                    startRadius,  // radius of the starting mask
                    endRadius);   // radius of the final mask
reveal.start();
Interpolators

Motion should be deliberate, swift and precise. Unlike typical ease-in-ease-out transitions, in Material Design, objects tend to start quickly and ease into their final position. Over the course of the animation, the object spends more time near its final destination. As a result, the user isn’t left waiting for the animation to finish, and the negative effects of motion are minimized. A new fast-in-slow-out interpolator has been added to achieve this motion.

For elements entering and exiting the screen (which should do so at peak velocity), check out the linear-out-slow-in and fast-out-linear-in interpolators respectively.

Adaptive design

Our final core concept of material is creating a single adaptive design that works across devices of all sizes and shapes, from watches to giant TVs. Adaptive design techniques help us realize the vision that each device reflects a different view of the same underlying system. Each view is tailored to the size and interaction appropriate for that device. Colors, iconography, hierarchy, and spatial relationships remain constant. The material design system provides flexible components and patterns to help you build a design that scales.

Toolbar

The toolbar is a generalization of the action bar pattern, providing similar functionality, but much more flexibility. Unlike the standard action bar, toolbar is a view in your hierarchy just like any other, so you can place instances wherever you like, interleave them with the rest of your views, animate, react to scroll events and so on. You can make the Toolbar act as your Activity’s Action Bar by calling Activity.setActionBar().

In this example, the blue toolbar is an extended height, overlaid by the screen content and provides the navigation button. Note that two further toolbars are used in the list and detail views.

For details of implementing toolbars, see this post.

Go Forth and Materialize

Material Design helps you to build understandable, beautiful and adaptive apps, which are alive with motion. Hopefully, this post has inspired you to apply these principles to your app and signposted some of the new (and compatibility) APIs to achieve this.

Join the discussion on

+Android Developers
Categories: Programming

Stuff The Internet Says On Scalability For October 24th, 2014

Hey, it's HighScalability time:


This is an ultrasound powered brain implant! (65nm GP CMOS technology, high speed, low power (100 µW))
  • 70: percentage of the worlds transactions processed using COBOL.  
  • Quotable Quotes:
    • John Siracusa: Apple has shown that it wants to succeed more than it fears being seen as a follower.
    • @Dries: "99% of Warren Buffett's wealth was built after his 50th birthday."
    • @Pinboard: It is insane to run a bookmarking site on AWS at any kind of scale. Unless you are competing with me, in which case it’s a great idea—do it!
    • @dvellante: I sound like a broken record but AWS has the scale to make infrastructure outsourcing marginal costs track SW curve 
    • @BrentO: LOL RT @SQLPerfTips: "guess which problem you are more likely to have - needing joins, or scaling beyond facebook?"
    • @astorrs: Legacy systems? Yes they're still relevant. ~20x the number of transactions as Google searches @IBM #DOES14 
    • @SoberBuildEng: "It was all the Agile guys' fault at the beginning.Y'know, if the toilet overflowed, it was 'What, are those Agile guys in there?!'" #DOES14
    • @cshl1: #DOES14  @netflix "$1.8M revenue / employee" << folks, this is an amazing number
    • Isaac Asimov: Probably more inhibiting than anything else is a feeling of responsibility. The great ideas of the ages have come from people who weren’t paid to have great ideas, but were paid to be teachers or patent clerks or petty officials, or were not paid at all. The great ideas came as side issues.

  • With Fabric can Twitter mend the broken threads of developer trust? A good start would be removing 3rd party client user limit caps. Not sure a kit of many colors will do it.

  • Not only do I wish I had said this, I wish I had even almost thought it. tjradcliffe: I distinguish between two types of puzzles: human-made (which I call puzzles) and everything else (which I call problems.) In those terms, I hate puzzles and love problems. Puzzles are contrived by humans and are generally as much psychology problems as anything else. They basically require you to think like the human who created them, and they have bizarre and arbitrary constraints that are totally unlike the real world, where, as Feyrabend told us, "Anything goes."

  • David Rosenthal with a great look at Facebook's Warm Storage: 9 [BLOB] types have dropped by 2 orders of magnitude within 8 months...the vast majority of the BLOBs generate I/O rates at least 2 orders of magnitude less than recently generated BLOBs...Within a data center it uses erasure coding...Between data centers it uses XOR coding...When fully deployed, this will save 87PB of storage...heterogeneity as a way of avoiding correlated failures.

  • Gene Tene on is it a CPU bound future: I don't think CPU speed is a problem. The CPUs and main RAM channels are still (by far) the highest performing parts of our systems. For example, yes, you can move ~10-20Gbps over various links today (wired or wifi, "disk" (ssd) or network), but a single Xeon chip today can sustain well over 10x that bandwidth in random access to DRAM. A single chip has more than enough CPU bandwidth to stream through that data, too. E.g. a single current Haswell core can move more than that 10-20Gbps in/out of it's cache levels. and even relatively low end chips (e.g. laptops) will have 4 or more of these cores on a single chip these days. < BTW, a great thread if you are interested in latency issues.

Don't miss all that the Internet has to say on Scalability, click below and become eventually consistent with all scalability knowledge (which means this post has many more items to read so please keep on reading)...

Categories: Architecture

The Future of IT Leaders

I’ll need to elaborate on this at some point, to share what I’ve experienced across lots of businesses large and small, as well as some of the biggest businesses on the planet, as they transform themselves for the digital economy.

Meanwhile, here is an interesting read on CIO Straight Talk magazine.

In their words, "CIO Straight Talk is a series of "straight talking" articles from senior IT executives and leading companies and government and nonprofit organizations."

This first edition is focused on learning, failing and learning in the Second Machine Age, and features two non-practitioner experts on current topics:

“Andrew McAfee, co-author of the New York Times bestseller The Second Machine Age, cofounder of MIT’s Initiative on the Digital Economy and Principal Research Scientist at MIT Sloan School of Management, talks about ‘The CIO’s role in the enterprise of the future.’ Says McAfee: ‘The overall trend is that companies of all stripes will need, proportionately, many fewer people in IT. Those who remain will be very highly valued, very highly skilled, very important… Enterprises are going to need someone to help them navigate the second machine age… I think that if the CIO plays her cards right, this can absolutely be her role in the enterprise.’”

Michelle Gallen, the CEO of Shhmooze, a social networking start-up, talks about failure, not to be confused Failure Lite – ‘I failed. How nice. I learned so much’ – often hailed breezily by management experts as something everyone should experience and every company should encourage. Real failure, according to this serial entrepreneur, isn’t pretty. Says Gallen: ‘I don’t think you learn without failing… In the start-up world, innovation is the ability to take an idea and turn it into an invoice. Lots of larger business organizations also rely on cash flow to keep them alive, and therefore innovation has to be monetized. If you’re Apple or Microsoft, you’ve got a war chest, and you can actually allow failure. A lot of companies can’t actually afford it. It’s quite an expensive hobby, failing.’”

So there you have it -- failure is an expensive hobby and the few IT leaders left in organizations will be very highly valued, very highly skilled, and very important.

There’s more to the story and I’ll share what I’ve learned over the past few years helping companies cross the Cloud chasm and accelerating their digital transformation.

Categories: Architecture, Programming

Happy Permutation Day

Herding Cats - Glen Alleman - Fri, 10/24/2014 - 15:05

10/24/2014

1024 - 2014

Thanks to Mr. Honner, a mathematics teacher in at Brooklyn Technical High School. If you like mathematics and appreciate the contribution a good teacher can make to mathematically understanding which is woefully lacking in our project management domain, sign up to get his blog posts.

Categories: Project Management

Agile Concepts: Scale Requires Cadence and Synchronization

Bands need to sync up with the beat.

Bands need to sync up with the beat.

In music, cadence is the number of beats in a bar. When I was young I was in a band. Our drummer generally set the cadence with the beat. In classic rock, the cadence was based on four-four time. When anyone of band members slipped out of time they would use the beat to synchronize. Most songs that include solos leverage the beat to re-sync the band when the soloist returns to the melody. Projects with more than one team use sprint cadence and the ceremonies of Scrum or Scaled Agile Framework Enterprise (SAFe) to stay synchronized or to re-resynchronize. Techniques for synchronization include:

  1. Matching cadence. All techniques for intergroup synchronization begin with matching cadences. When projects teams need to act in a coordinate fashion either because the functionality they are creating has to integrate or because teams might have to help each other need to be on the same cycle. Matching cadences allows teams to more easily integrate, plan and demonstrate the overall functionality being developed.
  2. Joint Planning. When teams are on the same cadence, they can plan together. Getting groups in the same room to plan allows cross-coordination and communication. For example, SAFe uses two day planning exercises to synchronize the planning for program intervals. I have also seen and led planning exercises for smaller groups Scrum teams that fall below the scale SAFe should be used (yes . . . you can scale SAFe work with groups smaller than 50 if you know what you are doing).
  3. Joint Builds. In a perfect world all teams in a project would be operating on a single, unbranched code base so that daily builds and tests would expose any inconsistencies. In many organizations teams either have not matured to that level of coordination or have technical constraints that preclude continuous integration. Matching cadence allows teams to get to done at the same time and to integrate at the end of every sprint. Integration provides technical feedback that helps the overall project stay on track.
  4. Joint Demonstrations. Demonstrations are to stakeholders what joint builds are to developers. Joint demonstrations provide feedback to help the overall project stay functionally on track.
  5. Scrum of Scrums. The Scrum of Scrums is the meeting of Scrum masters (the concept can and should be used for product owners also) on a periodic basis during a sprint. SAFe suggest twice a week; I typically suggest starting at twice a week and then more often if significant issues or risks crop up that need to shared and coordinated. When teams use slower cadences I generally recommend having Scrum of Scrums meetings more often to ensure that teams stay coordinated.

Using Agile at scale for work that requires more than one team will require adopting some techniques for coordination. Matching the cadence is the first place to start. Teams with the same cadence start and end sprints at the same time, making it possible to plan and demonstrate together. Joint planning and demonstration makes it easier for everyone to hear the same story at the same time. We often apply the analogy of herding to coordinating large projects, however cadence and other Agile techniques can be as useful as a good cowboy and horse for keeping the herd together.


Categories: Process Management

Getting Your Apps Ready for Nexus 6 and Nexus 9

Android Developers Blog - Fri, 10/24/2014 - 00:53

By Katherine Kuan, Developer Advocate

Updated material design Tumblr app on Nexus 6.

Last week, we unveiled the Nexus 6 and Nexus 9, the newest additions to our Nexus family that will ship with Android 5.0 Lollipop. Together, they deliver a pure Google experience, showcasing fresh visual styles with material design, improved performance, and additional features.

Let’s make sure your apps and games are optimized to give your users the best mobile experience on these devices. We’ve outlined some best practices below.

Nexus 6 Screen

The Nexus 6 boasts an impressive 5.96” Quad HD screen display at a resolution of 2560 x 1440 (493 ppi). This translates to ~ 730 x 410 dp (density independent pixels).

Check your assets

It has a quantized density of 560 dpi, which falls in between the xxhdpi and xxxhdpi primary density buckets. For the Nexus 6, the platform will scale down xxxhdpi assets, but if those aren’t available, then it will scale up xxhdpi assets.

Provide at least an xxxhdpi app icon because devices can display large app icons on the launcher. It’s best practice to place your app icons in mipmap- folders (not the drawable- folders) because they are used at resolutions different from the device’s current density. For example, an xxxhdpi app icon can be used on the launcher for an xxhdpi device.

res/
   mipmap-mdpi/
      ic_launcher.png
   mipmap-hdpi/
      ic_launcher.png
   mipmap-xhdpi/
      ic_launcher.png  
   mipmap-xxhdpi/
      ic_launcher.png
   mipmap-xxxhdpi/   
      ic_launcher.png  # App icon used on Nexus 6 device launcher

Choosing to add xxxhdpi versions for the rest of your assets will provide a sharper visual experience on the Nexus 6, but does increase apk size, so you should make an appropriate decision for your app.

res/
   drawable-mdpi/
      ic_sunny.png
   drawable-hdpi/
      ic_sunny.png
   drawable-xhdpi/   
      ic_sunny.png
   drawable-xxhdpi/  # Fall back to these if xxxhdpi versions aren’t available
      ic_sunny.png 
   drawable-xxxhdpi/ # Higher resolution assets for Nexus 6
      ic_sunny.png
Make sure you are not filtered on Google Play

If you are using the <compatible-screens> element in the AndroidManifest.xml file, you should stop using it because it’s not scalable to re-compile and publish your app each time new devices come out. However, if you must use it, make sure to update the manifest to add the configuration for these devices (by screen size and density). Otherwise your app may be excluded from Google Play search results on these devices.

Nexus 9 Screen

The Nexus 9 is a premium 8.9” tablet with a screen size of 2048 x 1536 pixels (288 ppi), which translates to 1024 x 768 dip. This is a 4:3 aspect ratio, which is unique compared to earlier tablets. The Nexus 9 falls into the xhdpi density bucket, and you should already have assets in the drawable-xhdpi folder.

Updated Material Design Wall Street Journal app on Nexus 9.

Enable NDK apps for 64-bit

The Nexus 9 runs on a 64-bit Dual Core processor, which makes it the first Android device to ship with a 64-bit ARM instruction set. Support for 64-bit processors was just added in Android 5.0, so if you have an NDK app, enable it by updating the APP_ABI value in your Application.mk file:

APP_ABI := armeabi armeabi-v7a arm64-v8a x86 x86_64 mips mips64

More detailed instructions are provided in the developer site. You can test your 64-bit enabled app on a physical device with a 64-bit processor running Android 5.0, or take advantage of the recently announced 64-bit emulator in Android Studio.

Update your hardware keyboard support

The Nexus 9 Keyboard Folio will be available as an accessory in Google Play. It’s very important that you don’t lock your app to a single orientation. The Nexus 9’s natural orientation is portrait mode, while it’s used in landscape mode with the keyboard. If you lock to the device’s natural orientation, the app may appear sideways for devices with keyboards.

Users should be able to navigate around the main content of the app with the keyboard, while relying on touch input or keyboard shortcuts for toolbar actions and button bars. Therefore, ensure that your app has proper keyboard navigation and shortcuts for primary actions. Keyboard shortcuts that are invoked with Ctrl + [shortcut] combo can be defined via menu items using:

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/menu_create"
        android:title="@string/menu_create"
        android:alphabeticShortcut="c” />
</menu/>

Alternatively, shortcuts can be defined using Activity#onKeyShortcut or View#onKeyShortcut. Learn more about keyboard actions here.

In MainActivity.java:

@Override
public boolean onKeyShortcut(int keyCode, KeyEvent event) {
    switch (keyCode) {
        case KeyEvent.KEYCODE_R:
            Toast.makeText(this, "Reply", Toast.LENGTH_SHORT).show();
            return true;
        default:
            return super.onKeyShortcut(keyCode, event);
    }
}
Responsive layouts with w- and sw- qualifiers

In order to take advantage of the screen real estate on the Nexus 6 and Nexus 9, we emphasize the importance of responsive design. In the past, if you assumed that landscape mode is significantly wider than portrait mode, you may run into problems on a device like the Nexus 9, which has an aspect ratio of 4:3. Instead of declaring layouts using the layout-land or layout-port resource folder qualifiers, we strongly recommend switching to the w<N>dp width resource folder qualifier so that content is laid out based on available screen width.

Think about content first and foremost. Decide on min and max screen real estate that your content requires, and determine cutoff points at different screen widths where you can modify the layout composition for your app (# of grid columns, multi-pane layout, etc…).

For example, a single pane layout for your main activity on phones can be defined in:

res/layout/activity_main.xml

On larger screen devices, where the current orientation is at least 600dp in width, a new two-pane layout with a list alongside a detail pane could be declared in:

res/layout-w600dp/activity_main.xml

On even larger screen devices, where the current orientation is at least 720dp in width, a new multi-pane layout where the detail pane requires even more horizontal space could be declared in:

res/layout-w720dp/activity_main.xml

As for attributes based on form factor, instead of declaring them in values-large or values-xlarge resource directories, use the sw<N>dp smallest width qualifier. For example, you could style your TextViews to have a medium font size on phones.

In res/values/styles.xml:

<style name="DescriptionTextStyle">
  <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
</style>

Meanwhile, TextViews could have a large font size when the smallest width of the device (taking the minimum of the landscape and portrait widths) is 600dp or wider. This ensures the font size of your app doesn’t change when you rotate this large screen device.

In res/values-sw600dp/styles.xml:

<style name="DescriptionTextStyle">
  <item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
</style> 
Take advantage of 5.0 and Material

Set your android:targetSdkVersion to "21". Take note of the important behavior changes in Android 5.0 Lollipop including ART, the new Android runtime, to ensure that your app continues to run well. You can also leverage new platform APIs like richer notifications.

Nexus 6 and Nexus 9 users will be immersed in the new world of material design, and they’ll expect the same seamless transitions, bold colors, and delightful details from your app. As you invest time in bringing your app up to date with our latest design language, there’s a whole host of resources to help you make the leap, including important new updates to the support library, videos, and a getting started guide. Good luck and we can’t wait to see your apps!

Join the discussion on

+Android Developers
Categories: Programming

GPS on Android Wear Devices

Android Developers Blog - Fri, 10/24/2014 - 00:03

By Wayne Piekarski, Developer Advocate

With the latest release of Android Wear, wearables with built-in GPS like the Sony Smartwatch 3 can now give you a GPS location update directly from the wearable, without a paired phone nearby. You can now build an app like MyTracks that lets a user track their run even when they leave their phone at home. For wearable devices that do not have built-in GPS, a software solution has always existed in Google Play Services that automatically uses the GPS from your connected phone.

The Golfshot wearable app uses built-in GPS to calculate your distance to the next hole, even when you don’t have your phone with you.


Implementing GPS location updates

Implementing GPS location updates for Android Wear is simple. On the wearable, use the FusedLocationProviderApi from Google Play services to request location updates. This is the same API that has been available on mobile, so you can easily reuse your existing code and samples.

FusedLocationProviderApi automatically makes the most power-efficient decision about where to get location updates. If the phone is connected to the wearable, it uses the GPS on the phone and sends the updates to the wearable. If the phone is not connected to the wearable and the wearable has a built-in GPS, then it uses the wearable’s GPS.

One case you’ll need to handle is if the phone is not connected to the wearable and the wearable does not have built-in GPS. You will need to detect this and provide a graceful recovery mechanism, such as a message telling the user to bring their phone with them. However, for the most part, deciding which GPS to use, and sending the position from the phone to the wearable, is handled automatically. You do not need to deal with the low-level implementation details yourself.

Data synchronization

When writing an app that runs on the wearable, you will eventually want to synchronize the data it collects with the paired phone. When the wearable is being taken out for a run, especially with the built-in GPS, there may not be a phone present. So you will want to store your location data using the Data Layer API, and when the phone reconnects with the wearable later, the data will be automatically synchronized.

For more details about how to use the location API, check out the extensive documentation and sample here.

Android Wear apps on Google Play

Also, as a heads up, starting on November 3 with the public release of Android 5.0, you will be able to submit your apps for clearer designation as Android Wear apps on Google Play. If your apps follow the criteria in the Wear App Quality checklist and are accepted as Wear apps on Play, it will be easier for Android Wear users to discover your apps. Stay tuned for more information about how to submit your apps for Android Wear review through the Google Play Developer Console.

Join the discussion on

+Android Developers
Categories: Programming

What If We Could Weaponize Empathy?

Coding Horror - Jeff Atwood - Thu, 10/23/2014 - 19:43

One of my favorite insights on the subject of online community is from Tom Chick:

Here is something I've never articulated because I thought, perhaps naively, it was understood:

The priority for participating on this forum is not the quality of the content. I ultimately don't care how smart or funny or observant you are. Those are plusses, but they're never prerequisites. The priority is on how you treat each other. I expect spats, arguments, occasional insults, and even inevitable grudges. We've all done that. But in the end, I expect you to act like a group of friends who care about each other, no matter how dumb some of us might be, no matter what political opinions some of us hold, no matter what games some of us like or dislike. This community is small enough, intimate enough, that I feel it's a reasonable expectation.

Indeed, disagreement and arguments are inevitable and even healthy parts of any community. The difference between a sane community and a terrifying warzone is the degree to which disagreement is pursued in the community, gated by the level of respect community members have for each other.

In other words, if a fight is important to you, fight nasty. If that means lying, lie. If that means insults, insult. If that means silencing people, silence.

I may be a fan of the smackdown learning model and kayfabe, but I am definitely not a fan of fighting nasty.

I expect you to act like a group of friends who care about each other, no matter how dumb some of us might be, no matter what political opinions some of us hold, no matter what games some of us like or dislike.

There's a word for this: empathy.

One of the first things I learned when I began researching discussion platforms two years ago is the importance of empathy as the fundamental basis of all stable long term communities. The goal of discussion software shouldn't be to teach you how to click the reply button, and how to make bold text, but how to engage in civilized online discussion with other human beings without that discussion inevitably breaking down into the collective howling of wolves.

That's what the discussion software should be teaching you: Empathy.

You. Me. Us. We can all occasionally use a gentle reminder that there is a real human being on the other side of our screen, a person remarkably like us.

I've been immersed in the world of social discussion for two years now, and I keep going back to the well of empathy, time and time again. The first thing we did was start with a solid set of community guidelines on civilized discussion, and I'm proud to say that we ship and prominently feature those guidelines with every copy of Discourse. They are bedrock. But these guidelines only work to the extent that they are understood, and the community helps enforce them.

In Your Community Door, I described the danger of allowing cruel and hateful behavior in your community – behavior so obviously corrosive that it should never be tolerated in any quantity. If your community isn't capable of regularly exorcising the most toxic content, and the people responsible for that kind of content, it's in trouble. Those rare bad apples are group poison.

Hate is easy to recognize. Cruelty is easy to recognize. You do not tolerate these in your community, full stop.

But what about behavior that isn't so obviously corrosive? What about behavior patterns that seem sort of vaguely negative, but … nobody can show you exactly how this behavior is directly hurting anyone? What am I talking about? Take a look at the Flamewarriors Online Discussion Archetypes, a bunch of discussion behaviors that never quite run afoul of the rules, per se, but result in discussions that degenerate, go in circles, or make people not want to be around them.

What we're getting into is shades of grey, the really difficult part of community moderation. I've been working on Discourse long enough to identify some subtle dark patterns of community discussion that – while nowhere near as dangerous as hate and cruelty – are still harmful enough to the overall empathy level of a community that they should be actively recognized when they emerge, and interventions staged.

1. Endless Contrarianism

Disagreement is fine, even expected, provided people can disagree in an agreeable way. But when someone joins your community for the sole purpose of disagreeing, that's Endless Contrarianism.

Example: As an athiest, Edward shows up on a religion discussion area to educate everyone there about the futility of religion. Is that really the purpose of the community? Does anyone in the community expect to defend the very concept of religion while participating there?

If all a community member can seem to contribute is endlessly pointing out how wrong everyone else is, and how everything about this community is headed in the wrong direction – that's not building constructive discussion – or the community. Edward is just arguing for the sake of argument. Take it to debate school.

2. Axe-Grinding

Part of what makes discussion fun is that it's flexible; a variety of topics will be discussed, and those discussions may naturally meander a bit within the context defined by the site and whatever categories of discussion are allowed there. Axe-Grinding is when a user keeps constantly gravitating back to the same pet issue or theme for weeks or months on end.

Example: Sara finds any opportunity to trigger up a GMO debate, no matter what the actual topic is. Viewing Sara's post history, GMO and Monsanto are constant, repeated themes in any context. Sara's negative review of a movie will mention eating GMO popcorn, because it's not really about the movie – it's always about her pet issue.

This kind of inflexible, overbearing single-issue focus tends to drag discussion into strange, unwanted directions, and rapidly becomes tiresome to other participants who have probably heard everything this person has to say on that topic multiple times already. Either Sara needs to let that topic go, or she needs to find a dedicated place (e.g. GMO discussion areas) where others want to discuss it as much as she does, and take it there.

3. Griefing

In discussion, griefing is when someone goes out of their way to bait a particular person for weeks or months on end. By that I mean they pointedly follow them around, choosing to engage on whatever topic that person appears in, and needle the other person in any way they can, but always strictly by the book and not in violation of any rules… technically.

Example: Whenever Joe sees George in a discussion topic, Joe now pops in to represent the opposing position, or point out flaws in George's reasoning. Joe also takes any opportunity to remind people of previous mistakes George made, or times when George was rude.

When the discussion becomes more about the person than the topic, you're in deep trouble. It's not supposed to be about the participants, but the topic at hand. When griefing occurs, the discussion becomes a stage for personal conflict rather than a way to honestly explore topics and have an entertaining discussion. Ideally the root of the conflict between Joe and George can be addressed and resolved, or Joe can be encouraged to move on and leave the conflict behind. Otherwise, one of these users needs to find another place to go.

4. Persistent Negativity

Nobody expects discussions to be all sweetness and light, but neverending vitriol and negativity are giant wet blankets. It's hard to enjoy anything when someone's constantly reminding you how terrible the world is. Persistent negativity is when someone's negative contributions to the discussion far outweigh their positive contributions.

Example: Even long after the game shipped, Fred mentions that the game took far too long to ship, and that it shipped with bugs. He paid a lot of money for this game, and feels he didn't get the enjoyment from the game that was promised for the price. He warns people away from buying expansions because this game has a bad track record and will probably fail. Nobody will be playing it online soon because of all the problems, so why bother even trying? Wherever topics happen to go, Fred is there to tell everyone this game is worse than they knew.

If Fred doesn't have anything positive to contribute, what exactly is the purpose of his participation in that community? What does he hope to achieve? Criticism is welcome, but that shouldn't be the sum total of everything Fred contributes, and he should be reasonably constructive in his criticism. People join communities to build things and celebrate the enjoyment of those things, not have other people dump all over it and constantly describe how much they suck and disappoint them. If there isn't any silver lining in Fred's cloud, and he can't be encouraged to find one, he should be asked to find other places to haunt.

5. Ranting

Discussions are social, and thus emotional. You should feel something. But prolonged, extreme appeal to emotion is fatiguing and incites arguments. Nobody wants to join a dry, technical session at the Harvard Debate Club, because that'd be boring, but there is a big difference between a persuasive post and a straight-up rant.

Example: Holly posts at the extremes – either something is the worst thing that ever happened, or the best thing that ever happened. She will post 6 to 10 times in a topic and state her position as forcefully as possible, for as long and as loud as it takes, to as many individual people in the discussion as it takes, to get her point across. The stronger the language in the post, the better she likes it.

If Holly can't make her point in a reasonable way in one post and a followup, perhaps she should rethink her approach. Yelling at people, turning the volume to 11, and describing the situation in the most emotional, extreme terms possible to elicit a response – unless this really is the worst or best thing to happen in years – is a bit like yelling fire in a crowded theater. It's irresponsible. Either tone it down, or take it somewhere that everyone talks that way.

6. Grudges

In any discussion, there is a general expectation that everyone there is participating in good faith – that they have an open mind, no particular agenda, and no bias against the participants or the topic. While short term disagreement is fine, it's important that the people in your community have the ability to reset and approach each new topic with a clean(ish) slate. When you don't do that, when people carry ill will from previous discussions toward the participants or topic into new discussions, that's a grudge.

Example: Tad strongly disagrees with a decision the community made about not creating a new category to house some discussion he finds problematic. So he now views the other leaders in the community, and the moderators, with great distrust. Tad feels like the community has turned on him, and so he has soured on the community. But he has too much invested here to leave, so Tad now likes to point out all the consequences of this "bad" decision often, and cite it as an example of how the community is going wrong. He also follows another moderator, Steve, around because he views him as the ringleader of the original decision, and continually writes long, critical replies to his posts.

Grudges can easily lead to every other dark community pattern on this list. I cannot emphasize enough how important it is to recognize grudges when they emerge so the community can intervene and point out what's happening, and all the negative consequences of a grudge. It's important in the broadest general life sense not to hold grudges; as the famous quote goes (as near as I can tell, attributed to Alcoholics Anonymous)

Holding a grudge is like drinking poison and expecting the other person to die.

So your community should be educating itself about the danger of grudges, the root of so many other community problems. But it is critically important that moderators never, and I mean never ever, hold grudges. That'd be disastrous.

What can you do?

I made a joke in the title of this post about weaponizing empathy. I'm not sure that's even possible. But you can start by having clear community guidelines, teaching your community to close the door on overt hate, and watching out for any overall empathy erosion caused by the six dark community behavior patterns I outlined above.

At the risk of sounding aspirational, here's one thing I know to be true, and I advise every community to take to heart: I expect you to act like a group of friends who care about each other, no matter how dumb some of us might be, no matter what political opinions some of us hold, no matter what things some of us like or dislike.

[advertisement] Stack Overflow Careers matches the best developers (you!) with the best employers. You can search our job listings or create a profile and even let employers find you.
Categories: Programming

Basis of #NoEstimates are 27 Year Old Reports

Herding Cats - Glen Alleman - Thu, 10/23/2014 - 17:52

The #NoEstimates movement appears to be based on a 27 year old report† that provides examples of FORTRAN and PASCAL programs as the basis on which estimates is done. 

Screen Shot 2014-10-21 at 10.51.54 PM

 

A lot has happend since 1987. For a short crtiique on the Software Crisis report - which is referenced in the #NoEstimates argument, see "There is No Software Engineering Crisis."

  • Parametric modeling tools - the structure of software projects are constrained by the external structures of their components. These can be parameterized for estimating purposes.
  • COCOMO - is an example of a parametic estimating tool. There are several others.
  • Reference Class Forecasting models, have been developed as the result of overruns and disasters in many areas, including SWDev. But now we know and we know better not to succumb to all the biases discovered in the past.
  • Monte Carlo Simulation, using Reference Class Forecasting, there as simple and cheap tools, http://www.riskamp.com/ for example. For $125.00 all the handwaving around forecasting cost, schedule, and other project variables can be modeled with ease. 
  • Object Oriented Programming - old news but no more debugging of FORTRAN "Unnamed COMMON" overwriting floating point numbers!!
  • Component Based Software, where we can buy parts and assemble them.
  • SOA and CORBA (TIBCO) where ETL and Enterprise Bus are the part of the Enterprise Architecture. Stop writing application code and start writing scripts to integrate. BTW the example of having developers write database apps for what is essentially a warehousing app, has missed the COTS, component based solutions bus.
  • FPA, while a bit long in the tooth, but idea is still valid.
  • Databases of Reference Classes
  • The Web and Web components, same as above.
  • CORBA, same as above.
  • All the web based languages
  • All the runtime interpretative languages with built in debuggers, rather compiled code with stop dead runtime debugging. 
  • ERP and COTS products and components, with out of the box functions that remove the need to write any code. Configure the system, sure. Write some scripting code ABAP e.g., but no coding in the developer sense.
  • Software as a Service, where you can buy the solution. That was unheard of in 1986 and 1987.
  • DevOps, another unheard idea back then.
  • Open Source and Reuse

1000's of research and practicum books and papers on how to estimate software projects have be published. Maybe it's time to catch up with the 21st Century approach of estimating the time, cost, and capabilities needed to deliver value for those paying for our work. These approaches answer the mail in the 1987 report, along with the much referenced NATO Software Crisis report published in 1986.

While estimates have always been needed to make decisions in the paradigm of Microeconomics of software development, the techniques, tools, and data have improved dramatically in the last 27 years. Let's acknowldge that and start taking advantage of the efforts to improve our lot in life of being good stewards of other peoples money. And when we hear #Noestimates can be used to forecast completion times and costs at the end, test that idea with activities in the Baloney Claims check list.

————————————

† #NoEstimates is an approach to software development that arose from the observation that large amounts of time were spent over the years in estimating and improving those estimates, but we see no value from that investment. Indeed, according to scholars Conte, Dunmore and Shens [1] a good estimate is one that is within 25% of the actual cost, 75% of the time. in http://www.mystes.fi/agile2014/

As a small aside, that's not what the statement actually says in the context of statistical estimating. It says there is a 75% confidence that there will be on overage of 25% which needs to be covered with management reserve for 25% to protect the budget. Since all project work is probabilistic, uncertainty is both naturally occurring and event based. Event based uncertainty can be reduced by spending money. This is a core concept of Agile development. Do small things to discover what will and won't work. Naturally occurring uncertainty, can only be handled with margin. In this statement - remember it's 27 years old - there is a likelihood that a 25% management reserve will be needed 25% of the time there is a project estimate produced. If you know that ahead of time, it's won't be a disappointment when it occurs 25% of the time.

This is standard best management practice in mature organizations. In some domains, it's mandatory to have Management Reserve built from Monte Carlo Simulations using Reference Classes of past performance.

Related articles How to Estimate Software Development Software Requirements Are Vague How Not To Make Decisions Using Bad Estimates #NoEstimates? #NoProjects? #NoManagers? #NoJustNo
Categories: Project Management

When to Release a Product

Software Requirements Blog - Seilevel.com - Thu, 10/23/2014 - 17:00
One of the projects I’ve been working on over the past year has been particularity challenging; it’s one of those everything that can go wrong does go wrong projects. This is a back office product which automates a process updating data records. The updates are transactional. We were almost done and ready to release when […]
Categories: Requirements

Recap of the 2014 Google Cloud Platform Roadshows

Google Code Blog - Thu, 10/23/2014 - 17:00
We just wrapped up the Google Cloud Platform Roadshows, a series of developer events in 35 cities worldwide, where we reached nearly 4,500 developers spanning the globe, from Texas to Tel Aviv to Tokyo.

Now that the series is finished, we wanted to thank everyone for coming and share with you the slides and live recording of the talks from our New York City event:


The Roadshow team sends huge thanks to everyone who attended and looks forward to seeing you next year. We'd love to hear from you in the meantime:


Posted by Tom Van Waardhuizen, Program Manager
Categories: Programming

Software architecture sketching in Iceland

Coding the Architecture - Simon Brown - Thu, 10/23/2014 - 10:46

I'll be in Iceland next month for the Agile Iceland 2014 conference, which I'm really looking forward to as everybody tells me that Iceland is a fantastic country to visit. While in Iceland, I'll also be running my 1-day software architecture sketching workshop on the 6th of November. If you're interested in learning how to communicate the design of your software in a simple yet effective way without using lots of complex UML diagrams, please do join me. Everybody who attends will also get a copy of my Software Architecture for Developers ebook too. :-)

Categories: Architecture

Neo4j: Cypher – Avoiding the Eager

Mark Needham - Thu, 10/23/2014 - 06:56

Although I love how easy Cypher’s LOAD CSV command makes it to get data into Neo4j, it currently breaks the rule of least surprise in the way it eagerly loads in all rows for some queries even those using periodic commit.

Neverwhere

Beware of the eager pipe

This is something that my colleague Michael noted in the second of his blog posts explaining how to use LOAD CSV successfully:

The biggest issue that people ran into, even when following the advice I gave earlier, was that for large imports of more than one million rows, Cypher ran into an out-of-memory situation.

That was not related to commit sizes, so it happened even with PERIODIC COMMIT of small batches.

I recently spent a few days importing data into Neo4j on a Windows machine with 4GB RAM so I was seeing this problem even earlier than Michael suggested.

Michael explains how to work out whether your query is suffering from unexpected eager evaluation:

If you profile that query you see that there is an “Eager” step in the query plan.

That is where the “pull in all data” happens.

You can profile queries by prefixing the word ‘PROFILE’. You’ll need to run your query in the console of /webadmin in your web browser or with the Neo4j shell.

I did this for my queries and was able to identify query patterns which get evaluated eagerly and in some cases we can work around it.

We’ll use the Northwind data set to demonstrate how the Eager pipe can sneak into our queries but keep in mind that this data set is sufficiently small to not cause issues.

This is what a row in the file looks like:

$ head -n 2 data/customerDb.csv
OrderID,CustomerID,EmployeeID,OrderDate,RequiredDate,ShippedDate,ShipVia,Freight,ShipName,ShipAddress,ShipCity,ShipRegion,ShipPostalCode,ShipCountry,CustomerID,CustomerCompanyName,ContactName,ContactTitle,Address,City,Region,PostalCode,Country,Phone,Fax,EmployeeID,LastName,FirstName,Title,TitleOfCourtesy,BirthDate,HireDate,Address,City,Region,PostalCode,Country,HomePhone,Extension,Photo,Notes,ReportsTo,PhotoPath,OrderID,ProductID,UnitPrice,Quantity,Discount,ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued,SupplierID,SupplierCompanyName,ContactName,ContactTitle,Address,City,Region,PostalCode,Country,Phone,Fax,HomePage,CategoryID,CategoryName,Description,Picture
10248,VINET,5,1996-07-04,1996-08-01,1996-07-16,3,32.38,Vins et alcools Chevalier,59 rue de l'Abbaye,Reims,,51100,France,VINET,Vins et alcools Chevalier,Paul Henriot,Accounting Manager,59 rue de l'Abbaye,Reims,,51100,France,26.47.15.10,26.47.15.11,5,Buchanan,Steven,Sales Manager,Mr.,1955-03-04,1993-10-17,14 Garrett Hill,London,,SW1 8JR,UK,(71) 555-4848,3453,\x,"Steven Buchanan graduated from St. Andrews University, Scotland, with a BSC degree in 1976.  Upon joining the company as a sales representative in 1992, he spent 6 months in an orientation program at the Seattle office and then returned to his permanent post in London.  He was promoted to sales manager in March 1993.  Mr. Buchanan has completed the courses ""Successful Telemarketing"" and ""International Sales Management.""  He is fluent in French.",2,http://accweb/emmployees/buchanan.bmp,10248,11,14,12,0,11,Queso Cabrales,5,4,1 kg pkg.,21,22,30,30,0,5,Cooperativa de Quesos 'Las Cabras',Antonio del Valle Saavedra,Export Administrator,Calle del Rosal 4,Oviedo,Asturias,33007,Spain,(98) 598 76 54,,,4,Dairy Products,Cheeses,\x
MERGE, MERGE, MERGE

The first thing we want to do is create a node for each employee and each order and then create a relationship between them.

We might start with the following query:

USING PERIODIC COMMIT 1000
LOAD CSV WITH HEADERS FROM "file:/Users/markneedham/projects/neo4j-northwind/data/customerDb.csv" AS row
MERGE (employee:Employee {employeeId: row.EmployeeID})
MERGE (order:Order {orderId: row.OrderID})
MERGE (employee)-[:SOLD]->(order)

This does the job but if we profile the query like so…

PROFILE LOAD CSV WITH HEADERS FROM "file:/Users/markneedham/projects/neo4j-northwind/data/customerDb.csv" AS row
WITH row LIMIT 0
MERGE (employee:Employee {employeeId: row.EmployeeID})
MERGE (order:Order {orderId: row.OrderID})
MERGE (employee)-[:SOLD]->(order)

…we’ll notice an ‘Eager’ lurking on the third line:

==> +----------------+------+--------+----------------------------------+-----------------------------------------+
==> |       Operator | Rows | DbHits |                      Identifiers |                                   Other |
==> +----------------+------+--------+----------------------------------+-----------------------------------------+
==> |    EmptyResult |    0 |      0 |                                  |                                         |
==> | UpdateGraph(0) |    0 |      0 |    employee, order,   UNNAMED216 |                            MergePattern |
==> |          Eager |    0 |      0 |                                  |                                         |
==> | UpdateGraph(1) |    0 |      0 | employee, employee, order, order | MergeNode; :Employee; MergeNode; :Order |
==> |          Slice |    0 |      0 |                                  |                            {  AUTOINT0} |
==> |        LoadCSV |    1 |      0 |                              row |                                         |
==> +----------------+------+--------+----------------------------------+-----------------------------------------+

You’ll notice that when we profile each query we’re stripping off the periodic commit section and adding a ‘WITH row LIMIT 0′. This allows us to generate enough of the query plan to identify the ‘Eager’ operator without actually importing any data.

We want to split that query into two so it can be processed in a non eager manner:

USING PERIODIC COMMIT 1000
LOAD CSV WITH HEADERS FROM "file:/Users/markneedham/projects/neo4j-northwind/data/customerDb.csv" AS row
WITH row LIMIT 0
MERGE (employee:Employee {employeeId: row.EmployeeID})
MERGE (order:Order {orderId: row.OrderID})
==> +-------------+------+--------+----------------------------------+-----------------------------------------+
==> |    Operator | Rows | DbHits |                      Identifiers |                                   Other |
==> +-------------+------+--------+----------------------------------+-----------------------------------------+
==> | EmptyResult |    0 |      0 |                                  |                                         |
==> | UpdateGraph |    0 |      0 | employee, employee, order, order | MergeNode; :Employee; MergeNode; :Order |
==> |       Slice |    0 |      0 |                                  |                            {  AUTOINT0} |
==> |     LoadCSV |    1 |      0 |                              row |                                         |
==> +-------------+------+--------+----------------------------------+-----------------------------------------+

Now that we’ve created the employees and orders we can join them together:

USING PERIODIC COMMIT 1000
LOAD CSV WITH HEADERS FROM "file:/Users/markneedham/projects/neo4j-northwind/data/customerDb.csv" AS row
MATCH (employee:Employee {employeeId: row.EmployeeID})
MATCH (order:Order {orderId: row.OrderID})
MERGE (employee)-[:SOLD]->(order)
==> +----------------+------+--------+-------------------------------+-----------------------------------------------------------+
==> |       Operator | Rows | DbHits |                   Identifiers |                                                     Other |
==> +----------------+------+--------+-------------------------------+-----------------------------------------------------------+
==> |    EmptyResult |    0 |      0 |                               |                                                           |
==> |    UpdateGraph |    0 |      0 | employee, order,   UNNAMED216 |                                              MergePattern |
==> |      Filter(0) |    0 |      0 |                               |          Property(order,orderId) == Property(row,OrderID) |
==> | NodeByLabel(0) |    0 |      0 |                  order, order |                                                    :Order |
==> |      Filter(1) |    0 |      0 |                               | Property(employee,employeeId) == Property(row,EmployeeID) |
==> | NodeByLabel(1) |    0 |      0 |            employee, employee |                                                 :Employee |
==> |          Slice |    0 |      0 |                               |                                              {  AUTOINT0} |
==> |        LoadCSV |    1 |      0 |                           row |                                                           |
==> +----------------+------+--------+-------------------------------+-----------------------------------------------------------+

Not an Eager in sight!

MATCH, MATCH, MATCH, MERGE, MERGE

If we fast forward a few steps we may now have refactored our import script to the point where we create our nodes in one query and the relationships in another query.

Our create query works as expected:

USING PERIODIC COMMIT 1000
LOAD CSV WITH HEADERS FROM "file:/Users/markneedham/projects/neo4j-northwind/data/customerDb.csv" AS row
MERGE (employee:Employee {employeeId: row.EmployeeID})
MERGE (order:Order {orderId: row.OrderID})
MERGE (product:Product {productId: row.ProductID})
==> +-------------+------+--------+----------------------------------------------------+--------------------------------------------------------------+
==> |    Operator | Rows | DbHits |                                        Identifiers |                                                        Other |
==> +-------------+------+--------+----------------------------------------------------+--------------------------------------------------------------+
==> | EmptyResult |    0 |      0 |                                                    |                                                              |
==> | UpdateGraph |    0 |      0 | employee, employee, order, order, product, product | MergeNode; :Employee; MergeNode; :Order; MergeNode; :Product |
==> |       Slice |    0 |      0 |                                                    |                                                 {  AUTOINT0} |
==> |     LoadCSV |    1 |      0 |                                                row |                                                              |
==> +-------------+------+--------+----------------------------------------------------+------------------------------------------------------------

We’ve now got employees, products and orders in the graph. Now let’s create relationships between the trio:

USING PERIODIC COMMIT 1000
LOAD CSV WITH HEADERS FROM "file:/Users/markneedham/projects/neo4j-northwind/data/customerDb.csv" AS row
MATCH (employee:Employee {employeeId: row.EmployeeID})
MATCH (order:Order {orderId: row.OrderID})
MATCH (product:Product {productId: row.ProductID})
MERGE (employee)-[:SOLD]->(order)
MERGE (order)-[:PRODUCT]->(product)

If we profile that we’ll notice Eager has sneaked in again!

==> +----------------+------+--------+-------------------------------+-----------------------------------------------------------+
==> |       Operator | Rows | DbHits |                   Identifiers |                                                     Other |
==> +----------------+------+--------+-------------------------------+-----------------------------------------------------------+
==> |    EmptyResult |    0 |      0 |                               |                                                           |
==> | UpdateGraph(0) |    0 |      0 |  order, product,   UNNAMED318 |                                              MergePattern |
==> |          Eager |    0 |      0 |                               |                                                           |
==> | UpdateGraph(1) |    0 |      0 | employee, order,   UNNAMED287 |                                              MergePattern |
==> |      Filter(0) |    0 |      0 |                               |    Property(product,productId) == Property(row,ProductID) |
==> | NodeByLabel(0) |    0 |      0 |              product, product |                                                  :Product |
==> |      Filter(1) |    0 |      0 |                               |          Property(order,orderId) == Property(row,OrderID) |
==> | NodeByLabel(1) |    0 |      0 |                  order, order |                                                    :Order |
==> |      Filter(2) |    0 |      0 |                               | Property(employee,employeeId) == Property(row,EmployeeID) |
==> | NodeByLabel(2) |    0 |      0 |            employee, employee |                                                 :Employee |
==> |          Slice |    0 |      0 |                               |                                              {  AUTOINT0} |
==> |        LoadCSV |    1 |      0 |                           row |                                                           |
==> +----------------+------+--------+-------------------------------+-----------------------------------------------------------+

In this case the Eager happens on our second call to MERGE as Michael identified in his post:

The issue is that within a single Cypher statement you have to isolate changes that affect matches further on, e.g. when you CREATE nodes with a label that are suddenly matched by a later MATCH or MERGE operation.

We can work around the problem in this case by having separate queries to create the relationships:

LOAD CSV WITH HEADERS FROM "file:/Users/markneedham/projects/neo4j-northwind/data/customerDb.csv" AS row
MATCH (employee:Employee {employeeId: row.EmployeeID})
MATCH (order:Order {orderId: row.OrderID})
MERGE (employee)-[:SOLD]->(order)
==> +----------------+------+--------+-------------------------------+-----------------------------------------------------------+
==> |       Operator | Rows | DbHits |                   Identifiers |                                                     Other |
==> +----------------+------+--------+-------------------------------+-----------------------------------------------------------+
==> |    EmptyResult |    0 |      0 |                               |                                                           |
==> |    UpdateGraph |    0 |      0 | employee, order,   UNNAMED236 |                                              MergePattern |
==> |      Filter(0) |    0 |      0 |                               |          Property(order,orderId) == Property(row,OrderID) |
==> | NodeByLabel(0) |    0 |      0 |                  order, order |                                                    :Order |
==> |      Filter(1) |    0 |      0 |                               | Property(employee,employeeId) == Property(row,EmployeeID) |
==> | NodeByLabel(1) |    0 |      0 |            employee, employee |                                                 :Employee |
==> |          Slice |    0 |      0 |                               |                                              {  AUTOINT0} |
==> |        LoadCSV |    1 |      0 |                           row |                                                           |
==> +----------------+------+--------+-------------------------------+-----------------------------------------------------------+
USING PERIODIC COMMIT 1000
LOAD CSV WITH HEADERS FROM "file:/Users/markneedham/projects/neo4j-northwind/data/customerDb.csv" AS row
MATCH (order:Order {orderId: row.OrderID})
MATCH (product:Product {productId: row.ProductID})
MERGE (order)-[:PRODUCT]->(product)
==> +----------------+------+--------+------------------------------+--------------------------------------------------------+
==> |       Operator | Rows | DbHits |                  Identifiers |                                                  Other |
==> +----------------+------+--------+------------------------------+--------------------------------------------------------+
==> |    EmptyResult |    0 |      0 |                              |                                                        |
==> |    UpdateGraph |    0 |      0 | order, product,   UNNAMED229 |                                           MergePattern |
==> |      Filter(0) |    0 |      0 |                              | Property(product,productId) == Property(row,ProductID) |
==> | NodeByLabel(0) |    0 |      0 |             product, product |                                               :Product |
==> |      Filter(1) |    0 |      0 |                              |       Property(order,orderId) == Property(row,OrderID) |
==> | NodeByLabel(1) |    0 |      0 |                 order, order |                                                 :Order |
==> |          Slice |    0 |      0 |                              |                                           {  AUTOINT0} |
==> |        LoadCSV |    1 |      0 |                          row |                                                        |
==> +----------------+------+--------+------------------------------+--------------------------------------------------------+
MERGE, SET

I try to make LOAD CSV scripts as idempotent as possible so that if we add more rows or columns of data to our CSV we can rerun the query without having to recreate everything.

This can lead you towards the following pattern where we’re creating suppliers:

USING PERIODIC COMMIT 1000
LOAD CSV WITH HEADERS FROM "file:/Users/markneedham/projects/neo4j-northwind/data/customerDb.csv" AS row
MERGE (supplier:Supplier {supplierId: row.SupplierID})
SET supplier.companyName = row.SupplierCompanyName

We want to ensure that there’s only one Supplier with that SupplierID but we might be incrementally adding new properties and decide to just replace everything by using the ‘SET’ command. If we profile that query, the Eager lurks:

==> +----------------+------+--------+--------------------+----------------------+
==> |       Operator | Rows | DbHits |        Identifiers |                Other |
==> +----------------+------+--------+--------------------+----------------------+
==> |    EmptyResult |    0 |      0 |                    |                      |
==> | UpdateGraph(0) |    0 |      0 |                    |          PropertySet |
==> |          Eager |    0 |      0 |                    |                      |
==> | UpdateGraph(1) |    0 |      0 | supplier, supplier | MergeNode; :Supplier |
==> |          Slice |    0 |      0 |                    |         {  AUTOINT0} |
==> |        LoadCSV |    1 |      0 |                row |                      |
==> +----------------+------+--------+--------------------+----------------------+

We can work around this at the cost of a bit of duplication using ‘ON CREATE SET’ and ‘ON MATCH SET':

USING PERIODIC COMMIT 1000
LOAD CSV WITH HEADERS FROM "file:/Users/markneedham/projects/neo4j-northwind/data/customerDb.csv" AS row
MERGE (supplier:Supplier {supplierId: row.SupplierID})
ON CREATE SET supplier.companyName = row.SupplierCompanyName
ON MATCH SET supplier.companyName = row.SupplierCompanyName
==> +-------------+------+--------+--------------------+----------------------+
==> |    Operator | Rows | DbHits |        Identifiers |                Other |
==> +-------------+------+--------+--------------------+----------------------+
==> | EmptyResult |    0 |      0 |                    |                      |
==> | UpdateGraph |    0 |      0 | supplier, supplier | MergeNode; :Supplier |
==> |       Slice |    0 |      0 |                    |         {  AUTOINT0} |
==> |     LoadCSV |    1 |      0 |                row |                      |
==> +-------------+------+--------+--------------------+----------------------+

With the data set I’ve been working with I was able to avoid OutOfMemory exceptions in some cases and reduce the amount of time it took to run the query by a factor of 3 in others.

As time goes on I expect all of these scenarios will be addressed but as of Neo4j 2.1.5 these are the patterns that I’ve identified as being overly eager.

If you know of any others do let me know and I can add them to the post or write a second part.

Categories: Programming