If you're a freelancer who works with multiple databases, you'll love this issue; you'll explore a tool that lets you connect to multiple databases using a common interface with syntax highlighting, and you can use it to migrate data between databases.
You'll also see one way to think about content strategy and how to use it to drive product awareness and adoption.
But let's start with the database tool.
If you've ever wanted a universal SQL command-line tool that lets you interact seamlessly with multiple databases, usql is the tool for you. It supports multiple databases, including PostgreSQL, MySQL, Oracle, and more, all from a single interface that resembles the psql
command from Postgres. Best of all, it runs everywhere.
To explore this tool, you'll create a SQLite3 database, copy data to MySQL, and sync updates back to SQLite3.
First, install SQLite3, MySQL, and usql.
Install SQlite3 using your package manager.
You can use Docker to spin up a local instance of a MySQL server by using the following command:
$ docker run --name mysql-container -e MYSQL_ROOT_PASSWORD=my-secret-pw -p 3306:3306 -d mysql:latest
On macOS, use Homebrew to install usql, as this is the best way to ensure its SQLite3 support works properly:
$ brew install xo/xo/usql
Otherwise, download a release for your platform.
Next, create the database you'll use.
To create the SQLite3 database, you'll use usql to connect and create a table. This will create a local file automatically.
Connect to the SQLite3 database called todos.db
:
$ usql sqlite3://todos.db
Create a tasks
table using the CREATE TABLE
command:
CREATE TABLE tasks (
id BIGINT PRIMARY KEY,
name VARCHAR,
complete BOOLEAN,
due_at DATETIME,
completed_at DATETIME
);
This table structure includes columns for task details such as ID, name, completion status, due date, and completion date. usql doesn't have its own interpreter, so you still have to use the correct data definition language for the database you're talking with.
Now insert two records into the tasks
table:
INSERT INTO tasks (id, name, complete, due_at, completed_at)
VALUES (1, 'Buy groceries', FALSE, '2024-07-01 10:00:00', NULL);
INSERT INTO tasks (id, name, complete, due_at, completed_at)
VALUES (2, 'Complete tutorial', FALSE, '2024-07-02 12:00:00', NULL);
Verify the records were created by querying the table:
select * from tasks;
You'll see both results:
id | name | complete | due_at | completed_at
----+-------------------+----------+----------------------+--------------
1 | Buy groceries | false | 2024-07-01T10:00:00Z |
2 | Complete tutorial | false | 2024-07-02T12:00:00Z |
(2 rows)
With those records created, you can copy them to a MySQL instance.
You can use usql to connect to SQLite3 and MySQL databases and copy data in both directions. Try it out.
First, create the todos
database in MySQL and then create the tasks
table.
Connect to MySQL. Without leaving usql
, use the \c
command to connect to MySQL:
\c mysql://root:my-secret-pw@localhost
Create the todos
database:
CREATE DATABASE todos;
Then switch to that database:
use todos;
Create the tasks
table in MySQL:
CREATE TABLE tasks (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255),
complete BOOLEAN,
due_at DATETIME,
completed_at DATETIME
);
Next, export the data from SQLite3 and import it into MySQL:
\copy sqlite3://todos.db mysql://root:my-secret-pw@localhost/todos "SELECT * FROM tasks" tasks
Verify it by selecting the tasks table in MySQL:
select * from tasks;
Both tasks are there:
id | name | complete | due_at | completed_at
----+-------------------+----------+---------------------------+--------------
1 | Buy groceries | 0 | 2024-07-01T10:00:00-05:00 |
2 | Complete tutorial | 0 | 2024-07-02T12:00:00-05:00 |
(2 rows)
With the data copied to MySQL, update the first task so it's marked as completed on July 1:
UPDATE tasks
SET complete = TRUE, completed_at = '2024-07-01 11:00:00'
WHERE id = 1;
Verify the change:
select * from tasks;
You'll see the updated record:
select * from tasks;
id | name | complete | due_at | completed_at
----+-------------------+----------+---------------------------+---------------------------
1 | Buy groceries | 1 | 2024-07-01T10:00:00-05:00 | 2024-07-01T11:00:00-05:00
2 | Complete tutorial | 0 | 2024-07-02T12:00:00-05:00 |
(2 rows)
Now, move the data back. Since the original table already contains records, you'll need to truncate the table to ensure it matches, or you'll violate the column constraints for the primary key, as the copy command will attempt to add records.
Switch back to the SQLite3 database:
\c sqlite3://todos.db
Truncate the table:
DELETE from tasks
Finally, use the \copy
command again to export the updated data from MySQL and import it back into SQLite3. You have to format the datetime
fields during this process to avoid type mismatches:
\copy mysql://root:my-secret-pw@localhost/todos sqlite3://todos.db "SELECT id, name, complete, DATE_FORMAT(due_at, '%Y-%m-%d %H:%i:%s'), DATE_FORMAT(completed_at, '%Y-%m-%d %H:%i:%s') FROM tasks" tasks
While converting dates from SQLite3 to MySQL didn't require date casting, sending data in the other direction does. When you migrate data using usql, you're responsible for handling any data conversion.
select * from tasks;
The update is present in SQLite now:
id | name | complete | due_at | completed_at
----+-------------------+----------+----------------------+----------------------
1 | Buy groceries | true | 2024-07-01T10:00:00Z | 2024-07-01T11:00:00Z
2 | Complete tutorial | false | 2024-07-02T12:00:00Z |
(2 rows)
You've successfully moved data from one database to another.
usql lets you manage multiple databases without juggling multiple tools. You've experimented with copying data between databases without intermediate files or scripts, but the documentation explains many more valuable features.
"The funnel" is the path people take as they discover and adopt a product. They become aware of the product, they become familiar with it, then they adopt it and start giving you money, and then you retain them month-over-month as customers. Marketers call it a "funnel" because it's wide at the top and narrow at the bottom. It's more like a leaky bucket or a sifter; you can't assume that everyone who hears about your product will become a customer. People "drop out" of various funnel stages.
Content is a popular way to drive product awareness because its impact is something marketers can measure. I know how many people read this newsletter each month and what links they click on. I can even track repeat visitors to my website. That's much less effort and money than going to trade shows.
However, not all content is the right kind of content for everyone. You have to create content that lines up with where people are in their funnel journey. Over the years, I've discovered you can boil your content strategy down to three groups of people:
Let's look at each one and how it maps to the funnel.
These are your frequent users, the audience that your product documentation serves well. Your users read your documentation to ensure they're using the product correctly. They may have heard about a new feature, so they'll run to the docs to see if it's the right way to go. This kind of material is the core of your business because it's where you support and retain your customers.
In larger companies, engineers and product folks should help make this content solid, comprehensive, and technically correct. But if you're a solo developer, this is a large part of your product development. Good reference and conceptual documentation drives adoption because people who eventually discover the product will see the comprehensive documentation as a mark of quality software.
You should nail this before you start doing blog posts about features. Document every SDK feature. Create a glossary of your key terms. Write explainer material about your key concepts. Create diagrams of essential components that help people understand things better. And don't forget to go deep. Too much documentation only covers the basics. To retain customers, you must ensure the documentation grows with them.
Once you have comprehensive documentation, you can start thinking about expanding your audience beyond power users.
You built your product for a reason; it solves a pain point. Now you have to let a wider audience know about your solution. Tap into that with content that helps people discover your product by targeting their needs.
Create tutorials about people's problems and show how your product solves them. For example, the problem might be that they need to move data from one system to another. A tutorial about a command-line tool that makes that easy is just what they need. That tutorial can lead them to more content that shows the tool solves related problems too.
Don't focus on your solution. Focus on the problem. Make the person with the problem feel like a hero because they solved it with your solution. Do this with your product enough times, and you'll get more engaged users.
Case studies are a great fit here, too. Find power users and companies using the product and interview them. Have them talk about their use cases and explain how they used the product to take away the pain. Record the interviews, post them as videos, and chop them up into clips for TikTok or YouTube shorts. Transcribe them as written case studies. Then produce tutorials that show how to build a small demo. Tie that back to specific pieces of documentation.
Create awareness of your product by demonstrating how you solve people's problems. Use content as the method for creating that awareness. People will be searching for their problems, not your solution. Keep that in mind when targeting this audience.
The last group is where you can have a longer-term impact. Some people haven't encountered the problems your product solves yet, so you have to make them aware of those problems before you can tell them about your solution.
If you have a home with copper water pipes, there's a chance that those pipes can break down and spring a pinhole leak. It's not something you think about very often. What if that happens while you're away on vacation? You could come home to a flooded house, thousands of dollars of damage, and a massive headache. There are products you can install on your water line that use pressure to detect a leak, and they can turn the water off for you, saving you money and giving you peace of mind.
This example is how you create awareness, explain a problem, and provide a solution, and it's extremely common in the consumer world. There's tons of informative educational content for homeowners; the number of things that can go wrong seems endless. You'll find this content on the websites of roofing contractors, plumbers, electricians, and landscapers, who educate you about what can go wrong, what to look for, and who to call. They're doing this because they want more customers.
Companies that put effort into creating "thought leadership" content can get the same benefit. Suppose your product solves problems for a particular type of software engineer. In that case, you might have all kinds of content tangentially related to that field, from best-practices guides to thought-provoking interviews with experts. You could partner with others to create this kind of content, too.
This content can make people aware of issues they don't have yet and who they can turn to when they do. This content won't pay off immediately, but it's part of that comprehensive strategy that drives people down the funnel. Eventually, they'll have these problems, and they'll come to you for content about how to solve them. You'll have that ready, too.
Don't spend much time on this content until you have the other pieces. Too many people try to start with thought leadership content. It won't come across as genuine if you haven't created the content demonstrating your products and services are truly helpful.
Your goal is to pull people through the funnel by addressing the needs of these audience segments. Someone who doesn't know about the problems your product solves won't be interested in your webinar, but if you have a webinar about a general topic, they might join. Then you can interact with them more.
The key is to align content across all of these factors. Identify a problem. Then figure out:
Pull it together and connect the dots for people; you'll be their hero. They will become aware of your product by becoming aware of the problems they may run into. They will become familiar with your product as the solution to those problems. And they will engage as you help them solve more problems. You'll move people from awareness to adoption and build trust.
Here are two things to try before next month:
Thanks for reading!
I'd love to talk with you about this newsletter on Mastodon, Twitter, or LinkedIn. Let's connect!
Please support this newsletter and my work by encouraging others to subscribe or by buying a friend a copy of Exercises for Programmers, Small, Sharp Software Tools, or any of my other books.