There is not only “how *Klib was born”,

And the true portrayal of the “indie developer,”

Ten thousand words long, deep dry goods, please proceed with caution…


After 50 days, two years and 258 hours of hand-crafting, Klib has finally arrived.

Klib has just been released these two days and has received many positive comments from users. Catch up and document the birth of Klib.

Klib is the new Kindle annotation, notes/extracts management tool, macOS platform.

  • To learn more
  • Mac App Store download

origin

At the end of 2016, I was thinking about what project TO do next. I did not decide, but I just had a general direction: to do a slightly larger project, and technical requirements, that is, to do an interface interaction. I series tools (iPic, iTimer, iPaste, iHosts) I made before are very vertical and all menubar tools, SO I want to make a breakthrough.

Coincidentally, I had set a reading plan for myself at that time, which was to read books regularly and write articles on my blog after reading them. I’m mainly an independent developer, and I don’t have much access to information, so I have to force myself to keep updating in this way. And to write articles, very important content is reading the book. I’m used to reading e-books on a Kindle, so there was an immediate need to copy notes and notes from the Kindle for writing articles.

I did a quick search of the tagging management tools available on macOS at the time and found none available. So began what programmers love to do best: build wheels.

The time, just in 2017 New Year’s Day, see the diary of that day. By the way, I have the habit of writing diary every day, has insisted for several years, is also to force myself to fight alone, can keep thinking, introspection.

design

The name design is borrowed here just to cover all the thinking that goes into the early stages of a product. There are all sorts of things to think about: market environment, business model, competitive product analysis, name, Logo, what to make it look like, interaction, how to launch, how to operate, timing, etc. It’s getting a little early, so here’s a quick reminder of some important points.

positioning

I’ve always preferred to make simple products, and this tool is no different. One of my core needs is to export notes from my Kindle, and the most intuitive implication is to be able to keep and review them regularly. Well, that’s it, any more will be hard to simplify, easy to use. Repeat + summary:

Positioning: Streamlined, macOS platform, Kindle note management tool

Feature set:

  • Export notes from your Kindle
  • Persistent Notes
  • Convenient to review

The names are easy to decide, because all of my tools start with I (iPic, iTimer, iPaste, iHosts), and so is this one. Plus it’s kindles, so it’s called: iKindle. Of course, you know it didn’t end up that way; This hole, I’ll fill in later.

Logo is also easy, as you can see from the Logo of my previous product:

The iKindle Logo must look something like this:

Of course, you know, that changed, too. That’s the next story.

interaction

With the groundwork in place, you can consider specific interactions.

The interaction must be intuitive and intuitive. In the beginning, the general idea was something like this (thankfully I still had the screenshots) :

The left side is the list of books, the upper right side is the list of notes in the book, and the lower right side is the content of selected notes for easy editing. It evolved, of course.

First book

I didn’t start out by author, because I’m not in the habit of following authors; And, even if chase, also do not necessarily have to classify by author, search not ok.

But too many books put together, and there is a problem of ordering. By title, last read, or what? In fact, if you have a lot of books, it doesn’t matter how many books you order. Then why not have fewer books? Okay, so if I’m just looking at the last few books, like three books, do I have to worry about sorting? Those earlier books, you can just file them away and search them later.

That’s where the iKindle comes in: distinguishing between what you’re reading now and what you’ve already read. Formally, books that have been read are put together and can be folded and hidden. Yeah, it’s great!

Then there’s the list of notes

The intuitive thinking of a programmer is to list all the attributes, such as note content, type (annotation or note), location, and date added. This is easy to do with lists.

The problem is, these latter attributes take up a lot of screen space and aren’t important, as long as I can see them when I need them.

So, hide them all, hide them in the introduction, so that the list of notes only shows the content of the notes. Yeah, it’s great!

Then read and edit the current notes

You’ll find that in the original design, this section also takes up a lot of screen space, but has to have a lot of white space. Also, for my actual notes, many of which are one-sentence, I can almost show it in the list, no need for this extra area. In addition, the real need for editing is not so much (most of the annotation is before and after the unnecessary content, symbols), most of the time just look at it.

So, I killed that part, too. What if the notes are really long? I naturally thought of Finder’s quick preview. OK, let’s move it over. Yeah, it’s great!

Next up is search

This doesn’t have to be specially designed, it’s good to be consistent with the system, it’s bad to be inconsistent. Yeah, it’s great!

Finally, the overall interaction

I have a look, after the above improvement, this is not a system “remind items” look? All right, let’s make it a reminder. Yeah, it’s great!

The development of

The design is almost done, and you can code it. My development sequence is usually three steps: data structure, heap UI, complete business logic.

The data structure

There are three data structures: Kindle data structure, in-memory data structure and persistent data structure.

Kindle’s own data structure

Okay, a quick quip: The Kindle’s data structure is crap! At the very least, the open data structure really adds up to a plain text, something like the following:

Steve Jobs:A Biography (Walter Isaacson)

- your position in the labeling of # 5676-5677 | add 1:33:54 on August 22, 2015, Saturday afternoon



A well-run company spawns innovation far more than any single creative individual.

= = = = = = = = = =

Copy the code

Looks all right, doesn’t it? Here are some more multilingual versions:

- Your Highlight on Location 1-6 | Added on Thursday, January 5, 2017 4:20:05 PM

- Ihre Markierung bei Position 6-7 | Hinzugefugt am Mittwoch, 1. 2017 12:21:36 Februar

9-12 - Votre surlignement a l ʼ emplacement | Ajoute le mercredi 1 fevrier 2017 12:51:12

- Tu subrayado en la posicion 33-35 | Anadido el miercoles, 1 2017 12:42:10 DE febrero DE

- position No. 39-42 の ハ イ ラ イ ト | every day: on February 1, 2017 water 13:00:33 obsidian

- В а ш kind guide ы д е л е н н ы й о т р ы kind guide о seem kind guide м е с т е 45-49 | Д о б а kind guide л е н о : с р е д а, 1 ф е kind guide р а л second 2017 f. Kind guide 13:12:38

- you are in position # 38 and 39 of the annotation | add on January 5, 2017 4:07:22 Thursday afternoon

Copy the code

There’s an urge just to recognize dates: to get the date text, identify the format, Locale; Also, you don’t know what time zone the date is in.

Here I make a trick: the parsing capability of the data structure can be updated dynamically. That is, the latest way to parse data from the cloud while the binaries remain the same. This way, when users give me feedback on formats that I don’t support, I can just update the parsing capabilities in the cloud, and the client can be painlessly updated back to the desktop. Give yourself a thumbs up for this design!

In-memory data structures

This is not too much to say, just define the book, note properties.

The main trick is: how do you recognize the uniqueness of notes? As you can see from the previous text, notes don’t have such a thing as a unique ID. Since there is no such thing, it would be better to take the whole note or the Hash value of the whole note as the unique ID. Anyway, the amount of data in notes is not large, and a person’s notes in a lifetime may not be as big as a picture taken on iPhone.

Persistent data structures

This step, mainly between structured storage and unstructured storage. The former data neat, suitable for note storage, but poor scalability. The latter has roughly opposite advantages and disadvantages.

In the end, I opted for structured storage. Specifically, SQLite. On the one hand, the note-taking class data is too neat. On the other hand, holding the attitude of learning, anyway, I am not familiar with which, just pull one out for practice.

Another consideration: openness of data structures. Data is user owned and valuable, and if you use proprietary binary data structures, there is no way for users to parse it in case maintenance stops. With public SQLite, any SQLite tool can view user-generated data. Doing so is responsible to the user.

Pile of UI

There’s not much to say about that part.

One is the use of some core controls, such as NSOutlineView, NSTextView, NSPopover, NSSearchField. Among them, NSOutlineView in Source List mode is a bit cratered, such as delayed UI refresh, icon loss and other phenomena. Friends who have similar problems can talk to me.

Another aspect is the details of the interface, such as font, size, color, white space, spacing, and so on. I’m kind of lazy about that, because it’s basically a copy of the system reminders.

Implementing business logic

Open up the data stream

For example, when selecting a book on the right, the list of notes on the right can change accordingly; When editing notes, data can be persisted; When viewing notes, normal data can be read; And so on. Does it all sound like crap? Well, that’s what it is. Just do it right. The key is to structure your code well and not have problems with duplicating code, heavy coupling, and so on.

User guidance layer

For example, you can guide users to manual import at the beginning and how to operate during the process. I didn’t do much of this because I wanted the program to be boot-free. However, guide the user to import this step, do really bad, need to improve.

Some peripheral functions

For example, account system, log and feedback system, etc. I’m not going to lay it out here.

test

Unit testing

In fact, unit testing is done at the beginning of development. Especially for the data structure part, to fully test. If this part is fine, as long as the program runs, it should be fine. If there is a problem with this part, it will be enough to fix the Bug.

Also, refine unit tests as soon as you define data structures and complete new functionality. This is when you are most familiar with the code, most aware of it, and most willing to write unit tests. It would be a shame to miss this moment.

Refine test cases

Like unit tests, test cases are not completed after product development results, but are refined immediately after each functional logic is developed. The truth is the same, because this time is the most thorough understanding of logic, clear time, must not miss.

Version of the test

Unit test run, the heart will have the bottom. Add to that the previously completed test cases, and release testing is nothing more than running through the use cases.

I didn’t do automated testing, continuous integration, mainly UI automated testing that wasn’t easy to do and was expensive. For a small project like mine, an indie developer, running test cases by hand is probably the most cost-effective.

It is worth noting that virtual machines are recommended for version testing. Build a clean system and mirror it beforehand. During each test, you only need to restore the VM to the specified image. In addition, you can test other versions of the system (such as macOS 10.11) on the current system (such as macOS 10.12).

shelves

Their hard to make things, of course, is the hope that the more people the user the better. The most direct and effective way to reach more users is to launch the Mac App Store (MAS).

Internal test, public test

Before the shelves, to ensure the availability of their products, good, the best way is to let a part of the user to use, that is, the internal test, public test (the following unified called public test).

It’s important to note that the goal of open beta is not to find bugs, it’s your job to do it yourself. The public beta has the following purposes:

  • Test the market: that is, whether the product is needed and how badly needed it is, whether the hypothetical market exists and how big it is, etc
  • Test design: If someone wants it, is it what he wants? Where is it well designed? Are there any fatal flaws?
  • Quality inspection: because they can cover the situation is limited, or to rely on the actual use of real users to final quality inspection.

My internal test is mainly in the previous user group, V2EX, in this special thanks to participate in the public test of friends!

Mac App Store

Well, here comes the Mac App Store (MAS). MAS is a pit in the following aspects:

Sandbox restrictions

Sandboxes restrict the use of many interfaces, system permissions, and have a significant impact on programming and product interaction.

For example, the sandbox does not allow the product access to the user’s file system unless the user manually does it (i.e. authorizes the action itself). This means that the iKindle cannot automatically import the currently connected Kindle device directly at first, but must be manually operated by the user. This requires proper guidance. Once used, the user no longer needs to manually operate. That’s why the iKindle will automatically import later.

And crucially, even if the sandbox was opened during development, Apple could still use the sandbox as a reason to reject it during review. While Apple has well-documented these limitations, the average developer obviously doesn’t fully grasp them. Just as you can’t take your first steps after reading all the laws, it’s more practical to solve problems when you encounter them. Fortunately, I didn’t have that problem this time.

The name

All right, let’s get to that. Why, you may wonder, is the name “iKindle” used until “Sandbox Limits”? Is there a wrong number? Yes, it is called the iKindle.

However, Apple does not allow the word Kindle in App names. So it had to be changed. It’s a really painful process. On the one hand, it wasn’t easy to come up with a good name. I struggled with it for a long time (see my blog) and finally settled on Klib (Kindle Library).

On the other hand, everything is name related — code, App name, copy, screenshots, etc. Once the name is changed, all that has to be changed. It’s a huge chore, and I don’t want to do it again.

The Logo, for example, looks like this:

Release and promotion

Finally, after two rejections, Klib finally made it to the Mac App Store.

Then there is the question of how to spread the word about Klib, that is, how to distribute it.

Product Hunt

In this link, I have no idea how to promote overseas. After all, we are Chinese and it is hard to infiltrate the enemy, let alone influence foreign countries.

What to do? The most direct and effective way I’ve found so far is to have a successful launch in Product Hunt. In this way, foreign media will also find better products to report in Product Hunt. Therefore, Product Hunt has become the key for Klib to go abroad and enter the world.

There’s a lot to be said for Product Hunt’s launch, but here are a few highlights:

  • Release time
    • In terms of the day of the week, Every Tuesday is the best. Because the number of users of Product Hunt is the largest on Tuesday, there is enough time to enter the Weekly Report of Product Hunt. However, considering that Klib is a niche product, it is unlikely to make it into the day’s Top 1. Following the logic of “chicken heads and tails”, I chose Monday in the US for the release.
    • From the point of view of several points, one way is to publish at 00:00 in the morning, which can take full advantage of the 24 hours for dissemination; Another option is to post in the morning, when the media people and reviewers are just waking up and giving them more exposure. Since I don’t know any foreign media people, I will publish it at 00:00. Due to the time zone, Product Hunt will switch the Product list of yesterday and today at 4pm Beijing time.
  • Name, slogan
    • The name is Klib. What matters is the slogan. To be concise, to highlight product features, to catch the eye of the user.
  • screenshots
    • You can make giFs if you need to, although I hate it when giFs are used on more than one product, it makes the interface blink and blink and feel Low. But I can’t help it. It really catches the eye. Also, Product Hunt’s Twitter account has a dedicated retweet drive.
    • Basically, I reused the Mac App Store screenshots.
  • Immediately after Posting, add more information to the first comment. Such as further introduction of products, future planning, contact information, etc.
  • Forward, spread. That is, more people click on it, vote on it, discuss it. In particular, retweets from big names can be very effective.My biggest achievement was Ben Tossell (Community Lead of Product Hunt) participating in the discussion. Unfortunately, he didn’t retweet it.
    • But don’t be a vote-getter. Product Hunt has its own ranking algorithm.
  • Respond to messages in a timely manner. The user’s message, want to reply immediately (boon, can stay up at night basically, stare at). In addition, users’ replies can be forwarded to Twitter with thanks.

In the end, Klib got 200+ likes on Product Hunt, more than 10 international users participated in the discussion, and was listed in the Top 10 of the day, basically satisfied.

The user group

Good reviews and comments on the Mac App Store are important. And the people who are most likely to give you good reviews are the people who used your previous products. I didn’t start out with my own user base, and now I think it’s a pity. Fortunately, now we have wechat group, Telegram group, also have some very friendly users, thank you!

The media

Of course, the explosion of media is indispensable, and their influence is incomparable to that of individuals. It is best to:

  • Keep in touch with media friends at ordinary times, don’t cram at the last minute;
  • Send the experience version before launch, give them time to prepare the copywriting;
  • Timely notification when online, so that they can arrange the release time; Exchange code can also be provided to facilitate the other side to do activities.
  • Press conference, also want to help forward, and thank you.

Other influences

Use all the influence at your disposal to make Klib reach as many people as possible. For example, let friends help forwarding and praise, weibo forwarding lottery, circle of friends, and so on.

other

pricing

Pricing is a metaphysical door, too high no one to buy, too low their not cost-effective. Currently, Klib is free plus in-app purchase (one-time buy-out). The idea is to make it easier for more people to use Klib and lower the barriers. As much as I wanted to continue with the subscription model, I was frustrated by the lack of user acceptance, and the nature of Klib itself didn’t work well with the subscription model, so I took a buyout approach.

Take this opportunity to make a personal point: buyouts are not developer-friendly, subscriptions are practical. After all, developers often need to make continuous improvements to their products (not because the product was released in the first place, but because the product was improved), and not be able to benefit from those improvements is not healthy. In the end, the harm may be done to the users themselves, because if the developer fails to update, the users are left with a version that needs to be improved.

The current price is ¥50, the first half price for a limited time, that is, ¥25, buy as you earn.

The meaning of starting

Klib is currently the first Kindle note-management tool for macOS and available on the Mac App Store. This uniqueness makes sense. Because there is no direct competing products, there is even a certain pricing power.

For users, it is easier for the first launch to position the product in this category, and it is not easy for latecomers to steal the positioning in the user’s mind.

The significance of a single day’s sales

If daily sales can get your App to the top of the charts, it will generate some additional traffic, because other users may look twice because of the charts.

On the second day of launch (the first day was too slow to update the App Store and no data was available), Klib ranked 22nd in Free and 14th in Grossing in China.

after

So far, Klib has been a success on the Mac App Store and has received a lot of feedback from users. Going forward, I will continue to improve Klib by adding multi-view support, syncing notes with Amazon, syncing notes with other Kindle platforms, exporting to Evernote, and more. Of course, I will be very careful to add features and keep Klib lean.

Thank you

There really are a lot of people to thank…

  • Thanks to my family for supporting me as an indie developer (mainly accepting not making money…)
  • Thank you for your trust
  • Thank friends for their help (Kindle Mate author for multilingual support, Allen for Logo making, 61 for twitter short links)
  • Thank the media for their coverage (name the minority who first reported)
  • Thanks to all the likes and criticisms
  • Thanks Apple (despite the MAS hole)
  • Thanks to the Kindle
  • Of course, thanks CCTV

The last

Hopefully, Klib will encourage you to read more books and take notes, even if it’s just a little bit different.