I am not a product manager but I dabble. At work we've recently started an initiative that really needs some proper user story mapping (in my humble opinion). We're a fully distributed team and our goto for this kind of thing is Miro.
Because of the nature of this project, I have a lot of documentation to comb through and lot of user story cards to create and organize. The problem is, I'm too impatient to create them directly in Miro with all that pointing and clicking and rewriting.
I know google sheets can be copied to Miro boards and the data will be imported as sticky notes. I also know that google sheets can be uploaded as CSV files.
Here is the idea: a script for quickly entering user stories and exporting those user stories as a CSV file that can be uploaded to Google Sheets. I have reasons to spend more time with Python, so that is what I'm going to write this script in.
I'm going to build this script progressively.
Collecting input
Let's start by collecting input.
role = input("As a(n): ")
function = input("I want to: ")
outcome = input("So that: ")
print(f"As a(n) {role} I want to {function} so that {outcome}")
Easy enough. Python gives us the input()
method and these nice f-strings
for string interpolation.
Run the script and you can input your information but the script will terminate as soon as you've typed in your first story. That is no good because I want to input many stories. So after I'm done completing one story, I want it to prompt me again. I'll add a while loop:
while True:
role = input("As a(n): ")
function = input("I want to: ")
outcome = input("So that: ")
print(f"As a(n) {role} I want to {function} so that {outcome}\n\n")
Now we're looping forever (or until you press Ctrl-C). I've also added two line breaks at the end of the last line so there is some space between stories. The only issue is that the formatting is a little funky. I'd like it to clear the screen after each story so the console does not get crowded:
import os
os.system("clear")
while True:
role = input("As a(n): ")
function = input("I want to: ")
outcome = input("So that: ")
os.system("clear")
print(f"As a(n) {role} I want to {function} so that {outcome}\n\n")
We import the os
module and send the clear
command to the console after each story is input.
Writing the stories to a CSV file
So how do we write to a file in python?
import os
os.system("clear")
file = open("stories.csv", "w")
try:
while True:
role = input("As a(n): ")
function = input("I want to: ")
outcome = input("So that: ")
os.system("clear")
file.write(f"As a(n) {role} I want to {function} so that {outcome}\n")
except KeyboardInterrupt:
file.close()
os.system("clear")
print("g'bye")
Python gives us the open()
function which takes the name of the file to write to and the mode to open the file with. (In this case "w" for write.) We need to make sure to close the file when we're done with it so I added a try/except block. By catching the KeyboardInterrupt
function in the except block, I can close the file when Ctrl-C is pressed.
Testing and Loose Ends
I just ran a simple manual test: run the script, upload the resulting CSV file to google sheets and copy-paste the cells from that sheet to Miro. It works like a charm.
The last thing I want to do is clean up the hardcoded file name so the user can change it if they'd like:
import os
os.system("clear")
file_path = input("Path to stories csv (./stories.csv): ")
file_path = "stories.csv" if file_path == "" else file_path
print(f"Writing stories to {file_path}\n\n")
file = open(file_path, "w")
try:
while True:
role = input("As a(n): ")
function = input("I want to: ")
outcome = input("So that: ")
os.system("clear")
file.write(f"As a(n) {role} I want to {function} so that {outcome}\n")
except KeyboardInterrupt:
file.close()
os.system("clear")
print("g'bye")
I've prompted the user for a file name and provided a default.
Since we're accepting user input for the filename, the user can give us a bad filename and this would cause the script to output a terrible looking error. Since I'm the only user of this script, I normally wouldn't mind too much. But since I'm also getting comfortable with Python, let's make it nicer.
To do that, I need to figure out what error Python will give me if we provide a bad filename. Try giving it a filename like "~/blah blah %$#@ no" and see what happens. We get a FileNotFoundError
.
What do we want to do when we get this error? We can force the default filename, or we can end the script with a friendly message. I like the last option so I don't accidentally write over a file that maybe I wanted to keep around.
#!/usr/bin/env python3
import os
os.system("clear")
file_path = input("Path to stories csv (./stories.csv): ")
file_path = "stories.csv" if file_path == "" else file_path
try:
file = open(file_path, "w")
print(f"Writing stories to {file_path}\n\n")
while True:
role = input("As a(n): ")
function = input("I want to: ")
outcome = input("So that: ")
os.system("clear")
file.write(f"As a(n) {role} I want to {function} so that {outcome}\n")
except KeyboardInterrupt:
file.close()
os.system('clear')
print("g'bye")
except FileNotFoundError:
print(f"{file_path} is not a valid filename.")
I've added a new except
block and printed a friendly message. I've also added a shebang to the beginning of the script so I can put it in my bin folder and run it from anywhere. This now lives in my dotfiles repo until I decide to get rid of it.
Nothing else to see here
Quick and dirty tools are some of my favorite things about coding and Python is a great language to create them in.
Top comments (0)