Writing

Logs of a Software Engineer | EP.2: JKOPay

文章發表於
...

Introduction

Last week, LinkedIn popped up a notification saying, "OOO liked your work anniversary." It suddenly hit me—it's been a full year since I joined the company. The journey has been filled with luck and growth, and I think it’s worth writing down.

If you haven’t read the first episode, check out Logs of a Software Engineer | EP.1: From Zero to One.

What I Learned This Year

Looking back at myself when I first joined the company—I was just someone who had done a few simple projects and had no idea what real software engineering or teamwork was like. That clueless version of me is still vivid in my mind. Honestly, even a year later, I still feel like I haven’t improved that much (maybe?).

In a fast-paced startup, there's rarely time to onboard newbies with hand-holding. Not long after joining the team, I was given my first real project. That experience forced me to grow quickly and taught me a lot. I'm extremely grateful to my manager for trusting me and to the challenging environment that pushed me forward.

Over the past year, I participated in four projects. Though none were massive in scale, the deadlines were tight, which was overwhelming for someone still learning the ropes. I ended up working overtime almost every day—came close to sleeping at the office. Here are some of the key lessons I’ve gathered:

Technical Skills

Modular UI Components

When I first started, I struggled a lot with UI development. Before joining the company, I had never worked with concepts like component reuse or CSS-in-JS, and I’d never even heard of Storybook—a tool that helps with component development and testing.

I still remember the first time I discussed API formats with a backend engineer. I panicked just because their variable names didn’t match what I had expected in the component. I even asked my manager, “What am I supposed to do now?”

Back then, I was used to building everything myself—from writing the API to consuming it. There was no concept of collaboration or standard processes. Honestly, I wasn’t even sure what my job was 🫥.

A year later, I helped build out our internal component library—from just 4 or 5 shared components to more than 20. I learned that a truly reusable and scalable component isn’t just about replicating UI—it requires deep communication with designers to understand the design logic and use cases. Once the final design is handed over, you need to write a flexible, extensible component and iterate based on actual usage feedback.

React & Redux

Our tech stack is React + Redux. In the beginning, I didn’t even know you could have multiple React.useEffects in a single component—or what a Custom Hook was.

When building my first project, I didn’t understand any of these patterns, so I dumped everything—UI, logic, data handling—into one giant file. It ended up being over 1,000 lines and completely unmanageable. My manager eventually reviewed the code and told me it was unusable—I had to rewrite everything from scratch. Worst of all, I dragged my manager into working weekends with me to get it done. Q_Q

Now, I’ve gained a better grasp of the React API and started considering performance and architecture in development. For example, I evaluate whether to use React.useMemo or React.useCallback for optimization, and I’m mindful of component re-renders to keep things clean and predictable.

I’ve also become proficient in managing complex, multi-step forms using React + Redux with Formik and Yup. This includes validation, state management, and error handling—all contributing to a smoother user experience.

Lately, I’ve been responsible for migrating a legacy MPA project to a SPA. This has deepened my understanding of the need for abstraction and modularity as a platform scales. Balancing flexibility with maintainability is something I’m currently focusing on and actively learning.

Code Quality

I used to write code with a “just make it work” mindset, with no real sense of software design principles. Looking back at code I wrote just a few months ago is painful—side effects everywhere, messy naming, poor readability, and barely extensible.

Now, I strive to write functions that are immediately understandable to reviewers. I’ve adopted functional programming principles to reduce side effects, improve abstraction, and make code more reusable and extensible.

In some projects, I also introduced testing workflows, practicing both TDD (Test-Driven Development) and BDD (Behavior-Driven Development). The benefit? You clarify product requirements and user flows up front, reduce basic bugs, and gain confidence during the testing phase.

Product Development Process

In software development, delays from any party can affect the whole schedule. This is especially true for frontend engineers, since we heavily rely on both design and backend deliverables. If everyone submits work at the last minute, frontend often bears the brunt.

So what do we do when the design isn’t finalized or APIs aren’t ready? We can’t afford to wait for everything to be perfect before starting development.

When design is still in progress, I’ll begin by drafting all page structures and user flows based on known requirements, and work closely with the project manager to validate the direction. If BDD is adopted, I’ll sync on feature specs and start building the layout prototype for early feedback.

If the API isn't done yet, I’ll ask backend engineers for a draft of the API spec. As long as I have a schema, I can use Mock Service Worker (MSW) to simulate API responses. This lets me test page behavior, response formats, and even error scenarios.

By the time design and mock APIs are finalized, I can quickly fill in the remaining logic and move everything to the testing environment for QA, keeping things on track.

Communication Skills

Effective communication drastically reduces misunderstandings between teams and is critical for timelines and alignment. For example:

  • When talking with the PM, I clarify realistic timelines and confirm whether the features match their expectations to avoid building the wrong thing.
  • When working with designers, I discuss feasibility, understand the logic behind designs, and ensure that our implementation meets their standards.
  • When integrating with backend or mobile teams, I clarify API or WebView function definitions to ensure smooth collaboration.
  • When reporting to my manager, I summarize progress, roadblocks, solutions, and strategic decisions clearly and concisely.

These situations all require continuous communication and coordination to ensure mutual satisfaction. I'm still learning how to convey information efficiently and empathetically in these collaborations. My goal is to handle communication challenges more smoothly in the future and make every partnership more productive.

Conclusion

When I joined a year ago, the frontend team was still in its infancy—just me and my manager. We didn’t have much of a dev culture yet. Everything from building projects to setting up Nginx and deployment pipelines had to be figured out through hands-on trial and error.

Yes, I fell into countless pitfalls and made countless mistakes. The pressure was real, and time off was rare. But solving problems with my own hands brought a level of fulfillment that's hard to describe. I’m deeply grateful to my manager and all the teammates who were always patient with my basic, beginner questions.

Today, our frontend team has grown to five strong members—each one incredibly skilled. I'm excited for what's ahead.

If you enjoyed this article, please click the buttons below to share it with more people. Your support means a lot to me as a writer.
Buy me a coffee