DEV Community

Cover image for Building Apps That Don't Make Any Money
Marco Ledesma
Marco Ledesma

Posted on

Building Apps That Don't Make Any Money

I've forgotten when it was released, but at some point in the past, I released an app called Bill Panda, which you can read about following the link. It was my first complete app that I built to solve a personal problem. I went through the full experience of building it, tearing it down, rebuilding it, tearing it down again, and building it again. I created an LLC that the app is published under, a business banking account, and a light website to market the app. This is a post reflecting on some things I learned during this experience.

Why I built it in the first place

For a long time I was using a spreadsheet to manage my recurring bills. There were apps out there, like Mint, that automate some of this stuff for you. But I always disliked that I couldn't mark my bills as paid ahead of time. I also couldn't use the data to create any cash projections. So i thought, why not build my own? It needed to do a few simple things:

  1. Track my recurring bills.
  2. Notify me of upcoming bills.
  3. Allow me to mark them as paid/unpaid.
  4. Let me add notes
  5. And eventually, reporting, so I can make cash projections.

I originally built it using Laravel - a web application framework. The frontend was all in Vue and the backend was PHP. You can see a demo of it here (I demoed it for a Hackathon, which I won second place :D): Bill Panda Web. The second time I used React Native. The third and final time, it was all Swift UI. It's been a fun journey building the app. I'm finally at a point where I can begin thinking about new features for it. But before I get to those, I thought I'd share a few mistakes I made along the way. You may find this helpful if:

  1. You are about to build a payment system with recurrence.
  2. You work with recurring events in general.
  3. You plan on building your own app.

Mistakes

1. Regarding Recurring Events - Don't store every occurrence in your database!

When I built the web-based version, i made a critical mistake. For my use-case, you should never populate your database with all occurrences of a recurring event. Not only are you creating a TON of data, you also corner yourself by having to answer questions like "this event repeats daily until the end of time, do i create every single event until the end of time in my database? Do i cap it to the first 1,000 events?” Whats the right number of recurring events to create? There is no right number.

During my research developing recurring events, I ran into this amazing post on Github by user bmoeskau: https://github.com/bmoeskau/Extensible/blob/master/recurrence-overview.md. This post sent me in the right direction. You do not create every occurrence, you compute them. You follow a recurrence rule standard that's been around since 1998. I highly suggest reading the github post I linked above if you are going to create a recurring event system!

2. Your friends and family may not like to use your app if they know that you have access to their finances

If you've built the application, you have access to the database. You can promise you'll never look at the database, but cmon, you probably will. Trust is a big thing when it comes to finances - your friends and family probably won't want to use your app if it means handing over all their data. You have to guarantee that their data will not be accessible to you. During the time that I developed the web app, I did not have a way around this. But by pivoting the technology I used, I did find a way.

At some point in the last couple of years, Apple announced SwiftUI.
This looked so interesting that I ended up diving back into iOS development (I've jumped back and forth between iOS/Android app development and Web Development in my history). As I started working in SwiftUI, I thought, why not try CoreData one more time? Maybe work with CoreData and CloudKit. If i was to incorporate CloudKit, the user never has to sign into the app. All their data can live inside a private CloudKit container that I, as the developer, have ZERO access to. It also has an incredible generous free tier that makes it so that I don't have to pay anything. Furthermore, CloudKit data syncs across your iOS devices seamlessly. It had everything I needed (it was also a huge, painful, learning curve). Happy to say that I made the right decision :). The app is running fully on CloudKit.

3. Not working with technology you love

If you have a hobby project and your goal isn't really to get rich, then don't work with technology you loath. This is not to say that I hate Laravel or Vue (they powered the first iteration) - I truly love those technologies. No, the one i tend to loath sometimes is React Native -- which I used for the second iteration of the app.

If you look at a prior post of mine (https://dev.to/m4rcoperuano/react-native-best-practices-when-using-flatlist-or-sectionlist-4j41), I wrote:

...React Native has been the only [language]that has been able to change my mind and has me questioning why I would ever want to code in Swift or Java again.

Looking back, this is still true.....sometimes. Sometimes I hate it. The debugging (not knowing if the bug is in your javascript code, your native module, the react native run time, or once its packaged) is maddening. This doesn't mean I would never code with React Native. For example, if you want to make a cross-platform app, or if it's a requirement from your client/job, then its no problem. But if you're doing it for fun, and you don't care about cross-platform, then save yourself the headache. Work with the native code and framework.

But I digress. If you are working on a hobby project, work with tech that you love. It will motivate you to keep going back to it. Personally, I love using SwiftUI and sometimes wish it was all I did.

Sidequest: Why Is SwiftUI Awesome?

SwiftUI is pretty darn cool once you get the hang of it. This is a framework that Apple has developed so that its easier to make native iOS apps. Here's a quick example:

struct MonthHeader: View {
   var monthName: String;
   var totalDue: Int;
   var amountPaid: Int;

   var body: some View {
      VStack(alignment:.leading, spacing: 2) {
         Text(monthName)
            .font(.headline)
            .foregroundColor(Color.textGeneral)

         HStack {
            Text("\(amountPaid.toCurrency) paid ")
               .foregroundColor(Color.brand)
               .font(.subheadline.bold())
            +
            Text("out of \(totalDue.toCurrency)")
            Spacer()
         }
      }
      .padding()
      .background(.thinMaterial)
      .listRowInsets(EdgeInsets(
         top: 0,
         leading: 0,
         bottom: 0,
         trailing: 0))
   }
}
Enter fullscreen mode Exit fullscreen mode

This is a pretty simple view that displays this:

Image description

I find this code super readable. You have:

  • 3 required parameters defined at the very top. These are your "props", essentially (if you are familiar with Vue or React)
struct MonthHeader: View {
   var monthName: String;
   var totalDue: Int;
   var amountPaid: Int;
....
Enter fullscreen mode Exit fullscreen mode
  • You then have you "body" field, which is essentially a template tag, or what you return from a React component (again, if you are familiar with web). You can learn what the code does by reading my comments below:
   var body: some View {
      //VStack stands for Vertical Stack
      VStack(alignment:.leading, spacing: 2) {
         //Inside it we have a Text field that displays your prop,
         // monthName. It's then modified to look like a headline 
         // with a specific foregroundColor.
         Text(monthName)
            .font(.headline)
            .foregroundColor(Color.textGeneral)

         //Then you have an HStack, or Horizontal Stack, that takes
         // your prop amountPaid and uses an extension (a function) 
         // that converts it to currency. It also sets the color to a
         // specific "brand" color that I selected, and makes the 
         // font a subheadline that is bolded. 

         //Finally, another text element is right next to it 
         // (concatenated) that represents the amount due. The reason 
         // is separated from the first Text element is because I 
         // don't want it to be colored at all.
         HStack {
            Text("\(amountPaid.toCurrency) paid ")
               .foregroundColor(Color.brand)
               .font(.subheadline.bold())
            +
            Text("out of \(totalDue.toCurrency)")
            Spacer()
         }
      }
      //Then i apply some padding, change its background color to a 
      // .thinMaterial, which apple has provided -- it changes the 
      // background color to be blurred and translucent
      .padding()
      .background(.thinMaterial) 
      //finally, i remove any default padding provided by default 
      // from Apple's SwiftUI framework
      .listRowInsets(EdgeInsets(
         top: 0,
         leading: 0,
         bottom: 0,
         trailing: 0))
   }
Enter fullscreen mode Exit fullscreen mode

Compared to the past, where you would have to create Swift ViewControllers, or worse, Objective-C ViewControllers, this is much welcome change. If my job was to create Swift apps full time, man, that would be exciting.

Summary

It took about 3 years to get the app to a state where I was happy with it. The app was built during nights and weekends, sometimes on vacations. It, thankfully, wasn't too stressful to build. If you love to code and you have a goal in mind, then you'll find the time to make the app that you always wanted to make. Its okay if it takes a long time--we have day jobs. Will I ever make money on this app? I don't really know and I don't really think about it. It serves its purpose to me and a few others (I have about 40+ daily users!). That's all I need to be content with it :).

Top comments (4)

Collapse
 
perisicnikola37 profile image
Nikola Perišić • Edited

Cool story. Thanks for sharing Marco :)
Can you tell me how you got more than 40 users a day? Did you do the marketing or was it organic?

Collapse
 
m4rcoperuano profile image
Marco Ledesma

Hey @perisicnikola37, the only marketing I did was just through Linked In and word of mouth (family/friends and such). That's really it though. According to my analytics via Apple, the main data source is App Store searches. Thanks for reading my post!

Collapse
 
perisicnikola37 profile image
Nikola Perišić

That's cool Marco. Thank you for answering me. I have one more question :) Why did you use "panda" in the application name? What do pandas have in common with bills? 😀

Thread Thread
 
m4rcoperuano profile image
Marco Ledesma

Nothing at all! I'm not sure why I chose panda as the animal name at the time. Looking back, i think it just allowed me to call it something, anything, so I don't have to think about it and just get to coding :)