DEV Community

kels0la
kels0la

Posted on

Coding Experience Reflection and Demo: Building a “Social Media Micropayments Platform” — Phase 1

Introduction

This “coding experience reflection” should’ve been written months ago, but if you’ve ever coded something intended for production before, you probably understand. Tinker with this, add that; optimize this, configure that; fail here, and finally succeed there. Coding is full of ups and downs, and no matter the task, it always seems to take longer than you initially expect.

But even if I’m a little late to the celebratory reflection writing, I still feel very accomplished with this third iteration of my coding career. Before we get into that though, let me briefly get you up to speed.

In case you haven’t read any of my Medium.com “BitcoinOptimist” coding blog posts, I enrolled in a 6-month “full-stack developer boot camp” a few years back. After completing the boot camp, I worked on a group project with a few other guys for a couple months, but even after that, I still felt overwhelmed. I relied on the guru of the group for almost everything and I suffered from imposter syndrome at its worst. Welcome to coding iteration number one.

To improve my skills, I challenged myself and decided to build the dice game Yahtzee from the ground up, without any help from others. Just self-conducted research, documentation, and my own brain power at my disposal. (What a scary thought that was at the time.)

Eventually, the logic came together for a smooth, bug-free Yahtzee game. After the fact, I felt much more comfortable with React, and my JavaScript knowledge improved considerably too. Especially great, considering these were the two main goals of the project and the “languages” I believed any aspiring front-end developer should know. Coding iteration two was a success.

Third Iteration Experience

And now that the obligatory catch-up is over, we can continue with the third iteration of my coding journey: Laying the groundwork for my micropayment-based, social media applications.

The basic goal of this iteration was to build a MERN stack app (Mongo, Express, React, Node) with CRUD functionality and a high quality UI/UX (User Interface and User Experience). Something we did before as a group, but never on my own.

First thing first was to design my Database Schemas, setup my React Router with boilerplate Page components, and add an Accordion Navbar. (At the time, I was obsessed with getting an Accordion Nav to work, but in the end, I only used it on mobile and my FAQ page. It didn’t make any sense on desktop.)

On deck after that was setting up Tailwind.css configuration. When working as a group we integrated Tailwind with our project, and I fell in love (and got comfortable) with it then. It gives you full control over customization — unlike Bootstrap or Materialize — and the classes are quite easy to remember. Sure, you have to do the flexbox and mobile-friendliness stuff yourself (it’s much easier than media queries though), but the benefits outweigh the drawbacks, especially if you want to have total control over your .css like I do. Kudos to its creator, Adam Wathan.

With the pages setup and the Accordion working, it was time to take what I learned from Net Ninja’s React Redux tutorial video series and apply it to my application for some light/dark mode toggling. You can’t have a website without it in this day and age, ya know.

Getting comfortable with Redux was a challenge, but I’m glad I decided to tackle it and use it as my overall state management system. Looking back at it though, if I did my light/dark mode differently, I would probably use .css variables instead, as I think they would jive better with some 3rd party package’s I used. But overall, I’m content with the decision to use Redux for this “integral” website feature. (I mean, I know Redux after all…)

Then along came frontend forms hooked-up to state, to Express communications from Axios, to Mongo queries sent back to the front-end, to results.data getting set as state, to that state magically appearing before your eyes. At least that’s what happens when a user creates a post, anyway.

Now if you asked me to describe this data sending and retrieval process before this iteration, I probably would have bumbled and fumbled through the explanation, but now, I feel like my grip is tight and strong.

From the front-end, I can configure the http routes and pass params and data to the backend routes and controller, where I can then retrieve and use the data to trigger specific queries via MongoDB. Queries which were intimidating to learn at first, but pretty straightforward to understand once you begin implementing them. I suppose it helped that Mongo’s documentation is excellent as well.

Mongo’s documentation was also quite helpful during the next task: Adding comments to posts and displaying them on the page. A must have for any social media-like application.

Once I figured out how to use Mongoose’s ObjectID to tie comments to a parent post, I was well on my way to completing this task. With a few well-placed console.logs on my front-end, I was able to get the comment data to display pretty quickly.

But that was the easy part and the next part took me much longer to get just right. That is, setting up a tier two commenting system — like YouTube or Facebook’s — where users can reply to a specific comment, and split off to create what you could consider a “side conversation” from the actual post itself.

This took quite a few coding sessions and iterations to get just right, but once I did, something great happened. My coding confidence level had grown, and I felt quite comfortable using Mongo as a database. It was a groundbreaking moment for me and I was quite proud at the time.

With this newfound confidence in Mongo, I decided to add a few other cool features. I added the ability to “Thumbs Up” a post or comment — which you can think of as a “Like” on Facebook — and increment each Thumb to the post or comment itself. In addition, I also added the functionality to capture a “View” for a post, and add that to the database too. Another social media application necessity I could cross off the to-do list.

As far as calculating the views went, I discovered YouTube increments theirs when someone sits on the page for longer than 30 seconds, so that’s what I decided to implement too. The code for that was pretty simple. Just add a setTimeout function for 30 seconds after the content is loaded on the page, and trigger the database call when it is reached. But after some testing, I realized the function triggered even after leaving the page, so that’s when I had to learn a little more about React’s Lifecycle Methods. I would need to know more than just componentDidMount going forward.

After reading through some documentation, I tried adding the componentWillUnmount method with a clearTimeout function inside of it. Once I did, viola! The view incrementing machine was working properly and bug-free, the way it ought to be.

To touch on the subject of “bugs,” because of this experience, I think about them a little differently now. I used to think of bugs as inherently bad, but I realized they’re just the label you use when a built-out functionality doesn’t work 100% as intended yet. To me, “bugs” are now part of the building process, rather than something, “OMG! ANYTHING BUT THAT!” awful.

I mean, when building something complex, even if you do your best pseudo-coding and try to take into account every angle of your application, it’s still highly unlikely you’re going to get it right and “bug-free” immediately. You listen to what the bug has to say, figure out why it’s behaving that way, and use that information to code it away. It’s all a part of the building process and it shouldn’t be perceived as something bad. (Unless you let it survive and go into production, of course.)

To get back on course, my next task was again with Mongo. I needed 4 queries to sort posts based upon [1] the category the post was assigned to, [2] different time-based parameters, and [3] the number of Thumbs a post received. In other words, when a user clicked on a category, only posts assigned to that category would appear, and they would be sorted by the number of Thumbs the post received, with the greatest being at the top (obviously). The time-based parameters would be the most Thumbs received within the past 36 hours, week, and all-time. The 4th sort would be the most recent posts, which was pretty easy considering Mongo does that straight out-of-the-box.

For the most part, this was a breeze. It only became challenging once I needed to add Pagination to the fold. (If you’re not sure what Pagination means, it’s pulling say, 20 posts from the database at first, then after a user clicks “View More” or the “Next Page” button, 20 more posts are pulled from the database and displayed on the screen.)

Before diving into that task though, I needed to do some research. I read a handful of “how-to” articles on the subject and watched a few YouTube videos as well (Traversy Media & Web Dev Simplified if I remember correctly). With that knowledge at hand, I successfully implemented pagination in my application. Yeah, it took a while to wipe away all the bugs, but eventually, my localhost’s windshield was clear.

The most challenging part of this pagination process actually came from React and not Mongo. Because I am an accountant by degree, I didn’t want any repetitive, unnecessary calls made to the database. That costs money. Well, if you clicked on one query, then another query, and went back to the first query, the same database call would be made again. The application did not consider the previous results. (I guess you could call that a bug.)

So, when a user clicked on a different query and came back to one they already selected, I added a check to see if the selected query array had saved posts or not, and wired it to NOT trigger a database call if it did. In addition, when a user clicked “View 20 More Posts” I tacked on the new results to the selected query array. In the end, my state saved all posts retrieved from the database, and only triggered a database call when more were ACTUALLY needed. A cost saving measure I continue to look at fondly.

But the time spent completing this task ended up being somewhat in vain. A week or two later, I realized a Social Media application should have Infinite Scrolling pagination and not this antiquated pagination method I had just implemented. Essentially, I needed to rewire everything I just did, which was not an easy pill to swallow at the time.

After hours upon hours of tinkering away at this task, I eventually got what I wanted: A pagination system like Facebook, Twitter, and other Social Media applications. The kind where as you get to the bottom of your post list, more “magically” appear beneath them. You know, the kind where you can scroll through your phone forever and ever and ever, until there’s nothing in the database left to retrieve. In the case of Facebook, that may just be never.

Currently, this task stands as both my most challenging, as well as my favorite. The reason it was such a challenge was because the Web Dev Simplified tutorial taught it using React Hooks, and my application is built using React Class Components. Thus, I had to figure out how to make it work with a different state management system. Then to increase the difficulty further, you also need to use a different kind of ‘Ref’ for class components over functional components, and this complication was one I discovered only midway through… But like I said, eventually I figured it out, and once I did, it became my proudest coding accomplishment to date.

(Note: Hooks didn’t exist when I first started coding, and when I did try to implement them for something, the state within the Hooks component would re-render when light/dark mode was toggled. I had enough on my plate at the time, so I just stuck with what worked and what I already knew.)

At this point, I completely shed my imposter syndrome skin. I finally had my coding confidence and I no longer felt intimidated by any task set before me. I felt like I could learn to code anything, and once that feeling took full effect, I realized the visions for my micropayment platforms would eventually be realized. When I started, I wasn’t so sure, but now, I knew.

But I digress. Let’s get back on topic now with one of the most important decisions I had to make along the way: Deciding which Rich Text Editor (RTE) to implement.

(Rich Text Editor’s enables users to add formatting to their posts, like bold or italics, and to embed links or share videos from YouTube.)

In the group project from the past, we used Draft.js as our RTE of choice. I did like it, but there were a few things I didn’t care for from a design perspective, and because people couldn’t use it on mobile. After doing plenty of research, I came across CKEditor, which seemed to be the most robust and customizable editor on the market. So I went with that.

To be totally honest, with tons of options and high customizability, implementing CKEditor was far more challenging than implementing Draft.js — and far more challenging is putting it lightly. If you want that customizability like I do, it’s not as simple as downloading an NPM package to your repo and importing it into your component. It’s much more complex than that. It includes forking into its own repo, learning the steps to “build” the editor, updating your actual project’s package.json after updates, and a plethora of other different things you need to learn that aren’t completely obvious. The learning curve is steep with this one.

But when the other options don’t fulfill your needs and this one does, you go through the mental taxing and time it takes to figure it out. In the end, it works exactly as intended, and I can safely say I know my way around it now. (Sure took long enough…)

With the Editor implemented, posts properly paginating, and my core functionality built out, I had mostly minor tasks left ahead of me before phase one would be complete (or so I thought). Here are some of the ones worth mentioning.

  • Using localStorage to save a user’s preferences
  • Adding a CancelToken to certain Axios routes in case data isn’t retrieved yet when a user exits a component
  • Using post “slugs” rather than ID’s in the browser to aid in link sharing
  • Adding Tooltips and visually-appealing transitions to various parts of the application
  • Adding Social Media Share Buttons to posts
  • Creating different views for the post lists via conditional rendering

Also worth mentioning are the validation and protection measures I added to the application. To “sanitize” and filter potentially malicious data from entering the database and appearing on a user’s browser, I implemented an NPM package called ‘dompurify’ to my Post Schema. Basically, through a pre-validation function, the package goes through the data before it enters the database and removes the bad stuff if it exists. It defends against things like XSS injections and so forth.

To also defend against improper use, I wrote some validation measures on both the front-end and back-end at the recommendation of a friend. This way, if someone tries to add something to the database with or without the UI (using Postman for example), they’ll receive an error if it doesn’t live up to the measures. Why is this important? Because it’ll goof up how the data looks on the front-end, and I certainly don’t want screenshots of my platform looking broken. I’ll pass, on being made a mockery of.

When it comes to accidental errors on the frontend from well-intentioned users, though, I’ve added prompts to fix the fields where the error exists, and make them disappear immediately when the correction is made. I thought about using an NPM package for this, but I decided to just code it in myself.

I did use an NPM package called ‘react-toastify’ to communicate important notifications to a user when an action is made: Positive actions such as creating a post or adding a thumb, and negative actions such as receiving an error. The “toast” notification pops on the screen for 3 seconds to share the information with the user, and then goes away. Kind of like a one-lined, timed modal. It’s pretty cool.

Also pretty cool was the end result of implementing the ‘Codemirror’ NPM package. What Codemirror does is gives developers an easy way to add coding snippets to an application. If you’ve ever been to codepen.io before, that’s Codemirror at work. Well, since one of the main interests of users on my platform is coding, I created a category called “Code Share” for them, so this snippet generating package was exactly what I needed. And thankfully, it was a million times easier to integrate than CKEditor — my second biggest headache to date.

My worst headache to date came while working with “Cloud” technologies. Non-coding things like Hosting & DNS, Cloud Database configuration, SSL Certificates, CORS, etc. Code issues are easily solvable; non-coding technology issues are a whole different beast.

The first pain in my head came while setting up and configuring Mongo Atlas (the cloud database for MongoDB). I watched a ‘Traversy Media’ YouTube tutorial on the subject, and it seemed pretty easy, but I just couldn’t get it to sync with my application. I tried a bunch of different things and scoured stackoverflow.com for possible solutions, but I came up empty and dejected each and every time.

I told my coding buddy Meng about my troubles, and since he had successfully integrated Atlas before, he offered to take a look at it with me via Microsoft Teams. About an hour into our session, we (he) figured out my connectivity issue by using the Network tab as his debugger, and we quickly came across the second hiccup after that. As embarrassing as it is to say, Mongo pluralizes collection names, and I forgot to reflect that when I set it up. (Oops)

The cool takeaway from this Teams session was Meng’s use of the Network tab for debugging purposes. Based upon the error received in the tab, it gave him a clue to what the problem really was — just like console.logs on the front-end. This was eye-opening to me, because I had no idea how to tell if one thing was connected to another (other than it just working) or how to debug networking issues like this. Heck, I didn’t even know this was a networking issue in the first place, but thankfully this set the record straight. (Thanks Meng, I would probably be stuck on it still if it weren’t for you).

Once I had Atlas working on my localhost, I pushed the changes to production to test them out at my actual domain. (The domain is hosted by Google’s Firebase, which gives you an SSL certificate automatically. Take a mental note of that one.)

ERROR. No dice. The application tried to retrieve the documents from Atlas, but they couldn’t come through. A CORS ‘Access-Control-Allow-Origin’ error was getting in their way. GREAT. Time for more stackoverflow research on a “web-based” subject matter I knew nothing about. And to make matters worse, this time Meng couldn’t offer any advice.

Well, I studied and studied and studied, and tried everything I could possibly try. I added the CORS NPM package and integrated it how all the stackoverflow people described, and I tried setting the headers to enable the ‘Access-Control-Allow-Origin’ from anywhere (*) as well. I reached a point where I didn’t know what to do, so I e-mailed Firebase and awaited their reply.

A few days later, they directed me to some documentation that came from Google Cloud Platform (GCP) and a stackoverflow link that discussed adding configuration to an app.yaml file. I set up the file and the error remained, so I continued my research and realized even though I was using Google’s Firebase, I need to add the Google Cloud Platform SDK for the app.yaml file to work. It seems stupid now, but how was I to know?

But even after setting up GCP and trying different things within the app.yaml file, the same error persisted. Until one morning, all the sudden, it was working. I was in shock.

I was in shock because the last change I made was removing EVERYTHING within the app.yaml file and deploying the latest changes to GCP. It made no sense to why it was suddenly working, but I was ecstatic that it was. I could finally move on from this extremely annoying setback.

From there, I only had a few more design changes to make before I could begin writing this reflection and creating the demo. I made my final changes and pushed them to production, only to find inconsistencies with the SSL certificate and the build version being displayed.

On my desktop with Chrome, after multiple refreshes, the SSL certificate was there and the latest updates existed. On my phone, the SSL certificate never showed up in the first place. On my friend’s desktop with Safari, the SSL certificate was there, but the changes weren’t reflected. With Microsoft Edge, the SSL certificate didn’t exist, but the latest changes were there (after a few refreshes). I really didn’t know what to make of it at the time.

Once I had some time to reflect and collect my thoughts, I decided to try a few things out. Since I added GCP’s DNS information to my domain provider while setting it up, I decided to get rid of Firebase’s DNS info and give that a try. Once I removed it and deployed a new version of my application to GCP, I noticed the SSL certificate was gone from everywhere. The latest update took effect, but the SSL certificate was nowhere to be found.

This really wasn’t too surprising since Firebase’s servers were no longer pointed at my domain anymore, and they were the reason I had the SSL certificate in the first place. But it was frustrating because I knew it was another thing I needed to deal with.

Hoping to avoid the problem, I decided to add Firebase’s DNS info to my domain provider and remove GCP’s. I just prayed like mad that my CORS error wouldn’t reappear. But surprise surprise there she was again. Access-Control-Allow-Origin and all. That’s when I realized removing everything from my app.yaml wasn’t what fixed the problem in the first place. It was using Google Cloud Platform DNS info instead of Google’s Firebase that did. (You can remove the mental note now.)

Well, I spent a couple large blocks of time looking into SSL certificates and how to get one, and what I discovered is that it was going to cost me. A free one wasn’t going to happen anymore.

Well, this expense will be inevitable, but I’m holding off for now since the final product isn’t ready anyway. So if you go to bitcoinoptimists.com between then and now, don’t be surprised when you don’t see one! (Don’t worry, I’m not asking for your credit card information or Social Security # anyway)

The Learning Process
Now that I no longer suffer from imposter syndrome, I would like to share some advice that helped me get there, for those that are suffering from it now.

For starters, nothing is more important to your learning process than actual experience. That advice is tried and true, and putting that into action means setting aside chunks of time and actually doing the deed. Pick a project, give it your full attention, and code it. (If you’re up for it, make it CRUD-based). Keep coding away at it with new addition after new addition, but make sure to take it one step at a time. Don’t get ahead of yourself; you’ll feel overwhelmed if you do.

Secondly, if you’re not yet very confident with your skills, continue expanding your knowledge on something you already know, or focus on getting better at one particular thing. I chose to focus on learning as much as I could about JavaScript & React, and that has helped me out immensely.

When it comes to keeping yourself grounded with “one step at a time,” my recommendation is to start a word doc and do two things with it:

[1] Keep a list of each coding task you complete (it feels GOOD when you do)

a. Added light/dark mode to Redux

b. Successfully integrated ‘codemirror’ NPM package

c. Etc.

[2] Write down and “talk out” each coding task you start

If I hadn’t “talked out” each coding task with myself in a word doc, I don’t think I would be where I am today. I would probably be stuck. But when I ran into walls, I would start writing down questions I didn’t know the answers to at that moment, and after “talking it out,” I eventually would come up with a solution. Sure, I “talked out” many things that didn’t work, but in the end, that trial-and-error process helped me get to the point where it finally did. When you’re stuck on something, start writing about it to yourself. It helped me, and I’m sure it’ll help you too.

Also incredibly helpful is just talking code with someone else. I built the entire thing myself, but I also had Zoom/Teams sessions with Meng where we would share what we built with each other, and the thought process we took to get there — as well as getting help or a different perspective when needed. Find someone you can talk the codes with; I promise you, you won’t regret it.

Aside from that, I do recommend reading lots of code and documentation and watching tutorial videos — those were also integral to my learning process — but my piece of advice there is to select content that you actually want to add to the application you’re building. I learned how to integrate the challenging Infinite Scrolling Pagination system because I was really motivated to include it within my application. Now watching a Python tutorial? Not unless I actually need it. (and I don’t yet, so I won’t yet)

The Future: Bringing the Social Media Micropayment Platform(s) to life

In my next coding iteration, I’m going to integrate the NPM package, HandCash Connect. With HandCash, I get micropayment capabilities and user accounts, which will enable me to tie payments to specific actions on the platform. Essentially, this will give users the ability to earn Bitcoin (SV) through tipping, $.10 thumbs, paywalls, and so forth.

Aside from this micropayments aspect, I’ve got a few other things in store. I will be…

  • Building a following function
  • Saving/Bookmarking posts by users
  • Adding paywall capabilities and keeping track of that data
  • Building a leaderboard of posts and users who receive the most tips
  • Adding an “Account” page to view public information about the users (and enable editing for the actual user)
  • And more

Once I do, I’ll be sure to share it with you over Social Media, so give ol’ kelsola a follow if you would like to remain in the loop. But for now, that’s a wrap.

If you would like to check out my YouTube demo video, you can find it here here: https://www.youtube.com/watch?v=LrONWCx3Hdc&feature=youtu.be

And the website itself: https://bitcoinoptimists.com/

Thank you for your time,

Sam

Top comments (0)