Playgrounds and why to use them
Imagine that you have a task to develop a package or a library. For example, during the last refactoring session, someone mentioned that a piece of functionality should be extracted into a separate package. Or, the company made a decision to open-source a part of internal software or developments. Or, you just have an interesting idea that you want to make public. In all these situations you have to start somewhere. One of the possible ways is to start just from a playground.
A couple of years ago, I read a fascinating book Growing Object-Oriented Software, Guided by Tests
. In the fourth chapter you will find an idea that any project should start with "build, deploy, and test". The authors further explain that the preferable way to do it is to build, deploy and test a “walking skeleton” (an implementation of the thinnest possible slice of real functionality that we can automatically build, deploy, and test end-to-end.). Only after accomplishing that, everything will be in place for test-driven development. Even though this idea might seem unusual, it makes lots of sense.
Let’s try to implement this idea. When you have a big application, it is obvious how you can implement this approach; just set up and start using a test/staging server. But, what if you write a package or a library? Should you do the same? Would it be worth the time? This is exactly how I came up with the idea of playgrounds.
The idea of a playground is pretty simple. Before implementing any functionality within a new package/library, you should create a very simple app/program that is going to use it. Ideally, you put yourself in the client’s shoes and try to imagine how a client would use your package/library. This step will lead to a more client-oriented oriented interface. However, in some cases, the interface is already defined. Then, you identify the simplest use case, implement it, and run you playground with this simplest use case. So, we start with a “walking skeleton”.
A playground is a simple application or a program that uses a piece of software in development as a dependency. It contains a few important use cases, including edge cases, and provides fast feedback in a short visual form.
Then, while you develop your code, you use the following strategy. Whenever you encounter an edge case or a piece of functionality that seems complex or crucial for the client, you reflect its usage in the playground by updating an existing use case or creating a new one. Each of these use cases should provide clear and demonstrative visual output. Btw, using the playground does not mean that you shouldn’t write any tests or avoid other good practices. No, it’s just an additional tool that is going to additionally cover the edge cases and important parts of functionality.
Even if you don’t agree with the start from the “build, deploy, and test“ idea, playgrounds are still useful. You can just identify two of the three most important use cases and use them in the playground with the predefined data. Even if you have a staging server or environment and you prefer testing your libraries in a whole application, I highly recommend you to create a playground for each library. It will give you the possibility to look at the usage of the library from the very different way that you are not used to use and, eventually, give you some insights and ideas for improvements.
One might call it a form of manual testing, but that’s not quite right. With manual testing, you have to do a sequence of actions to get and check the final result. Using a playground doesn’t require it. You just run a short app/program and check the results visually (or visually compare the results with the previous executions).
There are some obvious benefits in using playgrounds. They allow:
- using the package/library from the client’s side (it gives insights for improvements)
- using the package/library outside of the production, staging, and/or testing environments
- using whatever stability version you want without affecting other dependencies
- checking the correctness of new releases (a fast visual feedback that everything works)
- checking the smoothness of update process (especially, if configurations should be updated)
- using a development branch within a playground
- getting a fast feedback for edge cases
- getting a fast feedback for regressions
There is another significant benefit that I want to describe in more details. As playgrounds are very simple and easy to create, they can be easily duplicated. The duplicated playgrounds can be used as development environments for new features. Imagine that you have something interesting to implement, but it is too vague, and you don’t know where to start and where it's going to go. Just copy a playground and play around with a copy without worrying that you can break something. Sure, that the same can be done in a new branch, but in the playground you interact with your package/library from the client's side. When you are done and you have the direction for the new feature, just delete the copy. In addition, due to their simplicity, the playgrounds can be easily moved, put in different environments, containerized, added to CI/CD pipelines, etc.
But, what is even more important for me is the possibility to get the fast feedback for the crucial and important use cases. Especially when new releases come out. Even if your code is fully covered by tests, it doesn’t guarantee that the code works correctly or as expected. So, creating and using a playground gives me a little bit more confidence that the code works as expected. And, if it is well organized, it doesn’t take long not to create it, nor to run it with a new release.
Comment this page: