April 4, 2023

What I’ve been working on

A lot has happened in the last couple of weeks. I think I’m now a permanent member of the “web development is fun” club. It’s like a slightly more frustrating LEGO with an endless amount of ever changing parts. What’s not to love? That being said, here’s what I’ve been working on in the last couple of weeks.

My new portfolio: marcel.fyi

This one took me a while but I’m very happy with the result. It was harder than my other projects because “Ah fuck it, I’ll just leave it like that” is easier to achieve when it’s not about presenting you and your work but only about learning something new. I powered through and I’m quite happy with the result.

👉 https://marcel.fyi

(I don’t understand why the domain was still available. Sorry other Marcels, it’s mine now.)

Next.js and React are still something I’m actively trying to wrap my head around but since it’s a known problem and I need ever changing challenges to keep me motivated, I wanted to spice it up a little.

Spline is a fantastic tool to add 3D elements to websites. I’m cheap, though, and paying $7/month seems crazy to me just to add a silly 3D avatar to the upper left corner of some random website. A couple of years ago, in one of my previous “let’s learn programming” bursts, I bought Three.js Journey, a fantastic course that I just wasn’t equipped to understand yet. Fast forward a couple of months of intense learning of basic programming skills later: No problem. I fired up Blender, built a 3D character of myself, found out how to hook everything up to Three.js and React Three Fiber and voilĂ . Not only am I saving $7 a month, I also learned valuable skills in the process.

Drawmatic

Drawmatic is a little app that gives you a new drawing prompt each day. The rudimentary drawing tools and time limit are there to give you a little kick of non-perfectionistic creativity to start your day. Your allotted drawing time is only counted when you’re actually making lines.

Finished drawings are being saved to local storage. I even added a “Create an image from this HTML element and copy it to your clipboard or save it to your computer” feature! All of this is unfortunately slightly broken on mobile but what can you do.

Gone Fishing

I needed something to teach myself user auth and databases so I grabbed myself a copy of Supabase and build a… I guess… game…? There’s no gameplay loop and it doesn’t make sense and isn’t fun but it works. A user can sign up via magic link. When they come back to the site and haven’t added a username yet there’s a prompt for that and after that they can… fish. For those three items that I was willing to add to the database.

I implemented a working rarity system. A way to sell items. A lot of unnecessary Framer Motion fine tuning for the bucket button and, here’s the kicker: I won’t release it to the public because it’s obviously a piece of shit that has no right to exist except as a playground for me.

That’s it for now. Thanks for reading.

Byeeee!

January 23, 2023

Likes are out, reactions are in

My friends and I have been using Goblin Mode for over a month now. At first there was no way to interact with others at all. You could update your status and read the ones from your friends. That felt okay but we somehow thought that at least a bit of interaction could be a good addition.

Then I added likes which resulted in an significantly improved experience. People felt a little better connected to their friends. The problem quickly became that likes are a bit one-dimensional. You don’t want to “like” that somebody has a bad day.

So I took the chance and replaced likes with reactions while refactoring the whole thing. Reactions are basically the same list of tags you can add to your status updates but you can now use them to add one as a little piece of communication to somebody else’s status.

On the one hand this enables to react with better fitting communication-nuggets. On the other hand it enables micro-humour by allowing people to search for and react with funny reactions. Stuff like “This is my step count, what’s yours?” is now possible as well.

Based on the two days since this feature was released I’d say that the overall amount of interactions has decreased while the quality has increased. Receiving a reaction is far more valuable than only receiving a generic like.

Next up: Image attachments.

I noticed that my current implementation of… basically everything results in me not being able to create good Firebase security rules for Goblin Mode. So I‘m refactoring… basically everything. What sounds like a pain in the ass is actually a lot of fun. The next iteration will be so much better. Hopefully.

January 8, 2023

Work in progress: Goblin Mode

A lot has happened since I shared these two posts about the project I’m currently working on. I figured it’s time to let you know what has happened in the meantime. Here’s the short version: I learned a lot. Like A LOT. This is my third app ever and it’s the one where a lot of previously vague concepts finally clicked. I’m injecting dependencies, juggle with types and create view models like there’s no tomorrow. It’s so much fun!

What was supposed to be a placeholder icon has grown on me over time

A couple of weeks ago I invited some friends to try out the app and see if the overall idea works. This was a huge moment for me. People signed up for something I programmed. They created literal user accounts saved to a database I connected to an app I coded. Crazy. It got even cooler after that: They started using the app. And somehow they didn’t stop. I’m not sure if they’re only using the App because they want to be nice but it feels like they enjoy sharing one-off status updates with a closed and private group of friends. No endless timeline, no fame, only letting people know what you’re up to.

Let me give you an overview of how the app looks like at the moment.

This is the main view. You see your own current status and how old it is. Below that you’ll see all current status of your friends.

I wrote the code for all of this like three separate times. The first two iterations didn’t care about the amount of database requests at all. They worked but they weren’t scalable. I’m now using Firestore realtime updates and it’s amazing. If a friend updates their status while you’re in the app, the status automatically gets loaded from the server and displayed on top of the stack.

But what happens when a friend hasn’t updated their status since midnight?

SPIDERS!

They become stale. I like the idea of having a predefined tabula rasa moment. Each day starts with a clean slate. If you post something one minute before midnight that status will only be fresh for one minute. Slightly weird, but I kind of like it.

Speaking of likes: I implemented a system to like status. It works well and is fun. I’ll probably replace it with a system to react with a tag, though. Liking feels wrong when a friend posts a status about them being tired, feeling empty or being sad. I want to be able to react to these with “🤡 Clown”.

There are more than 130 tags now. I built an admin area and support for admin accounts into the app and can CRUD tags and tag categories in seconds. New tags and categories show up on user’s devices without the need for an app update. It’s all in the cloud, baby!

I also build a system for tags and tag categories that are behind the paywall. My current idea for monetizing the app would be to put most of the cool tags behind a subscription of some kind. Those server bills need to be paid!

With the ever increasing amount of tags my friends asked for a tag search feature. That has been implemented as well. For those moments when you need to share your shower thought quickly.

And last but not least: I revamped the whole follow/unfollow system I talked about here. It became clear that asynchronous following isn’t the right concept for an app that’s meant for you to share semi-private status updates. Now there’s a whole screen dedicated to see who requests being friends with you. If you accept a request you become friends with the other person and you can both see the status of each other. If you cancel a friendship both ex-friends stop being able to see the respective status. Fair and easy.

I’m toying with the idea of limiting the maximum number of friends each person can have. Just to drive the point of the app home. That didn’t work out very well for Path back in the day but maybe times have changed. Who knows.


That’s it for now. I still don’t know if I’m going to release this to the public at any point. I’m still a novice coder and my implementation of everything related to Firebase has a big potential to suck. I’m generally cool with my code not being the best but in this case it could result in me racking up an enormous Firebase bill. That would not be fun at all.

As I said: Who knows. I might find a way to limit the app features enough to let people try it out without me becoming poor while allowing people to pay to cover the database costs. It sure would be an interesting problem to have.


Do you feel like there’s a Goblin Mode shaped hole in the lives of you and your friends?

December 18, 2022

Added follow/unfollow and eyecandy

I’m guessing wildly how a performant and thought-through data structure is supposed to look like but this one is mine and it works and I’m proud of it. I had another breakthrough in understanding why MVVM makes sense while working on a feature related to this, by the way. What seemed like a lot of files and complicated connections between things that could just live in one file now makes sense.

Oh and I think I found the name for this project but I have to live with it for a couple of days first before I’ll announce it to the world. It was called “Shmood” for the first couple of days but I decided that that name doesn’t feel right.

And while we’re at it, here’s a bit of eye candy, featuring POW.

December 15, 2022

Uploading, fetching and async-awaiting

I’m having the time of my life over here. Without getting too much into what my next app will be: Look at this! All the data gets fetched from Firebase. Creating a new tag uploads it to firebase. The categories are documents in Firebase as well. The view showing categories and tags together is based on an array of objects that combines both. I’m juggling with data!

I wouldn’t have been able to do any of this a couple of months ago. We’re looking at a logged in user, authenticated through email and password, that has an isAdmin flag set to true. Only admin users are able to see the tag management section and are able to create new ones.

Databases! Optionals! ViewModels! Aysnc/Await! Everything comes together.

This is so much fun that I have to force myself to stop working to get a good night’s sleep.

December 11, 2022

“How fucking slick is that?!”

Some of you might have guessed it: I’m a big fan of the internet. The simple fact that I could work through this amazing seven(!) hour video about SwiftUI and Firebase by Stephan Dowless for free is still mind-blowing to me. It is free knowledge. Potentially life-changing information just lying around on the internet and all you have to do is consume it.

Stephan is an incredibly enthusiastic instructor who made the time fly by. Even though he obviously doesn’t do this for the first time, he still bursts out stuff like “How fucking slick is that!?” all the time. I felt thoroughly entertained. This is easily one of the most helpful courses I’ve worked through.

I know now that Firebase is the way to go for what I’m currently looking for. The course went through the whole process of building a low-tech Twitter clone. From signing up to fetching data from Firebase to storing images and writing and liking tweets. Not only do I now understand the basics of Firebase (and how to work with databases in general), I also got a better insight into how slightly more complex apps are supposed to be structured. MVVM is easier to understand when applied to a project with a certain complexity. I didn’t get it when other people tried to explain it with simpler examples.

This was very well invested time and I feel like I’m ready to start my next project. Something with databases! On the internet! How exciting!

December 9, 2022

Baby’s first steps in Firebase

Today I worked through this tutorial and came away with the conclusion that Firebase seems to be exactly what I was looking for. The Firebase SDK seems to be straight-forward enough to work well with my current skillset.

This code here creates a user that can be authenticated by email and password. Just like that. I don’t have the slightest idea what’s happening behind the scenes but to be honest: At this point I don’t really care. I’m just happy that it works.

func register() {
    Auth.auth().createUser(withEmail: email, password: password) { result, error in
        if error != nil {
            print(error!.localizedDescription)
        }
    }
}

After working through the tutorial I even managed to implement a couple of experimental test functions myself. I’m off to a good start and managed to recreate my motivation by approaching the problem from a different angle.

Nice. I’m hyped.

December 8, 2022

DoubtKit

After spending a couple hours with tutorials and courses about CloudKit, I’m a little deflated. What I found was either outdated or at least not current and while I’m also trying to get an understanding of previous solutions, I want to concentrate on learning what’s going to be the standard of the future.

I kind of hit a wall with CloudKit there. The one very good course I worked through uses Combine but CloudKit offers methods for Swift’s “new” async/await as well. My knowledge of Combine is now larger than ever but I don’t want to go ahead and start building apps with something I feel like will be looked at as outdated code very soon.

There’s hope though. Because I don’t have anyone to pester with questions, I have to rely on good online content. That’s why I’m going to have a look at Firebase. A user friendly SDK and a shitton of noob friendly tutorials might be a better experience for my database needs for now.

Stay tuned for more database related adventures.

December 4, 2022

Playing with APIs

After working through a whole bunch of very insightful videos about concurrency in Swift and SwiftUI I needed something to test my newfound knowledge with. Listening to somebody explain something is always easier than implementing the knowledge yourself.

Here’s the result of part of my weekend. An app that doesn’t do much but what it does happens as asynchronously as possible. It’s hooked up to the Google Books API which means it downloads data from some server somewhere! How cool is that?! I even got to use Combine to debounce the search field.

November 27, 2022

All your databases are belong to us

Currently I’m spending most of my programming time learning new things instead of actually building something. My next project should include technology I don’t know anything about yet. I’d love for it to be something that’s online.

Building little apps that store data on your device is cute and everything but for me the magic lies in stuff being on the internet. Unfortunately I don’t yet know anything about how databases work.

character design, happy programmer sitting in front of computer, 8k, octane render, extreme detail, cinematic lighting –v 4 – Midjourney

I stumbled upon Swiftful Thinking, a YouTube channel explaining Swift and SwiftUI topics in a way that resonates very well with how I learn. His videos taught me that CloudKit is exactly what I was looking for. Who would have thought that that’s a database solution from Apple that I’m already paying for? I know how to connect an app to CloudKit, how to put data in a database and how to fetch it again. I even know what CRUD stands for. Look at me, knowing my acronyms.

Continue reading “All your databases are belong to us”
November 22, 2022

The app status of Stoins has changed to Pending Developer Release

Would you look at that. Henlo got rejected a bunch of times and it seems I learned a few things in the process. Very unintuitive things like “Even though there’s a dedicated input field to link to the privacy policy you better put the same link in the description of the app or you might get rejected”.

Stoins will be released tomorrow!

November 21, 2022

Stoins is waiting for review

I did it. Stoins is ready to be pushed out the door. I don’t expect it to get through review without a few resubmissions but that’s just part of the game. 🤞

November 17, 2022

Lost in Localizable.strings

Update: Somebody actually solved my issue. Internet is great. Scroll down to see how this is fixed.

When I wrote about the couple of problems I don’t know how to solve in Stoins, I didn’t anticipate to quickly run into the next one. Stoins is supposed to be available in English and German. With English as the default, I set out to add German translations and watched a couple of tutorials on how to do so.

It’s relatively straight-forward.

  1. Create a Localizable.strings file for every language you want
  2. Xcode finds all translatable strings automatically and you translate them one by one
  3. Done

Unfortunately that’s not exactly how it went. Most strings were found, sure, but those outside of Text() views weren’t and I don’t understand why or how to force Xcode to translate them.

An example

Take everything with a grain of salt. I don’t know what I’m doing. I’m that much of a beginner that we can just accept the fact that literally anything I do can be done in a better way. For now my main goal is for stuff to just work. I don’t want to win any prizes for great code. Yet.

This is an object in Stoins. It’s the blueprint for an achievement:

struct Achievement: Identifiable {
    let id = UUID()
    let name: String
    let description: String
    let image: String
    let badge: String
    
    var conditionAchieved: (() -> Bool)
}

I have an array of objects like this that I use to create the interface. The array looks a little like this:

@Published var achievementsStreaks = [
        Achievement(name: "Fortnight", description: "Have a 14 days streak", image: "badge_fortnight", badge: "badge_fortnight.gltf") {
            var result = false

            // Code that defines if 'result' is true or false

            }
            return result
        },
        
        // Second Achievement
        // Third achievement
        // etc
]

(I’m a bit proud of my use of closures here, ngl. They were very brain-breaking for me and now I’m able to use them without hurting myself in confusion.)

So far, so good. All of this works surprisingly well in terms of how the app is supposed to behave. The only remaining problem is that I can’t seem to figure out how to localize the name and description. Xcode doesn’t manage to automatically find the name and description attributes and when I add them manually to Localizable.strings nothing happens.

I thought I found the answer in this WWDC video about localization in SwiftUI but using LocalizedStringKey only works for views not structs, it seems.

For now I’ll leave it as it is. Only the about screen and achievements are affected which means it’s not an app-breaking issue for those who don’t speak English. Not great. Not terrible. A solid 3.6.

Still, I’d love to publish an update to this post where I explain how somebody helped me solve this and how it was a very easy fix. If that’s you, hit me up. There’s a very cozy comments section down below.

Update: As expected the answer to this couldn’t be more easy, I just wasn’t able to find it. Thanks Philipp for pointing me to this article. And thanks Bei Li! Every user facing string needs to be wrapped in String(localized:""). That’s it. Everything works now. lol.

November 16, 2022

Manufactured motivation and perfectionism

The hardest thing about learning to code is when my ingrained software-design-perfectionism clashes with what I’m able to do. Stoins is going great. I’d say it’s an above average app for somebody who just started coding. Yet I can’t wrap my head around the solutions to some of the problems I’m facing and I struggle with accepting flaws that are solely there because I’m not good enough yet.

Everything works, don’t get me wrong. It’s just not as good as I know it could be. I think a better understanding of concurrency could solve one of the problems. Perhaps a second problem would go away with more knowledge about threads. Oh and something, something state machines? I just don’t understand any of it enough to solve my app’s bugs.

Here’s the thing though: Motivation doesn’t come and go by some magical whim of fate. Motivation is something you create. I know that my motivation is heavily influenced by progress. I tried fixing these issues for so long without getting anywhere that I’m at a point where I need to accept that those are flaws I need to live with. It’s my second self-coded app ever, of course it has problems.

I’m sure my next project will teach me some of the things I need to learn to come back to Stoins and fix it. A cycle of learning through manufactured motivation and not giving in to perfectionism.