Testing Blog

Discomfort as a Tool for Change

Monday, February 13, 2017
Share on Twitter Share on Facebook
Google
Labels: Dave Gladfelter

8 comments :

  1. taeoldFebruary 13, 2017 at 3:22:00 PM PST

    Thanks for a fun post - I enjoyed reading it.

    A short question w.r.t. SWEs writing APIs and the fakes. If writing fakes is painful enough to incentivize SWEs to write good and simple APIs, wouldn't the same force incentivize the SWEs to update the APIs? API design is hard to thing to get it right - even more so on the first attempt. If the SWEs are now responsible for updating Fakes (which I assume to be less than pleasant), wouldn't they shy away from improving the API?

    ReplyDelete
    Replies
    1. Dave GFebruary 14, 2017 at 8:25:00 AM PST

      Thanks for the question, taeold. I agree that all else being equal, if you make something more expensive it'll happen less.

      Usually API changes are actually additions. It's hard to change the black box behavior of a service in a loosely-coupled system because you have to convince all clients to migrate to expect the new reponse.

      Off the top of my head, API definitions or black-box behavior can change for several reasons:

      1) The API leaks implementation details and the implementation needs to change for some reason.
      2) A new feature is added.
      3) The domain changes. (typically rare)
      4) There is an error in the implementation that leaks bad API responses.

      API owners are motivated by management performance reviews. For 2-4, they will be given poor marks if they do not respond to defects and changing business demands, so they will implement the changes and update the Fake despite the additional cost.

      Almost all bad APIs I've seen are examples of 1. This is a symptom of a bad design and probably made the Fake hard to write in the first place. In a system that hides no implementation details, the Fake is as complicated as the original system. I would hope that teams in this situation would come to the awareness of their fundamental problem and fix it since that would lower long-term costs for everyone.

      A few years ago I worked with a team whose primary query API sent clients the entire storage record, which was a kind of state machine snapshot, consisting of dozens of poorly-defined, nested, high-cardinality fields. Clients generally only needed one or two pieces of data, but they had little guidance as what was public and unchanging and often picked an internal, implementation-specific field to use. The service owners didn't know what clients needed because they were internally focused. Imagine how hard that API would be to support with a Fake and how motivated that team would be to learn what the domain actually was and implement an API using that knowledge if a realistic Fake was mandatory.

      Dave

      p.s. In case you're curious, the team eventually did move to a better API. They came to realize how much their API constrained their implementation since any internal change was a potential hard-to-debug defect only caught in integration tests.

      Delete
      Replies
        Reply
    2. taeoldFebruary 14, 2017 at 10:41:00 AM PST

      Thanks for your thorough reply Dave.

      I've neglected to think about the many other factors at play in a significant API change; substantial rewrite of a fake may only play a minor role. But the motivation write a good API to make it easy to write fakes is at full force in both initial design and painful redesign of the API.

      Daniel

      Delete
      Replies
        Reply
    3. Reply
  2. UnknownFebruary 15, 2017 at 2:30:00 PM PST

    Very nice post Dave

    ReplyDelete
    Replies
      Reply
  3. AnonymousFebruary 23, 2017 at 5:43:00 AM PST

    Hi Dave - Thank you for writing out this post to minimize product-wide problems. In particular I was interested in Fakes as a solution to identify if an API is easy to use. I don't know if this would be the right place to inquire implementation details of Fakes but thought I would ask:

    1) Is Fakes a good way for controlling the underlying persisted data(test data/fixtures) which the actual service use to generate the responses?

    2) And if so, Should Fakes also implement ways to insert and delete test data/fixtures?

    ReplyDelete
    Replies
    1. Dave GladfelterFebruary 23, 2017 at 11:11:00 AM PST

      > 1) Is Fakes a good way for controlling the underlying persisted data(test data/fixtures) which the actual service use to generate the responses?

      I think the answer to your question is entirely dependent on your architecture. The only hard-and-fast definition of Fakes is that they are simplified implementations of the service useful for functional testing.

      I work on a product now where the external API is basically a filesystem as web service, so a good Fake at that level would definitely not control an underlying persistent datastore but would most likely use an in-memory representation. I've worked on a product where there are multiple levels of bidirectional-interacting services, some of which touch the same underlying datastores or otherwise have side communication channels such that you can't write a Fake of service A without some way of propagating state changes (side-effects) to the Fake of service B.

      It's probable that there are domains where such a complex, coupled architecture is inevitable. In those cases, the Fakes would have to have some communication channel, and it might be by talking to a lightweight common storage. However, I think it's likely that when confronted with the complication of writing and maintaining a web of interacting Fakes, teams will realize that there are better architectural alternatives (e.g. isolated microservices) in many cases. In either case, it's not the Fakes that make life difficult, they simply put the pain that is felt by the clients onto the service owners.

      > 2) And if so, Should Fakes also implement ways to insert and delete test data/fixtures?

      I think based on my answer to 1) the general answer is "no". For test fixtures using Fakes I expect the Fakes to provide seeded data for read-only services and for the test to generate the test data during the setup phase by making writes to read/write services' Fakes. I don't expect any of that data to reach a real database like Bigtable or MySQL because such heavy-weight dependencies are inappropriate for functional tests.

      My approach to test data in end-to-end (Fake-less) tests is to generate it using the public APIs of the system, since they are least likely to change in ways that cause the data to violate the data stores' schema and most likely to generate realistic data (aside from thorny issues such as legacy/migrated data.)

      Delete
      Replies
        Reply
    2. Reply
  4. gallauJune 5, 2017 at 5:22:00 AM PDT

    Hi David I enjoyed your post, with fakes in your experience would you design them to support prod like response times delays or is production response delays a feature more suitable more a mock stub framework? I am asking this from a performance testing point of view. Thanks again for the post

    ReplyDelete
    Replies
    1. Dave GladfelterJune 27, 2017 at 1:59:00 PM PDT

      Hi John, I've helped SWEs add statistical delay strategies into fakes and that's worked fine. At Google we have a very standardized RPC system such that the often easier choice is to insert transparent, data-driven proxies that can fuzz timing as needed. In the case above the bespoke delay code was for performance testing a third-party, non-Google interaction so there was no existing infrastructure for inserting performance delays. If you have a common RPC mechanism, using dynamic proxies is the more general, lower-maintenance solution.

      Delete
      Replies
        Reply
    2. Reply
Add comment
Load more...

The comments you read and contribute here belong only to the person who posted them. We reserve the right to remove off-topic comments.

  

Labels


  • TotT 104
  • GTAC 61
  • James Whittaker 42
  • Misko Hevery 32
  • Code Health 31
  • Anthony Vallone 27
  • Patrick Copeland 23
  • Jobs 18
  • Andrew Trenk 13
  • C++ 11
  • Patrik Höglund 8
  • JavaScript 7
  • Allen Hutchison 6
  • George Pirocanac 6
  • Zhanyong Wan 6
  • Harry Robinson 5
  • Java 5
  • Julian Harty 5
  • Adam Bender 4
  • Alberto Savoia 4
  • Ben Yu 4
  • Erik Kuefler 4
  • Philip Zembrod 4
  • Shyam Seshadri 4
  • Chrome 3
  • Dillon Bly 3
  • John Thomas 3
  • Lesley Katzen 3
  • Marc Kaplan 3
  • Markus Clermont 3
  • Max Kanat-Alexander 3
  • Sonal Shah 3
  • APIs 2
  • Abhishek Arya 2
  • Alan Myrvold 2
  • Alek Icev 2
  • Android 2
  • April Fools 2
  • Chaitali Narla 2
  • Chris Lewis 2
  • Chrome OS 2
  • Diego Salas 2
  • Dori Reuveni 2
  • Jason Arbon 2
  • Jochen Wuttke 2
  • Kostya Serebryany 2
  • Marc Eaddy 2
  • Marko Ivanković 2
  • Mobile 2
  • Oliver Chang 2
  • Simon Stewart 2
  • Stefan Kennedy 2
  • Test Flakiness 2
  • Titus Winters 2
  • Tony Voellm 2
  • WebRTC 2
  • Yiming Sun 2
  • Yvette Nameth 2
  • Zuri Kemp 2
  • Aaron Jacobs 1
  • Adam Porter 1
  • Adam Raider 1
  • Adel Saoud 1
  • Alan Faulkner 1
  • Alex Eagle 1
  • Amy Fu 1
  • Anantha Keesara 1
  • Antoine Picard 1
  • App Engine 1
  • Ari Shamash 1
  • Arif Sukoco 1
  • Benjamin Pick 1
  • Bob Nystrom 1
  • Bruce Leban 1
  • Carlos Arguelles 1
  • Carlos Israel Ortiz García 1
  • Cathal Weakliam 1
  • Christopher Semturs 1
  • Clay Murphy 1
  • Dagang Wei 1
  • Dan Maksimovich 1
  • Dan Shi 1
  • Dan Willemsen 1
  • Dave Chen 1
  • Dave Gladfelter 1
  • David Bendory 1
  • David Mandelberg 1
  • Derek Snyder 1
  • Diego Cavalcanti 1
  • Dmitry Vyukov 1
  • Eduardo Bravo Ortiz 1
  • Ekaterina Kamenskaya 1
  • Elliott Karpilovsky 1
  • Elliotte Rusty Harold 1
  • Espresso 1
  • Felipe Sodré 1
  • Francois Aube 1
  • Gene Volovich 1
  • Google+ 1
  • Goran Petrovic 1
  • Goranka Bjedov 1
  • Hank Duan 1
  • Havard Rast Blok 1
  • Hongfei Ding 1
  • Jason Elbaum 1
  • Jason Huggins 1
  • Jay Han 1
  • Jeff Hoy 1
  • Jeff Listfield 1
  • Jessica Tomechak 1
  • Jim Reardon 1
  • Joe Allan Muharsky 1
  • Joel Hynoski 1
  • John Micco 1
  • John Penix 1
  • Jonathan Rockway 1
  • Jonathan Velasquez 1
  • Josh Armour 1
  • Julie Ralph 1
  • Kai Kent 1
  • Kanu Tewary 1
  • Karin Lundberg 1
  • Kaue Silveira 1
  • Kevin Bourrillion 1
  • Kevin Graney 1
  • Kirkland 1
  • Kurt Alfred Kluever 1
  • Manjusha Parvathaneni 1
  • Marek Kiszkis 1
  • Marius Latinis 1
  • Mark Ivey 1
  • Mark Manley 1
  • Mark Striebeck 1
  • Matt Lowrie 1
  • Meredith Whittaker 1
  • Michael Bachman 1
  • Michael Klepikov 1
  • Mike Aizatsky 1
  • Mike Wacker 1
  • Mona El Mahdy 1
  • Noel Yap 1
  • Palak Bansal 1
  • Patricia Legaspi 1
  • Per Jacobsson 1
  • Peter Arrenbrecht 1
  • Peter Spragins 1
  • Phil Norman 1
  • Phil Rollet 1
  • Pooja Gupta 1
  • Project Showcase 1
  • Radoslav Vasilev 1
  • Rajat Dewan 1
  • Rajat Jain 1
  • Rich Martin 1
  • Richard Bustamante 1
  • Roshan Sembacuttiaratchy 1
  • Ruslan Khamitov 1
  • Sam Lee 1
  • Sean Jordan 1
  • Sebastian Dörner 1
  • Sharon Zhou 1
  • Shiva Garg 1
  • Siddartha Janga 1
  • Simran Basi 1
  • Stan Chan 1
  • Stephen Ng 1
  • Tejas Shah 1
  • Test Analytics 1
  • Test Engineer 1
  • Tim Lyakhovetskiy 1
  • Tom O'Neill 1
  • Vojta Jína 1
  • automation 1
  • dead code 1
  • iOS 1
  • mutation testing 1


Archive


  • ►  2025 (1)
    • ►  Jan (1)
  • ►  2024 (13)
    • ►  Dec (1)
    • ►  Oct (1)
    • ►  Sep (1)
    • ►  Aug (1)
    • ►  Jul (1)
    • ►  May (3)
    • ►  Apr (3)
    • ►  Mar (1)
    • ►  Feb (1)
  • ►  2023 (14)
    • ►  Dec (2)
    • ►  Nov (2)
    • ►  Oct (5)
    • ►  Sep (3)
    • ►  Aug (1)
    • ►  Apr (1)
  • ►  2022 (2)
    • ►  Feb (2)
  • ►  2021 (3)
    • ►  Jun (1)
    • ►  Apr (1)
    • ►  Mar (1)
  • ►  2020 (8)
    • ►  Dec (2)
    • ►  Nov (1)
    • ►  Oct (1)
    • ►  Aug (2)
    • ►  Jul (1)
    • ►  May (1)
  • ►  2019 (4)
    • ►  Dec (1)
    • ►  Nov (1)
    • ►  Jul (1)
    • ►  Jan (1)
  • ►  2018 (7)
    • ►  Nov (1)
    • ►  Sep (1)
    • ►  Jul (1)
    • ►  Jun (2)
    • ►  May (1)
    • ►  Feb (1)
  • ▼  2017 (17)
    • ►  Dec (1)
    • ►  Nov (1)
    • ►  Oct (1)
    • ►  Sep (1)
    • ►  Aug (1)
    • ►  Jul (2)
    • ►  Jun (2)
    • ►  May (3)
    • ►  Apr (2)
    • ▼  Feb (1)
      • Discomfort as a Tool for Change
    • ►  Jan (2)
  • ►  2016 (15)
    • ►  Dec (1)
    • ►  Nov (2)
    • ►  Oct (1)
    • ►  Sep (2)
    • ►  Aug (1)
    • ►  Jun (2)
    • ►  May (3)
    • ►  Apr (1)
    • ►  Mar (1)
    • ►  Feb (1)
  • ►  2015 (14)
    • ►  Dec (1)
    • ►  Nov (1)
    • ►  Oct (2)
    • ►  Aug (1)
    • ►  Jun (1)
    • ►  May (2)
    • ►  Apr (2)
    • ►  Mar (1)
    • ►  Feb (1)
    • ►  Jan (2)
  • ►  2014 (24)
    • ►  Dec (2)
    • ►  Nov (1)
    • ►  Oct (2)
    • ►  Sep (2)
    • ►  Aug (2)
    • ►  Jul (3)
    • ►  Jun (3)
    • ►  May (2)
    • ►  Apr (2)
    • ►  Mar (2)
    • ►  Feb (1)
    • ►  Jan (2)
  • ►  2013 (16)
    • ►  Dec (1)
    • ►  Nov (1)
    • ►  Oct (1)
    • ►  Aug (2)
    • ►  Jul (1)
    • ►  Jun (2)
    • ►  May (2)
    • ►  Apr (2)
    • ►  Mar (2)
    • ►  Jan (2)
  • ►  2012 (11)
    • ►  Dec (1)
    • ►  Nov (2)
    • ►  Oct (3)
    • ►  Sep (1)
    • ►  Aug (4)
  • ►  2011 (39)
    • ►  Nov (2)
    • ►  Oct (5)
    • ►  Sep (2)
    • ►  Aug (4)
    • ►  Jul (2)
    • ►  Jun (5)
    • ►  May (4)
    • ►  Apr (3)
    • ►  Mar (4)
    • ►  Feb (5)
    • ►  Jan (3)
  • ►  2010 (37)
    • ►  Dec (3)
    • ►  Nov (3)
    • ►  Oct (4)
    • ►  Sep (8)
    • ►  Aug (3)
    • ►  Jul (3)
    • ►  Jun (2)
    • ►  May (2)
    • ►  Apr (3)
    • ►  Mar (3)
    • ►  Feb (2)
    • ►  Jan (1)
  • ►  2009 (54)
    • ►  Dec (3)
    • ►  Nov (2)
    • ►  Oct (3)
    • ►  Sep (5)
    • ►  Aug (4)
    • ►  Jul (15)
    • ►  Jun (8)
    • ►  May (3)
    • ►  Apr (2)
    • ►  Feb (5)
    • ►  Jan (4)
  • ►  2008 (75)
    • ►  Dec (6)
    • ►  Nov (8)
    • ►  Oct (9)
    • ►  Sep (8)
    • ►  Aug (9)
    • ►  Jul (9)
    • ►  Jun (6)
    • ►  May (6)
    • ►  Apr (4)
    • ►  Mar (4)
    • ►  Feb (4)
    • ►  Jan (2)
  • ►  2007 (41)
    • ►  Oct (6)
    • ►  Sep (5)
    • ►  Aug (3)
    • ►  Jul (2)
    • ►  Jun (2)
    • ►  May (2)
    • ►  Apr (7)
    • ►  Mar (5)
    • ►  Feb (5)
    • ►  Jan (4)

Feed

  • Google
  • Privacy
  • Terms